2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 03:06:37 +00:00

THZ: z_Last_fhem_err implemented, aesthetics and DevIo (Forum #110125)

git-svn-id: https://svn.fhem.de/fhem/trunk@21871 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
immi 2020-05-05 18:29:00 +00:00
parent 18f5bc0b22
commit 3f9fb855e0

View File

@ -1,8 +1,8 @@
##############################################
##############################################
# 00_THZ
# $Id$
# by immi 10/2019
my $thzversion = "0.182"; #
# by immi 05/2020
my $thzversion = "0.184";
# this code is based on the hard work of Robert; I just tried to port it
# http://robert.penz.name/heat-pump-lwz/
########################################################################################
@ -32,6 +32,7 @@ use Time::HiRes qw(gettimeofday);
use feature ":5.10";
use SetExtensions;
use Blocking;
use DevIo;
sub THZ_Read($);
sub THZ_ReadAnswer($);
@ -424,6 +425,7 @@ my %sets439539common = (
"p25Hyst5" => {cmd2=>"0A05C4", argMin => "0", argMax => "5", type =>"5temp", unit =>" K"},
"p29HystAsymmetry" => {cmd2=>"0A05C5", argMin => "1", argMax => "5", type =>"1clean", unit =>""},
"p30integralComponent" => {cmd2=>"0A0162", argMin => "10", argMax => "999", type =>"1clean", unit =>" Kmin"},
"p31MaxBoosterStgHtg" => {cmd2=>"0A059F", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
"p32HystDHW" => {cmd2=>"0A0140", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"},
"p33BoosterTimeoutDHW" => {cmd2=>"0A0588", argMin => "0", argMax => "200", type =>"1clean", unit =>" min"}, #during DHW heating
"p79BoosterTimeoutHC" => {cmd2=>"0A05A0", argMin => "0", argMax => "60", type =>"1clean", unit =>" min"}, #delayed enabling of booster heater
@ -708,7 +710,7 @@ my %sets206 = (
"progHC2Saturday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
"progHC2Sunday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
"progFAN1StartTime" => {parent=>"pFanProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
"progFAN1EndTime" => {parent=>"pFanProg", argMin => "00:00", argMax => "23:59", type =>"ütime", unit =>""},
"progFAN1EndTime" => {parent=>"pFanProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
"progFAN1Enable" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
"progFAN1Monday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
"progFAN1Tuesday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
@ -860,7 +862,6 @@ my $internalHash;
########################################################################################
sub THZ_Initialize($) {
my ($hash) = @_;
require "$attr{global}{modpath}/FHEM/DevIo.pm";
# Provider
$hash->{ReadFn} = "THZ_Read";
@ -1021,7 +1022,6 @@ sub THZ_Write($$) {
DevIo_SimpleWrite($hash, $bstring, 1);
}
#####################################
# sub THZ_Read($)
# called from the global loop, when the select for hash reports data
@ -1057,7 +1057,6 @@ Log3 $name, 3, "$name/RAW: $msg - $err - $hash->{helper}{step}";
}
#####################################
#
# THZ_Resethelper()
@ -1074,7 +1073,6 @@ sub THZ_Resethelper($) {
}
sub THZ_Testloopapproach($) {
my ($hash) = @_;
my $cmd="sGlobal";
@ -1090,10 +1088,8 @@ sub THZ_testtimer($) {
my ($hash) = @_;
my $counter=1;
my $stringa = ("starttest \n");
foreach my $a (keys %intAt)
{
if ($intAt{$a}{FN} eq "THZ_GetRefresh")
{
foreach my $a (keys %intAt) {
if ($intAt{$a}{FN} eq "THZ_GetRefresh") {
$stringa = $stringa . ("timer ". $counter ." ARG". $intAt{$a}{ARG} ."fn " . $intAt{$a}{FN} ."\n") ;
$counter+=1;
}
@ -1111,8 +1107,7 @@ sub THZ_testtimer($) {
########################################################################################
sub THZ_Ready($) {
my ($hash) = @_;
if($hash->{STATE} eq "disconnected")
{ #RemoveInternalTimer(0, "THZ_GetRefresh"); #non necessario in THZ_getrefresh non vengono piu' rinnoovati
if($hash->{STATE} eq "disconnected") { #RemoveInternalTimer(0, "THZ_GetRefresh"); #non necessario in THZ_getrefresh non vengono piu' rinnoovati
#THZ_testtimer($hash);
select(undef, undef, undef, 0.010); #equivalent to sleep 10ms
#Log3 $hash->{NAME}, 3, "THZ_Ready: readyevent";
@ -1124,13 +1119,8 @@ sub THZ_Ready($) {
my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
return ($InBytes>0);
}
}
#####################################
#
# THZ_Set - provides a method for setting the heatpump
@ -1159,31 +1149,10 @@ sub THZ_Set($@){
#if (($value->{argMax} - $value->{argMin})<2 ) {$setList .= ":uzsuToggle," . join (",", ($value->{argMin} .. $value->{argMax})) . " ";}
if (($value->{argMax} - $value->{argMin})<5 ) {$setList .= ":uzsuSelectRadio," . join (",", ($value->{argMin} .. $value->{argMax})) . " ";}
else {$setList .= ":textField ";}
#else {$setList .= ":slider,$value->{argMin},1,$value->{argMax} ";}
#else {$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:1 " ;}
}
elsif ($value->{type} eq "2opmode"){
$setList .= ":" . join (",", (sort {lc $a cmp lc $b} values %OpMode)) . " ";
#$setList .= ":uzsuSelectRadio," . join (",", (sort {lc $a cmp lc $b} values %OpMode)) . " ";
#attr Mythz widgetOverride pOpMode:uzsuDropDown,automatic,standby
}
#elsif ($value->{type} eq "9holy"){
#$setList .= ":time ";
# $setList .= ":textField ";
# }
#elsif ($value->{type} eq "5temp") {
# $setList .= ":slider,$value->{argMin},0.1,$value->{argMax},1 " ;
#$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:0.1 " ;
#$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:0.1,angleOffset:-125,angleArc:250 "
#attr Mythz widgetOverride p01RoomTempDayHC1:knob,min:22,max:26,step:0.1,angleOffset:-125,angleArc:250
#attr Mythz widgetOverride p01RoomTempDayHC1:slider,$value->{argMin},0.1,$value->{argMax}
#attr Mythz widgetOverride p01RoomTempDayHC1:uzsuDropDown,21,29
#attr Mythz widgetOverride p01RoomTempDayHC1:uzsuSelectRadio,44,234,21
# }
#elsif ($value->{type} eq "6gradient") {
# $setList .= ":slider,$value->{argMin},0.01,$value->{argMax},1 " ;
#$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:0.01 " ;
# }
else {
#$setList .= ":textField ";
$setList .= " ";
@ -1191,15 +1160,10 @@ sub THZ_Set($@){
}
return "Unknown argument $cmd, choose one of $setList";
}
return "\"set $name $cmd\" needs at least one further argument: <value-to-be-modified>" if(!defined($arg));
my $cmdHex2 = $cmdhash->{cmd2};
my $argMax = $cmdhash->{argMax};
my $argMin = $cmdhash->{argMin};
#-- check the parameter range
if ($cmdhash->{type} =~ /ptime/) {
$arg1=undef;
@ -1230,7 +1194,9 @@ sub THZ_Set($@){
$cmdHex2=THZ_encodecommand($cmdHex2, "get"); #read before write the register
($err, $msg) = THZ_Get_Comunication($hash, $cmdHex2);
if (defined($err)) {
Log3 $hash->{NAME}, 3, "THZ_Set: error reading register: '$err'";
$err="THZ_Set: error reading register: '$err'";
Log3 $hash->{NAME}, 3, $err;
eadingsSingleUpdate($hash, "z_Last_fhem_err", $err, 0);
return ($msg ."\n msg " . $err);
}
substr($msg, 0, 2, ""); #remove the checksum from the head of the payload
@ -1253,7 +1219,6 @@ sub THZ_Set($@){
my $parsingtype = @$parsingrule[$i]->[3];
my $dec = @$parsingrule[$i]->[4];
Log3 $hash->{NAME}, 5, "write command (parsed element/pos/len/dec/parsingtype): $i / $pos / $len / $dec / $parsingtype";
$arg *= $dec if ($dec != 1);
$arg = time2quaters($arg) if ($parsingtype eq "quater");
$arg= join('', (split(':', $arg))) if ($parsingtype eq "hex2time"); # only in firmware 2.x
@ -1261,7 +1226,6 @@ sub THZ_Set($@){
$arg=(hex(substr($msg, $pos, 1)) & (15-2**$1)) | (2**$1*$arg) if ($parsingtype =~ /bit(\d)/);
$arg = substr((sprintf(("%0".$len."X"), $arg)), (-1*$len)); #04X converts to hex and fills up 0s; for negative, it must be trunckated.
substr($msg, $pos, $len, $arg);
if (defined($arg1)) { #only in case of "8party" or "7prog"
$arg1 = time2quaters($arg1);
$arg1 = substr((sprintf(("%02X"), $arg1)), -2);
@ -1273,17 +1237,15 @@ sub THZ_Set($@){
($err, $msg) = THZ_Get_Comunication($hash, $cmdHex2);
#$err=undef;
if (defined($err)) {
Log3 $hash->{NAME}, 3, "THZ_Set: Error msg: $err -- $cmdHex2 -> $msg";
$err="THZ_Set: Error msg: $err -- $cmdHex2 -> $msg";
Log3 $hash->{NAME}, 3, $err;
readingsSingleUpdate($hash, "z_Last_fhem_err", $err, 0);
return($cmdHex2 . "-". $msg ."--" . $err);
}
else {
select(undef, undef, undef, 0.25);
if (defined($gets{$cmd})) {
$msg=THZ_Get($hash, $name, $cmd);
}
else {
$msg=$cmd.": OK";
}
if (defined($gets{$cmd})) {$msg=THZ_Get($hash, $name, $cmd);}
else {$msg=$cmd.": OK";}
#because of F8 reset introduced by andre topic=33211 msg695420
#take care of program of the week
if ($a[1] =~ /Mo-So/){
@ -1315,8 +1277,6 @@ sub THZ_Set($@){
}
}
########################################################################################
#
# THZ_GetNB - NonBlocking Get parameter from heatpump
@ -1350,7 +1310,6 @@ sub THZ_GetNB($){
}
}
########################################################################################
#
# THZ_GetNBDone - Finish Function
@ -1369,7 +1328,6 @@ sub THZ_GetNBDone($){
return;
}
########################################################################################
#
# THZ_GetNBAbort - Abort Function
@ -1385,7 +1343,6 @@ sub THZ_GetNBAbort($){
return;
}
########################################################################################
#
# THZ_AvoidCollisions - prevents collisions between parent and child process is used at the beginning of THZ_Get and THZ_Set
@ -1413,10 +1370,6 @@ sub THZ_AvoidCollisions($) {
return;
}
#####################################
#
# THZ_Get - provides a method for polling the heatpump
@ -1428,11 +1381,9 @@ sub THZ_Get($@) {
my ($hash, @a) = @_;
my $dev = $hash->{DeviceName};
my $name = $hash->{NAME};
return "\"get $name\" needs one parameter" if(@a != 2);
my $cmd = $a[1];
my ($err, $msg2) =("", " ");
if ($cmd eq "debug_read_raw_register_slow") {
THZ_debugread($hash);
return ("all raw registers read and saved");
@ -1441,8 +1392,6 @@ sub THZ_Get($@) {
$err=THZ_backup_readings($hash);
return $err;
}
my $cmdhash = $gets{$cmd};
#return "Unknown argument $cmd, choose one of " . join(" ", sort keys %gets) if(!defined($cmdhash));
if(!defined($cmdhash)) {
@ -1451,7 +1400,6 @@ sub THZ_Get($@) {
$getList .= "zBackupParameters:noArg";
return "Unknown argument $cmd, choose one of $getList";
}
Log3 $hash->{NAME}, 5, "THZ_Get: Try to get '$cmd'";
THZ_AvoidCollisions($hash);
my $parent = $cmdhash->{parent}; #if I have a father read from it
@ -1465,29 +1413,31 @@ sub THZ_Get($@) {
my $i=0;
for (@$parsingrule) {
last if ((@$parsingrule[$i]->[0]) =~ m/$cmd/);
$i++;}
$i++;
}
$msg2=(split ' ', $risultato)[$i*2+1];
Log3 $hash->{NAME}, 5, "THZ_split: $msg2 --- $risultato";
}
else {
my $cmdHex2 = $cmdhash->{cmd2};
if(defined($cmdHex2) ) {
#empty
if(defined($cmdHex2) ) {#empty
($err, $msg2) = THZ_Get_Comunication($hash, THZ_encodecommand($cmdHex2,"get") );
if (defined($err)) {
Log3 $hash->{NAME}, 3, "THZ_Get: Error msg2: $err -- $cmdHex2 -> $msg2";
$err="THZ_Get: Error msg2: $err -- $cmdHex2 -> $msg2";
Log3 $hash->{NAME}, 3, $err;
readingsSingleUpdate($hash, "z_Last_fhem_err", $err, 0);
return ($msg2 ."\n msg2 " . $err);
}
$msg2 = THZ_Parse1($hash,$msg2);
}
my $cmdHex3 = $cmdhash->{cmd3};
if(defined($cmdHex3)) {
my $msg3= " ";
#empty
my $msg3= " "; #empty
($err, $msg3) = THZ_Get_Comunication($hash, THZ_encodecommand($cmdHex3,"get"));
if (defined($err)) {
Log3 $hash->{NAME}, 3, "THZ_Get: Error msg3: $err -- $cmdHex3 -> $msg3";
$err="THZ_Get: Error msg3: $err -- $cmdHex3 -> $msg3";
Log3 $hash->{NAME}, 3, $err;
readingsSingleUpdate($hash, "z_Last_fhem_err", $err, 0);
return ($msg3 ."\n msg3 " . $err);
}
$msg2 = THZ_Parse1($hash,$msg3) * 1000 + $msg2 ;
@ -1495,16 +1445,11 @@ sub THZ_Get($@) {
}
my $unit = $cmdhash->{unit};
$msg2 = $msg2 . $unit if(defined($unit)) ;
my $activatetrigger =1;
readingsSingleUpdate($hash, $cmd, $msg2, $activatetrigger);
return ($msg2);
}
#####################################
#
# THZ_Get_Comunication- provides a method for comunication called from THZ_Get or THZ_Set
@ -1517,23 +1462,17 @@ sub THZ_Get_Comunication($$) {
my ($err, $msg) =("", " ");
Log3 $hash->{NAME}, 5, "THZ_Get_Comunication: Check if port is open. State = '($hash->{STATE})'";
if (!(($hash->{STATE}) eq "opened")) { return("closed connection", "");}
select(undef, undef, undef, 0.001);
THZ_Write($hash, "02"); # step0 --> STX start of text
($err, $msg) = THZ_ReadAnswer($hash);
#Expectedanswer0 is "10" DLE data link escape
if ($msg ne "10") {$err .= " THZ_Get_Com: error found at step0 $msg"; $err .=" NAK!!" if ($msg eq "15"); select(undef, undef, undef, 0.1); return($err, $msg) ;}
else {
THZ_Write($hash, $cmdHex); # step1 --> send request SOH start of heading -- Null -- ?? -- DLE data link escape -- EOT End of Text
($err, $msg) = THZ_ReadAnswer($hash);
}
if ((defined($err))) { $err .= " THZ_Get_Com: error found at step1 "; select(undef, undef, undef, 0.1); return($err, $msg) ;}
# Expectedanswer1 is "1002", DLE data link escape -- STX start of text
if ($msg eq "10") { ($err, $msg) = THZ_ReadAnswer($hash);}
elsif ($msg eq "15") { $err .= " THZ_Get_Com: error found at step1 NAK!! "; select(undef, undef, undef, 0.1); return($err, $msg) ;}
if ($msg eq "1002" || $msg eq "02") {
@ -1541,21 +1480,11 @@ sub THZ_Get_Comunication($$) {
($err, $msg) = THZ_ReadAnswer($hash); # Expectedanswer2 // read from the heatpump
THZ_Write($hash, "10");
}
if ((defined($err))) { $err .= " THZ_Get_Com: error found at step2"; select(undef, undef, undef, 0.1);}
else {($err, $msg) = THZ_decode($msg);} #clean up and remove footer and header
return($err, $msg) ;
}
#####################################
#
# THZ_ReadAnswer- provides a method for simple read
@ -1640,9 +1569,6 @@ sub quaters2time($) {
return $time;
}
####################################
#
# time2quarters - convert from time to quarters in hex; specific to the week programm registers
@ -1662,8 +1588,6 @@ sub time2quaters($) {
return ($num);
}
####################################
#
# bitmap2string - convert from bitmap to concatenated string
@ -1683,8 +1607,6 @@ sub bitmap2string($$) {
return $res;
}
####################################
#
# THZ_replacebytes - replaces bytes in string
@ -1708,15 +1630,17 @@ sub THZ_replacebytes($$$) {
return ($new_stringa);
}
####################################
#
## usage THZ_overwritechecksum("0100XX". $cmd."1003"); not needed anymore
#
########################################################################################
sub THZ_overwritechecksum($) {
my ($stringa) = @_;
my $checksumadded=substr($stringa,0,4) . THZ_checksum($stringa) . substr($stringa,6);
return($checksumadded);
}
####################################
#
# THZ_encodecommand - creates a telegram for the heatpump with a given command
@ -1745,10 +1669,6 @@ sub THZ_encodecommand($$) {
return($header. $checksumadded .$footer);
}
####################################
#
# THZ_decode - decodes a telegram from the heatpump -- no parsing here
@ -1771,12 +1691,10 @@ sub THZ_decode($) {
$find = "2B18"; # - each sequece 2B 18 must be replaced with single byte 2B
$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("decode: NAK received from device",$message_orig);
}
#check header and if ok 0100, check checksum and return the decoded msg
my $header = substr($message_orig,0,4);
if ($header eq "0100") {
@ -1792,11 +1710,9 @@ sub THZ_decode($) {
if ($header eq "0102") { return("decode: CRC error in request", $message_orig);}
if ($header eq "0104") { return("decode: UNKNOWN Register REQUEST", $message_orig);}
if ($header eq "0180") { return(undef, $message_orig);}
return("decode: new unknown answer " , $message_orig);
}
###############################
#added by jakob do not know if needed
#
@ -1815,7 +1731,6 @@ local $SIG{__WARN__} = sub {
};
#######################################
#THZ_Parse1($) could be used in order to test an external config file; I do not know if I want it
#e.g. {THZ_Parse1(undef,"F70B000500E6")}
@ -1832,19 +1747,18 @@ sub THZ_Parse1($$) {
my $parsingelement;
# search for the type in %gets
foreach my $cmdhash (values %gets) {
if (defined ($cmdhash->{cmd2}) and ($cmdhash->{cmd2} eq $parsingcmd))
{$msgtype = $cmdhash->{type} ;
if (defined ($cmdhash->{cmd2}) and ($cmdhash->{cmd2} eq $parsingcmd)) {
$msgtype = $cmdhash->{type} ;
last
}
elsif (defined ($cmdhash->{cmd3}))
{ if ($cmdhash->{cmd3} eq $parsingcmd)
{$msgtype = $cmdhash->{type} ;
elsif (defined ($cmdhash->{cmd3})){
if ($cmdhash->{cmd3} eq $parsingcmd) {
$msgtype = $cmdhash->{type} ;
last
}
}
}
$parsingrule = $parsinghash{$msgtype} if(defined($msgtype));
my $ParsedMsg = $message;
if(defined($parsingrule)) {
$ParsedMsg = "";
@ -1900,10 +1814,6 @@ sub THZ_Parse1($$) {
return (undef, $ParsedMsg);
}
########################################################################################
# only for debug
#
@ -1950,13 +1860,13 @@ sub THZ_debugread($){
select(undef, undef, undef, 0.001);
($err, $msg) = THZ_ReadAnswer($hash);
THZ_Write($hash, "10");
if (defined($err)) {return ($msg ."\n" . $err);}
else { #clean up and remove footer and header
($err, $msg) = THZ_decode($msg);
if (defined($err)) {
$msg = THZ_Parse1($hash,$msg);
$msg=$cmdHex2 ."-". $msg ."-". $err;}
$msg=$cmdHex2 ."-". $msg ."-". $err;
}
my $activatetrigger =1;
# readingsSingleUpdate($hash, $cmd, $msg, $activatetrigger);
open (MYFILE, '>>data.txt');
@ -1969,15 +1879,15 @@ sub THZ_debugread($){
}
#######################################
#
#THZ_Attr($)
#in case of change of attribute starting with interval_ refresh all
#
########################################################################################
sub THZ_Attr(@) {
my ($cmd, $name, $attrName, $attrVal) = @_;
my $hash = $defs{$name};
$attrVal = "4.39" if (($cmd eq "del") and ($attrName eq "firmware"));
if ( $attrName eq "firmware" ) {
if ($attrVal eq "2.06") {
%sets = %sets206;
@ -2005,44 +1915,30 @@ sub THZ_Attr(@) {
THZ_Refresh_all_gets($hash);
}
}
if( $attrName =~ /^interval_/ ) {
#DevIo_CloseDev($hash);
#sleep 1;
#DevIo_OpenDev($hash, 1, "THZ_Refresh_all_gets");
THZ_Refresh_all_gets($hash);
}
return undef;
}
#####################################
sub THZ_Undef($$) {
my ($hash, $arg) = @_;
my $name = $hash->{NAME};
RemoveInternalTimer(0, "THZ_GetRefresh");
#THZ_RemoveInternalTimer("THZ_GetRefresh");
foreach my $d (sort keys %defs) {
if(defined($defs{$d}) &&
defined($defs{$d}{IODev}) &&
$defs{$d}{IODev} == $hash)
{
if(defined($defs{$d}) && defined($defs{$d}{IODev}) && $defs{$d}{IODev} == $hash) {
my $lev = ($reread_active ? 4 : 2);
Log3 $hash->{NAME}, $lev, "deleting port for $d";
delete $defs{$d}{IODev};
}
}
BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));
DevIo_CloseDev($hash);
return undef;
}
##########################################
# nearest rounds to the nearrest value multiple of the first argumen
# nearest_ceil(10, 45); --> 50
@ -2054,24 +1950,16 @@ sub nearest_ceil($$) {
my $targ = abs(shift);
my $Math1 = 0.5000000000003;
my @res = map { $targ * POSIX::floor(($_ + $Math1 * $targ) / $targ) } @_;
return wantarray ? @res : $res[0];
}
sub nearest_floor($$) {
my $targ = abs(shift);
my $Math1 = 0.5000000000003;
my @res = map { $targ * POSIX::ceil(($_ - $Math1 * $targ) / $targ) } @_;
return wantarray ? @res : $res[0];
}
##########################################
# THZ_RemoveInternalTimer($)
# modified takes as an argument the function to be called, not the argument
@ -2082,21 +1970,17 @@ sub nearest_floor($$) {
# delete($intAt{$a}) if($intAt{$a}{FN} eq $callingfun);
# }
#}
################################
#
sub function_heatSetTemp($$) {
my ($start, $stop) = @_;
my ($p13GradientHC1, $p14LowEndHC1, $p15RoomInfluenceHC1);
my $pOpMode = " ";
my $devname; #normally Mythz but could be defined differently
foreach (keys %defs) {
$devname=$_;
last if(($defs{$_}{TYPE}) =~ "THZ");
}
if (AttrVal($devname, "firmware" , "4.39") =~ /^2/ ) {
($p13GradientHC1, $p14LowEndHC1, $p15RoomInfluenceHC1) = (split ' ',ReadingsVal($devname,"pHeat1",0))[1,3,5];
}
@ -2113,12 +1997,10 @@ sub function_heatSetTemp($$) {
$pOpMode ="DEMO: no data";
$outside_tempFiltered = 0; $p14LowEndHC1 =0.5;
}
my $a= 0.7 + ($roomSetTemp * (1 + $p13GradientHC1 * 0.87)) + $p14LowEndHC1 + ($p15RoomInfluenceHC1 * $p13GradientHC1 * ($roomSetTemp - $insideTemp) /10);
my $a1= 0.7 + ($roomSetTemp * (1 + $p13GradientHC1 * 0.87)) + $p14LowEndHC1;
my $b= -14 * $p13GradientHC1 / $roomSetTemp;
my $c= -1 * $p13GradientHC1 /75;
my $Simul_heatSetTemp; my $Simul_heatSetTemp_simplified; my @ret;
foreach ($start..$stop) {
my $tmp =$_ * $_ * $c + $_ * $b;
@ -2201,44 +2083,34 @@ polyline { stroke:black; fill:none; }
<text x="751" y="155" class="ylabel" text-anchor="middle">20</text> <polyline points="751,19 751,140" class="hgrid"/>
<g>
END
$ret .= '<polyline points="44,140 49,140"/> <text x="39" y="144" class="ylabel" text-anchor="end">' . $v0min . '</text>';
$ret .= '<polyline points="44,110 49,110"/> <text x="39" y="114" class="ylabel" text-anchor="end">' . $v1 . '</text>';
$ret .= '<polyline points="44,80 49,80"/> <text x="39" y="84" class="ylabel" text-anchor="end">' . $v2 . '</text>';
$ret .= '<polyline points="44,49 49,49"/> <text x="39" y="53" class="ylabel" text-anchor="end">' . $v3 . '</text>';
$ret .= '<polyline points="44,19 49,19"/> <text x="39" y="23" class="ylabel" text-anchor="end">' . $v4 . '</text>';
$ret .= '</g> <g>';
$ret .= '<polyline points="751,140 756,140"/> <text x="760" y="144" class="ylabel">'. $v0min .'</text>';
$ret .= '<polyline points="751,110 756,110"/> <text x="760" y="114" class="ylabel">'. $v1 .'</text>';
$ret .= '<polyline points="751,80 756,80"/> <text x="760" y="84" class="ylabel">' . $v2 .'</text>';
$ret .= '<polyline points="751,49 756,49"/> <text x="760" y="53" class="ylabel">' . $v3 .'</text>';
$ret .= '<polyline points="751,19 756,19"/> <text x="760" y="23" class="ylabel">' . $v4 .'</text>';
$ret .= '</g>' ."\n";
$ret .= '<polyline points="44,140 49,140"/> <text x="39" y="144" class="ylabel" text-anchor="end">' . $v0min . '</text>'
. '<polyline points="44,110 49,110"/> <text x="39" y="114" class="ylabel" text-anchor="end">' . $v1 . '</text>'
. '<polyline points="44,80 49,80"/> <text x="39" y="84" class="ylabel" text-anchor="end">' . $v2 . '</text>'
. '<polyline points="44,49 49,49"/> <text x="39" y="53" class="ylabel" text-anchor="end">' . $v3 . '</text>'
. '<polyline points="44,19 49,19"/> <text x="39" y="23" class="ylabel" text-anchor="end">' . $v4 . '</text> </g> <g>'
. '<polyline points="751,140 756,140"/> <text x="760" y="144" class="ylabel">' . $v0min . '</text>'
. '<polyline points="751,110 756,110"/> <text x="760" y="114" class="ylabel">' . $v1 . '</text>'
. '<polyline points="751,80 756,80"/> <text x="760" y="84" class="ylabel">' . $v2 . '</text>'
. '<polyline points="751,49 756,49"/> <text x="760" y="53" class="ylabel">' . $v3 . '</text>'
. '<polyline points="751,19 756,19"/> <text x="760" y="23" class="ylabel">' . $v4 . '</text></g>' ."\n";
#labels ######################
$ret .= '<text line_id="line_1" x="70" y="100" class="l1"> --- heat curve with insideTemp correction</text>' ;
$ret .= '<text line_id="line_3" x="70" y="115" class="l3"> --- heat curve simplified</text>' ;
$ret .= '<text line_id="line_0" x="70" y="130" class="l0"> --- working point: ';
$ret .= 'outside_tempFiltered=' . $outside_tempFiltered . '°C heatSetTemp=' . $heatSetTemp . '°C </text>';
$ret .= '<text line_id="line_3" x="650" y="50" class="title"> -'. $pOpMode . '- </text>' ." \n" ;
$ret .= '<text line_id="line_1" x="70" y="100" class="l1"> --- heat curve with insideTemp correction</text>'
. '<text line_id="line_3" x="70" y="115" class="l3"> --- heat curve simplified</text>'
. '<text line_id="line_0" x="70" y="130" class="l0"> --- working point: outside_tempFiltered='
. $outside_tempFiltered . '°C heatSetTemp=' . $heatSetTemp . '°C </text>'
. '<text line_id="line_3" x="650" y="50" class="title"> -'. $pOpMode . '- </text>' ." \n";
#title ######################
$ret .= '<text id="svg_title" x="400" y="14.4" class="title" text-anchor="middle">';
$ret .= $titlestring .' </text>' . "\n";
$ret .= '<text id="svg_title" x="400" y="14.4" class="title" text-anchor="middle">'. $titlestring .' </text>' . "\n";
#point ######################
$ret .='<polyline id="line_0" style="stroke-width:2" class="l0" points="';
my ($px,$py) = (sprintf("%.1f", (($outside_tempFiltered+15)*(750-49)/(15+20)+49)),sprintf("%.1f", (($heatSetTemp-$v4)*(140-19)/($v0min-$v4)+19)));
$ret.= ($px-3) . "," . ($py) ." " . ($px) . "," . ($py-3) ." " . ($px+3) . "," . ($py) ." " . ($px) . "," . ($py+3) ." " . ($px-3) . "," . ($py) ." " . '"/>' . "\n";
#curve with inside temperature correction ######################
$ret .='<polyline id="line_1" title="Heat Curve with insideTemp correction" style="stroke-width:1" class="l1" points="';
foreach (@{$ycurvevalues}) {
$ret.= (sprintf("%.1f", ($_->[0]+15)*(750-49)/(15+20)+49) ). "," . sprintf("%.1f", (($_->[1]-$v4)*(140-19)/($v0min-$v4)+19)) ." ";
}
$ret .= '"/> ' . "\n";
#curve without inside temperature correction ######################
$ret .='<polyline id="line_3" title="Heat Curve simplified" style="stroke-width:1" class="l3" points="';
foreach (@{$ycurvevalues}) {
@ -2246,16 +2118,10 @@ $ret.= (sprintf("%.1f", ($_->[0]+15)*(750-49)/(15+20)+49) ). "," . sprintf("%.1f
}
$ret .= '"/> ' . "\n";
$ret .= '</svg>';
my $FW_RETTYPE = "image/svg+xml";
return ($FW_RETTYPE, $ret);
}
sub THZ_detailFn(@){
my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn.
my $hash = $defs{$d}; #$d is the name of the defined device
@ -2294,18 +2160,12 @@ sub THZ_backup_readings($){
return "saved Readings in $backupfile";
}
1;
=pod
=item device
=item summary Monitors and controls Tecalor/StiebelEltron heatpumps via RS232 or ser2net
=item summary_DE Kommuniziert mittels RS232 oder ser2net mit einer Tecalor/SE W&auml;rmepumpe
=item summary_DE Kommuniziert mittels RS232 oder ser2net mit einer Tecalor/SE Wärmepumpe
=item cloudfree
=item openapi
=begin html
@ -2388,19 +2248,15 @@ sub THZ_backup_readings($){
<a name="THZ"></a>
<h3>THZ</h3>
<ul>
THZ Modul: Kommuniziert mittels einem seriellen Interface RS232/USB (z.B. /dev/ttyxx), oder mittels ser2net (z.B. 10.0.x.x:5555) mit einer Tecalor / Stiebel
Eltron W&auml;rmepumpe. <br>
Getestet mit einer Tecalor THZ303/Sol (Serielle Geschwindigkeit 57600/115200@USB) und einer THZ403 (Serielle Geschwindigkeit 115200) mit identischer
Firmware 4.39. <br>
THZ Modul: Kommuniziert mittels einem seriellen Interface RS232/USB (z.B. /dev/ttyxx), oder mittels ser2net (z.B. 10.0.x.x:5555) mit einer Tecalor / Stiebel Eltron Wärmepumpe. <br>
Getestet mit einer Tecalor THZ303/Sol (Serielle Geschwindigkeit 57600/115200@USB) und einer THZ403 (Serielle Geschwindigkeit 115200) mit identischer Firmware 4.39. <br>
Getestet mit einer Stiebel LWZ404 (Serielle Geschwindigkeit 115200@USB) mit Firmware 5.39. <br>
Getestet auf FritzBox, nas-qnap, Raspberry Pi and MacOS.<br>
Dieses Modul funktioniert nicht mit &aumlterer Firmware; Gleichwohl, das "parsing" k&ouml;nnte leicht angepasst werden da die Register gut
beschrieben wurden.
Dieses Modul funktioniert nicht mit älterer Firmware; Gleichwohl, das "parsing" könnte leicht angepasst werden da die Register gut beschrieben wurden.
https://answers.launchpad.net/heatpumpmonitor/+question/100347 <br>
Implementiert: Lesen der Statusinformation sowie Lesen und Schreiben einzelner Einstellungen.
Genauere Beschreinung des Modules --> 00_THZ wiki http://www.fhemwiki.de/wiki/Tecalor_THZ_W%C3%A4rmepumpe
<br><br>
<a name="THZdefine"></a>
<b>Define</b>
<ul>
@ -2472,5 +2328,3 @@ sub THZ_backup_readings($){
=cut