2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 09:16:53 +00:00

THZ: major cleanup

git-svn-id: https://svn.fhem.de/fhem/trunk@5984 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
immiimmi 2014-05-26 20:36:22 +00:00
parent fc28248e25
commit 0038e01747

View File

@ -2,7 +2,7 @@
# 00_THZ
# $Id$
# by immi 05/2014
# v. 0.100
# v. 0.101
# this code is based on the hard work of Robert; I just tried to port it
# http://robert.penz.name/heat-pump-lwz/
# http://heatpumpmonitor.penz.name/heatpumpmonitorwiki/
@ -37,8 +37,8 @@ sub THZ_Read($);
sub THZ_ReadAnswer($);
sub THZ_Ready($);
sub THZ_Write($$);
sub THZ_Parse($);
sub THZ_Parse1($);
sub THZ_Parse($$);
#sub THZ_Parse1($);
sub THZ_checksum($);
sub THZ_replacebytes($$$);
sub THZ_decode($);
@ -53,6 +53,9 @@ sub THZ_Refresh_all_gets($);
sub THZ_Get_Comunication($$);
sub THZ_PrintcurveSVG;
#new by Jakob
sub mysubstr($$$$);
########################################################################################
@ -283,6 +286,9 @@ my %OpMode = ("1" =>"standby", "11" => "automatic", "3" =>"DAYmode", "4" =>"setb
my %Rev_OpMode = reverse %OpMode;
my %OpModeHC = ("1" =>"normal", "2" => "setback", "3" =>"standby", "4" =>"restart", "5" =>"restart");
my %SomWinMode = ( "01" =>"winter", "02" => "summer");
my $firstLoadAll = 0;
my $noanswerreceived = 0;
my $internalHash;
########################################################################################
#
# THZ_Initialize($)
@ -529,35 +535,22 @@ sub THZ_Set($@){
elsif ((substr($cmdHex2,0,5) eq "0A056") or (substr($cmdHex2,0,5) eq "0A057") or (substr($cmdHex2,0,6) eq "0A0588") or (substr($cmdHex2,0,6) eq "0A05A0") or (substr($cmdHex2,0,6) eq "0B059D") or (substr($cmdHex2,0,6) eq "0A05B7") or (substr($cmdHex2,0,6) eq "0A05B8") ) { } # fann speed and boostetimeout: do not multiply
elsif (substr($cmdHex2,2,4) eq "010E") {$arg=$arg*100} #gradientHC1 &HC2
else {$arg=$arg*10}
THZ_Write($hash, "02"); # STX start of text
($err, $msg) = THZ_ReadAnswer($hash); #Expectedanswer1 is "10" DLE data link escape
my $msgtmp= $msg . " sent" . $arg ."---";
if ($msg eq "10") {
$cmdHex2=THZ_encodecommand(($cmdHex2 . substr((sprintf("%04X", $arg)), -4)),"set"); #04X converts to hex and fills up 0s; for negative, it must be trunckated.
THZ_Write($hash, $cmdHex2); # send request SOH start of heading -- Null -- ?? -- DLE data link escape -- EOT End of Text
select(undef, undef, undef, 0.2); #maybe important for older firmware
($err, $msg) = THZ_ReadAnswer($hash); #Expectedanswer is "10", DLE data link escape
}
$msgtmp= $msgtmp ."\n" ."set--" . $cmdHex2 ."\n" . $msg;
if ($msg eq "10") {
($err, $msg) = THZ_ReadAnswer($hash); #Expectedanswer is "02" -- STX start of text
THZ_Write($hash, "10"); # DLE data link escape // ack datatranfer
($err, $msg) = THZ_ReadAnswer($hash); # Expectedanswer3 // read from the heatpump
THZ_Write($hash, "10");
}
elsif ($msg eq "1002") {
THZ_Write($hash, "10"); # DLE data link escape // ack datatranfer
($err, $msg) = THZ_ReadAnswer($hash); # Expectedanswer3 // read from the heatpump
THZ_Write($hash, "10");
}
$msgtmp= $msgtmp ."\n" . $msg;
if (defined($err)) {return ($cmdHex2 . "-". $msg ."--" . $err);}
else {
sleep 1;
$msg=THZ_Get($hash, $name, $cmd);
$msgtmp= $msgtmp ."\n" . $msg;
return ($msg);
}
Log3 $hash->{NAME}, 5, "THZ_Set: Check if port is open. State = '($hash->{STATE})'";
#if (($hash->{STATE} eq "DISCONNECTED"))
#{
# DevIo_OpenDev($hash, 0, "");
#}
$cmdHex2=THZ_encodecommand(($cmdHex2 . substr((sprintf("%04X", $arg)), -4)),"set"); #04X converts to hex and fills up 0s; for negative, it must be trunckated.
($err, $msg) = THZ_Get_Comunication($hash, $cmdHex2);
if (defined($err)) {
return ($cmdHex2 . "-". $msg ."--" . $err);}
else {
select(undef,undef,undef,0.2);
$msg=THZ_Get($hash, $name, $cmd);
return ($msg);
}
}
@ -579,43 +572,49 @@ sub THZ_Get($@){
return "\"get $name\" needs one parameter" if(@a != 2);
my $cmd = $a[1];
my ($err, $msg) =("", " ");
my ($err, $msg2) =("", " ");
if ($cmd eq "debug_read_raw_register_slow") {
if ($cmd eq "debug_read_raw_register_slow") {
THZ_debugread($hash);
return ("all raw registers read and saved");
}
my $cmdhash = $gets{$cmd};
return "Unknown argument $cmd, choose one of " .
join(" ", sort keys %gets) if(!defined($cmdhash));
Log3 $hash->{NAME}, 5, "THZ_Get: Try to get '$cmd'";
my $cmdHex2 = $cmdhash->{cmd2};
if(defined($cmdHex2) ) {
($err, $msg) = THZ_Get_Comunication($hash, $cmdHex2);
if (defined($err)) {return ($msg ."\n msg2 " . $err);}
$msg = THZ_Parse($msg);
$cmdHex2=THZ_encodecommand($cmdHex2,"get");
($err, $msg2) = THZ_Get_Comunication($hash, $cmdHex2);
if (defined($err)) {
Log3 $hash->{NAME}, 5, "THZ_Get: Error msg2: '$err'";
return ($msg2 ."\n msg2 " . $err);
}
$msg2 = THZ_Parse($hash,$msg2);
}
my $cmdHex3 = $cmdhash->{cmd3};
if(defined($cmdHex3)) {
select(undef, undef, undef, 0.1);
my $msg3= " ";
$cmdHex3=THZ_encodecommand($cmdHex3,"get");
($err, $msg3) = THZ_Get_Comunication($hash, $cmdHex3);
if (defined($err)) {return ($msg3 ."\n msg3 " . $err);}
$msg = THZ_Parse($msg3) * 1000 + $msg ;
if (defined($err)) {
Log3 $hash->{NAME}, 5, "THZ_Get: Error msg3: '$err'";
return ($msg3 ."\n msg3 " . $err);
}
$msg2 = THZ_Parse($hash,$msg3) * 1000 + $msg2 ;
}
my $unit = $cmdhash->{unit};
if(defined($cmdHex3)) {
$msg = $msg . " " . $unit;
$msg2 = $msg2 . " " . $unit;
}
my $activatetrigger =1;
readingsSingleUpdate($hash, $cmd, $msg, $activatetrigger);
return ($msg);
readingsSingleUpdate($hash, $cmd, $msg2, $activatetrigger);
return ($msg2);
}
@ -630,22 +629,31 @@ sub THZ_Get($@){
sub THZ_Get_Comunication($$) {
my ($hash, $cmdHex) = @_;
my ($err, $msg) =("", " ");
Log3 $hash->{NAME}, 5, "THZ_Get_Comunication: Check if port is open. State = '($hash->{STATE})'";
THZ_Write($hash, "02"); # STX start of text
($err, $msg) = THZ_ReadAnswer($hash); #Expectedanswer1 is "10" DLE data link escape
if ($msg eq "10") {
$cmdHex=THZ_encodecommand($cmdHex,"get");
#$cmdHex=THZ_encodecommand($cmdHex,"get");
THZ_Write($hash, $cmdHex); # send request SOH start of heading -- Null -- ?? -- DLE data link escape -- EOT End of Text
select(undef, undef, undef, 0.1); # delay added for Tom!!!!!!
select(undef, undef, undef, 0.2); # delay added for Tom!!!!!!
($err, $msg) = THZ_ReadAnswer($hash); #Expectedanswer2 is "1002", DLE data link escape -- STX start of text
}
if($msg eq "1002") {
THZ_Write($hash, "10"); # DLE data link escape // ack datatranfer
($err, $msg) = THZ_ReadAnswer($hash); # Expectedanswer3 // read from the heatpump
THZ_Write($hash, "10");
}
if ($msg eq "10") {
($err, $msg) = THZ_ReadAnswer($hash);
}
if($msg eq "1002" || $msg eq "02") {
THZ_Write($hash, "10"); # DLE data link escape // ack datatranfer
($err, $msg) = THZ_ReadAnswer($hash); # Expectedanswer3 // read from the heatpump
THZ_Write($hash, "10");
}
if (!(defined($err))) {($err, $msg) = THZ_decode($msg);} #clean up and remove footer and header
return($err, $msg) ;
}
@ -824,40 +832,69 @@ sub THZ_encodecommand($$) {
#
########################################################################################
sub THZ_decode($) {
my ($message_orig) = @_;
# raw data received from device have to be de-escaped before header evaluation and data use:
# - each sequece 2B 18 must be replaced with single byte 2B
# - each sequece 10 10 must be replaced with single byte 10
my $find = "1010";
my $replace = "10";
$message_orig=THZ_replacebytes($message_orig, $find, $replace);
$find = "2B18";
$replace = "2B";
$message_orig=THZ_replacebytes($message_orig, $find, $replace);
my $find = "1010";
my $replace = "10";
$message_orig=THZ_replacebytes($message_orig, $find, $replace);
$find = "2B18";
$replace = "2B";
$message_orig=THZ_replacebytes($message_orig, $find, $replace);
#Check if answer is NAK
if (length($message_orig) == 2 && $message_orig eq "15") {
return("NAK received from device",$message_orig);
}
#check header and if ok 0100, check checksum and return the decoded msg
if ("0100" eq substr($message_orig,0,4)) {
my $header = substr($message_orig,0,4);
if ($header eq "0100")
{
if (THZ_checksum($message_orig) eq substr($message_orig,4,2)) {
$message_orig =~ /0100(.*)1003/;
my $message = $1;
return (undef, $message)
$message_orig =~ /0100(.*)1003/;
my $message = $1;
return (undef, $message);
}
else {return (THZ_checksum($message_orig) . "crc_error", $message_orig)}; }
if ("0103" eq substr($message_orig,0,4)) { return (" command not known", $message_orig)};
if ("0102" eq substr($message_orig,0,4)) { return (" CRC error in request", $message_orig)}
else {return (" new error code " , $message_orig);};
else {return (THZ_checksum($message_orig) . "crc_error in answer", $message_orig)};
}
if ($header eq "0103")
{
return ("command not known", $message_orig);
}
if ($header eq "0102")
{
return ("CRC error in request", $message_orig);
}
if ($header eq "0104")
{
return ("UNKNOWN REQUEST", $message_orig);
}
if ($header eq "0180")
{
return (undef, $message_orig);
}
return ("new unknown answer " , $message_orig);
}
########################################################################################
#
# THZ_Parse -0A01
#
########################################################################################
sub THZ_Parse($) {
my ($message) = @_;
sub THZ_Parse($$) {
my ($hash,$message) = @_;
Log3 $hash->{NAME}, 5, "Parse message: $message";
my $length = length($message);
Log3 $hash->{NAME}, 4, "Message length: $length";
given (substr($message,2,2)) {
when ("0A") {
if (substr($message,4,4) eq "0116") {$message = hex2int(substr($message, 8,4))/10 ." °C" }
@ -990,6 +1027,9 @@ sub THZ_Parse($) {
"Date: " . (hex(substr($message,12,2))+2000) . "/" . hex(substr($message,14,2)) . "/" . hex(substr($message,16,2));
}
when ("FB") { #allFB
# 1 2 3 5 6 7 8 9
#012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
#0DFBFDA8005D014E010602CF01CCFDA8FDA80007014C200813021C021C0258001A001E0013006100000000
$message = "outsideTemp: " . hex2int(substr($message, 8,4))/10 . " " .
"flowTemp: " . hex2int(substr($message,12,4))/10 . " " . #Vorlauf Temperatur
"returnTemp: " . hex2int(substr($message,16,4))/10 . " " . #Rücklauf Temperatur
@ -1024,11 +1064,11 @@ sub THZ_Parse($) {
"mainVentilatorSpeed: " . hex(substr($message,70,4))/1 . " " . # m3/h
"outside_tempFiltered: " . hex2int(substr($message,74,4))/10 . " " .
"relHumidity: " . hex2int(substr($message,78,4))/10 . " " .
"dewPoint: " . hex2int(substr($message,86,4))/1 . " " .
"P_Nd: " . hex2int(substr($message,86,4))/100 . " " . #bar
"P_Hd: " . hex2int(substr($message,90,4))/100 . " " . #bar
"actualPower_Qc: " . hex2int(substr($message,94,8))/1 . " " . #kw
"actualPower_Pel: " . hex2int(substr($message,102,4))/1 . " " . #kw
"dewPoint: " . hex2int(mysubstr($hash,$message,86,4))/1 . " " .
"P_Nd: " . hex2int(mysubstr($hash,$message,86,4))/100 . " " . #bar
"P_Hd: " . hex2int(mysubstr($hash,$message,90,4))/100 . " " . #bar
"actualPower_Qc: " . hex2int(mysubstr($hash,$message,94,8))/1 . " " . #kw
"actualPower_Pel: " . hex2int(mysubstr($hash,$message,102,4))/1 . " " . #kw
"collectorTemp: " . hex2int(substr($message, 4,4))/10 . " " . #kw
"insideTemp: " . hex2int(substr($message, 32,4))/10 ; #Innentemperatur
}
@ -1063,6 +1103,63 @@ sub THZ_Parse($) {
}
#######################################
#mysubstr($$$)
#Same function as subst. But checks if offset + lenght is
#available in the string. If not, returns zeros.
#######################################
sub mysubstr($$$$)
{
my ($hash,$message,$start, $length) = @_;
my $ReturnValue = "";
if (length($message) < ($start + $length))
{
Log3 $hash->{NAME},5, "mysubstr: offset($start) + length($length) is greater then message : '$message'";
my $msg;
for(my $i = 0;$i < $length;$i++)
{
$msg += "0";
}
$ReturnValue = uc(unpack('H*',pack('H*', $msg)));
Log3 $hash->{NAME},5,"mysubstr: retval instead '$ReturnValue'";
return $ReturnValue;
}
return substr($message,$start,$length);
}
local $SIG{__WARN__} = sub
{
my $message = shift;
if (!defined($internalHash)) {
Log 3, "EXCEPTION in THZ: '$message'";
}
else
{
Log3 $internalHash->{NAME},3, "EXCEPTION in THZ: '$message'";
}
};
#######################################
#THZ_Parse1($) could be used in order to test an external config file; I do not know if I want it
#
@ -1185,7 +1282,7 @@ sub THZ_Undef($$) {
$defs{$d}{IODev} == $hash)
{
my $lev = ($reread_active ? 4 : 2);
Log GetLogLevel($name,$lev), "deleting port for $d";
Log3 $hash->{NAME}, $lev, "deleting port for $d";
delete $defs{$d}{IODev};
}
}
@ -1272,11 +1369,11 @@ polyline { stroke:black; fill:none; }
</g>
END
my $insideTemp=(split ' ',ReadingsVal("Mythz","sGlobal",0))[81];
my $insideTemp=(split ' ',ReadingsVal("Mythz","sGlobal",14))[81];
$insideTemp="n.a." if ($insideTemp eq "-60"); #in case internal room sensor not connected
my $roomSetTemp =(split ' ',ReadingsVal("Mythz","sHC1",0))[21];
my $p13GradientHC1 = ReadingsVal("Mythz","p13GradientHC1",0);
my $heatSetTemp =(split ' ',ReadingsVal("Mythz","sHC1",0))[11];
my $roomSetTemp =(split ' ',ReadingsVal("Mythz","sHC1",16))[21];
my $p13GradientHC1 = ReadingsVal("Mythz","p13GradientHC1",0.4);
my $heatSetTemp =(split ' ',ReadingsVal("Mythz","sHC1",17))[11];
my $p15RoomInfluenceHC1 = (split ' ',ReadingsVal("Mythz","p15RoomInfluenceHC1",0))[0];
my $outside_tempFiltered =(split ' ',ReadingsVal("Mythz","sGlobal",0))[65];
my $p14LowEndHC1 =(split ' ',ReadingsVal("Mythz","p14LowEndHC1",0))[0];