#!/usr/bin/perl # simple read operation against waterkotte 8126 # (c) 2008 lintenhofer@inode.at use strict; use Device::SerialPort; use DBI; use Proc::Daemon; use Proc::PID::File; use Mail::Sendmail; use POSIX; #use Term::ANSIColor qw(:constants); #use Data::Dumper; my %MySQLParams = ( 'databasehost' => 'gorm.flake', 'database' => 'haus', 'databaseuser' => 'root', 'databasepwd' => 'xs4R00t' ); my %SMTPParams = ( smtp => 'gorm.flake', To => 'philipp@gorm.flake', From => 'wp@gorm.flake', Subject => 'WP-Ausfallsmeldung !!!', Message => ''); my $logfile = '/home/philipp/logs/wp_polld.log'; my $xmlfile = '/home/philipp/logs/wp_data.xml'; my $sms_send = '/home/philipp/bin/relaySMS2Gorm.sh +436646221039'; use constant TYPE_UNDEF => 0; use constant TYPE_DATE => 1; use constant TYPE_TIME => 2; use constant TYPE_DATETIME => 3; use constant TYPE_DEC => 4; use constant TYPE_FLOAT1 => 5; use constant TYPE_FLOAT3 => 6; use constant TYPE_BIN => 7; use constant TYPE_BOOL => 8; use constant TYPE_SPECI => 9; our (%yield,%wp_memory,$currErrorBuffer); $currErrorBuffer = 0; require('/home/philipp/bin/wp/WPmemaddr.pl'); require('/home/philipp/bin/wp/WPhelperfunctions.pl'); ##################################################################################################### ##################################################################################################### # main # MAIN: { Proc::Daemon::Init(); if (Proc::PID::File->running(dir => '/tmp')) { exit(0); } ################################################################################ open(STDOUT, ">>$logfile") || die "failed to re-open STDOUT to $logfile"; open(STDERR, ">&STDOUT") || die "failed to re-open STDERR to STDOUT"; ################################################################################ $SIG{INT} = $SIG{TERM} = sub { print "stopped at ".localtime(). "\n=================================================\n"; $::exit = 1 }; ################################################################################ ################################################################################ ################################################################################ print "started at ".localtime()." with PID ".$$."\n"; while (1) { my @comdump; if (my $serial = Device::SerialPort->new("/dev/ttyr00",0,'/tmp/wp_op.lock')) { # $serial->baudrate(9600); # $serial->parity("none"); # $serial->databits(8); # $serial->stopbits(1); # $serial->write_setting || undef $serial; # read 374 (0x176) bytes from address 0x0000 if (($serial->write("\xff\x10\x02\x01\x15\x00\x00\x01\x76\x10\x03\x79\x2c\xff"))==14) { sleep 1; my ($count,$data) = $serial->read(512); if($count > 10) { for(my $i=0; $i < length($data); $i++) { @comdump[$i] = ord(substr($data,$i,1)); } interpretData(0x0000,0x0176,@comdump); @comdump = (); if (scalar(%yield) > 0) { if (!write2MySQL(%MySQLParams)) { if (open(XML,">>$xmlfile")) { print XML createXML(); close(XML); print STDERR (localtime().": could not write to database, saved data to $xmlfile\n"); } else { print STDERR (localtime().": could not write XML to $xmlfile\n"); } } alertonErrors(%SMTPParams); } } else { print STDERR (localtime().": received less/equal than 10 bytes\n"); } } else { print STDERR (localtime().": error writing to rs232\n"); } %yield = (); $serial->close() || print STDERR (localtime().": close failed\n"); } else { print STDERR (localtime().": open failed\n"); } if ($::exit) { exit; } else { sleep 59; } } ################################################################################ ################################################################################ } ##################################################################################################### ##################################################################################################### # functions # ##################################################################################################### # interpretData(): # - interpret data bytes of frame # - pushes results to %yield # sub interpretData { my ($startaddr,$readBytes,@comdump) = @_; my @data = fetchFrameData(@comdump); # check size of data-chunk (frame minus header/trailer) if ($readBytes == scalar(@data)) { while (my ($currKey, $currAttr) = each(%wp_memory)) { if (( $currAttr->{addr}>=$startaddr) && ($currAttr->{addr}<($startaddr+$readBytes)) && ($currAttr->{type} != TYPE_UNDEF)) { my ($currVal,$arrIdx); for(my $offset=$currAttr->{addr};$offset<($currAttr->{addr}+$currAttr->{bytes});$offset++) { # attention: offset of address is only equal to index of array if $startaddr == 0! $arrIdx = $offset-$startaddr; $currVal .= sprintf("%02x",@data[$arrIdx]); } if ($currAttr->{type} == TYPE_DEC) { $currVal = hex($currVal); } elsif ($currAttr->{type} == TYPE_FLOAT1) { $currVal = hex2float1($currVal); } elsif ($currAttr->{type} == TYPE_FLOAT3) { $currVal = hex2float3($currVal); } elsif ($currAttr->{type} == TYPE_DATE) { $currVal = sprintf("%02d-%02d-%02d",hex(substr($currVal,4,2)),hex(substr($currVal,2,2)),hex(substr($currVal,0,2))); } elsif ($currAttr->{type} == TYPE_TIME) { $currVal = sprintf("%02d:%02d:%02d",hex(substr($currVal,4,2)),hex(substr($currVal,2,2)),hex(substr($currVal,0,2))); } elsif ($currAttr->{type} == TYPE_DATETIME) { $currVal = sprintf("%02d.%02d.%02d,%02d:%02d:%02d",hex(substr($currVal,6,2)),hex(substr($currVal,8,2)),hex(substr($currVal,10,2)),hex(substr($currVal,4,2)),hex(substr($currVal,2,2)),hex(substr($currVal,0,2))); } elsif ($currAttr->{type} == TYPE_BIN) { $currVal = sprintf("%08b",hex($currVal)); } elsif ($currAttr->{type} == TYPE_BOOL) { $currVal = (hex($currVal)==1)?1:2; } elsif ($currAttr->{type} == TYPE_SPECI) { if ($currAttr->{menu}=='00.02') { $currVal = '3.2.3.1'; } } #print GREEN $currKey." (".$currAttr->{menu}.") -> ".$currAttr->{addr}." (".$currAttr->{bytes}.") => ".$currVal."\n"; $yield{$currAttr->{menu}} = {'desc' => $currKey, 'val' => $currVal}; } #else #{ #print RED $currKey." (".$currAttr->{menu}.") -> ".$currAttr->{addr}." (".$currAttr->{bytes}.") => N/A\n"; #} } } else { print STDERR (localtime().": dataframe size (".(scalar(@data)).") not equal to read bytes (".$readBytes.")\n"); foreach (@data) { printf (STDERR "%02x ",$_); } print STDERR "\n"; return 0; } } ##################################################################################################### # write2MySQL(): # - persist all data to mysqldb # sub write2MySQL { my %params = @_; my $sql = "INSERT INTO wp_data ("; $sql .= "tsp_0501_0500,"; foreach (sort keys %yield) { my $menuentry = $_; $menuentry =~ s/(\d\d)(\.)(\d\d)/m_$1$3/; $sql .= $menuentry.","; } chop($sql); $sql .= ") VALUES ("; $sql .= "unix_timestamp('".%yield->{'05.01'}->{'val'}." ".%yield->{'05.00'}->{'val'}."'),"; foreach (sort keys %yield) { $sql .= "\"".%yield->{$_}->{'val'}."\","; } chop($sql); $sql .= ")"; if (my $dbh = DBI->connect("DBI:mysql:".%params->{'database'}.":".%params->{'databasehost'},%params->{'databaseuser'},%params->{'databasepwd'})) { my $sth = $dbh->prepare($sql); my $returncode = 1; if (!$sth->execute) { print STDERR (localtime().": ".DBI->errstr."\n"); $returncode = 0; } $sth->finish; $dbh->disconnect; return $returncode; } else { print STDERR (localtime().": error connecting to database\n"); return 0;} } ##################################################################################################### # alertonErrors(): # - check Di-Buffer for errors and create mail and sms # # sub alertonErrors { my $DiBuffer = %yield->{'09.02'}->{'val'}; $DiBuffer = sprintf('%d', oct("0b$DiBuffer")); my @errors = ('Störung Kompressor/Öldruck','Störung ND-Pressostat','Störung HD-Pressostat','Störung Pumpe WQ','Systemdruck min','frei','externe Sollwertbeeinfl.','externe Abschaltung'); if (($DiBuffer & 0xDF)&&($currErrorBuffer ne %yield->{'09.02'}->{'val'})) { $currErrorBuffer = %yield->{'09.02'}->{'val'}; my $SMSMsg = ''; for(my $i=0;$i<8;$i++,$DiBuffer>>=1) { if(($i!=5)&&($DiBuffer & 0x01)) { $SMTPParams{Message} .= @errors[$i]."\n"; $SMSMsg .= @errors[$i]." "; } } # send sms system("$sms_send 'Ausfall Wärmepumpe: ".$SMSMsg."'"); if (sendmail(%SMTPParams)) { print STDERR (localtime().': Di-Buffer = '.$currErrorBuffer."\n"); } else { print STDERR (localtime().': '.$Mail::Sendmail::error); } } else { $SMTPParams{Message} = ''; } }