diff --git a/fhem/contrib/98_WKRCD4.pm b/fhem/contrib/98_WKRCD4.pm
index 5434bca41..7ee70efc5 100644
--- a/fhem/contrib/98_WKRCD4.pm
+++ b/fhem/contrib/98_WKRCD4.pm
@@ -3,33 +3,58 @@
# Vorlage: Modul WHR962, diverse Foreneinträge sowie Artikel über Auswertung der
# Wärmepumpe mit Linux / Perl im Linux Magazin aus 2010
# insbesondere:
-# http://www.haustechnikdialog.de/Forum/t/6144/Waterkotte-5017-3-an-den-Computer-anschliessen?page=2 (Speicheradressen-Liste)
-# http://www.ip-symcon.de/forum/threads/2092-ComPort-und-Waterkotte-abfragen (Protokollbeschreibung)
-# http://www.haustechnikdialog.de/Forum/t/6144/Waterkotte-5017-3-an-den-Computer-anschliessen?page=4 (Beispiel Befehls-Strings)
-#
-
+# http://www.haustechnikdialog.de/Forum/t/6144/Waterkotte-5017-3-an-den-Computer-anschliessen?page=2 (Speicheradressen-Liste)
+# http://www.ip-symcon.de/forum/threads/2092-ComPort-und-Waterkotte-abfragen (Protokollbeschreibung)
+# http://www.haustechnikdialog.de/Forum/t/6144/Waterkotte-5017-3-an-den-Computer-anschliessen?page=4 (Beispiel Befehls-Strings)
+#
+# 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 .
+#
+##############################################################################
+# Changelog:
+#
+# 2013-11-1 initial version
+# 2013-12-25 bug fixes, GPL comment added, loglevel reading removed
+# 2014-4-7 performance tuning, read handling with binary string instead of hex string
+# 2014-5-22 decode mode - heating, cooling, warm water on / off
+# 2015-7-23 added utf8 encoding of state string, Added name to Log3 calls
+#
+
package main;
use strict;
use warnings;
-use Time::HiRes qw(gettimeofday);
+use Time::HiRes qw(gettimeofday);
+use Encode qw(decode encode);
#
# list of Readings / values that can explicitely be requested
# from the WP with the GET command
-my %WKRCD4_gets = (
- "Hzg-TempBasisSoll" => "Hzg-TempBasisSoll",
- "WW-Temp-Soll" => "Temp-WW-Soll"
+my %WKRCD4_gets = (
+ "Hzg-TempBasisSoll" => "Hzg-TempBasisSoll",
+ "WW-Temp-Soll" => "Temp-WW-Soll"
);
# list of Readings / values that can be written to the WP
-my %WKRCD4_sets = (
- "Hzg-TempBasisSoll" => "Hzg-TempBasisSoll"
+my %WKRCD4_sets = (
+ "Hzg-TempBasisSoll" => "Hzg-TempBasisSoll"
);
# Definition of the values that can be read / written
# with the relative address, number of bytes and
-# fmat to be used in sprintfd when formatting the value
+# fmat to be used in sprintf when formatting the value
# unp to be used in pack / unpack commands
# min / max for setting values
#
@@ -85,15 +110,18 @@ my %frameReadings = (
'BetrStundenWwPu' => { addr => 0x0072, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'BetrStundenSt2' => { addr => 0x0076, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Zeit' => { addr => 0x0064, bytes => 0x0006, fmat=> '%4$02d.%5$02d.%6$02d %3$02d:%2$02d:%1$02d', unp => 'CCCCCC'},
- 'SetBetriebsMode' => { addr => 0x014E, bytes => 0x0003, unp => 'N', pack => 'xC*'},
- 'Display-Zeile-1' => { addr => 0x008E, bytes => 0x0002, unp => 'n' },
- 'Display-Zeile-2' => { addr => 0x0090, bytes => 0x0001, unp => 'C' },
- 'Status-Gesamt' => { addr => 0x00D2, bytes => 0x0001, unp => 'C' },
+ 'SetBetriebsMode' => { addr => 0x014E, bytes => 0x0003, unp => 'N', pack => 'xC*'},
+ 'Display-Zeile-1' => { addr => 0x008E, bytes => 0x0002, unp => 'n' },
+ 'Display-Zeile-2' => { addr => 0x0090, bytes => 0x0001, unp => 'C' },
+ 'Status-Gesamt' => { addr => 0x00D2, bytes => 0x0001, unp => 'C' },
'Status-Heizung' => { addr => 0x00D4, bytes => 0x0003, unp => 'B24' },
'Status-Kuehlung' => { addr => 0x00DA, bytes => 0x0003, unp => 'B24' },
'Mode-Heizung' => { addr => 0x00DF, bytes => 0x0001, unp => 'B8' },
'Mode-Kuehlung' => { addr => 0x00E0, bytes => 0x0001, unp => 'B8' },
- 'Mode-Warmwasser' => { addr => 0x00E1, bytes => 0x0001, unp => 'B8' }
+ 'Mode-Warmwasser' => { addr => 0x00E1, bytes => 0x0001, unp => 'B8' },
+ 'Heizung' => { addr => 0x00DF, bytes => 0x0001, unp => 'b' },
+ 'Kuehlung' => { addr => 0x00E0, bytes => 0x0001, unp => 'b' },
+ 'Warmwasser' => { addr => 0x00E1, bytes => 0x0001, unp => 'b' }
);
#
@@ -102,69 +130,69 @@ my %frameReadings = (
#########################################################################
sub WKRCD4_Initialize($)
{
- my ($hash) = @_;
+ my ($hash) = @_;
- require "$attr{global}{modpath}/FHEM/DevIo.pm";
+ require "$attr{global}{modpath}/FHEM/DevIo.pm";
- $hash->{ReadFn} = "WKRCD4_Read";
- $hash->{ReadyFn} = "WKRCD4_Ready";
- $hash->{DefFn} = "WKRCD4_Define";
- $hash->{UndefFn} = "WKRCD4_Undef";
- $hash->{SetFn} = "WKRCD4_Set";
- $hash->{GetFn} = "WKRCD4_Get";
- $hash->{AttrList} =
- "do_not_notify:1,0 loglevel:0,1,2,3,4,5,6 " . $readingFnAttributes;
+ $hash->{ReadFn} = "WKRCD4_Read";
+ $hash->{ReadyFn} = "WKRCD4_Ready";
+ $hash->{DefFn} = "WKRCD4_Define";
+ $hash->{UndefFn} = "WKRCD4_Undef";
+ $hash->{SetFn} = "WKRCD4_Set";
+ $hash->{GetFn} = "WKRCD4_Get";
+ $hash->{AttrList} =
+ "do_not_notify:1,0 " . $readingFnAttributes;
}
#
# Define command
# init internal values, open device,
# set internal timer to send read command / wakeup
-######################################################################### #
+######################################################################### #
sub WKRCD4_Define($$)
{
- my ( $hash, $def ) = @_;
- my @a = split( "[ \t][ \t]*", $def );
+ my ( $hash, $def ) = @_;
+ my @a = split( "[ \t][ \t]*", $def );
- return "wrong syntax: define WKRCD4 [devicename|none] interval"
- if ( @a < 3 );
+ return "wrong syntax: define WKRCD4 [devicename\@speed|none] [interval]"
+ if ( @a < 3 );
- DevIo_CloseDev($hash);
- my $name = $a[0];
- my $dev = $a[2];
- my $interval = 60;
-
- if ( $dev eq "none" ) {
- Log3 undef, 1, "WKRCD4 device is none, commands will be echoed only";
- return undef;
- }
-
- if(int(@a) == 4) {
- $interval= $a[3];
- if ($interval < 20) {
- return "interval too small, please use something > 20, default is 60";
- }
- }
+ DevIo_CloseDev($hash);
+ my $name = $a[0];
+ my $dev = $a[2];
+ my $interval = 60;
+
+ if ( $dev eq "none" ) {
+ Log3 undef, 1, "$name: device is none, commands will be echoed only";
+ return undef;
+ }
+
+ if(int(@a) == 4) {
+ $interval= $a[3];
+ if ($interval < 20) {
+ return "interval too small, please use something > 20, default is 60";
+ }
+ }
- $hash->{buffer} = "";
-
- $hash->{DeviceName} = $dev;
- $hash->{INTERVAL} = $interval;
+ $hash->{buffer} = "";
+
+ $hash->{DeviceName} = $dev;
+ $hash->{INTERVAL} = $interval;
- $hash->{SerialRequests} = 0;
- $hash->{SerialGoodReads} = 0;
- $hash->{SerialBadReads} = 0;
+ $hash->{SerialRequests} = 0;
+ $hash->{SerialGoodReads} = 0;
+ $hash->{SerialBadReads} = 0;
- # send wakeup string (read 2 values preceeded with AT)
- $hash->{LastRequestAdr} = 8;
- $hash->{LastRequestLen} = 4;
- $hash->{LastRequest} = gettimeofday();
- my $ret = DevIo_OpenDev( $hash, 0, "WKRCD4_Wakeup" );
-
- # initial read after 3 secs, there timer is set to interval for update and wakeup
- InternalTimer(gettimeofday()+3, "WKRCD4_GetUpdate", $hash, 0);
+ # send wakeup string (read 2 values preceeded with AT)
+ $hash->{LastRequestAdr} = 8;
+ $hash->{LastRequestLen} = 4;
+ $hash->{LastRequest} = gettimeofday();
+ my $ret = DevIo_OpenDev( $hash, 0, "WKRCD4_Wakeup" );
+
+ # initial read after 3 secs, there timer is set to interval for update and wakeup
+ InternalTimer(gettimeofday()+3, "WKRCD4_GetUpdate", $hash, 0);
- return $ret;
+ return $ret;
}
#
@@ -172,10 +200,10 @@ sub WKRCD4_Define($$)
#########################################################################
sub WKRCD4_Undef($$)
{
- my ( $hash, $arg ) = @_;
- DevIo_CloseDev($hash);
- RemoveInternalTimer($hash);
- return undef;
+ my ( $hash, $arg ) = @_;
+ DevIo_CloseDev($hash);
+ RemoveInternalTimer($hash);
+ return undef;
}
@@ -183,12 +211,12 @@ sub WKRCD4_Undef($$)
# Encode the data to be sent to the device (0x10 gets doubled)
#########################################################################
sub Encode10 (@) {
- my @a = ();
- for my $byte (@_) {
- push @a, $byte;
- push @a, $byte if $byte == 0x10;
- }
- return @a;
+ my @a = ();
+ for my $byte (@_) {
+ push @a, $byte;
+ push @a, $byte if $byte == 0x10;
+ }
+ return @a;
}
#
@@ -196,20 +224,20 @@ sub Encode10 (@) {
#########################################################################
sub WPCMD($$$$;@)
{
- my ($hash, $cmd, $addr, $len, @value ) = @_;
- my $name = $hash->{NAME};
- my @frame = ();
-
- if ($cmd eq "read") {
- @frame = (0x01, 0x15, Encode10($addr>>8, $addr%256), Encode10($len>>8, $len%256));
- } elsif ($cmd eq "write") {
- @frame = (0x01, 0x13, Encode10($addr>>8, $addr%256), Encode10(@value));
- } else {
- Log3 $name, 3, "undefined cmd ($cmd) in WPCMD";
- return 0;
- }
- my $crc = CRC16(@frame);
- return (0xff, 0x10, 0x02, @frame, 0x10, 0x03, $crc >> 8, $crc % 256, 0xff);
+ my ($hash, $cmd, $addr, $len, @value ) = @_;
+ my $name = $hash->{NAME};
+ my @frame = ();
+
+ if ($cmd eq "read") {
+ @frame = (0x01, 0x15, Encode10($addr>>8, $addr%256), Encode10($len>>8, $len%256));
+ } elsif ($cmd eq "write") {
+ @frame = (0x01, 0x13, Encode10($addr>>8, $addr%256), Encode10(@value));
+ } else {
+ Log3 $name, 3, "$name: undefined cmd ($cmd) in WPCMD";
+ return 0;
+ }
+ my $crc = CRC16(@frame);
+ return (0xff, 0x10, 0x02, @frame, 0x10, 0x03, $crc >> 8, $crc % 256, 0xff);
}
#
@@ -217,93 +245,93 @@ sub WPCMD($$$$;@)
#########################################################################
sub WKRCD4_Get($@)
{
- my ( $hash, @a ) = @_;
- return "\"get WKRCD4\" needs at least an argument" if ( @a < 2 );
+ my ( $hash, @a ) = @_;
+ return "\"get WKRCD4\" needs at least an argument" if ( @a < 2 );
- my $name = shift @a;
- my $attr = shift @a;
- my $arg = join("", @a);
-
- if(!$WKRCD4_gets{$attr}) {
- my @cList = keys %WKRCD4_gets;
- return "Unknown argument $attr, choose one of " . join(" ", @cList);
- }
+ my $name = shift @a;
+ my $attr = shift @a;
+ my $arg = join("", @a);
+
+ if(!$WKRCD4_gets{$attr}) {
+ my @cList = keys %WKRCD4_gets;
+ return "Unknown argument $attr, choose one of " . join(" ", @cList);
+ }
- # get Hash pointer for the attribute requested from the global hash
- my $properties = $frameReadings{$WKRCD4_sets{$attr}};
- if(!$properties) {
- return "No Entry in frameReadings found for $attr";
- }
+ # get Hash pointer for the attribute requested from the global hash
+ my $properties = $frameReadings{$WKRCD4_gets{$attr}};
+ if(!$properties) {
+ return "No Entry in frameReadings found for $attr";
+ }
- # get details about the attribute requested from its hash
- my $addr = $properties->{addr};
- my $bytes = $properties->{bytes};
- Log3 $name, 4, sprintf ("Read %02x bytes starting from %02x for $attr", $bytes, $addr);
+ # get details about the attribute requested from its hash
+ my $addr = $properties->{addr};
+ my $bytes = $properties->{bytes};
+ Log3 $name, 4, sprintf ("$name: Get will read %02x bytes starting from %02x for $attr", $bytes, $addr);
- # create command for WP
- my $cmd = pack('C*', WPCMD($hash, 'read', $addr, $bytes));
+ # create command for WP
+ my $cmd = pack('C*', WPCMD($hash, 'read', $addr, $bytes));
- # set internal variables to track what is happending
- $hash->{LastRequestAdr} = $addr;
- $hash->{LastRequestLen} = $bytes;
- $hash->{LastRequest} = gettimeofday();
- $hash->{SerialRequests}++;
+ # set internal variables to track what is happending
+ $hash->{LastRequestAdr} = $addr;
+ $hash->{LastRequestLen} = $bytes;
+ $hash->{LastRequest} = gettimeofday();
+ $hash->{SerialRequests}++;
- Log3 $name, 4, "Get -> Call DevIo_SimpleWrite: " . unpack ('H*', $cmd);
- DevIo_SimpleWrite( $hash, $cmd , 0 );
-
- return sprintf ("Read %02x bytes starting from %02x", $bytes, $addr);
+ Log3 $name, 4, "$name: Get -> Call DevIo_SimpleWrite: " . unpack ('H*', $cmd);
+ DevIo_SimpleWrite( $hash, $cmd , 0 );
+
+ return sprintf ("Read %02x bytes starting from %02x", $bytes, $addr);
}
-
+
#
# SET command
#########################################################################
sub WKRCD4_Set($@)
{
- my ( $hash, @a ) = @_;
- return "\"set WKRCD4\" needs at least an argument" if ( @a < 2 );
+ my ( $hash, @a ) = @_;
+ return "\"set WKRCD4\" needs at least an argument" if ( @a < 2 );
- my $name = shift @a;
- my $attr = shift @a;
- my $arg = join("", @a);
-
- if(!defined($WKRCD4_sets{$attr})) {
- my @cList = keys %WKRCD4_sets;
- return "Unknown argument $attr, choose one of " . join(" ", @cList);
- }
+ my $name = shift @a;
+ my $attr = shift @a;
+ my $arg = join("", @a);
+
+ if(!defined($WKRCD4_sets{$attr})) {
+ my @cList = keys %WKRCD4_sets;
+ return "Unknown argument $attr, choose one of " . join(" ", @cList);
+ }
- # get Hash pointer for the attribute requested from the global hash
- my $properties = $frameReadings{$WKRCD4_sets{$attr}};
- if(!$properties) {
- return "No Entry in frameReadings found for $attr";
- }
+ # get Hash pointer for the attribute requested from the global hash
+ my $properties = $frameReadings{$WKRCD4_sets{$attr}};
+ if(!$properties) {
+ return "No Entry in frameReadings found for $attr";
+ }
- # get details about the attribute requested from its hash
- my $addr = $properties->{addr};
- my $bytes = $properties->{bytes};
- my $min = $properties->{min};
- my $max = $properties->{max};
- my $unp = $properties->{unp};
-
+ # get details about the attribute requested from its hash
+ my $addr = $properties->{addr};
+ my $bytes = $properties->{bytes};
+ my $min = $properties->{min};
+ my $max = $properties->{max};
+ my $unp = $properties->{unp};
+
return "a numerical value between $min and $max is expected, got $arg instead"
if($arg !~ m/^[\d.]+$/ || $arg < $min || $arg > $max);
-
- # convert string to value needed for command
- my $vp = pack($unp, $arg);
- my @value = unpack ('C*', $vp);
-
- Log3 $name, 4, sprintf ("Write $attr: %02x bytes starting from %02x with %s (%s) packed with $unp", $bytes, $addr, unpack ('H*', $vp), unpack ($unp, $vp));
- my $cmd = pack('C*', WPCMD($hash, 'write', $addr, $bytes, @value));
-
- # set internal variables to track what is happending
- $hash->{LastRequestAdr} = $addr;
- $hash->{LastRequestLen} = $bytes;
- $hash->{LastRequest} = gettimeofday();
- $hash->{SerialRequests}++;
- Log3 $name, 4, "Set -> Call DevIo_SimpleWrite: " . unpack ('H*', $cmd);
- DevIo_SimpleWrite( $hash, $cmd , 0 );
-
- return sprintf ("Wrote %02x bytes starting from %02x with %s (%s)", $bytes, $addr, unpack ('H*', $vp), unpack ($unp, $vp));
+
+ # convert string to value needed for command
+ my $vp = pack($unp, $arg);
+ my @value = unpack ('C*', $vp);
+
+ Log3 $name, 4, sprintf ("$name: Set will write $attr: %02x bytes starting from %02x with %s (%s) packed with $unp", $bytes, $addr, unpack ('H*', $vp), unpack ($unp, $vp));
+ my $cmd = pack('C*', WPCMD($hash, 'write', $addr, $bytes, @value));
+
+ # set internal variables to track what is happending
+ $hash->{LastRequestAdr} = $addr;
+ $hash->{LastRequestLen} = $bytes;
+ $hash->{LastRequest} = gettimeofday();
+ $hash->{SerialRequests}++;
+ Log3 $name, 4, "Set -> Call DevIo_SimpleWrite: " . unpack ('H*', $cmd);
+ DevIo_SimpleWrite( $hash, $cmd , 0 );
+
+ return sprintf ("Wrote %02x bytes starting from %02x with %s (%s)", $bytes, $addr, unpack ('H*', $vp), unpack ($unp, $vp));
}
@@ -312,64 +340,62 @@ sub WKRCD4_Set($@)
# called from the global loop, when the select for hash->{FD} reports data
sub WKRCD4_Read($)
{
- my ($hash) = @_;
- my $name = $hash->{NAME};
-
- # read from serial device
- my $buf = DevIo_SimpleRead($hash);
- return "" if ( !defined($buf) );
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+
+ # read from serial device
+ my $buf = DevIo_SimpleRead($hash);
+ return "" if ( !defined($buf) );
- # convert to hex string to make parsing with regex easier
- $hash->{buffer} .= unpack ('H*', $buf);
- Log3 $name, 5, "Current buffer content: " . $hash->{buffer};
+ $hash->{buffer} .= $buf;
+ Log3 $name, 5, "$name: read buffer content: " . unpack ('H*', $hash->{buffer});
- # did we already get a full frame?
- if ($hash->{buffer} =~ "ff1002(.{4})(.*)1003(.{4})ff(.*)")
- {
- my $msg = $1;
- my $frame = $msg . $2;
- my $crc = $3;
-
- Log3 $name, 4, "Match msg: " .$msg . " " . $frame . " CRC " . $crc . " Rest " . $4;
- $hash->{buffer} = $4;
+ # did we already get a full frame?
+ if ( $hash->{buffer} !~ /\xff\x10\x02(.{2})(.*)\x10\x03(.{2})\xff(.*)/s )
+ {
+ Log3 $name, 5, "$name: read NoMatch: " . unpack ('H*', $hash->{buffer});
+ return "";
+ }
+ my $msg = unpack ('H*', $1);
+ my @aframe = unpack ('C*', $1 . $2);
+ my $crc = unpack ('S>', $3);
+ my $rest = $4;
+
+ $hash->{buffer} = $rest;
+ Log3 $name, 4, "$name: read match msg: $msg CRC $crc";
+ Log3 $name, 5, "$name: read frame is " . unpack ('H*', pack ('C*', @aframe)) . ", Rest " . unpack ('H*', $rest);
- # convert frame contents to byte array
- my @aframe = unpack ('C*', pack ('H*', $frame));
-
- # calculate CRC and compare with CRC from read
- my $crc2 = sprintf("%04x",CRC16(@aframe));
- if ($crc eq $crc2)
- {
- Log3 $name, 4, "CRC Ok.";
- $hash->{SerialGoodReads}++;
-
- # reply to read request ?
- if ($msg eq "0017") {
- my @data;
- for(my $i=0,my $offset=2;$offset<=$#aframe;$offset++,$i++)
- {
- # remove duplicate 0x10 (frames are encoded like this)
- if (($aframe[$offset]==16)&&($aframe[$offset+1]==16)) { $offset++; }
- $data[$i] = $aframe[$offset];
- }
- Log3 $name, 4, "Parse with relative request start " . $hash->{LastRequestAdr} . " Len " . $hash->{LastRequestLen};
- # extract values from data
- parseReadings($hash, @data);
- } elsif ($msg eq "0011") {
- # reply to write
- } else {
- Log3 $name, 3, "Unknown Msg type " . $msg . " in " . $hash->{buffer};
- }
- } else
- {
- Log3 $name, 3, "Bad CRC from WP: " . $crc . " berechnet: " . $crc2 . " Frame ". $frame;
- $hash->{SerialBadReads} ++;
- };
- @aframe = ();
- } else {
- Log3 $name, 5, "NoMatch: " . $hash->{buffer};
- };
- return "";
+ # calculate CRC and compare with CRC from read
+ my $crc2 = CRC16(@aframe);
+ if ($crc != $crc2) {
+ Log3 $name, 3, "$name: read Bad CRC from WP: $crc, berechnet: $crc2";
+ Log3 $name, 4, "$name: read Frame was " . unpack ('H*', pack ('C*', @aframe));
+ $hash->{SerialBadReads} ++;
+ @aframe = ();
+ return "";
+ };
+ Log3 $name, 4, "$name: read CRC Ok.";
+ $hash->{SerialGoodReads}++;
+
+ # reply to read request ?
+ if ($msg eq "0017") {
+ my @data;
+ for(my $i=0,my $offset=2;$offset<=$#aframe;$offset++,$i++)
+ {
+ # remove duplicate 0x10 (frames are encoded like this)
+ if (($aframe[$offset]==16)&&($aframe[$offset+1]==16)) { $offset++; }
+ $data[$i] = $aframe[$offset];
+ }
+ Log3 $name, 4, "$name: read -> Parse with relative request start " . $hash->{LastRequestAdr} . " Len " . $hash->{LastRequestLen};
+ # extract values from data
+ parseReadings($hash, @data);
+ } elsif ($msg eq "0011") {
+ # reply to write
+ } else {
+ Log3 $name, 3, "$name: read got unknown Msg type " . $msg . " in " . $hash->{buffer};
+ }
+ @aframe = ();
+ return "";
}
#
@@ -377,15 +403,15 @@ sub WKRCD4_Read($)
#########################################################################
sub WKRCD4_Ready($)
{
- my ($hash) = @_;
+ my ($hash) = @_;
- return DevIo_OpenDev( $hash, 1, undef )
- if ( $hash->{STATE} eq "disconnected" );
+ return DevIo_OpenDev( $hash, 1, undef )
+ if ( $hash->{STATE} eq "disconnected" );
- # This is relevant for windows/USB only
- my $po = $hash->{USBDev};
- my ( $BlockingFlags, $InBytes, $OutBytes, $ErrorFlags ) = $po->status;
- return ( $InBytes > 0 );
+ # This is relevant for windows/USB only
+ my $po = $hash->{USBDev};
+ my ( $BlockingFlags, $InBytes, $OutBytes, $ErrorFlags ) = $po->status;
+ return ( $InBytes > 0 );
}
#
@@ -393,20 +419,20 @@ sub WKRCD4_Ready($)
#########################################################################
sub WKRCD4_Wakeup($)
{
- my ($hash) = @_;
- my $name = $hash->{NAME};
-
- $hash->{SerialRequests}++;
-
- $hash->{LastRequestAdr} = 8;
- $hash->{LastRequestLen} = 4;
- $hash->{LastRequest} = gettimeofday();
-
- my $cmd = "41540D100201150008000410037EA010020115003000041003FDC3100201150034000410037D90";
- DevIo_SimpleWrite( $hash, $cmd , 1 );
-
- Log3 $name, 5, "sent wakeup string: " . $cmd . " done.";
- return undef;
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+
+ $hash->{SerialRequests}++;
+
+ $hash->{LastRequestAdr} = 8;
+ $hash->{LastRequestLen} = 4;
+ $hash->{LastRequest} = gettimeofday();
+
+ my $cmd = "41540D100201150008000410037EA010020115003000041003FDC3100201150034000410037D90";
+ DevIo_SimpleWrite( $hash, $cmd , 1 );
+
+ Log3 $name, 5, "$name: sent wakeup string: " . $cmd . " done.";
+ return undef;
}
#
@@ -414,23 +440,23 @@ sub WKRCD4_Wakeup($)
###################################
sub WKRCD4_GetUpdate($)
{
- my ($hash) = @_;
- my $name = $hash->{NAME};
-
- InternalTimer(gettimeofday()+$hash->{INTERVAL}, "WKRCD4_GetUpdate", $hash, 1);
- InternalTimer(gettimeofday()+$hash->{INTERVAL}/2, "WKRCD4_Wakeup", $hash, 1);
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+
+ InternalTimer(gettimeofday()+$hash->{INTERVAL}, "WKRCD4_GetUpdate", $hash, 1);
+ InternalTimer(gettimeofday()+$hash->{INTERVAL}/2, "WKRCD4_Wakeup", $hash, 1);
- $hash->{SerialRequests}++;
-
- my $cmd = pack('C*', WPCMD($hash, 'read', 0, 0x170));
- $hash->{LastRequestAdr} = 0;
- $hash->{LastRequestLen} = 0x170;
- $hash->{LastRequest} = gettimeofday();
- DevIo_SimpleWrite( $hash, $cmd , 0 );
-
- Log3 $name, 5, "GetUpdate -> Call DevIo_SimpleWrite: " . unpack ('H*', $cmd);
-
- return 1;
+ $hash->{SerialRequests}++;
+
+ my $cmd = pack('C*', WPCMD($hash, 'read', 0, 0x170));
+ $hash->{LastRequestAdr} = 0;
+ $hash->{LastRequestLen} = 0x170;
+ $hash->{LastRequest} = gettimeofday();
+ DevIo_SimpleWrite( $hash, $cmd , 0 );
+
+ Log3 $name, 5, "$name: GetUpdate -> Call DevIo_SimpleWrite: " . unpack ('H*', $cmd);
+
+ return 1;
}
#
@@ -459,45 +485,55 @@ sub CRC16
sub parseReadings
{
my ($hash, @data) = @_;
- my $name = $hash->{NAME};
+ my $name = $hash->{NAME};
- my $reqStart = $hash->{LastRequestAdr};
- my $reqLen = $hash->{LastRequestLen};
+ my $reqStart = $hash->{LastRequestAdr};
+ my $reqLen = $hash->{LastRequestLen};
- # get enough bytes?
+ # get enough bytes?
if (@data >= $reqLen)
{
- readingsBeginUpdate($hash);
- # go through all possible readings from global hash
+ readingsBeginUpdate($hash);
+ # go through all possible readings from global hash
while (my ($reading, $property) = each(%frameReadings))
{
- my $addr = $property->{addr};
- my $bytes = $property->{bytes};
-
- # is reading inside data we got?
+ my $addr = $property->{addr};
+ my $bytes = $property->{bytes};
+
+ # is reading inside data we got?
if (($addr >= $reqStart) &&
- ($addr + $bytes <= $reqStart + $reqLen))
+ ($addr + $bytes <= $reqStart + $reqLen))
{
- my $Idx = $addr - $reqStart;
- # get relevant slice from data array
- my @slice = @data[$Idx .. $Idx + $bytes - 1];
-
- # convert according to rules in global hash or defaults
- my $pack = ($property->{pack}) ? $property->{pack} : 'C*';
- my $unpack = ($property->{unp}) ? $property->{unp} : 'H*';
- my $fmat = ($property->{fmat}) ? $property->{fmat} : '%s';
- #my $value = sprintf ($fmat, unpack ($unpack, pack ($pack, @slice))) . " packed with $pack, unpacked with $unpack, (hex " . unpack ('H*', pack ('C*', @slice)) . ") format $fmat";
- my $value = sprintf ($fmat, unpack ($unpack, pack ($pack, @slice)));
-
- readingsBulkUpdate( $hash, $reading, $value );
- Log3 $name, 4, "parse set reading $reading to $value" if (@data <= 20);
+ my $Idx = $addr - $reqStart;
+ # get relevant slice from data array
+ my @slice = @data[$Idx .. $Idx + $bytes - 1];
+
+ # convert according to rules in global hash or defaults
+ my $pack = ($property->{pack}) ? $property->{pack} : 'C*';
+ my $unpack = ($property->{unp}) ? $property->{unp} : 'H*';
+ my $fmat = ($property->{fmat}) ? $property->{fmat} : '%s';
+ #my $value = sprintf ($fmat, unpack ($unpack, pack ($pack, @slice))) . " packed with $pack, unpacked with $unpack, (hex " . unpack ('H*', pack ('C*', @slice)) . ") format $fmat";
+ my $value = sprintf ($fmat, unpack ($unpack, pack ($pack, @slice)));
+
+ readingsBulkUpdate( $hash, $reading, $value );
+ Log3 $name, 4, "$name: parse set reading $reading to $value" if (@data <= 20);
}
}
- readingsEndUpdate( $hash, 1 );
- }
+ my $Status = "WP idle";
+ if (ReadingsVal($name, "Heizung", 0)) {
+ $Status = sprintf ("Heizung %s", ReadingsVal ($name, "Temp-Vorlauf", 0));
+ } elsif (ReadingsVal($name, "Kuehlung", 0)) {
+ $Status = sprintf ("Kühlung %s", ReadingsVal ($name, "Temp-Vorlauf", 0));
+ } elsif (ReadingsVal($name, "Kuehlung", 0)) {
+ $Status = sprintf ("Warmwasser %s", ReadingsVal ($name, "Temp-WW", 0));
+ }
+ $Status = encode ("utf8", $Status);
+ readingsBulkUpdate( $hash, "Status", $Status);
+ readingsEndUpdate( $hash, 1 );
+ }
else
{
- Log3 $name, 3, "Data len smaller than requested ($reqLen) : " . unpack ('H*', pack ('C*', @data));
+ Log3 $name, 3, "$name: parse - data len smaller than requested ($reqLen) : " . unpack ('H*', pack ('C*', @data));
return 0;
}
}