# $Id$ #################################################################################################### # # 44_TEK603.pm # # Copyright: Stephan Eisler # Email: stephan@eisler.de # # This file is part of fhem. # # Fhem is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # Fhem is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with fhem. If not, see . # #################################################################################################### package main; use strict; use warnings; use DevIo; use Digest::CRC; # libdigest-crc-perl sub TEK603_Initialize($) { my ($hash) = @_; $hash->{ReadFn} = 'TEK603_read'; $hash->{ReadyFn} = 'TEK603_ready'; $hash->{DefFn} = 'TEK603_define'; $hash->{UndefFn} = 'TEK603_undef'; $hash->{AttrList} = 'do_not_notify:0,1 dummy:1,0 disable:1,0 loglevel:0,1,2,3,4,5,6 ' . $readingFnAttributes; } sub TEK603_define($$) { my ($hash, $def) = @_; my @a = split('[ \t][ \t]*', $def); my $name = $a[0]; my $dev = $a[2]; $hash->{DEF} = $dev; my $msg = ''; if( @a != 3) { $msg = 'wrong syntax: define TEK603 {none | devicename | hostname:port}'; Log3 $name, 3, $msg; return $msg; } DevIo_CloseDev($hash); $hash->{PORTSTATE} = $hash->{STATE}; if($dev eq 'none') { Log3 $name, 3, "device is none, commands will be echoed only"; $attr{$name}{dummy} = 1; return undef; } $hash->{DeviceName} = $dev; my $ret = DevIo_OpenDev($hash, 0, 'TEK603_doInit'); return $ret; } sub TEK603_doInit($) { my ($hash) = @_; my $po = $hash->{USBDev}; my $dev = $hash->{DeviceName}; my $name = $hash->{NAME}; return if (IsDisabled($name)); # Wenn / enthalten ist ist es kein ser2net-Device, daher initialisieren if ($dev =~ m/\//) { # Parameter 115200, 8, 1, even, none $po->reset_error(); $po->baudrate(115200); $po->databits(8); $po->stopbits(1); $po->parity('none'); $po->handshake('none'); $po->dtr_active(1); $po->rts_active(1); if (!$po->write_settings) { undef $po; $hash->{STATE} = $name . 'Error on write serial line settings on device ' . $dev; Log3 $name, 3, $hash->{STATE}; return $hash->{STATE} . "\n"; } } Log3 $name, 3, "connected to device $dev"; $hash->{STATE} = 'open'; $hash->{PORTSTATE} = $hash->{STATE}; return undef; } sub TEK603_undef($$) { my ($hash, $name) = @_; foreach my $d (sort keys %defs) { if(defined($defs{$d}) && defined($defs{$d}{IODev}) && $defs{$d}{IODev} == $hash) { Log3 $name, 4, "deleting port for $d"; delete $defs{$d}{IODev}; } } DevIo_CloseDev($hash); $hash->{PORTSTATE} = $hash->{STATE}; return undef; } sub TEK603_ready() { my ($hash) = @_; my $name = $hash->{NAME}; return if (IsDisabled($name)); return DevIo_OpenDev($hash, 1, 'TEK603_doInit') if($hash->{STATE} eq 'disconnected'); # This is relevant for windows/USB only my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags); my $po = $hash->{USBDev}; if ($po) { ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status; return ($InBytes > 0); } # Someone set us up the bomb Log3($hash->{NAME}, 1, qq[Can't read from $hash->{DeviceName}]); # disable device Log3($hash->{NAME}, 1, qq[Disabled device due read errors]); CommandAttr(undef, $hash->{NAME} . ' disable 1'); return; } sub TEK603_read($) { my ($hash) = @_; my $name = $hash->{NAME}; return if (IsDisabled($name)); my $buf = DevIo_SimpleRead($hash); return '' if(!defined($buf)); # convert to hex string $hash->{buffer} = unpack ('H*', $buf); my $lenght = hex(substr($hash->{buffer},4,4))*2; #my $cmd = substr($hash->{buffer},8,2); #my $flags = substr($hash->{buffer},10,2); my $time = sprintf '%02d:%02d:%02d', hex(substr($hash->{buffer},12,2)), hex(substr($hash->{buffer},14,2)), hex(substr($hash->{buffer},16,2)); #my $epromStart = hex(substr($hash->{buffer},18,4)); #my $epromEnd = hex(substr($hash->{buffer},22,4)); my $payloadlenght = $lenght - 26 - 4; my $payload = substr($hash->{buffer},26,$payloadlenght); my $crc = substr($hash->{buffer},26 + $payloadlenght,4); my $ctx = Digest::CRC->new(width=>16, init=>0x0, poly=>0x1021, refout=>0, xorout=>0); $ctx->add(pack 'H*',(substr($hash->{buffer},0,26 + $payloadlenght))); my $digest = $ctx->hexdigest; return '' if($crc ne $digest); # payload my $temp = sprintf '%.2f', ((hex(substr($payload, 0,2)) - 40 - 32) / 1.8); my $Ullage = hex(substr($payload,2,2)) * 256 + hex(substr($payload,4,2)); my $RemainingUsableLevel = hex(substr($payload,6,2)) * 256 + hex(substr($payload,8,2)); my $TotalUsableCapacity = hex(substr($payload,10,2)) * 256 + hex(substr($payload,12,2)); return '' if($temp eq "-40.00" && $Ullage eq "0"); # TankLevel=NO_DATA # Calculations my $RemainingUsablePercent = round($RemainingUsableLevel / $TotalUsableCapacity * 100,01); #Log3 $name, 5, $hash->{buffer}; Log3 $name, 5, "Time:$time Temp:$temp Ullage:$Ullage RemainingUsableLevel:$RemainingUsableLevel RemainingUsablePercent:$RemainingUsablePercent TotalUsableCapacity:$TotalUsableCapacity"; readingsBeginUpdate($hash); readingsBulkUpdate($hash, "Time", $time); readingsBulkUpdate($hash, "Temperature", $temp); readingsBulkUpdate($hash, "Ullage", $Ullage); readingsBulkUpdate($hash, "RemainingUsableLevel", $RemainingUsableLevel); readingsBulkUpdate($hash, "RemainingUsablePercent", $RemainingUsablePercent); readingsBulkUpdate($hash, "TotalUsableCapacity", $TotalUsableCapacity); readingsEndUpdate($hash, 1); } sub TEK603_reconnect($) { my ($hash) = @_; my $name = $hash->{NAME}; Log3 $name, 3, "Wrong Data received. We reconnect Device"; # Sometime the device sends a lot of waste and we must reconnect. DevIo_CloseDev($hash); $hash->{PORTSTATE} = $hash->{STATE}; select(undef, undef, undef, 0.1); DevIo_OpenDev($hash, 0, 'TEK603_doInit'); } 1; =pod =item summary devices communicating with TEK603 =begin html

TEK603


=end html =cut