23_LUXTRONIK2.pm 134 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568
  1. ###############################################################
  2. # $Id: 23_LUXTRONIK2.pm 16594 2018-04-12 16:58:59Z tupol $Date: $
  3. #
  4. # 23_LUXTRONIK2.pm
  5. #
  6. # (c) 2012-2017 Torsten Poitzsch
  7. # (c) 2012-2013 Jan-Hinrich Fessel (oskar at fessel . org)
  8. #
  9. # Copyright notice
  10. #
  11. # The module reads and writes parameters of the heat pump controller
  12. # Luxtronik 2.0 used in Alpha Innotec and Siemens Novelan (WPR NET) heat pumps.
  13. #
  14. # This script is free software; you can redistribute it and/or modify
  15. # it under the terms of the GNU General Public License as published by
  16. # the Free Software Foundation; either version 2 of the License, or
  17. # (at your option) any later version.
  18. #
  19. # The GNU General Public License can be found at
  20. # http://www.gnu.org/copyleft/gpl.html.
  21. # A copy is found in the textfile GPL.txt and important notices to the license
  22. # from the author is found in LICENSE.txt distributed with these scripts.
  23. #
  24. # This script is distributed in the hope that it will be useful,
  25. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. # GNU General Public License for more details.
  28. #
  29. # This copyright notice MUST APPEAR in all copies of the script!
  30. #
  31. ################################################################
  32. ##############################################
  33. package main;
  34. my $missingModul = "";
  35. use strict;
  36. use warnings;
  37. use Blocking;
  38. use IO::Socket;
  39. use Time::HiRes qw/ time /;
  40. eval "use Net::Telnet;1" or $missingModul .= "Net::Telnet ";
  41. sub LUXTRONIK2_doStatisticThermalPower ($$$$$$$$$);
  42. sub LUXTRONIK2_doStatisticMinMax ($$$);
  43. sub LUXTRONIK2_doStatisticMinMaxSingle ($$$$);
  44. sub LUXTRONIK2_storeReadings ($$$$$$);
  45. sub LUXTRONIK2_doStatisticDelta ($$$$$) ;
  46. sub LUXTRONIK2_doStatisticDeltaSingle ($$$$$$$);
  47. sub LUXTRONIK2_readData ($);
  48. #List of firmware versions that are known to be compatible with this modul
  49. my $testedFirmware = "#V1.51#V1.54C#V1.60#V1.61#V1.64#V1.69#V1.70#V1.73#V1.77#V1.80#V1.81#";
  50. my $compatibleFirmware = "#V1.51#V1.54C#V1.60#V1.61#V1.64#V1.69#V1.70#V1.73#V1.77#V1.80#V1.81#";
  51. sub ##########################################
  52. LUXTRONIK2_Log($$$)
  53. {
  54. my ( $hash, $loglevel, $text ) = @_;
  55. my $xline = ( caller(0) )[2];
  56. my $xsubroutine = ( caller(1) )[3];
  57. my $sub = ( split( ':', $xsubroutine ) )[2];
  58. $sub =~ s/LUXTRONIK2_//;
  59. my $instName = ( ref($hash) eq "HASH" ) ? $hash->{NAME} : $hash;
  60. Log3 $instName, $loglevel, "LUXTRONIK2 $instName: $sub.$xline " . $text;
  61. }
  62. sub ########################################
  63. LUXTRONIK2_Initialize($)
  64. {
  65. my ($hash) = @_;
  66. $hash->{DefFn} = "LUXTRONIK2_Define";
  67. $hash->{UndefFn} = "LUXTRONIK2_Undefine";
  68. $hash->{GetFn} = "LUXTRONIK2_Get";
  69. $hash->{SetFn} = "LUXTRONIK2_Set";
  70. $hash->{AttrFn} = "LUXTRONIK2_Attr";
  71. $hash->{AttrList} = "disable:0,1 ".
  72. "allowSetParameter:0,1 ".
  73. "autoSynchClock:slider,10,5,300 ".
  74. "boilerVolumn ".
  75. "compressor2ElectricalPowerWatt ".
  76. "doStatistics:0,1,2 ".
  77. "heatPumpElectricalPowerFactor ".
  78. "heatPumpElectricalPowerWatt ".
  79. "heatRodElectricalPowerWatt ".
  80. "ignoreFirmwareCheck:0,1 ".
  81. "statusHTML ".
  82. "userHeatpumpParameters ".
  83. "userHeatpumpValues ".
  84. $readingFnAttributes;
  85. }
  86. sub ########################################
  87. LUXTRONIK2_Define($$)
  88. {
  89. my ($hash, $def) = @_;
  90. my @a = split("[ \t][ \t]*", $def);
  91. return "Usage: define <name> LUXTRONIK2 <ip-address> [poll-interval]"
  92. if(@a <3 || @a >4);
  93. my $name = $a[0];
  94. my $host = $a[2];
  95. my $interval = 5*60;
  96. $interval = $a[3] if(int(@a) == 4);
  97. $interval = 10 if( $interval < 10 );
  98. $hash->{NAME} = $name;
  99. $hash->{STATE} = "Initializing";
  100. $hash->{HOST} = $host;
  101. if ( $host =~ /(.*):(.*)/ ) {
  102. $hash->{HOST} = $1;
  103. $hash->{PORT} = $2;
  104. $hash->{fhem}{portDefined} = 1;
  105. }
  106. else {
  107. $hash->{HOST} = $host;
  108. $hash->{PORT} = 8888;
  109. $hash->{fhem}{portDefined} = 0;
  110. }
  111. $hash->{INTERVAL} = $interval;
  112. $hash->{NOTIFYDEV} = "global";
  113. RemoveInternalTimer($hash);
  114. #Get first data after 10 seconds
  115. InternalTimer(gettimeofday() + 10, "LUXTRONIK2_GetUpdate", $hash, 0);
  116. #Reset temporary values
  117. $hash->{fhem}{durationFetchReadingsMin} = 0;
  118. $hash->{fhem}{durationFetchReadingsMax} = 0;
  119. $hash->{fhem}{alertFirmware} = 0;
  120. $hash->{fhem}{statBoilerHeatUpStep} = 0;
  121. $hash->{fhem}{statBoilerCoolDownStep} = 0;
  122. $hash->{fhem}{defrost}{mode}="none";
  123. $hash->{fhem}{hotWaterLastRun} = time();
  124. $hash->{fhem}{heatingPumpLastStop} = time();
  125. $hash->{fhem}{heatingPumpLastRun} = time();
  126. $hash->{fhem}{modulVersion} = '$Date: 2018-04-12 18:58:59 +0200 (Thu, 12 Apr 2018) $';
  127. return undef;
  128. }
  129. sub ########################################
  130. LUXTRONIK2_Undefine($$)
  131. {
  132. my ($hash, $arg) = @_;
  133. RemoveInternalTimer($hash);
  134. BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));
  135. return undef;
  136. }
  137. sub ########################################
  138. LUXTRONIK2_Attr(@)
  139. {
  140. my ($cmd,$name,$aName,$aVal) = @_;
  141. # $cmd can be "del" or "set"
  142. # $name is device name
  143. # aName and aVal are Attribute name and value
  144. if ($cmd eq "set") {
  145. if ($aName eq "1allowSetParameter") {
  146. eval { qr/$aVal/ };
  147. if ($@) {
  148. LUXTRONIK2_Log $name, 3, "Invalid allowSetParameter in attr $name $aName $aVal: $@";
  149. return "Invalid allowSetParameter $aVal";
  150. }
  151. }
  152. }
  153. return undef;
  154. }
  155. sub ########################################
  156. LUXTRONIK2_Set($$@)
  157. {
  158. my ($hash, $name, $cmd, $val) = @_;
  159. my $resultStr = "";
  160. if($cmd eq 'statusRequest') {
  161. $hash->{LOCAL} = 1;
  162. Log3 $name, 3, "set $name $cmd";
  163. LUXTRONIK2_GetUpdate($hash);
  164. $hash->{LOCAL} = 0;
  165. return undef;
  166. }
  167. elsif ($cmd eq 'resetStatistics') {
  168. Log3 $name, 3, "set $name $cmd $val";
  169. if ( $val eq "statBoilerGradientCoolDownMin"
  170. && exists($hash->{READINGS}{statBoilerGradientCoolDownMin})) {
  171. delete $hash->{READINGS}{statBoilerGradientCoolDownMin};
  172. $resultStr .= " statBoilerGradientCoolDownMin";
  173. }
  174. elsif ($val =~ /all|statAmbientTemp\.\.\.|statElectricity\.\.\.|statHours\.\.\.|statHeatQ\.\.\./) {
  175. my $regExp;
  176. if ($val eq "all") { $regExp = "stat"; }
  177. else { $regExp = substr $val, 0, -3; }
  178. foreach (sort keys %{ $hash->{READINGS} }) {
  179. if ($_ =~ /^\.?$regExp/ && $_ ne "state") {
  180. delete $hash->{READINGS}{$_};
  181. $resultStr .= " " . $_;
  182. }
  183. }
  184. }
  185. if ( $resultStr eq "" ) {
  186. $resultStr = "$name: No statistics to reset";
  187. } else {
  188. $resultStr = "$name: Statistic value(s) deleted:" . $resultStr;
  189. WriteStatefile();
  190. }
  191. # LUXTRONIK2_Log $hash, 3, $resultStr;
  192. return $resultStr;
  193. }
  194. elsif($cmd eq 'INTERVAL' && int(@_)==4 ) {
  195. Log3 $name, 3, "set $name $cmd $val";
  196. $val = 10 if( $val < 10 );
  197. $hash->{INTERVAL}=$val;
  198. return "Polling interval set to $val seconds.";
  199. }
  200. elsif($cmd eq 'activeTariff' && int(@_)==4 ) {
  201. $val = 0 if( $val < 1 || $val > 9 );
  202. readingsSingleUpdate($hash,"activeTariff",$val, 1);
  203. $hash->{LOCAL} = 1;
  204. LUXTRONIK2_GetUpdate($hash);
  205. $hash->{LOCAL} = 0;
  206. Log3 $name, 3, "set $name $cmd $val";
  207. return undef;
  208. }
  209. #Check Firmware and Set-Parameter-lock
  210. if ( $cmd =~ /^(synchronizeClockHeatPump|hotWaterTemperatureTarget|opModeHotWater)$/i )
  211. {
  212. my $firmware = ReadingsVal($name,"firmware","");
  213. my $firmwareCheck = LUXTRONIK2_checkFirmware($firmware);
  214. # stop in case of incompatible firmware
  215. if ($firmwareCheck eq "fwNotCompatible") {
  216. LUXTRONIK2_Log $name, 3, " Error: Host firmware '$firmware' not compatible for parameter setting.";
  217. return "Firmware '$firmware' not compatible for parameter setting. ";
  218. # stop in case of untested firmware and firmware check enabled
  219. } elsif (AttrVal($name, "ignoreFirmwareCheck", 0)!= 1 &&
  220. $firmwareCheck eq "fwNotTested") {
  221. LUXTRONIK2_Log $name, 3, " Error: Host firmware '$firmware' not tested for parameter setting. To test set attribute 'ignoreFirmwareCheck' to 1";
  222. return "Firmware '$firmware' not compatible for parameter setting. To test set attribute 'ignoreFirmwareCheck' to 1.";
  223. # stop in case setting of parameters is not enabled
  224. } elsif ( AttrVal($name, "allowSetParameter", 0) != 1) {
  225. LUXTRONIK2_Log $name, 3, " Error: Setting of parameters not allowed. Please set attribut 'allowSetParameter' to 1";
  226. return "Setting of parameters not allowed. To unlock, please set attribut 'allowSetParameter' to 1.";
  227. }
  228. }
  229. if ($cmd eq 'synchronizeClockHeatPump') {
  230. $hash->{LOCAL} = 1;
  231. $resultStr = LUXTRONIK2_synchronizeClock($hash);
  232. $hash->{LOCAL} = 0;
  233. LUXTRONIK2_Log $name, 3, $resultStr;
  234. return $resultStr;
  235. }
  236. elsif ($cmd eq 'boostHotWater' && int(@_)<=4) {
  237. Log3 $name, 3, "set $name $cmd" unless $val;
  238. Log3 $name, 3, "set $name $cmd $val" if $val;
  239. return LUXTRONIK2_boostHotWater_Start( $hash, $val );
  240. }
  241. elsif(int(@_)==4 &&
  242. ($cmd eq 'hotWaterTemperatureTarget'
  243. || $cmd eq 'opModeHotWater'
  244. || $cmd eq 'returnTemperatureHyst'
  245. || $cmd eq 'returnTemperatureSetBack'
  246. || $cmd eq 'heatingCurveEndPoint'
  247. || $cmd eq 'heatingCurveOffset'
  248. || $cmd eq 'heatSourceDefrostAirEnd'
  249. || $cmd eq 'heatSourceDefrostAirThreshold')) {
  250. Log3 $name, 3, "set $name $cmd $val";
  251. $hash->{LOCAL} = 1;
  252. $resultStr = LUXTRONIK2_SetParameter ($hash, $cmd, $val);
  253. $hash->{LOCAL} = 0;
  254. return $resultStr;
  255. }
  256. # Einstellung->Entlüftung
  257. elsif( int(@_)==4 &&
  258. ( $cmd eq 'hotWaterCircPumpDeaerate' || $cmd eq 'heatingSystemCircPumpDeaerate' ) ) {
  259. Log3 $name, 3, "set $name $cmd $val";
  260. return "$name Error: Wrong parameter given - use on,off" if $val !~ /on|off/;
  261. $hash->{LOCAL} = 1;
  262. $resultStr = LUXTRONIK2_SetParameter ($hash, $cmd, $val);
  263. if( $val eq "on"
  264. || ReadingsVal( $name, "heatingSystemCircPumpDeaerate", "off" ) eq "on"
  265. || ReadingsVal( $name, "hotWaterCircPumpDeaerate", "off" ) eq "on" ) {
  266. $resultStr .= LUXTRONIK2_SetParameter ($hash, "runDeaerate", 1);
  267. }
  268. # only send "0" if no Deaerate checkbox is selected at all.
  269. else {
  270. $resultStr .= LUXTRONIK2_SetParameter ($hash, "runDeaerate", 0);
  271. }
  272. $hash->{LOCAL} = 0;
  273. return $resultStr;
  274. }
  275. my $list = "statusRequest:noArg"
  276. ." activeTariff:0,1,2,3,4,5,6,7,8,9"
  277. ." boostHotWater"
  278. ." heatingCurveEndPoint"
  279. ." heatingCurveOffset"
  280. ." heatingSystemCircPumpDeaerate:on,off"
  281. ." heatSourceDefrostAirEnd"
  282. ." heatSourceDefrostAirThreshold"
  283. ." hotWaterCircPumpDeaerate:on,off"
  284. ." hotWaterTemperatureTarget "
  285. ." resetStatistics:all,statBoilerGradientCoolDownMin,statAmbientTemp...,statElectricity...,statHours...,statHeatQ..."
  286. ." returnTemperatureHyst "
  287. ." returnTemperatureSetBack "
  288. ." opModeHotWater:Auto,Party,Off"
  289. ." synchronizeClockHeatPump:noArg"
  290. ." INTERVAL ";
  291. return "Unknown argument $cmd, choose one of $list";
  292. }
  293. sub ########################################
  294. LUXTRONIK2_Get($$@)
  295. {
  296. my ($hash, $name, $cmd, @val ) = @_;
  297. my $resultStr = "";
  298. my @nameOfValue = qw( ? ? ? ? ? ? ? ? ? ? Temperatur_TVL Temperatur_TRL Sollwert_TRL_HZ Temperatur_TRL_ext Temperatur_THG Temperatur_TA Mitteltemperatur Temperatur_TBW Einst_BWS_akt Temperatur_TWE Temperatur_TWA Temperatur_TFB1 Sollwert_TVL_MK1 Temperatur_RFV Temperatur_TFB2 Sollwert_TVL_MK2 Temperatur_TSK Temperatur_TSS Temperatur_TEE ASDin BWTin EVUin HDin MOTin NDin PEXin SWTin AVout BUPout HUPout MA1out MZ1out VENout VBOout VD1out VD2out ZIPout ZUPout ZW1out ZW2SSTout ZW3SSTout FP2out SLPout SUPout MZ2out MA2out Zaehler_BetrZeitVD1 Zaehler_BetrZeitImpVD1 Zaehler_BetrZeitVD2 Zaehler_BetrZeitImpVD2 Zaehler_BetrZeitZWE1 Zaehler_BetrZeitZWE2 Zaehler_BetrZeitZWE3 Zaehler_BetrZeitWP Zaehler_BetrZeitHz Zaehler_BetrZeitBW Zaehler_BetrZeitKue Time_WPein_akt Time_ZWE1_akt Time_ZWE2_akt Timer_EinschVerz Time_SSPAUS_akt Time_SSPEIN_akt Time_VDStd_akt Time_HRM_akt Time_HRW_akt Time_LGS_akt Time_SBW_akt Code_WP_akt BIV_Stufe_akt WP_BZ_akt SoftStand1 SoftStand2 SoftStand3 SoftStand4 SoftStand5 SoftStand6 SoftStand7 SoftStand8 SoftStand9 SoftStand10 AdresseIP_akt SubNetMask_akt Add_Broadcast Add_StdGateway ERROR_Time0 ERROR_Time1 ERROR_Time2 ERROR_Time3 ERROR_Time4 ERROR_Nr0 ERROR_Nr1 ERROR_Nr2 ERROR_Nr3 ERROR_Nr4 AnzahlFehlerInSpeicher Switchoff_file_Nr0 Switchoff_file_Nr1 Switchoff_file_Nr2 Switchoff_file_Nr3 Switchoff_file_Nr4 Switchoff_file_Time0 Switchoff_file_Time1 Switchoff_file_Time2 Switchoff_file_Time3 Switchoff_file_Time4 Comfort_exists HauptMenuStatus_Zeile1 HauptMenuStatus_Zeile2 HauptMenuStatus_Zeile3 HauptMenuStatus_Zeit HauptMenuAHP_Stufe HauptMenuAHP_Temp HauptMenuAHP_Zeit SH_BWW SH_HZ SH_MK1 SH_MK2 Einst_Kurzprogramm StatusSlave_1 StatusSlave_2 StatusSlave_3 StatusSlave_4 StatusSlave_5 AktuelleTimeStamp SH_MK3 Sollwert_TVL_MK3 Temperatur_TFB3 MZ3out MA3out FP3out Time_AbtIn Temperatur_RFV2 Temperatur_RFV3 SH_SW Zaehler_BetrZeitSW FreigabKuehl AnalogIn SonderZeichen SH_ZIP WebsrvProgrammWerteBeobachten WMZ_Heizung WMZ_Brauchwasser WMZ_Schwimmbad WMZ_Seit WMZ_Durchfluss AnalogOut1 AnalogOut2 Time_Heissgas Temp_Lueftung_Zuluft Temp_Lueftung_Abluft Zaehler_BetrZeitSolar AnalogOut3 AnalogOut4 Out_VZU Out_VAB Out_VSK Out_FRH AnalogIn2 AnalogIn3 SAXin SPLin Compact_exists Durchfluss_WQ LIN_exists LIN_ANSAUG_VERDAMPFER LIN_ANSAUG_VERDICHTER LIN_VDH LIN_UH LIN_UH_Soll LIN_HD LIN_ND LIN_VDH_out HZIO_PWM HZIO_VEN HZIO_EVU2 HZIO_STB SEC_Qh_Soll SEC_Qh_Ist SEC_TVL_Soll SEC_Software SEC_BZ SEC_VWV SEC_VD SEC_VerdEVI SEC_AnsEVI SEC_UEH_EVI SEC_UEH_EVI_S SEC_KondTemp SEC_FlussigEx SEC_UK_EEV SEC_EVI_Druck SEC_U_Inv Temperatur_THG_2 Temperatur_TWE_2 LIN_ANSAUG_VERDAMPFER_2 LIN_ANSAUG_VERDICHTER_2 LIN_VDH_2 LIN_UH_2 LIN_UH_Soll_2 LIN_HD_2 LIN_ND_2 HDin_2 AVout_2 VBOout_2 VD1out_2 LIN_VDH_out_2 Switchoff2_Nr0 Switchoff2_Nr1 Switchoff2_Nr2 Switchoff2_Nr3 Switchoff2_Nr4 Switchoff2_Time0 Switchoff2_Time1 Switchoff2_Time2 Switchoff2_Time3 Switchoff2_Time4 RBE_RT_Ist RBE_RT_Soll Temp_BW_oben Code_WP_akt_2 Freq_VD LIN_Temp_ND LIN_Temp_HD Abtauwunsch Abtauwunsch_2 Freq_Soll Freq_Min Freq_Max VBO_Soll VBO_Ist HZUP_PWM HZUP_Soll HZUP_Ist Temperatur_VLMax Temperatur_VLMax_2 SEC_EVi SEC_EEV Time_ZWE3_akt );
  299. my @nameOfParameter = qw(Transfert_LuxNet Einst_WK_akt Einst_BWS_akt Ba_Hz_akt Ba_Bw_akt Ba_Al_akt SU_FrkdHz SU_FrkdBw SU_FrkdAl Einst_HReg_akt Einst_HzHwMAt_akt Einst_HzHwHKE_akt Einst_HzHKRANH_akt Einst_HzHKRABS_akt Einst_HzMK1E_akt Einst_HzMK1ANH_akt Einst_HzMK1ABS_akt Einst_HzFtRl_akt Einst_HzFtMK1Vl_akt Einst_SUBW_akt Einst_BwTDI_akt_MO Einst_BwTDI_akt_DI Einst_BwTDI_akt_MI Einst_BwTDI_akt_DO Einst_BwTDI_akt_FR Einst_BwTDI_akt_SA Einst_BwTDI_akt_SO Einst_BwTDI_akt_AL Einst_AnlKonf_akt Einst_Sprache_akt Switchoff_Zahler Switchoff_index Einst_EvuTyp_akt Einst_RFVEinb_akt Einst_AbtZykMax_akt Einst_HREinb_akt Einst_ZWE1Art_akt Einst_ZWE1Fkt_akt Einst_ZWE2Art_akt Einst_ZWE2Fkt_akt Einst_BWBer_akt Einst_En_Inst Einst_MK1Typ_akt Einst_ABTLuft_akt Einst_TLAbt_akt Einst_LAbtTime_akt Einst_ASDTyp_akt Einst_LGST_akt Einst_BwWpTime_akt Einst_Popt_akt Einst_Kurzprog_akt Timer_Kurzprog_akt Einst_ManAbt_akt Einst_Ahz_akt Einst_TVL_Ahz_1 Einst_TVL_Ahz_2 Einst_TVL_Ahz_3 Einst_TVL_Ahz_4 Einst_TVL_Ahz_5 Einst_TVL_Ahz_6 Einst_TVL_Ahz_7 Einst_TVL_Ahz_8 Einst_TVL_Ahz_9 Einst_TVL_Ahz_10 Einst_TVL_Std_1 Einst_TVL_Std_2 Einst_TVL_Std_3 Einst_TVL_Std_4 Einst_TVL_Std_5 Einst_TVL_Std_6 Einst_TVL_Std_7 Einst_TVL_Std_8 Einst_TVL_Std_9 Einst_TVL_Std_10 Einst_BWS_Hyst_akt Temp_TBW_BwHD_saved Einst_ABT1_akt Einst_LABTpaus_akt AHZ_state_akt Sollwert_TRL_HZ_AHZ AHP_valrecords Timer_AHZ_akt Einst_BWTINP_akt Einst_ZUPTYP_akt Sollwert_TLG_max Einst_BWZIP_akt Einst_ERRmZWE_akt Einst_TRBegr_akt Einst_HRHyst_akt Einst_TRErhmax_akt Einst_ZWEFreig_akt Einst_TAmax_akt Einst_TAmin_akt Einst_TWQmin_akt Einst_THGmax_akt Einst_FRGT2VD_akt Einst_TV2VDBW_akt Einst_SuAll_akt Einst_TAbtEnd_akt Einst_NrKlingel_akt Einst_BWStyp_akt Einst_ABT2_akt Einst_UeVd_akt Einst_RTyp_akt Einst_AhpM_akt Soll_BWS_akt Timer_Password Einst_Zugangscode Einst_BA_Kuehl_akt Sollwert_Kuehl1_akt Einst_KuehlFreig_akt Einst_TAbsMin_akt TWQmin_saved CWP_saved Einst_Anode_akt Timer_pexoff_akt Einst_AnlPrio_Hzakt Einst_AnlPrio_Bwakt Einst_AnlPrio_Swakt Ba_Sw_akt Einst_RTypMK1_akt Einst_RTypMK2_akt Einst_TDC_Ein_akt Einst_TDC_Aus_akt Einst_TDC_Max_akt Einst_HysHzExEn_akt Einst_HysBwExEn_akt Einst_ZWE3Art_akt Einst_ZWE3Fkt_akt Einst_HzSup_akt Einst_MK2Typ_akt Einst_KuTyp_akt Sollwert_KuCft1_akt Sollwert_KuCft2_akt Sollwert_AtDif1_akt Sollwert_AtDif2_akt SU_FrkdSwb Einst_SwbBer_akt Einst_TV2VDSWB_akt Einst_MinSwan_Time_akt Einst_SuMk2_akt Einst_HzMK2E_akt Einst_HzMK2ANH_akt Einst_HzMK2ABS_akt Einst_HzMK2Hgr_akt Einst_HzFtMK2Vl_akt Temp_THG_BwHD_saved Temp_TA_BwHD_saved Einst_BwHup_akt Einst_TVLmax_akt Einst_MK1LzFaktor_akt Einst_MK2LzFaktor_akt Einst_MK1PerFaktor_akt Einst_MK2PerFaktor_akt Entl_Zyklus_akt Einst_Entl_time_akt Entl_Pause Entl_timer Einst_Entl_akt Ahz_HLeist_confirmed FirstInit_akt Einst_SuAll_akt2 Einst_SuAllWo_zeit_0_0 Einst_SuAllWo_zeit_0_1 Einst_SuAllWo_zeit_1_0 Einst_SuAllWo_zeit_1_1 Einst_SuAllWo_zeit_2_0 Einst_SuAllWo_zeit_2_1 Einst_SuAll25_zeit_0_0 Einst_SuAll25_zeit_0_1 Einst_SuAll25_zeit_1_0 Einst_SuAll25_zeit_1_1 Einst_SuAll25_zeit_2_0 Einst_SuAll25_zeit_2_1 Einst_SuAll25_zeit_0_2 Einst_SuAll25_zeit_0_3 Einst_SuAll25_zeit_1_2 Einst_SuAll25_zeit_1_3 Einst_SuAll25_zeit_2_2 Einst_SuAll25_zeit_2_3 Einst_SuAllTg_zeit_0_0 Einst_SuAllTg_zeit_0_1 Einst_SuAllTg_zeit_1_0 Einst_SuAllTg_zeit_1_1 Einst_SuAllTg_zeit_2_0 Einst_SuAllTg_zeit_2_1 Einst_SuAllTg_zeit_0_2 Einst_SuAllTg_zeit_0_3 Einst_SuAllTg_zeit_1_2 Einst_SuAllTg_zeit_1_3 Einst_SuAllTg_zeit_2_2 Einst_SuAllTg_zeit_2_3 Einst_SuAllTg_zeit_0_4 Einst_SuAllTg_zeit_0_5 Einst_SuAllTg_zeit_1_4 Einst_SuAllTg_zeit_1_5 Einst_SuAllTg_zeit_2_4 Einst_SuAllTg_zeit_2_5 Einst_SuAllTg_zeit_0_6 Einst_SuAllTg_zeit_0_7 Einst_SuAllTg_zeit_1_6 Einst_SuAllTg_zeit_1_7 Einst_SuAllTg_zeit_2_6 Einst_SuAllTg_zeit_2_7 Einst_SuAllTg_zeit_0_8 Einst_SuAllTg_zeit_0_9 Einst_SuAllTg_zeit_1_8 Einst_SuAllTg_zeit_1_9 Einst_SuAllTg_zeit_2_8 Einst_SuAllTg_zeit_2_9 Einst_SuAllTg_zeit_0_10 Einst_SuAllTg_zeit_0_11 Einst_SuAllTg_zeit_1_10 Einst_SuAllTg_zeit_1_11 Einst_SuAllTg_zeit_2_10 Einst_SuAllTg_zeit_2_11 Einst_SuAllTg_zeit_0_12 Einst_SuAllTg_zeit_0_13 Einst_SuAllTg_zeit_1_12 Einst_SuAllTg_zeit_1_13 Einst_SuAllTg_zeit_2_12 Einst_SuAllTg_zeit_2_13 Einst_SuHkr_akt Einst_SuHkrW0_zeit_0_0 Einst_SuHkrW0_zeit_0_1 Einst_SuHkrW0_zeit_1_0 Einst_SuHkrW0_zeit_1_1 Einst_SuHkrW0_zeit_2_0 Einst_SuHkrW0_zeit_2_1 Einst_SuHkr25_zeit_0_0 Einst_SuHkr25_zeit_0_1 Einst_SuHkr25_zeit_1_0 Einst_SuHkr25_zeit_1_1 Einst_SuHkr25_zeit_2_0 Einst_SuHkr25_zeit_2_1 Einst_SuHkr25_zeit_0_2 Einst_SuHkr25_zeit_0_3 Einst_SuHkr25_zeit_1_2 Einst_SuHkr25_zeit_1_3 Einst_SuHkr25_zeit_2_2 Einst_SuHkr25_zeit_2_3 Einst_SuHkrTG_zeit_0_0 Einst_SuHkrTG_zeit_0_1 Einst_SuHkrTG_zeit_1_0 Einst_SuHkrTG_zeit_1_1 Einst_SuHkrTG_zeit_2_0 Einst_SuHkrTG_zeit_2_1 Einst_SuHkrTG_zeit_0_2 Einst_SuHkrTG_zeit_0_3 Einst_SuHkrTG_zeit_1_2 Einst_SuHkrTG_zeit_1_3 Einst_SuHkrTG_zeit_2_2 Einst_SuHkrTG_zeit_2_3 Einst_SuHkrTG_zeit_0_4 Einst_SuHkrTG_zeit_0_5 Einst_SuHkrTG_zeit_1_4 Einst_SuHkrTG_zeit_1_5 Einst_SuHkrTG_zeit_2_4 Einst_SuHkrTG_zeit_2_5 Einst_SuHkrTG_zeit_0_6 Einst_SuHkrTG_zeit_0_7 Einst_SuHkrTG_zeit_1_6 Einst_SuHkrTG_zeit_1_7 Einst_SuHkrTG_zeit_2_6 Einst_SuHkrTG_zeit_2_7 Einst_SuHkrTG_zeit_0_8 Einst_SuHkrTG_zeit_0_9 Einst_SuHkrTG_zeit_1_8 Einst_SuHkrTG_zeit_1_9 Einst_SuHkrTG_zeit_2_8 Einst_SuHkrTG_zeit_2_9 Einst_SuHkrTG_zeit_0_10 Einst_SuHkrTG_zeit_0_11 Einst_SuHkrTG_zeit_1_10 Einst_SuHkrTG_zeit_1_11 Einst_SuHkrTG_zeit_2_10 Einst_SuHkrTG_zeit_2_11 Einst_SuHkrTG_zeit_0_12 Einst_SuHkrTG_zeit_0_13 Einst_SuHkrTG_zeit_1_12 Einst_SuHkrTG_zeit_1_13 Einst_SuHkrTG_zeit_2_12 Einst_SuHkrTG_zeit_2_13 Einst_SuMk1_akt Einst_SuMk1W0_zeit_0_0 Einst_SuMk1W0_zeit_0_1 Einst_SuMk1W0_zeit_1_0 Einst_SuMk1W0_zeit_1_1 Einst_SuMk1W0_zeit_2_0 Einst_SuMk1W0_zeit_2_1 Einst_SuMk125_zeit_0_0 Einst_SuMk125_zeit_0_1 Einst_SuMk125_zeit_1_0 Einst_SuMk125_zeit_1_1 Einst_SuMk125_zeit_2_0 Einst_SuMk125_zeit_2_1 Einst_SuMk125_zeit_0_2 Einst_SuMk125_zeit_0_3 Einst_SuMk125_zeit_1_2 Einst_SuMk125_zeit_1_3 Einst_SuMk125_zeit_2_2 Einst_SuMk125_zeit_2_3 Einst_SuMk1TG_zeit_0_0 Einst_SuMk1TG_zeit_0_1 Einst_SuMk1TG_zeit_1_0 Einst_SuMk1TG_zeit_1_1 Einst_SuMk1TG_zeit_2_0 Einst_SuMk1TG_zeit_2_1 Einst_SuMk1TG_zeit_0_2 Einst_SuMk1TG_zeit_0_3 Einst_SuMk1TG_zeit_1_2 Einst_SuMk1TG_zeit_1_3 Einst_SuMk1TG_zeit_2_2 Einst_SuMk1TG_zeit_2_3 Einst_SuMk1TG_zeit_0_4 Einst_SuMk1TG_zeit_0_5 Einst_SuMk1TG_zeit_1_4 Einst_SuMk1TG_zeit_1_5 Einst_SuMk1TG_zeit_2_4 Einst_SuMk1TG_zeit_2_5 Einst_SuMk1TG_zeit_0_6 Einst_SuMk1TG_zeit_0_7 Einst_SuMk1TG_zeit_1_6 Einst_SuMk1TG_zeit_1_7 Einst_SuMk1TG_zeit_2_6 Einst_SuMk1TG_zeit_2_7 Einst_SuMk1TG_zeit_0_8 Einst_SuMk1TG_zeit_0_9 Einst_SuMk1TG_zeit_1_8 Einst_SuMk1TG_zeit_1_9 Einst_SuMk1TG_zeit_2_8 Einst_SuMk1TG_zeit_2_9 Einst_SuMk1TG_zeit_0_10 Einst_SuMk1TG_zeit_0_11 Einst_SuMk1TG_zeit_1_10 Einst_SuMk1TG_zeit_1_11 Einst_SuMk1TG_zeit_2_10 Einst_SuMk1TG_zeit_2_11 Einst_SuMk1TG_zeit_0_12 Einst_SuMk1TG_zeit_0_13 Einst_SuMk1TG_zeit_1_12 Einst_SuMk1TG_zeit_1_13 Einst_SuMk1TG_zeit_2_12 Einst_SuMk1TG_zeit_2_13 Einst_SuMk2_akt2 Einst_SuMk2Wo_zeit_0_0 Einst_SuMk2Wo_zeit_0_1 Einst_SuMk2Wo_zeit_1_0 Einst_SuMk2Wo_zeit_1_1 Einst_SuMk2Wo_zeit_2_0 Einst_SuMk2Wo_zeit_2_1 Einst_SuMk225_zeit_0_0 Einst_SuMk225_zeit_0_1 Einst_SuMk225_zeit_1_0 Einst_SuMk225_zeit_1_1 Einst_SuMk225_zeit_2_0 Einst_SuMk225_zeit_2_1 Einst_SuMk225_zeit_0_2 Einst_SuMk225_zeit_0_3 Einst_SuMk225_zeit_1_2 Einst_SuMk225_zeit_1_3 Einst_SuMk225_zeit_2_2 Einst_SuMk225_zeit_2_3 Einst_SuMk2Tg_zeit_0_0 Einst_SuMk2Tg_zeit_0_1 Einst_SuMk2Tg_zeit_1_0 Einst_SuMk2Tg_zeit_1_1 Einst_SuMk2Tg_zeit_2_0 Einst_SuMk2Tg_zeit_2_1 Einst_SuMk2Tg_zeit_0_2 Einst_SuMk2Tg_zeit_0_3 Einst_SuMk2Tg_zeit_1_2 Einst_SuMk2Tg_zeit_1_3 Einst_SuMk2Tg_zeit_2_2 Einst_SuMk2Tg_zeit_2_3 Einst_SuMk2Tg_zeit_0_4 Einst_SuMk2Tg_zeit_0_5 Einst_SuMk2Tg_zeit_1_4 Einst_SuMk2Tg_zeit_1_5 Einst_SuMk2Tg_zeit_2_4 Einst_SuMk2Tg_zeit_2_5 Einst_SuMk2Tg_zeit_0_6 Einst_SuMk2Tg_zeit_0_7 Einst_SuMk2Tg_zeit_1_6 Einst_SuMk2Tg_zeit_1_7 Einst_SuMk2Tg_zeit_2_6 Einst_SuMk2Tg_zeit_2_7 Einst_SuMk2Tg_zeit_0_8 Einst_SuMk2Tg_zeit_0_9 Einst_SuMk2Tg_zeit_1_8 Einst_SuMk2Tg_zeit_1_9 Einst_SuMk2Tg_zeit_2_8 Einst_SuMk2Tg_zeit_2_9 Einst_SuMk2Tg_zeit_0_10 Einst_SuMk2Tg_zeit_0_11 Einst_SuMk2Tg_zeit_1_10 Einst_SuMk2Tg_zeit_1_11 Einst_SuMk2Tg_zeit_2_10 Einst_SuMk2Tg_zeit_2_11 Einst_SuMk2Tg_zeit_0_12 Einst_SuMk2Tg_zeit_0_13 Einst_SuMk2Tg_zeit_1_12 Einst_SuMk2Tg_zeit_1_13 Einst_SuMk2Tg_zeit_2_12 Einst_SuMk2Tg_zeit_2_13 Einst_SUBW_akt2 Einst_SuBwWO_zeit_0_0 Einst_SuBwWO_zeit_0_1 Einst_SuBwWO_zeit_1_0 Einst_SuBwWO_zeit_1_1 Einst_SuBwWO_zeit_2_0 Einst_SuBwWO_zeit_2_1 Einst_SuBwWO_zeit_3_0 Einst_SuBwWO_zeit_3_1 Einst_SuBwWO_zeit_4_0 Einst_SuBwWO_zeit_4_1 Einst_SuBw25_zeit_0_0 Einst_SuBw25_zeit_0_1 Einst_SuBw25_zeit_1_0 Einst_SuBw25_zeit_1_1 Einst_SuBw25_zeit_2_0 Einst_SuBw25_zeit_2_1 Einst_SuBw25_zeit_3_0 Einst_SuBw25_zeit_3_1 Einst_SuBw25_zeit_4_0 Einst_SuBw25_zeit_4_1 Einst_SuBw25_zeit_0_2 Einst_SuBw25_zeit_0_3 Einst_SuBw25_zeit_1_2 Einst_SuBw25_zeit_1_3 Einst_SuBw25_zeit_2_2 Einst_SuBw25_zeit_2_3 Einst_SuBw25_zeit_3_2 Einst_SuBw25_zeit_3_3 Einst_SuBw25_zeit_4_2 Einst_SuBw25_zeit_4_3 Einst_SuBwTG_zeit_0_0 Einst_SuBwTG_zeit_0_1 Einst_SuBwTG_zeit_1_0 Einst_SuBwTG_zeit_1_1 Einst_SuBwTG_zeit_2_0 Einst_SuBwTG_zeit_2_1 Einst_SuBwTG_zeit_3_0 Einst_SuBwTG_zeit_3_1 Einst_SuBwTG_zeit_4_0 Einst_SuBwTG_zeit_4_1 Einst_SuBwTG_zeit_0_2 Einst_SuBwTG_zeit_0_3 Einst_SuBwTG_zeit_1_2 Einst_SuBwTG_zeit_1_3 Einst_SuBwTG_zeit_2_2 Einst_SuBwTG_zeit_2_3 Einst_SuBwTG_zeit_3_2 Einst_SuBwTG_zeit_3_3 Einst_SuBwTG_zeit_4_2 Einst_SuBwTG_zeit_4_3 Einst_SuBwTG_zeit_0_4 Einst_SuBwTG_zeit_0_5 Einst_SuBwTG_zeit_1_4 Einst_SuBwTG_zeit_1_5 Einst_SuBwTG_zeit_2_4 Einst_SuBwTG_zeit_2_5 Einst_SuBwTG_zeit_3_4 Einst_SuBwTG_zeit_3_5 Einst_SuBwTG_zeit_4_4 Einst_SuBwTG_zeit_4_5 Einst_SuBwTG_zeit_0_6 Einst_SuBwTG_zeit_0_7 Einst_SuBwTG_zeit_1_6 Einst_SuBwTG_zeit_1_7 Einst_SuBwTG_zeit_2_6 Einst_SuBwTG_zeit_2_7 Einst_SuBwTG_zeit_3_6 Einst_SuBwTG_zeit_3_7 Einst_SuBwTG_zeit_4_6 Einst_SuBwTG_zeit_4_7 Einst_SuBwTG_zeit_0_8 Einst_SuBwTG_zeit_0_9 Einst_SuBwTG_zeit_1_8 Einst_SuBwTG_zeit_1_9 Einst_SuBwTG_zeit_2_8 Einst_SuBwTG_zeit_2_9 Einst_SuBwTG_zeit_3_8 Einst_SuBwTG_zeit_3_9 Einst_SuBwTG_zeit_4_8 Einst_SuBwTG_zeit_4_9 Einst_SuBwTG_zeit_0_10 Einst_SuBwTG_zeit_0_11 Einst_SuBwTG_zeit_1_10 Einst_SuBwTG_zeit_1_11 Einst_SuBwTG_zeit_2_10 Einst_SuBwTG_zeit_2_11 Einst_SuBwTG_zeit_3_10 Einst_SuBwTG_zeit_3_11 Einst_SuBwTG_zeit_4_10 Einst_SuBwTG_zeit_4_11 Einst_SuBwTG_zeit_0_12 Einst_SuBwTG_zeit_0_13 Einst_SuBwTG_zeit_1_12 Einst_SuBwTG_zeit_1_13 Einst_SuBwTG_zeit_2_12 Einst_SuBwTG_zeit_2_13 Einst_SuBwTG_zeit_3_12 Einst_SuBwTG_zeit_3_13 Einst_SuBwTG_zeit_4_12 Einst_SuBwTG_zeit_4_13 Einst_SuZIP_akt Einst_SuZIPWo_zeit_0_0 Einst_SuZIPWo_zeit_0_1 Einst_SuZIPWo_zeit_1_0 Einst_SuZIPWo_zeit_1_1 Einst_SuZIPWo_zeit_2_0 Einst_SuZIPWo_zeit_2_1 Einst_SuZIPWo_zeit_3_0 Einst_SuZIPWo_zeit_3_1 Einst_SuZIPWo_zeit_4_0 Einst_SuZIPWo_zeit_4_1 Einst_SuZIP25_zeit_0_0 Einst_SuZIP25_zeit_0_1 Einst_SuZIP25_zeit_1_0 Einst_SuZIP25_zeit_1_1 Einst_SuZIP25_zeit_2_0 Einst_SuZIP25_zeit_2_1 Einst_SuZIP25_zeit_3_0 Einst_SuZIP25_zeit_3_1 Einst_SuZIP25_zeit_4_0 Einst_SuZIP25_zeit_4_1 Einst_SuZIP25_zeit_0_2 Einst_SuZIP25_zeit_0_3 Einst_SuZIP25_zeit_1_2 Einst_SuZIP25_zeit_1_3 Einst_SuZIP25_zeit_2_2 Einst_SuZIP25_zeit_2_3 Einst_SuZIP25_zeit_3_2 Einst_SuZIP25_zeit_3_3 Einst_SuZIP25_zeit_4_2 Einst_SuZIP25_zeit_4_3 Einst_SuZIPTg_zeit_0_0 Einst_SuZIPTg_zeit_0_1 Einst_SuZIPTg_zeit_1_0 Einst_SuZIPTg_zeit_1_1 Einst_SuZIPTg_zeit_2_0 Einst_SuZIPTg_zeit_2_1 Einst_SuZIPTg_zeit_3_0 Einst_SuZIPTg_zeit_3_1 Einst_SuZIPTg_zeit_4_0 Einst_SuZIPTg_zeit_4_1 Einst_SuZIPTg_zeit_0_2 Einst_SuZIPTg_zeit_0_3 Einst_SuZIPTg_zeit_1_2 Einst_SuZIPTg_zeit_1_3 Einst_SuZIPTg_zeit_2_2 Einst_SuZIPTg_zeit_2_3 Einst_SuZIPTg_zeit_3_2 Einst_SuZIPTg_zeit_3_3 Einst_SuZIPTg_zeit_4_2 Einst_SuZIPTg_zeit_4_3 Einst_SuZIPTg_zeit_0_4 Einst_SuZIPTg_zeit_0_5 Einst_SuZIPTg_zeit_1_4 Einst_SuZIPTg_zeit_1_5 Einst_SuZIPTg_zeit_2_4 Einst_SuZIPTg_zeit_2_5 Einst_SuZIPTg_zeit_3_4 Einst_SuZIPTg_zeit_3_5 Einst_SuZIPTg_zeit_4_4 Einst_SuZIPTg_zeit_4_5 Einst_SuZIPTg_zeit_0_6 Einst_SuZIPTg_zeit_0_7 Einst_SuZIPTg_zeit_1_6 Einst_SuZIPTg_zeit_1_7 Einst_SuZIPTg_zeit_2_6 Einst_SuZIPTg_zeit_2_7 Einst_SuZIPTg_zeit_3_6 Einst_SuZIPTg_zeit_3_7 Einst_SuZIPTg_zeit_4_6 Einst_SuZIPTg_zeit_4_7 Einst_SuZIPTg_zeit_0_8 Einst_SuZIPTg_zeit_0_9 Einst_SuZIPTg_zeit_1_8 Einst_SuZIPTg_zeit_1_9 Einst_SuZIPTg_zeit_2_8 Einst_SuZIPTg_zeit_2_9 Einst_SuZIPTg_zeit_3_8 Einst_SuZIPTg_zeit_3_9 Einst_SuZIPTg_zeit_4_8 Einst_SuZIPTg_zeit_4_9 Einst_SuZIPTg_zeit_0_10 Einst_SuZIPTg_zeit_0_11 Einst_SuZIPTg_zeit_1_10 Einst_SuZIPTg_zeit_1_11 Einst_SuZIPTg_zeit_2_10 Einst_SuZIPTg_zeit_2_11 Einst_SuZIPTg_zeit_3_10 Einst_SuZIPTg_zeit_3_11 Einst_SuZIPTg_zeit_4_10 Einst_SuZIPTg_zeit_4_11 Einst_SuZIPTg_zeit_0_12 Einst_SuZIPTg_zeit_0_13 Einst_SuZIPTg_zeit_1_12 Einst_SuZIPTg_zeit_1_13 Einst_SuZIPTg_zeit_2_12 Einst_SuZIPTg_zeit_2_13 Einst_SuZIPTg_zeit_3_12 Einst_SuZIPTg_zeit_3_13 Einst_SuZIPTg_zeit_4_12 Einst_SuZIPTg_zeit_4_13 Einst_SuSwb_akt Einst_SuSwbWo_zeit_0_0 Einst_SuSwbWo_zeit_0_1 Einst_SuSwbWo_zeit_1_0 Einst_SuSwbWo_zeit_1_1 Einst_SuSwbWo_zeit_2_0 Einst_SuSwbWo_zeit_2_1 Einst_SuSwb25_zeit_0_0 Einst_SuSwb25_zeit_0_1 Einst_SuSwb25_zeit_1_0 Einst_SuSwb25_zeit_1_1 Einst_SuSwb25_zeit_2_0 Einst_SuSwb25_zeit_2_1 Einst_SuSwb25_zeit_0_2 Einst_SuSwb25_zeit_0_3 Einst_SuSwb25_zeit_1_2 Einst_SuSwb25_zeit_1_3 Einst_SuSwb25_zeit_2_2 Einst_SuSwb25_zeit_2_3 Einst_SuSwbTg_zeit_0_0 Einst_SuSwbTg_zeit_0_1 Einst_SuSwbTg_zeit_1_0 Einst_SuSwbTg_zeit_1_1 Einst_SuSwbTg_zeit_2_0 Einst_SuSwbTg_zeit_2_1 Einst_SuSwbTg_zeit_0_2 Einst_SuSwbTg_zeit_0_3 Einst_SuSwbTg_zeit_1_2 Einst_SuSwbTg_zeit_1_3 Einst_SuSwbTg_zeit_2_2 Einst_SuSwbTg_zeit_2_3 Einst_SuSwbTg_zeit_0_4 Einst_SuSwbTg_zeit_0_5 Einst_SuSwbTg_zeit_1_4 Einst_SuSwbTg_zeit_1_5 Einst_SuSwbTg_zeit_2_4 Einst_SuSwbTg_zeit_2_5 Einst_SuSwbTg_zeit_0_6 Einst_SuSwbTg_zeit_0_7 Einst_SuSwbTg_zeit_1_6 Einst_SuSwbTg_zeit_1_7 Einst_SuSwbTg_zeit_2_6 Einst_SuSwbTg_zeit_2_7 Einst_SuSwbTg_zeit_0_8 Einst_SuSwbTg_zeit_0_9 Einst_SuSwbTg_zeit_1_8 Einst_SuSwbTg_zeit_1_9 Einst_SuSwbTg_zeit_2_8 Einst_SuSwbTg_zeit_2_9 Einst_SuSwbTg_zeit_0_10 Einst_SuSwbTg_zeit_0_11 Einst_SuSwbTg_zeit_1_10 Einst_SuSwbTg_zeit_1_11 Einst_SuSwbTg_zeit_2_10 Einst_SuSwbTg_zeit_2_11 Einst_SuSwbTg_zeit_0_12 Einst_SuSwbTg_zeit_0_13 Einst_SuSwbTg_zeit_1_12 Einst_SuSwbTg_zeit_1_13 Einst_SuSwbTg_zeit_2_12 Einst_SuSwbTg_zeit_2_13 Zaehler_BetrZeitWP Zaehler_BetrZeitVD1 Zaehler_BetrZeitVD2 Zaehler_BetrZeitZWE1 Zaehler_BetrZeitZWE2 Zaehler_BetrZeitZWE3 Zaehler_BetrZeitImpVD1 Zaehler_BetrZeitImpVD2 Zaehler_BetrZeitEZMVD1 Zaehler_BetrZeitEZMVD2 Einst_Entl_HUP Einst_Entl_ZUP Einst_Entl_BUP Einst_Entl_VentBOSUP Einst_Entl_MA1 Einst_Entl_MZ1 Einst_Entl_ZIP Einst_Entl_MA2 Einst_Entl_MZ2 Einst_Entl_SUP Einst_Entl_SLP Einst_Entl_FP2 Einst_Entl_Laufzeit Einst_Vorl_max_MK1 Einst_Vorl_max_MK2 SU_FrkdMK1 SU_FrkdMK2 Ba_Hz_MK1_akt Ba_Hz_MK2_akt Einst_Zirk_Ein_akt Einst_Zirk_Aus_akt Einst_Heizgrenze Einst_Heizgrenze_Temp VariablenIBNgespeichert SchonIBNAssistant Heizgrenze_0 Heizgrenze_1 Heizgrenze_2 Heizgrenze_3 Heizgrenze_4 Heizgrenze_5 Heizgrenze_6 Heizgrenze_7 Heizgrenze_8 Heizgrenze_9 Heizgrenze_10 Heizgrenze_11 SchemenIBNgewahlt Switchoff_file_0_0 Switchoff_file_1_0 Switchoff_file_2_0 Switchoff_file_3_0 Switchoff_file_4_0 Switchoff_file_0_1 Switchoff_file_1_1 Switchoff_file_2_1 Switchoff_file_3_1 Switchoff_file_4_1 DauerDatenLoggerAktiv Laufvar_Heizgrenze Zaehler_BetrZeitHz Zaehler_BetrZeitBW Zaehler_BetrZeitKue SU_FstdHz SU_FstdBw SU_FstdSwb SU_FstdMK1 SU_FstdMK2 FerienAbsenkungHz FerienAbsenkungMK1 FerienAbsenkungMK2 FerienModusAktivHz FerienModusAktivBw FerienModusAktivSwb FerienModusAktivMk1 FerienModusAktivMk2 DisplayContrast_akt Ba_Hz_saved Ba_Bw_saved Ba_Sw_saved Ba_Hz_MK1_saved Ba_Hz_MK2_saved AdresseIP_akt SubNetMask_akt Add_Broadcast_akt Add_StdGateway_akt DHCPServerAktiv_akt WebserverPasswort_1_akt WebserverPasswort_2_akt WebserverPasswort_3_akt WebserverPasswort_4_akt WebserverPasswort_5_akt WebserverPasswort_6_akt WebServerWerteBekommen Einst_ParBetr_akt Einst_WpAnz_akt Einst_PhrTime_akt Einst_HysPar_akt IP_PB_Slave_0 IP_PB_Slave_1 IP_PB_Slave_2 IP_PB_Slave_3 IP_PB_Slave_4 IP_PB_Slave_5 Einst_BwHup_akt_backup Einst_SuMk3_akt Einst_HzMK3E_akt Einst_HzMK3ANH_akt Einst_HzMK3ABS_akt Einst_HzMK3Hgr_akt Einst_HzFtMK3Vl_akt Ba_Hz_MK3_akt Einst_MK3Typ_akt Einst_RTypMK3_akt Einst_MK3LzFaktor_akt Einst_MK3PerFaktor_akt FerienModusAktivMk3 SU_FrkdMK3 FerienAbsenkungMK3 SU_FstdMK3 Einst_SuMk3_akt2 Einst_SuMk3Wo_zeit_0_0 Einst_SuMk3Wo_zeit_0_1 Einst_SuMk3Wo_zeit_1_0 Einst_SuMk3Wo_zeit_1_1 Einst_SuMk3Wo_zeit_2_0 Einst_SuMk3Wo_zeit_2_1 Einst_SuMk325_zeit_0_0 Einst_SuMk325_zeit_0_1 Einst_SuMk325_zeit_1_0 Einst_SuMk325_zeit_1_1 Einst_SuMk325_zeit_2_0 Einst_SuMk325_zeit_2_1 Einst_SuMk325_zeit_0_2 Einst_SuMk325_zeit_0_3 Einst_SuMk325_zeit_1_2 Einst_SuMk325_zeit_1_3 Einst_SuMk325_zeit_2_2 Einst_SuMk325_zeit_2_3 Einst_SuMk3Tg_zeit_0_0 Einst_SuMk3Tg_zeit_0_1 Einst_SuMk3Tg_zeit_1_0 Einst_SuMk3Tg_zeit_1_1 Einst_SuMk3Tg_zeit_2_0 Einst_SuMk3Tg_zeit_2_1 Einst_SuMk3Tg_zeit_0_2 Einst_SuMk3Tg_zeit_0_3 Einst_SuMk3Tg_zeit_1_2 Einst_SuMk3Tg_zeit_1_3 Einst_SuMk3Tg_zeit_2_2 Einst_SuMk3Tg_zeit_2_3 Einst_SuMk3Tg_zeit_0_4 Einst_SuMk3Tg_zeit_0_5 Einst_SuMk3Tg_zeit_1_4 Einst_SuMk3Tg_zeit_1_5 Einst_SuMk3Tg_zeit_2_4 Einst_SuMk3Tg_zeit_2_5 Einst_SuMk3Tg_zeit_0_6 Einst_SuMk3Tg_zeit_0_7 Einst_SuMk3Tg_zeit_1_6 Einst_SuMk3Tg_zeit_1_7 Einst_SuMk3Tg_zeit_2_6 Einst_SuMk3Tg_zeit_2_7 Einst_SuMk3Tg_zeit_0_8 Einst_SuMk3Tg_zeit_0_9 Einst_SuMk3Tg_zeit_1_8 Einst_SuMk3Tg_zeit_1_9 Einst_SuMk3Tg_zeit_2_8 Einst_SuMk3Tg_zeit_2_9 Einst_SuMk3Tg_zeit_0_10 Einst_SuMk3Tg_zeit_0_11 Einst_SuMk3Tg_zeit_1_10 Einst_SuMk3Tg_zeit_1_11 Einst_SuMk3Tg_zeit_2_10 Einst_SuMk3Tg_zeit_2_11 Einst_SuMk3Tg_zeit_0_12 Einst_SuMk3Tg_zeit_0_13 Einst_SuMk3Tg_zeit_1_12 Einst_SuMk3Tg_zeit_1_13 Einst_SuMk3Tg_zeit_2_12 Einst_SuMk3Tg_zeit_2_13 Ba_Hz_MK3_saved Einst_Kuhl_Zeit_Ein_akt Einst_Kuhl_Zeit_Aus_akt Waermemenge_Seit Waermemenge_WQ Waermemenge_Hz Waermemenge_WQ_ges Einst_Entl_MA3 Einst_Entl_MZ3 Einst_Entl_FP3 Zaehler_BetrZeitSW Einst_Fernwartung_akt AdresseIPServ_akt Einst_TA_EG_akt Einst_TVLmax_EG_akt Einst_Popt_Nachlauf_akt FernwartungVertrag_akt FernwartungAktuZeit Einst_Effizienzpumpe_Nominal_akt Einst_Effizienzpumpe_Minimal_akt Einst_Effizienzpumpe_akt Einst_Waermemenge_akt Einst_Wm_Versorgung_Korrektur_akt Einst_Wm_Auswertung_Korrektur_akt SoftwareUpdateJetztGemacht_akt WP_SerienNummer_DATUM WP_SerienNummer_HEX WP_SerienNummer_INDEX ProgWerteWebSrvBeobarten Waermemenge_BW Waermemenge_SW Waermemenge_Datum Einst_Solar_akt BSTD_Solar Einst_TDC_Koll_Max_akt Einst_Akt_Kuehlung_akt Einst_Vorlauf_VBO_akt Einst_KRHyst_akt Einst_Akt_Kuehl_Speicher_min_akt Einst_Akt_Kuehl_Freig_WQE_akt NDAB_WW_Anzahl NDS_WW_KD_Quitt Einst_AbtZykMin_akt Einst_VD2_Zeit_Min_akt Einst_Hysterese_HR_verkuerzt_akt Einst_BA_Lueftung_akt Einst_SuLuf_akt Einst_SuLufWo_zeit_0_0_0 Einst_SuLufWo_zeit_0_1_0 Einst_SuLufWo_zeit_0_2_0 Einst_SuLuf25_zeit_0_0_0 Einst_SuLuf25_zeit_0_1_0 Einst_SuLuf25_zeit_0_2_0 Einst_SuLuf25_zeit_0_0_2 Einst_SuLuf25_zeit_0_1_2 Einst_SuLuf25_zeit_0_2_2 Einst_SuLufTg_zeit_0_0_0 Einst_SuLufTg_zeit_0_1_0 Einst_SuLufTg_zeit_0_2_0 Einst_SuLufTg_zeit_0_0_2 Einst_SuLufTg_zeit_0_1_2 Einst_SuLufTg_zeit_0_2_2 Einst_SuLufTg_zeit_0_0_4 Einst_SuLufTg_zeit_0_1_4 Einst_SuLufTg_zeit_0_2_4 Einst_SuLufTg_zeit_0_0_6 Einst_SuLufTg_zeit_0_1_6 Einst_SuLufTg_zeit_0_2_6 Einst_SuLufTg_zeit_0_0_8 Einst_SuLufTg_zeit_0_1_8 Einst_SuLufTg_zeit_0_2_8 Einst_SuLufTg_zeit_0_0_10 Einst_SuLufTg_zeit_0_1_10 Einst_SuLufTg_zeit_0_2_10 Einst_SuLufTg_zeit_0_0_12 Einst_SuLufTg_zeit_0_1_12 Einst_SuLufTg_zeit_0_2_12 Einst_SuLufWo_zeit_1_0_0 Einst_SuLufWo_zeit_1_1_0 Einst_SuLufWo_zeit_1_2_0 Einst_SuLuf25_zeit_1_0_0 Einst_SuLuf25_zeit_1_1_0 Einst_SuLuf25_zeit_1_2_0 Einst_SuLuf25_zeit_1_0_2 Einst_SuLuf25_zeit_1_1_2 Einst_SuLuf25_zeit_1_2_2 Einst_SuLufTg_zeit_1_0_0 Einst_SuLufTg_zeit_1_1_0 Einst_SuLufTg_zeit_1_2_0 Einst_SuLufTg_zeit_1_0_2 Einst_SuLufTg_zeit_1_1_2 Einst_SuLufTg_zeit_1_2_2 Einst_SuLufTg_zeit_1_0_4 Einst_SuLufTg_zeit_1_1_4 Einst_SuLufTg_zeit_1_2_4 Einst_SuLufTg_zeit_1_0_6 Einst_SuLufTg_zeit_1_1_6 Einst_SuLufTg_zeit_1_2_6 Einst_SuLufTg_zeit_1_0_8 Einst_SuLufTg_zeit_1_1_8 Einst_SuLufTg_zeit_1_2_8 Einst_SuLufTg_zeit_1_0_10 Einst_SuLufTg_zeit_1_1_10 Einst_SuLufTg_zeit_1_2_10 Einst_SuLufTg_zeit_1_0_12 Einst_SuLufTg_zeit_1_1_12 Einst_SuLufTg_zeit_1_2_12 FerienModusAktivLueftung Einst_BA_Lueftung_saved SU_FrkdLueftung SU_FstdLueftung Einst_Luf_Feuchteschutz_akt Einst_Luf_Reduziert_akt Einst_Luf_Nennlueftung_akt Einst_Luf_Intensivlueftung_akt Timer_Fil_4Makt Timer_Fil_WoAkt Sollwert_KuCft3_akt Sollwert_AtDif3_akt Bitmaske_0 Einst_Lueftungsstufen SysEin_Meldung_TDI SysEin_Typ_WZW Einst_GLT_aktiviert Einst_BW_max Einst_Sollwert_TRL_Kuehlen Einst_Medium_Waermequelle Einst_Photovoltaik_akt Einst_Multispeicher_akt Einst_PKuehlTime_akt Einst_Minimale_Ruecklaufsolltemperatur RBE_Einflussfaktor_RT_akt RBE_Freigabe_Kuehlung_akt RBE_Waermeverteilsystem_akt RBE_Zeit_Heizstab_aktiv SEC_ND_Alarmgrenze SEC_HD_Alarmgrenze SEC_Abtauendtemperatur Einst_Min_RPM_BW Einst_Luf_Feuchteschutz_Faktor_akt Einst_Luf_Reduziert_Faktor_akt Einst_Luf_Nennlueftung_Faktor_akt Einst_Luf_Intensivlueftung_Faktor_akt Einst_Freigabe_Zeit_ZWE Einst_min_VL_Kuehl Einst_Warmwasser_Nachheizung Switchoff_file_LWD2_0_0 Switchoff_file_LWD2_1_0 Switchoff_file_LWD2_2_0 Switchoff_file_LWD2_3_0 Switchoff_file_LWD2_4_0 Switchoff_file_LWD2_0_1 Switchoff_file_LWD2_1_1 Switchoff_file_LWD2_2_1 Switchoff_file_LWD2_3_1 Switchoff_file_LWD2_4_1 Switchoff_index_LWD2 Einst_Effizienzpumpe_Nominal_2 Einst_Effizienzpumpe_Minimal_2 Einst_Wm_Versorgung_Korrektur_2 Einst_Wm_Auswertung_Korrektur_2 Einst_isTwin Einst_TAmin_2 Einst_TVLmax_2 Einst_TA_EG_2 Einst_TVLmax_EG_2 Waermemenge_Hz_2 Waermemenge_BW_2 Waermemenge_SW_2 Waermemenge_Seit_2 Einst_Entl_ExVentilManAuf Einst_WW_Nachheizung_max Einst_Kuhl_Zeit_Ein_RT Einst_ZWE1_Pos Einst_ZWE2_Pos Einst_ZWE3_Pos Einst_Leistung_ZWE WP_SN2_DATUM WP_SN2_HEX WP_SN2_INDEX CWP_saved2 Einst_SmartGrid Einst_P155_HDS Einst_P155_PumpHeat_Max Einst_P155_PumpHeatCtrl Einst_P155_PumpDHWCtrl Einst_P155_PumpDHW_RPM Einst_P155_PumpPoolCtrl Einst_P155_PumpPool_RPM Einst_P155_PumpCool_RPM Einst_P155_PumpVBOCtrl Einst_P155_PumpVBO_RPM_C Einst_P155_PumpDHW_Max Einst_P155_PumpPool_Max Einst_P155_Sperrband_1 Einst_P155_Leistungsfreigabe Einst_P155_DHW_Freq Einst_SWHUP Einst_P155_SWB_Freq Einst_MK1_Regelung Einst_MK2_Regelung Einst_MK3_Regelung Einst_PV_WW_Sperrzeit Einst_Warmwasser_extra Einst_Vorl_akt_Kuehl WP_SN3_DATUM WP_SN3_HEX WP_SN3_INDEX Einst_Vorlauf_ZUP Einst_Abtauen_im_Warmwasser Waermemenge_ZWE Waermemenge_Reset Waermemenge_Reset_2 Einst_Brunnenpumpe_min Einst_Brunnenpumpe_max Einst_SmartHomeID Einst_SmartHK Einst_SmartMK1 Einst_SmartMK2 Einst_SmartMK3 Einst_SmartWW Einst_SmartDefrost Einst_Empty1071 Einst_MinVLMK1 Einst_MinVLMK2 Einst_MinVLMK3 Einst_MaxVLMK1 Einst_MaxVLMK2 Einst_MaxVLMK3 Einst_SmartPlusHz Einst_SmartMinusHz Einst_SmartPlusMK1 Einst_SmartMinusMK1 Einst_SmartPlusMK2 Einst_SmartMinusMK2 Einst_SmartPlusMK3 Einst_SmartMinusMK3
  300. );
  301. if($cmd eq 'heatingCurveParameter') {
  302. # Log3 $name, 3, "get $name $cmd";
  303. if (int @val !=4 ) {
  304. my $msg = "Wrong number of parameter (".int @val.")in get $name $cmd";
  305. Log3 $name, 3, $msg;
  306. return $msg;
  307. }
  308. else {
  309. return LUXTRONIK2_calcHeatingCurveParameter ( $hash, $val[0], $val[1], $val[2], $val[3]);
  310. }
  311. }
  312. elsif($cmd eq 'heatingCurveReturnTemperature') {
  313. # Log3 $name, 3, "get $name $cmd";
  314. if (int @val !=1) {
  315. my $msg = "Wrong number of parameter (".int @val.")in get $name $cmd";
  316. Log3 $name, 3, $msg;
  317. return $msg;
  318. }
  319. else {
  320. my $heatingCurveEndPoint = $hash->{READINGS}{heatingCurveEndPoint}{VAL};
  321. my $heatingCurveOffset = $hash->{READINGS}{heatingCurveOffset}{VAL};
  322. return LUXTRONIK2_getHeatingCurveReturnTemperature ( $hash, $val[0], $heatingCurveEndPoint, $heatingCurveOffset);
  323. }
  324. }
  325. elsif( $cmd eq 'rawData') {
  326. my ($state, $msg , $heatpump_values, $heatpump_parameters, $heatpump_visibility) = LUXTRONIK2_ReadData ($name);
  327. if ($state != 1) {
  328. return $msg;
  329. }
  330. else {
  331. my $index = 0;
  332. $resultStr = ("-" x 133) . "\n";
  333. $resultStr .="Heatpump Values (".scalar(@$heatpump_values).")";
  334. foreach (@$heatpump_values) {
  335. $resultStr .= "\n" . ("-" x 133) if $index % 15 == 0;
  336. $resultStr .= "\n|" if $index % 3 == 0;
  337. $resultStr .= sprintf ("%4s %-38s|", $index, $nameOfValue[$index] . " : " . $_);
  338. $index++;
  339. }
  340. $index = 0;
  341. $resultStr .= "\n\n\n" . ("-" x 133);
  342. $resultStr .="\nHeatpump Parameters (".scalar(@$heatpump_parameters).")";
  343. foreach (@$heatpump_parameters) {
  344. $resultStr .= "\n" . ("-" x 133) if $index % 15 == 0;
  345. $resultStr .= "\n|" if $index % 3 == 0;
  346. $resultStr .= sprintf ("%4s %-38s|", $index, $nameOfParameter[$index] . " : " . $_);
  347. $index++;
  348. }
  349. return $resultStr;
  350. }
  351. }
  352. my $list = "heatingCurveParameter "
  353. . "heatingCurveReturnTemperature "
  354. . "rawData:noArg ";
  355. return "Unknown argument $cmd, choose one of $list";
  356. }
  357. sub ########################################
  358. LUXTRONIK2_GetUpdate($)
  359. {
  360. my ($hash) = @_;
  361. my $name = $hash->{NAME};
  362. if(!$hash->{LOCAL}) {
  363. RemoveInternalTimer($hash);
  364. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "LUXTRONIK2_GetUpdate", $hash, 1);
  365. return undef if( AttrVal($name, "disable", 0 ) == 1 );
  366. }
  367. $hash->{helper}{RUNNING_PID} = BlockingCall("LUXTRONIK2_DoUpdate", $name, "LUXTRONIK2_UpdateDone", 25, "LUXTRONIK2_UpdateAborted", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
  368. }
  369. ########################################
  370. sub LUXTRONIK2_DoUpdate($)
  371. {
  372. my ($name) = @_;
  373. my $hash = $defs{$name};
  374. my $host = $hash->{HOST};
  375. my $port = $hash->{PORT};
  376. my $count=0;
  377. my $result="";
  378. my $firstLoop;
  379. # Read raw data and handle error return
  380. my $readingStartTime = time();
  381. my ($state, $msg , $retValues, $retParameters, $retVisibility) = LUXTRONIK2_ReadData ($name);
  382. my $readingEndTime = time();
  383. return ("$name|$state|$msg") if $state != 1 ;
  384. my @heatpump_values = @$retValues;
  385. my @heatpump_parameters = @$retParameters;
  386. my @heatpump_visibility = @$retVisibility;
  387. #return certain readings for further processing
  388. # 0 - name
  389. my $return_str="$name";
  390. # 1 - no error = 1
  391. $return_str .= "|1";
  392. # 2 - opStateHeatPump1
  393. $return_str .= "|".$heatpump_values[117];
  394. # 3 - opStateHeatPump3
  395. $return_str .= "|".$heatpump_values[119];
  396. # 4 - Stufe - ID_WEB_HauptMenuAHP_Stufe
  397. $return_str .= "|".$heatpump_values[121];
  398. # 5 - Temperature Value - ID_WEB_HauptMenuAHP_Temp
  399. $return_str .= "|".$heatpump_values[122];
  400. # 6 - Compressor1
  401. $return_str .= "|".$heatpump_values[44];
  402. # 7 - opModeHotWater
  403. $return_str .= "|".$heatpump_parameters[4];
  404. # 8 - hotWaterMonitoring
  405. $return_str .= "|".$heatpump_values[124];
  406. # 9 - hotWaterBoilerValve
  407. $return_str .= "|".$heatpump_values[38];
  408. # 10 - opModeHeating
  409. $return_str .= "|".$heatpump_parameters[3];
  410. # 11 - heatingLimit
  411. $return_str .= "|".$heatpump_parameters[699];
  412. # 12 - ambientTemperature
  413. $return_str .= "|".$heatpump_values[15];
  414. # 13 - averageAmbientTemperature
  415. $return_str .= "|".$heatpump_values[16];
  416. # 14 - hotWaterTemperature
  417. $return_str .= "|".$heatpump_values[17];
  418. # 15 - flowTemperature
  419. $return_str .= "|".$heatpump_values[10];
  420. # 16 - returnTemperature
  421. $return_str .= "|".$heatpump_values[11];
  422. # 17 - returnTemperatureTarget
  423. $return_str .= "|".$heatpump_values[12];
  424. # 18 - returnTemperatureExtern
  425. $return_str .= "|".($heatpump_visibility[24]==1 ? $heatpump_values[13] : "no");
  426. # 19 - flowRate
  427. $return_str .= "|".($heatpump_parameters[870]!=0 ? $heatpump_values[155] : "no");
  428. # 20 - firmware
  429. my $fwvalue = "";
  430. for(my $fi=81; $fi<91; $fi++) {
  431. $fwvalue .= chr($heatpump_values[$fi]) if $heatpump_values[$fi];
  432. }
  433. $return_str .= "|".$fwvalue;
  434. # 21 - thresholdHeatingLimit
  435. $return_str .= "|".$heatpump_parameters[700];
  436. # 22 - rawDeviceTimeCalc
  437. $return_str .= "|".$heatpump_values[134];
  438. # 23 - heatSourceIN
  439. $return_str .= "|".$heatpump_values[19];
  440. # 24 - heatSourceOUT
  441. $return_str .= "|".$heatpump_values[20];
  442. # 25 - hotWaterTemperatureTarget
  443. $return_str .= "|".$heatpump_values[18];
  444. # 26 - hotGasTemperature
  445. $return_str .= "|".$heatpump_values[14];
  446. # 27 - heatingSystemCircPump
  447. $return_str .= "|".$heatpump_values[39];
  448. # 28 - hotWaterCircPumpExtern
  449. $return_str .= "|". ($heatpump_visibility[57]==1 ? $heatpump_values[46] : "no");
  450. # 29 - readingFhemStartTime
  451. $return_str .= "|".$readingStartTime;
  452. # 30 - readingFhemEndTime
  453. $return_str .= "|".$readingEndTime;
  454. # 31 - typeHeatpump
  455. $return_str .= "|".$heatpump_values[78];
  456. # 32 - counterHours2ndHeatSource1
  457. $return_str .= "|". ($heatpump_visibility[84]==1 ? $heatpump_values[60] : "no");
  458. # 33 - counterHoursHeatpump
  459. $return_str .= "|". ($heatpump_visibility[87]==1 ? $heatpump_values[63] : "no");
  460. # 34 - counterHoursHeating
  461. $return_str .= "|". ($heatpump_visibility[195]==1 ? $heatpump_values[64] : "no");
  462. # 35 - counterHoursHotWater
  463. $return_str .= "|". ($heatpump_visibility[196]==1 ? $heatpump_values[65] : "no");
  464. # 36 - counterHeatQHeating
  465. $return_str .= "|". ($heatpump_visibility[0]==1 ? $heatpump_values[151] : "no");
  466. # 37 - counterHeatQHotWater
  467. $return_str .= "|". ($heatpump_visibility[1]==1 ? $heatpump_values[152] : "no");
  468. # 38 - counterHours2ndHeatSource2
  469. $return_str .= "|". ($heatpump_visibility[85]==1 ? $heatpump_values[61] : "no");
  470. # 39 - counterHours2ndHeatSource3
  471. $return_str .= "|". ($heatpump_visibility[86]==1 ? $heatpump_values[62] : "no");
  472. # 40 - opStateHeatPump2
  473. $return_str .= "|".$heatpump_values[118];
  474. # 41 - opStateHeatPump2Duration
  475. $return_str .= "|".$heatpump_values[120];
  476. # 42 - timeError0
  477. $return_str .= "|".$heatpump_values[95];
  478. # 43 - bivalentLevel
  479. $return_str .= "|".$heatpump_values[79];
  480. # 44 - Number of calculated values
  481. $return_str .= "|".scalar(@heatpump_values);
  482. # 45 - Number of set parameters
  483. $return_str .= "|".scalar(@heatpump_parameters);
  484. # 46 - opStateHeating
  485. $return_str .= "|".$heatpump_values[125];
  486. # 47 - deltaHeatingReduction
  487. $return_str .= "|".$heatpump_parameters[13];
  488. # 48 - thresholdTemperatureSetBack
  489. $return_str .= "|".$heatpump_parameters[111];
  490. # 49 - hotWaterTemperatureHysterese
  491. $return_str .= "|".$heatpump_parameters[74];
  492. # 50 - solarCollectorTemperature
  493. $return_str .= "|". ($heatpump_visibility[36]==1 ? $heatpump_values[26] : "no");
  494. # 51 - solarBufferTemperature
  495. $return_str .= "|". ($heatpump_visibility[37]==1 ? $heatpump_values[27] : "no");
  496. # 52 - counterHoursSolar
  497. $return_str .= "|". ($heatpump_visibility[248]==1 ? $heatpump_values[161] : "no");
  498. # 53 - Number of visibility attributes
  499. $return_str .= "|".scalar(@heatpump_visibility);
  500. # 54 - returnTemperatureSetBack
  501. $return_str .= "|".$heatpump_parameters[1];
  502. # 55 - mixer1FlowTemperature
  503. $return_str .= "|". ($heatpump_visibility[31]==1 ? $heatpump_values[21] : "no");
  504. # 56 - mixer1TargetTemperature
  505. $return_str .= "|". ($heatpump_visibility[32]==1 ? $heatpump_values[22] : "no");
  506. # 57 - mixer2FlowTemperature
  507. $return_str .= "|". ($heatpump_visibility[34]==1 ? $heatpump_values[24] : "no");
  508. # 58 - mixer2TargetTemperature
  509. $return_str .= "|". ($heatpump_visibility[35]==1 ? $heatpump_values[25] : "no");
  510. # 59 - mixer3FlowTemperature
  511. $return_str .= "|". ($heatpump_visibility[210]==1 ? $heatpump_values[137] : "no");
  512. # 60 - mixer3TargetTemperature
  513. $return_str .= "|". ($heatpump_visibility[211]==1 ? $heatpump_values[136] : "no");
  514. # 61 - hotWaterCircPumpDeaerate
  515. $return_str .= "|". ($heatpump_visibility[167]==1 ? $heatpump_parameters[684] : "no");
  516. # 62 - counterHeatQPool
  517. $return_str .= "|". ($heatpump_visibility[2]==1 ? $heatpump_values[153] : "no");
  518. # 63 - returnTemperatureTargetMin
  519. $heatpump_visibility[295]=1 unless defined($heatpump_visibility[295]);
  520. $return_str .= "|". ($heatpump_visibility[295]==1 ? $heatpump_parameters[979] : "no");
  521. # 64 - heatSourceMotor
  522. $return_str .= "|". ($heatpump_visibility[54]==1 ? $heatpump_values[43] : "no");
  523. # 65 - typeSerial
  524. $return_str .= "|";
  525. $return_str .= substr($heatpump_parameters[874],0,4)."/".substr($heatpump_parameters[874],4).= "-".sprintf("%03X",$heatpump_parameters[875])
  526. if $heatpump_parameters[874] || $heatpump_parameters[875] ;
  527. # 66 - heatSourceDefrostTimer
  528. $return_str .= "|". ($heatpump_visibility[219]==1 ? $heatpump_values[141] : "no");
  529. # 67 - defrostValve
  530. $return_str .= "|". ($heatpump_visibility[47]==1 ? $heatpump_values[37] : "no");
  531. # 68 - returnTempHyst
  532. $return_str .= "|". ($heatpump_visibility[93]==1 ? $heatpump_parameters[88] : "no");
  533. # 69 - Heating curve end point
  534. $return_str .= "|". ($heatpump_visibility[207]==1 ? $heatpump_parameters[11] : "no");
  535. # 70 - Heating curve parallel offset
  536. $return_str .= "|". ($heatpump_visibility[207]==1 ? $heatpump_parameters[12] : "no");
  537. # 71 - heatSourcedefrostAirThreshold
  538. $return_str .= "|". ($heatpump_visibility[97]==1 ? $heatpump_parameters[44] : "no");
  539. # 72 - heatSourcedefrostAirEnd
  540. $return_str .= "|". ($heatpump_visibility[105]==1 ? $heatpump_parameters[98] : "no");
  541. # 73 - analogOut4 - Voltage heating system circulation pump
  542. $return_str .= "|". ($heatpump_visibility[267]==1 ? $heatpump_values[163] : "no");
  543. # 74 - solarPump
  544. $return_str .= "|". ($heatpump_visibility[63]==1 ? $heatpump_values[52] : "no");
  545. # 75 - 2ndHeatSource1
  546. $return_str .= "|". ($heatpump_visibility[59]==1 ? $heatpump_values[48] : "no");
  547. # 76 userReadings (attributs: userHeatpumpParameters and userHeatpumpValues)
  548. $return_str .= "|";
  549. $firstLoop = 1;
  550. my @userReadings = split /,/, AttrVal( $name, "userHeatpumpParameters", "" );
  551. foreach (@userReadings) {
  552. $return_str .= "," unless $firstLoop;
  553. $firstLoop = 0;
  554. my ($rIndex, $rName) = split / /, trim($_);
  555. $rName = "userParameter$rIndex" unless defined $rName;
  556. $return_str .= $rName." ".$heatpump_parameters[$rIndex];
  557. }
  558. @userReadings = split /,/, AttrVal( $name, "userHeatpumpValues", "" );
  559. foreach (@userReadings) {
  560. $return_str .= "," unless $firstLoop;
  561. $firstLoop = 0;
  562. my ($rIndex, $rName) = split / /, trim($_);
  563. $rName = "userValue$rIndex" unless defined $rName;
  564. $return_str .= $rName." ".$heatpump_values[$rIndex];
  565. }
  566. # 77 - VentSupplyAirTemperature
  567. $return_str .= "|".($heatpump_visibility[264]==1 ? $heatpump_values[159] : "no");;
  568. # 78 - VentExhaustAirTemperature
  569. $return_str .= "|".($heatpump_visibility[265]==1 ? $heatpump_values[160] : "no");;
  570. # 79 - opModeVentilation
  571. $return_str .= "|".($heatpump_visibility[4]==1 ? $heatpump_parameters[894] : "no");;
  572. # 80 - heatingSystemCircPumpDeaerate
  573. $return_str .= "|". ($heatpump_visibility[161]==1 ? $heatpump_parameters[678] : "no");
  574. return $return_str;
  575. }
  576. sub ########################################
  577. LUXTRONIK2_UpdateDone($)
  578. {
  579. my ($string) = @_;
  580. return unless(defined($string));
  581. my $value = "";
  582. my $state = "";
  583. my @a = split("\\|",$string);
  584. my $hash = $defs{$a[0]};
  585. my $name = $a[0];
  586. delete($hash->{helper}{RUNNING_PID});
  587. return if($hash->{helper}{DISABLED});
  588. my $cop = 0;
  589. LUXTRONIK2_Log $hash, 4, $string;
  590. #Define Status Messages
  591. my %wpOpStat1 = ( 0 => "Wärmepumpe läuft",
  592. 1 => "Wärmepumpe steht",
  593. 2 => "Wärmepumpe kommt",
  594. 4 => "Fehler",
  595. 5 => "Abtauen",
  596. 6 => "Warte auf LIN-Verbindung",
  597. 7 => "Verdichter heizt auf",
  598. 8 => "Pumpenvorlauf" );
  599. my %wpOpStat2 = ( 0 => "Heizbetrieb",
  600. 1 => "Keine Anforderung",
  601. 2 => "Netz Einschaltverzögerung",
  602. 3 => "Schaltspielzeit",
  603. 4 => "EVU Sperrzeit",
  604. 5 => "Brauchwasser",
  605. 6 => "Stufe",
  606. 7 => "Abtauen",
  607. 8 => "Pumpenvorlauf",
  608. 9 => "Thermische Desinfektion",
  609. 10 => "Kühlbetrieb",
  610. 12 => "Schwimmbad/Photovoltaik",
  611. 13 => "Heizen_Ext_En",
  612. 14 => "Brauchw_Ext_En",
  613. 16 => "Durchflussüberwachung",
  614. 17 => "Elektrische Zusatzheizung" );
  615. my %wpMode = ( 0 => "Automatik",
  616. 1 => "Zusatzheizung",
  617. 2 => "Party",
  618. 3 => "Ferien",
  619. 4 => "Aus" );
  620. my %heatingState = ( 0 => "Abgesenkt",
  621. 1 => "Normal",
  622. 3 => "Aus");
  623. my %wpType = ( 0 => "ERC", 1 => "SW1",
  624. 2 => "SW2", 3 => "WW1",
  625. 4 => "WW2", 5 => "L1I",
  626. 6 => "L2I", 7 => "L1A",
  627. 8 => "L2A", 9 => "KSW",
  628. 10 => "KLW", 11 => "SWC",
  629. 12 => "LWC", 13 => "L2G",
  630. 14 => "WZS", 15 => "L1I407",
  631. 16 => "L2I407", 17 => "L1A407",
  632. 18 => "L2A407", 19 => "L2G407",
  633. 20 => "LWC407", 21 => "L1AREV", 22 => "L2AREV", 23 => "WWC1",
  634. 24 => "WWC2", 25 => "L2G404", 26 => "WZW", 27 => "L1S",
  635. 28 => "L1H", 29 => "L2H", 30 => "WZWD", 31 => "ERC",
  636. 40 => "WWB_20", 41 => "LD5", 42 => "LD7", 43 => "SW 37_45",
  637. 44 => "SW 58_69", 45 => "SW 29_56", 46 => "LD5 (230V)",
  638. 47 => "LD7 (230 V)", 48 => "LD9", 49 => "LD5 REV",
  639. 50 => "LD7 REV", 51 => "LD5 REV 230V",
  640. 52 => "LD7 REV 230V", 53 => "LD9 REV 230V",
  641. 54 => "SW 291", 55 => "LW SEC", 56 => "HMD 2", 57 => "MSW 4",
  642. 58 => "MSW 6", 59 => "MSW 8", 60 => "MSW 10", 61 => "MSW 12",
  643. 62 => "MSW 14", 63 => "MSW 17", 64 => "MSW 19", 65 => "MSW 23",
  644. 66 => "MSW 26", 67 => "MSW 30", 68 => "MSW 4S", 69 => "MSW 6S",
  645. 70 => "MSW 8S", 71 => "MSW 10S",72 => "MSW 13S", 73 => "MSW 16S",
  646. 74 => "MSW2-6S", 75 => "MSW4-16",76 => "LD2AG", 77 => "LWD90V",
  647. 78 => "MSW3-12", 79 => "MSW3-12S");
  648. my %ventMode = ( 0 => "Automatik",
  649. 1 => "Party",
  650. 2 => "Feuchteschutz",
  651. 3 => "Aus");
  652. my $counterRetry = $hash->{fhem}{counterRetry};
  653. $counterRetry++;
  654. my $doStatistic = AttrVal($name,"doStatistics",0);
  655. # Error
  656. if ($a[1]==0 ) {
  657. readingsSingleUpdate($hash,"state","Error: ".$a[2],1);
  658. $counterRetry = 0;
  659. if ( $hash->{fhem}{portDefined} == 0 ) {
  660. if ($hash->{PORT} == 8888 ) {
  661. $hash->{PORT} = 8889;
  662. LUXTRONIK2_Log $name, 3, "Error when using port 8888. Changed port to 8889";
  663. }
  664. elsif ($hash->{PORT} == 8889 ) {
  665. $hash->{PORT} = 8888;
  666. LUXTRONIK2_Log $name, 3, "Error when using port 8889. Changed port to 8888";
  667. }
  668. }
  669. }
  670. # Busy, restart update
  671. elsif ($a[1]==2 ) {
  672. if ($counterRetry <=3) {
  673. InternalTimer(gettimeofday() + 5, "LUXTRONIK2_GetUpdate", $hash, 0);
  674. }
  675. else {
  676. readingsSingleUpdate($hash,"state","Error: Reading skipped after $counterRetry tries",1);
  677. LUXTRONIK2_Log $hash, 2, "Device readout skipped after $counterRetry tries with parameter change on target";
  678. }
  679. }
  680. # Update readings
  681. elsif ($a[1]==1 ) {
  682. $counterRetry = 0;
  683. readingsBeginUpdate($hash);
  684. my $returnTemperaturLast = $hash->{READINGS}{"returnTemperature"}{VAL};
  685. # Temporary storage of values because needed several times
  686. my $ambientTemperature = LUXTRONIK2_CalcTemp($a[12]);
  687. my $averageAmbientTemperature = LUXTRONIK2_CalcTemp($a[13]);
  688. my $hotWaterTemperature = LUXTRONIK2_CalcTemp($a[14]);
  689. my $hotWaterTemperatureTarget = LUXTRONIK2_CalcTemp($a[25]);
  690. my $hotWaterTemperatureThreshold = LUXTRONIK2_CalcTemp($a[25] - $a[49]);
  691. my $heatSourceIN = LUXTRONIK2_CalcTemp($a[23]);
  692. my $heatSourceOUT = LUXTRONIK2_CalcTemp($a[24]);
  693. my $thresholdHeatingLimit = LUXTRONIK2_CalcTemp($a[21]);
  694. my $thresholdTemperatureSetBack = LUXTRONIK2_CalcTemp($a[48]);
  695. my $flowTemperature = LUXTRONIK2_CalcTemp($a[15]);
  696. my $returnTemperature = LUXTRONIK2_CalcTemp($a[16]);
  697. my $returnTemperatureTarget = LUXTRONIK2_CalcTemp($a[17]);
  698. my $returnTempHyst = LUXTRONIK2_CalcTemp($a[68]);
  699. my $returnTemperatureTargetMin = ($a[63] eq "no"?15:LUXTRONIK2_CalcTemp($a[63]) );
  700. my $compressor1 = $a[6]; #Ausgang Verdichter 1
  701. my $heatSourceMotor = $a[64]; #Ausgang Ventilator_BOSUP
  702. my $defrostValve = $a[67]; #AVout
  703. my $hotWaterBoilerValve = $a[9]; #BUP
  704. my $heatingSystemCircPump = $a[27]; #HUP
  705. my $opStateHeatPump3 = $a[3];
  706. my $analogOut4 = $a[73]; #Voltage heating system circulation pump
  707. my $flowRate = $a[19]; # flow rate
  708. # skips inconsistent flow rates (known problem of the used flow measurement devices)
  709. if ($flowRate !~ /no/ && $heatingSystemCircPump) {
  710. $flowRate = "inconsistent" if $flowRate == 0;
  711. }
  712. my $heatPumpPower = 0;
  713. my $heatRodPower = AttrVal($name, "heatRodElectricalPowerWatt", 0);
  714. #WM[kW] = delta_Temp [K] * Durchfluss [l/h] / ( 3.600 [kJ/kWh] / ( 4,179 [kJ/(kg*K)] (H2O Wärmekapazität bei 30 & 40°C) * 0,994 [kg/l] (H2O Dichte bei 35°C) )
  715. my $thermalPower = 0;
  716. # 0=Heizen, 5=Brauchwasser, 7=Abtauen, 16=Durchflussüberwachung
  717. if ($opStateHeatPump3 =~ /^(0|5|16)$/) {
  718. if ($flowRate !~ /no|inconsistent/) { $thermalPower = abs($flowTemperature - $returnTemperature) * $flowRate / 866.65; } #Nur bei Wärmezählern
  719. $heatPumpPower = AttrVal($name, "heatPumpElectricalPowerWatt", -1);
  720. $heatPumpPower *= (1 + ($flowTemperature-35) * AttrVal($name, "heatPumpElectricalPowerFactor", 0));
  721. }
  722. if ($flowRate !~ /no|inconsistent/) { readingsBulkUpdate( $hash, "thermalPower", sprintf "%.1f", $thermalPower); } #Nur bei Wärmezählern
  723. if ($heatPumpPower >-1 ) { readingsBulkUpdate( $hash, "heatPumpElectricalPowerEstimated", sprintf "%.0f", $heatPumpPower); }
  724. if ($heatPumpPower > 0 && $flowRate !~ /no|inconsistent/) { #Nur bei Wärmezählern
  725. $cop = $thermalPower * 1000 / $heatPumpPower;
  726. readingsBulkUpdate( $hash, "COP", sprintf "%.2f", $cop);
  727. }
  728. # if attribute doStatistic = 1 do all the statistic calculations
  729. # if attribute doStatistic = 2 do only those statistic calculations not included in FHEM Module statistics
  730. if ( $doStatistic == 1) {
  731. # LUXTRONIK2_doStatisticMinMax $hash, $readingName, $value
  732. LUXTRONIK2_doStatisticMinMax ( $hash, "statAmbientTemp", $ambientTemperature);
  733. }
  734. if ( $doStatistic >= 1) {
  735. #LUXTRONIK2_doStatisticBoilerHeatUp $hash, $currOpHours, $currHQ, $currTemp, $opState, $target
  736. $value = LUXTRONIK2_doStatisticBoilerHeatUp ($hash, $a[35], $a[37]/10, $hotWaterTemperature, $opStateHeatPump3,$hotWaterTemperatureTarget);
  737. if ($value ne "") {
  738. readingsBulkUpdate($hash,"statBoilerGradientHeatUp",$value);
  739. LUXTRONIK2_Log $name, 3, "statBoilerGradientHeatUp set to $value";
  740. }
  741. #LUXTRONIK2_doStatisticBoilerCoolDown $hash, $time, $currTemp, $opState, $target, $threshold
  742. $value = LUXTRONIK2_doStatisticBoilerCoolDown ($hash, $a[22], $hotWaterTemperature, $opStateHeatPump3, $hotWaterTemperatureTarget, $hotWaterTemperatureThreshold);
  743. if ($value ne "") {
  744. readingsBulkUpdate($hash,"statBoilerGradientCoolDown",$value);
  745. LUXTRONIK2_Log $name, 3, "statBoilerGradientCoolDown set to $value";
  746. my @new = split / /, $value;
  747. if ( exists( $hash->{READINGS}{statBoilerGradientCoolDownMin} ) ) {
  748. my @old = split / /, $hash->{READINGS}{statBoilerGradientCoolDownMin}{VAL};
  749. if ($new[5]>6 && $new[1]>$old[1] && $new[1] < 0) {
  750. readingsBulkUpdate($hash,"statBoilerGradientCoolDownMin",$value,1);
  751. LUXTRONIK2_Log $name, 3, "statBoilerGradientCoolDownMin set to '$value'";
  752. }
  753. } elsif ($new[5]>6 && $new[1] < 0) {
  754. readingsBulkUpdate($hash,"statBoilerGradientCoolDownMin",$value,1);
  755. LUXTRONIK2_Log $name, 3, "statBoilerGradientCoolDownMin set to '$value'";
  756. }
  757. }
  758. # LUXTRONIK2_doStatisticThermalPower: $hash, $MonitoredOpState, $currOpState, $currHeatQuantity, $currOpHours, $currAmbTemp, $currHeatSourceIn, $TargetTemp, $electricalPower
  759. $value = LUXTRONIK2_doStatisticThermalPower ($hash, 5, $opStateHeatPump3, $a[37]/10, $a[35], $ambientTemperature, $heatSourceIN,$hotWaterTemperatureTarget, $heatPumpPower);
  760. if ($value ne "") { readingsBulkUpdate($hash,"statThermalPowerBoiler",$value); }
  761. $value = LUXTRONIK2_doStatisticThermalPower ($hash, 0, $opStateHeatPump3, $a[36]/10, $a[34], $ambientTemperature, $heatSourceIN, $returnTemperatureTarget, $heatPumpPower);
  762. if ($value ne "") { readingsBulkUpdate($hash,"statThermalPowerHeating",$value); }
  763. }
  764. #Operating status of heat pump
  765. my $opStateHeatPump1 = $wpOpStat1{$a[2]}; ##############
  766. $opStateHeatPump1 = "unbekannt (".$a[2].")" unless $opStateHeatPump1;
  767. readingsBulkUpdate($hash,"opStateHeatPump1",$opStateHeatPump1);
  768. my $opStateHeatPump2 = "unknown ($a[40])"; ##############
  769. my $prefix = "";
  770. if ($a[40] == 0 || $a[40] == 2) { $prefix = "seit ";}
  771. elsif ($a[40] == 1) { $prefix = "in ";}
  772. if ($a[40] == 2) { #Sonderbehandlung bei WP-Fehlern
  773. $opStateHeatPump2 = $prefix . strftime "%d.%m.%Y %H:%M:%S", localtime($a[42]);
  774. }
  775. else {
  776. $opStateHeatPump2 = $prefix . LUXTRONIK2_FormatDuration($a[41]);
  777. }
  778. readingsBulkUpdate($hash,"opStateHeatPump2",$opStateHeatPump2);
  779. my $opStateHeatPump3Txt = $wpOpStat2{$opStateHeatPump3}; ##############
  780. # refine text of third state
  781. if ($opStateHeatPump3==6) {
  782. $opStateHeatPump3Txt = "Stufe ".$a[4]." ".LUXTRONIK2_CalcTemp($a[5])." C ";
  783. }
  784. elsif ($opStateHeatPump3==7) {
  785. if ( $defrostValve==1 ) {$opStateHeatPump3Txt = "Abtauen (Kreisumkehr)";}
  786. elsif ( $compressor1==0 && $heatSourceMotor==1 ) {$opStateHeatPump3Txt = "Luftabtauen";}
  787. else {$opStateHeatPump3Txt = "Abtauen";}
  788. }
  789. $opStateHeatPump3Txt = "unbekannt (".$opStateHeatPump3.")" unless $opStateHeatPump3Txt;
  790. readingsBulkUpdate($hash,"opStateHeatPump3",$opStateHeatPump3Txt);
  791. # Hot water operating mode
  792. $value = $wpMode{$a[7]};
  793. $value = "unbekannt (".$a[7].")" unless $value;
  794. readingsBulkUpdate($hash,"opModeHotWater",$value);
  795. # opStateHotWater
  796. if ($a[8]==0) {$value="Sperrzeit";}
  797. elsif ($a[8]==1 && $hotWaterBoilerValve==1) {$value="Aufheizen";}
  798. elsif ($a[8]==1 && $hotWaterBoilerValve==0) {$value="Temp. OK";}
  799. elsif ($a[8]==3) {$value="Aus";}
  800. else {$value = "unbekannt (".$a[8]."/".$hotWaterBoilerValve.")";}
  801. readingsBulkUpdate($hash,"opStateHotWater",$value);
  802. # Heating operating mode
  803. $value = $wpMode{$a[10]};
  804. $value = "unbekannt (".$a[10].")" unless $value;
  805. readingsBulkUpdate($hash,"opModeHeating",$value);
  806. # Heating operating state
  807. # Consider also heating limit
  808. if ($a[10] == 0 && $a[11] == 1
  809. && $averageAmbientTemperature >= $thresholdHeatingLimit
  810. && ($returnTemperatureTarget eq $returnTemperatureTargetMin || $returnTemperatureTarget == 20 && $ambientTemperature<10)
  811. ) {
  812. if ($ambientTemperature>=10 ) {
  813. $value = "Heizgrenze (Soll ".$returnTemperatureTargetMin."°C)";
  814. }
  815. else {
  816. $value = "Frostschutz (Soll 20°C)";
  817. }
  818. }
  819. else {
  820. $value = $heatingState{$a[46]};
  821. $value = "unbekannt (".$a[46].")" unless $value;
  822. # Consider heating reduction limit
  823. if ($a[46] == 0) {
  824. if ($thresholdTemperatureSetBack <= $ambientTemperature) {
  825. $value .= " ".LUXTRONIK2_CalcTemp($a[47])."°C"; #° ° &#176; &#x00B0;
  826. }
  827. else {
  828. $value = "Normal da < ".$thresholdTemperatureSetBack."°C";
  829. }
  830. }
  831. }
  832. readingsBulkUpdate($hash,"opStateHeating",$value);
  833. # Ventilation operating mode
  834. if ( $a[79] !~ /no/ ) {
  835. $value = $ventMode{$a[79]};
  836. $value = "unbekannt (".$a[79].")" unless $value;
  837. readingsBulkUpdate($hash,"opModeVentilation",$value);
  838. }
  839. # Defrost times
  840. if ($compressor1 != $heatSourceMotor) {
  841. if ($hash->{fhem}{defrost}{mode} eq "none") {
  842. $hash->{fhem}{defrost}{startTime} = time();
  843. $hash->{fhem}{defrost}{mode} = "air" if $heatSourceMotor;
  844. $hash->{fhem}{defrost}{mode} = "reverse" unless $heatSourceMotor;
  845. $hash->{fhem}{defrost}{ambStart} = $ambientTemperature;
  846. $hash->{fhem}{defrost}{hsInStart} = $heatSourceIN;
  847. $hash->{fhem}{defrost}{hsOutStart} = $heatSourceOUT;
  848. }
  849. $hash->{fhem}{defrost}{amb} = $ambientTemperature;
  850. $hash->{fhem}{defrost}{hsIn} = $heatSourceIN;
  851. $hash->{fhem}{defrost}{hsOut} = $heatSourceOUT;
  852. }
  853. # Defrost-Readings creation
  854. elsif ( $hash->{fhem}{defrost}{mode} ne "none" ) {
  855. my $value = "Mode: " . $hash->{fhem}{defrost}{mode} . " Time: ";
  856. $value .= strftime ( "%M:%S", localtime( time() - $hash->{fhem}{defrost}{startTime} ) );
  857. $value .= " Amb: ".$hash->{fhem}{defrost}{ambStart} . " - ". $hash->{fhem}{defrost}{amb};
  858. $value .= " hsIN: ".$hash->{fhem}{defrost}{hsInStart} . " - ". $hash->{fhem}{defrost}{hsIn};
  859. #$value .= " hsOUT: ".$hash->{fhem}{defrost}{hsOutStart} . " - ". $heatSourceOUT;
  860. readingsBulkUpdate( $hash, "heatSourceDefrostLast", $value);
  861. my $rName = "heatSourceDefrostCounter";
  862. $rName .= "Air" if $hash->{fhem}{defrost}{mode} eq "air";
  863. $rName .= "Reverse" if $hash->{fhem}{defrost}{mode} eq "reverse";
  864. my $rValue = ReadingsVal ( $name, $rName, 0 ) + 1;
  865. readingsBulkUpdate ( $hash, $rName, 0 ) if $rValue == 1; #for statistics module
  866. readingsBulkUpdate ( $hash, $rName, $rValue );
  867. $hash->{fhem}{defrost}{mode} = "none";
  868. # 16 => "Durchflussüberwachung"
  869. if ($opStateHeatPump3 == 16) {
  870. readingsBulkUpdate( $hash, "heatSourceDefrostLastTimeout", "Amb: ".$hash->{fhem}{defrost}{amb}." hsIN: ".$hash->{fhem}{defrost}{hsIn}." hsOUT: ".$hash->{fhem}{defrost}{hsOut});
  871. }
  872. }
  873. # Determine last real heatings system return temperature, circulation needs to run at least 3 min or has been stopped less than 2 min ago
  874. $hash->{fhem}{hotWaterLastRun} = time() if $hotWaterBoilerValve;
  875. $hash->{fhem}{heatingPumpLastStop} = time() if !$heatingSystemCircPump;
  876. $hash->{fhem}{heatingPumpLastRun} = time() if $heatingSystemCircPump;
  877. readingsBulkUpdate( $hash, "returnTemperatureHeating", $returnTemperature)
  878. if ( $heatingSystemCircPump && !$hotWaterBoilerValve
  879. && time() - $hash->{fhem}{hotWaterLastRun} >= 180
  880. && time() - $hash->{fhem}{heatingPumpLastStop} >= 120
  881. || !$heatingSystemCircPump && !$hotWaterBoilerValve
  882. && $returnTemperature > $flowTemperature
  883. && $returnTemperature > $returnTemperaturLast);
  884. # || ( !$heatingSystemCircPump && !$hotWaterBoilerValve
  885. # && time() - $hash->{fhem}{hotWaterLastRun} >= 180
  886. # && time() - $hash->{fhem}{heatingPumpLastRun} < $hash->{INTERVAL}+10);
  887. # Device and reading times, delays and durations
  888. $value = strftime "%Y-%m-%d %H:%M:%S", localtime($a[22]);
  889. readingsBulkUpdate($hash, "deviceTimeCalc", $value);
  890. my $delayDeviceTimeCalc=sprintf("%.0f",$a[29]-$a[22]);
  891. readingsBulkUpdate($hash, "delayDeviceTimeCalc", $delayDeviceTimeCalc);
  892. my $durationFetchReadings = sprintf("%.3f",$a[30]-$a[29]);
  893. readingsBulkUpdate($hash, "durationFetchReadings", $durationFetchReadings);
  894. #Remember min and max reading durations, will be reset when initializing the device
  895. if ($hash->{fhem}{durationFetchReadingsMin} == 0 || $hash->{fhem}{durationFetchReadingsMin} > $durationFetchReadings) {
  896. $hash->{fhem}{durationFetchReadingsMin} = $durationFetchReadings;
  897. }
  898. if ($hash->{fhem}{durationFetchReadingsMax} < $durationFetchReadings) {
  899. $hash->{fhem}{durationFetchReadingsMax} = $durationFetchReadings;
  900. }
  901. # Temperatures and flow rate
  902. readingsBulkUpdate( $hash, "ambientTemperature", $ambientTemperature);
  903. readingsBulkUpdate( $hash, "averageAmbientTemperature", $averageAmbientTemperature);
  904. readingsBulkUpdate( $hash, "heatingLimit",$a[11]?"on":"off");
  905. readingsBulkUpdate( $hash, "thresholdHeatingLimit", $thresholdHeatingLimit);
  906. readingsBulkUpdate( $hash, "thresholdTemperatureSetBack", $thresholdTemperatureSetBack);
  907. if ($a[69] !~ /no/) {readingsBulkUpdate( $hash, "heatingCurveEndPoint",LUXTRONIK2_CalcTemp($a[69]));}
  908. if ($a[70] !~ /no/) {readingsBulkUpdate( $hash, "heatingCurveOffset",LUXTRONIK2_CalcTemp($a[70]));}
  909. readingsBulkUpdate( $hash, "hotWaterTemperature", $hotWaterTemperature);
  910. readingsBulkUpdate( $hash, "hotWaterTemperatureTarget",$hotWaterTemperatureTarget);
  911. readingsBulkUpdate( $hash, "flowTemperature", $flowTemperature);
  912. readingsBulkUpdate( $hash, "returnTemperature", $returnTemperature);
  913. readingsBulkUpdate( $hash, "returnTemperatureTarget", $returnTemperatureTarget);
  914. readingsBulkUpdate( $hash, "returnTemperatureHyst", $returnTempHyst);
  915. readingsBulkUpdate( $hash, "returnTemperatureSetBack",LUXTRONIK2_CalcTemp($a[54]));
  916. if ($a[18] !~ /no/) {readingsBulkUpdate( $hash, "returnTemperatureExtern",LUXTRONIK2_CalcTemp($a[18]));}
  917. if ($analogOut4 !~ /no/) {readingsBulkUpdate( $hash, "heatingSystemCircPumpVoltage", $analogOut4/100);}
  918. if ($flowRate !~ /no|inconsistent/ ) { readingsBulkUpdate( $hash, "flowRate",$flowRate); }
  919. readingsBulkUpdate( $hash, "heatSourceIN", $heatSourceIN );
  920. readingsBulkUpdate( $hash, "heatSourceOUT", $heatSourceOUT );
  921. readingsBulkUpdate( $hash, "heatSourceMotor", $heatSourceMotor?"on":"off");
  922. if ($a[71] !~ /no/) {readingsBulkUpdate( $hash, "heatSourceDefrostAirThreshold",LUXTRONIK2_CalcTemp($a[71]));}
  923. if ($a[72] !~ /no/) {readingsBulkUpdate( $hash, "heatSourceDefrostAirEnd",LUXTRONIK2_CalcTemp($a[72]));}
  924. if ($a[66] !~ /no/) {readingsBulkUpdate( $hash, "heatSourceDefrostTimer",$a[66]);}
  925. readingsBulkUpdate( $hash, "compressor1",$compressor1?"on":"off");
  926. readingsBulkUpdate( $hash, "hotGasTemperature",LUXTRONIK2_CalcTemp($a[26]));
  927. if ($a[55] !~ /no/) {readingsBulkUpdate( $hash, "mixer1FlowTemperature",LUXTRONIK2_CalcTemp($a[55]));}
  928. if ($a[56] !~ /no/) {readingsBulkUpdate( $hash, "mixer1TargetTemperature",LUXTRONIK2_CalcTemp($a[56]));}
  929. if ($a[57] !~ /no/) {readingsBulkUpdate( $hash, "mixer2FlowTemperature",LUXTRONIK2_CalcTemp($a[57]));}
  930. if ($a[58] !~ /no/) {readingsBulkUpdate( $hash, "mixer2TargetTemperature",LUXTRONIK2_CalcTemp($a[58]));}
  931. if ($a[59] !~ /no/) {readingsBulkUpdate( $hash, "mixer3FlowTemperature",LUXTRONIK2_CalcTemp($a[59]));}
  932. if ($a[60] !~ /no/) {readingsBulkUpdate( $hash, "mixer3TargetTemperature",LUXTRONIK2_CalcTemp($a[60]));}
  933. if ($a[77] !~ /no/) {readingsBulkUpdate( $hash, "ventSupplyAirTemperature",LUXTRONIK2_CalcTemp($a[77]));}
  934. if ($a[78] !~ /no/) {readingsBulkUpdate( $hash, "ventExhaustAirTemperature",LUXTRONIK2_CalcTemp($a[78]));}
  935. # Operating hours (seconds->hours) and heat quantities
  936. # LUXTRONIK2_storeReadings: $hash, $readingName, $value, $factor, $doStatistic, $electricalPower
  937. LUXTRONIK2_storeReadings $hash, "counterHours2ndHeatSource1", $a[32], 3600, $doStatistic, $heatRodPower;
  938. LUXTRONIK2_storeReadings $hash, "counterHours2ndHeatSource2", $a[38], 3600, $doStatistic, $heatRodPower;
  939. LUXTRONIK2_storeReadings $hash, "counterHours2ndHeatSource3", $a[39], 3600, $doStatistic, $heatRodPower;
  940. LUXTRONIK2_storeReadings $hash, "counterHoursHeatPump", $a[33], 3600, $doStatistic, $heatPumpPower;
  941. LUXTRONIK2_storeReadings $hash, "counterHoursHeating", $a[34], 3600, $doStatistic, $heatPumpPower;
  942. LUXTRONIK2_storeReadings $hash, "counterHoursHotWater", $a[35], 3600, $doStatistic, $heatPumpPower;
  943. my $heatQTotal = 0 ;
  944. if ($a[36] !~ /no/) {
  945. LUXTRONIK2_storeReadings $hash, "counterHeatQHeating", $a[36], 10, ($flowRate !~ /no/ ? $doStatistic : 0), -1;
  946. $heatQTotal += $a[36];
  947. }
  948. if ($a[37] !~ /no/) {
  949. LUXTRONIK2_storeReadings $hash, "counterHeatQHotWater", $a[37], 10, ($flowRate !~ /no/ ? $doStatistic : 0), -1;
  950. $heatQTotal += $a[37];
  951. }
  952. if ($a[62] !~ /no/) {
  953. LUXTRONIK2_storeReadings $hash, "counterHeatQPool", $a[62], 10, ($flowRate !~ /no/ ? $doStatistic : 0), -1;
  954. $heatQTotal += $a[62];
  955. }
  956. LUXTRONIK2_storeReadings $hash, "counterHeatQTotal", $heatQTotal, 10, ($flowRate !~ /no/ ? $doStatistic : 0), -1;
  957. # Input / Output status
  958. readingsBulkUpdate($hash,"heatingSystemCircPump",$heatingSystemCircPump?"on":"off");
  959. readingsBulkUpdate($hash,"hotWaterCircPumpExtern",$a[28]?"on":"off");
  960. readingsBulkUpdate($hash,"hotWaterSwitchingValve",$hotWaterBoilerValve?"on":"off");
  961. if ($a[74] !~ /no/) { readingsBulkUpdate($hash,"solarPump",$a[74]?"on":"off"); }
  962. if ($a[75] !~ /no/) { readingsBulkUpdate($hash,"2ndHeatSource1",$a[75]?"on":"off"); }
  963. # Deaerate Function
  964. readingsBulkUpdate( $hash, "hotWaterCircPumpDeaerate",$a[61]?"on":"off") unless $a[61] eq "no";
  965. readingsBulkUpdate( $hash, "heatingSystemCircPumpDeaerate",$a[80]?"on":"off") unless $a[80] eq "no";
  966. # bivalentLevel
  967. readingsBulkUpdate($hash,"bivalentLevel",$a[43]);
  968. # Firmware
  969. my $firmware = $a[20];
  970. readingsBulkUpdate($hash,"firmware",$firmware);
  971. my $firmwareCheck = LUXTRONIK2_checkFirmware($firmware);
  972. # if unknown firmware, ask at each startup to inform community
  973. if ($hash->{fhem}{alertFirmware} != 1 && $firmwareCheck eq "fwNotTested") {
  974. $hash->{fhem}{alertFirmware} = 1;
  975. LUXTRONIK2_Log $hash, 2, "Alert: Host uses untested Firmware '$a[20]'. Please inform FHEM community about compatibility.";
  976. }
  977. # Type of Heatpump
  978. $value = $wpType{$a[31]};
  979. $value = "unbekannt (".$a[31].")" unless $value;
  980. readingsBulkUpdate($hash,"typeHeatpump",$value);
  981. $hash->{MODEL} = $value;
  982. readingsBulkUpdate($hash,"typeSerial",$a[65]) if $a[65] ne "";
  983. # Solar
  984. if ($a[50] !~ /no/) {readingsBulkUpdate($hash, "solarCollectorTemperature", LUXTRONIK2_CalcTemp($a[50]));}
  985. if ($a[51] !~ /no/) {readingsBulkUpdate($hash, "solarBufferTemperature", LUXTRONIK2_CalcTemp($a[51]));}
  986. if ($a[52] !~ /no/) {readingsBulkUpdate($hash, "counterHoursSolar", sprintf("%.1f", $a[52]/3600));}
  987. # HTML for floorplan
  988. if(AttrVal($name, "statusHTML", "none") ne "none") {
  989. $value = ""; #"<div class=fp_" . $a[0] . "_title>" . $a[0] . "</div> \n";
  990. $value .= "$opStateHeatPump1<br>\n";
  991. $value .= "$opStateHeatPump2<br>\n";
  992. $value .= "$opStateHeatPump3Txt<br>\n";
  993. $value .= "Brauchwasser: ".$hotWaterTemperature."°C";
  994. readingsBulkUpdate($hash,"floorplanHTML",$value);
  995. }
  996. # State update
  997. $value = "$opStateHeatPump1 $opStateHeatPump2 - $opStateHeatPump3Txt";
  998. if ($thermalPower != 0) {
  999. $value .= sprintf (" (%.1f kW", $thermalPower);
  1000. if ($heatPumpPower>0) {$value .= sprintf (", COP: %.2f", $cop);}
  1001. $value .= ")"; }
  1002. readingsBulkUpdate($hash, "state", $value);
  1003. # Special readings
  1004. # $compressor1 = $a[6]; #Ausgang Verdichter 1
  1005. # $heatSourceMotor = $a[64]; #Ausgang Ventilator_BOSUP
  1006. # $defrostValve = $a[67]; #AVout
  1007. # $hotWaterBoilerValve = $a[9]; #BUP
  1008. # $heatingSystemCircPump = $a[27]; #HUP
  1009. # 0=Heizen, 1=keine Anforderung, 3=Schaltspielzeit, 5=Brauchwasser, 7=Abtauen, 16=Durchflussüberwachung
  1010. my $lastHeatingCycle = ReadingsVal($name, "heatingCycle", "");
  1011. if ( $opStateHeatPump3 == 0 ) {
  1012. readingsBulkUpdate($hash, "heatingCycle", "running");
  1013. }
  1014. elsif ( $opStateHeatPump3 > 1 && $lastHeatingCycle eq "running") {
  1015. readingsBulkUpdate($hash, "heatingCycle", "paused");
  1016. }
  1017. elsif ( $opStateHeatPump3 == 1 && $lastHeatingCycle eq "running") {
  1018. readingsBulkUpdate($hash, "heatingCycle", "finished");
  1019. }
  1020. elsif ( $opStateHeatPump3 =~ /1|3/ && $lastHeatingCycle ne "finished" && $returnTemperature-$returnTemperatureTarget >= $returnTempHyst ) {
  1021. readingsBulkUpdate($hash, "heatingCycle", "finished");
  1022. }
  1023. elsif ( $opStateHeatPump3 == 1 && $lastHeatingCycle eq "paused") {
  1024. readingsBulkUpdate($hash, "heatingCycle", "discontinued");
  1025. }
  1026. # 76 userHeatpumpParameters
  1027. if (defined $a[76]) {
  1028. my @userReadings = split /,/, $a[76];
  1029. foreach (@userReadings) {
  1030. my( $rName, $rValue) = split / /, $_;
  1031. readingsBulkUpdate($hash, $rName, $rValue);
  1032. }
  1033. }
  1034. readingsEndUpdate($hash,1);
  1035. $hash->{helper}{fetched_calc_values} = $a[44];
  1036. $hash->{helper}{fetched_parameters} = $a[45];
  1037. $hash->{helper}{fetched_visib_attr} = $a[53];
  1038. ############################
  1039. #Auto Synchronize Device Clock
  1040. my $autoSynchClock = AttrVal($name, "autoSynchClock", 0);
  1041. $autoSynchClock = 10 unless ($autoSynchClock >= 10 || $autoSynchClock == 0);
  1042. $autoSynchClock = 600 unless $autoSynchClock <= 600;
  1043. if ($autoSynchClock != 0 and abs($delayDeviceTimeCalc) > $autoSynchClock ) {
  1044. LUXTRONIK2_Log $name, 3, "autoSynchClock triggered (delayDeviceTimeCalc ".abs($delayDeviceTimeCalc)." > $autoSynchClock).";
  1045. # Firmware not tested and Firmware Check not ignored
  1046. if ($firmwareCheck eq "fwNotTested" && AttrVal($name, "ignoreFirmwareCheck", 0)!= 1) {
  1047. LUXTRONIK2_Log $name, 1, "Host firmware '$firmware' not tested for clock synchronization. To test set 'ignoreFirmwareCheck' to 1.";
  1048. $attr{$name}{autoSynchClock} = 0;
  1049. LUXTRONIK2_Log $name, 3, "Attribute 'autoSynchClock' set to 0.";
  1050. #Firmware not compatible
  1051. } elsif ($firmwareCheck eq "fwNotCompatible") {
  1052. LUXTRONIK2_Log $name, 1, "Host firmware '$firmware' not compatible for host clock synchronization.";
  1053. $attr{$name}{autoSynchClock} = 0;
  1054. LUXTRONIK2_Log $name, 3, "Attribute 'autoSynchClock' set to 0.";
  1055. #Firmware OK -> Synchronize Clock
  1056. } else {
  1057. $value = LUXTRONIK2_synchronizeClock($hash, 600);
  1058. LUXTRONIK2_Log $hash, 3, $value;
  1059. }
  1060. }
  1061. #End of Auto Synchronize Device Clock
  1062. ############################
  1063. }
  1064. else {
  1065. LUXTRONIK2_Log $hash, 5, "Status = $a[1]";
  1066. }
  1067. $hash->{fhem}{counterRetry} = $counterRetry;
  1068. }
  1069. sub ########################################
  1070. LUXTRONIK2_UpdateAborted($)
  1071. {
  1072. my ($hash) = @_;
  1073. delete($hash->{helper}{RUNNING_PID});
  1074. my $name = $hash->{NAME};
  1075. my $host = $hash->{HOST};
  1076. LUXTRONIK2_Log $hash, 1, "Timeout when connecting to host $host";
  1077. }
  1078. ########################################
  1079. sub LUXTRONIK2_ReadData($)
  1080. {
  1081. my ($name) = @_;
  1082. my $hash = $defs{$name};
  1083. my $host = $hash->{HOST};
  1084. my $port = $hash->{PORT};
  1085. my @heatpump_values;
  1086. my @heatpump_parameters;
  1087. my @heatpump_visibility;
  1088. my $count=0;
  1089. my $result="";
  1090. my $readingStartTime = time();
  1091. LUXTRONIK2_Log $name, 5, "Opening connection to $host:$port";
  1092. my $socket = new IO::Socket::INET (
  1093. PeerAddr => $host,
  1094. PeerPort => $port,
  1095. # Type = SOCK_STREAM, # probably needed on some systems
  1096. Proto => 'tcp'
  1097. );
  1098. if (!$socket) {
  1099. LUXTRONIK2_Log $name, 1, "Could not open connection to host $host:$port";
  1100. return (0, "Can't connect to $host:$port");
  1101. }
  1102. $socket->autoflush(1);
  1103. ############################
  1104. #Fetch operational values (FOV)
  1105. ############################
  1106. LUXTRONIK2_Log $name, 5, "Ask host for operational values";
  1107. $socket->send( pack( "N2", (3004,0) ) );
  1108. LUXTRONIK2_Log $name, 5, "Start to receive operational values";
  1109. #(FOV) read first 4 bytes of response -> should be request_echo = 3004
  1110. $socket->recv( $result,4, MSG_WAITALL );
  1111. $count = unpack("N", $result);
  1112. if($count != 3004) {
  1113. LUXTRONIK2_Log $name, 2, "Fetching operational values - wrong echo of request 3004: ".length($result)." -> ".$count;
  1114. $socket->close();
  1115. return (0, "3004 != $count");
  1116. }
  1117. #(FOV) read next 4 bytes of response -> should be status = 0
  1118. $socket->recv($result,4, MSG_WAITALL );
  1119. $count = unpack("N", $result);
  1120. if($count > 0) {
  1121. LUXTRONIK2_Log $name, 4, "Parameter on target changed, restart parameter reading after 5 seconds";
  1122. $socket->close();
  1123. return (2, "Status = $count - parameter on target changed, restart device reading after 5 seconds");
  1124. }
  1125. #(FOV) read next 4 bytes of response -> should be count_calc_values > 0
  1126. $socket->recv($result,4, MSG_WAITALL );
  1127. my $count_calc_values = unpack("N", $result);
  1128. if($count_calc_values == 0) {
  1129. LUXTRONIK2_Log $name, 2, "Fetching operational values - 0 values announced: ".length($result)." -> ".$count_calc_values;
  1130. $socket->close();
  1131. return (0, "0 values read");
  1132. }
  1133. #(FOV) read remaining response -> should be previous number of parameters
  1134. $socket->recv( $result, $count_calc_values*4, MSG_WAITALL );
  1135. if( length($result) != $count_calc_values*4 ) {
  1136. LUXTRONIK2_Log $name, 1, "Operational values length check: ".length($result)." should have been ". $count_calc_values * 4;
  1137. $socket->close();
  1138. return (0, "Number of values read mismatch ( $!)\n");
  1139. }
  1140. #(FOV) unpack response in array
  1141. @heatpump_values = unpack("N$count_calc_values", $result);
  1142. if(scalar(@heatpump_values) != $count_calc_values) {
  1143. LUXTRONIK2_Log $name, 2, "Unpacking problem by operation values: ".scalar(@heatpump_values)." instead of ".$count_calc_values;
  1144. $socket->close();
  1145. return (0, "Unpacking problem of operational values");
  1146. }
  1147. LUXTRONIK2_Log $name, 5, "$count_calc_values operational values received";
  1148. ############################
  1149. #Fetch set parameters (FSP)
  1150. ############################
  1151. LUXTRONIK2_Log $name, 5, "Ask host for set parameters";
  1152. $socket->send( pack( "N2", (3003,0) ) );
  1153. LUXTRONIK2_Log $name, 5, "Start to receive set parameters";
  1154. #(FSP) read first 4 bytes of response -> should be request_echo=3003
  1155. $socket->recv($result,4, MSG_WAITALL );
  1156. $count = unpack("N", $result);
  1157. if($count != 3003) {
  1158. LUXTRONIK2_Log $name, 2, "Wrong echo of request 3003: ".length($result)." -> ".$count;
  1159. $socket->close();
  1160. return (0, "3003 != 3003");
  1161. }
  1162. #(FSP) read next 4 bytes of response -> should be number_of_parameters > 0
  1163. $socket->recv($result,4, MSG_WAITALL );
  1164. my $count_set_parameter = unpack("N", $result);
  1165. if($count_set_parameter == 0) {
  1166. LUXTRONIK2_Log $name, 2, "0 parameter read: ".length($result)." -> ".$count_set_parameter;
  1167. $socket->close();
  1168. return (0, "0 parameter read");
  1169. }
  1170. #(FSP) read remaining response -> should be previous number of parameters
  1171. $socket->recv( $result, $count_set_parameter*4, MSG_WAITALL );
  1172. if( length($result) != $count_set_parameter*4 ) {
  1173. LUXTRONIK2_Log $name, 1, "Parameter length check: ".length($result)." should have been ". ($count_set_parameter * 4);
  1174. $socket->close();
  1175. return (0, "Number of parameters read mismatch ( $!)\n");
  1176. }
  1177. @heatpump_parameters = unpack("N$count_set_parameter", $result);
  1178. if(scalar(@heatpump_parameters) != $count_set_parameter) {
  1179. LUXTRONIK2_Log $name, 2, "Unpacking problem by set parameter: ".scalar(@heatpump_parameters)." instead of ".$count_set_parameter;
  1180. $socket->close();
  1181. return (0, "Unpacking problem of set parameters");
  1182. }
  1183. LUXTRONIK2_Log $name, 5, "$count_set_parameter set values received";
  1184. ############################
  1185. #Fetch Visibility Attributes (FVA)
  1186. ############################
  1187. LUXTRONIK2_Log $name, 5, "Ask host for visibility attributes";
  1188. $socket->send( pack( "N2", (3005,0) ) );
  1189. LUXTRONIK2_Log $name, 5, "Start to receive visibility attributes";
  1190. #(FVA) read first 4 bytes of response -> should be request_echo=3005
  1191. $socket->recv($result,4, MSG_WAITALL );
  1192. $count = unpack("N", $result);
  1193. if($count != 3005) {
  1194. LUXTRONIK2_Log $name, 2, "Wrong echo of request 3005: ".length($result)." -> ".$count;
  1195. $socket->close();
  1196. return (0, "3005 != $count");
  1197. }
  1198. #(FVA) read next 4 bytes of response -> should be number_of_Visibility_Attributes > 0
  1199. $socket->recv($result,4, MSG_WAITALL );
  1200. my $countVisibAttr = unpack("N", $result);
  1201. if($countVisibAttr == 0) {
  1202. LUXTRONIK2_Log $name, 2, "0 visibility attributes announced: ".length($result)." -> ".$countVisibAttr;
  1203. $socket->close();
  1204. return (0, "0 visibility attributes announced");
  1205. }
  1206. #(FVA) read remaining response bytewise -> should be previous number of parameters
  1207. $socket->recv( $result, $countVisibAttr, MSG_WAITALL );
  1208. if( length( $result ) != $countVisibAttr ) {
  1209. LUXTRONIK2_Log $name, 1, "Visibility attributes length check: ".length($result)." should have been ". $countVisibAttr;
  1210. $socket->close();
  1211. return (0, "Number of Visibility attributes read mismatch ( $!)\n");
  1212. }
  1213. @heatpump_visibility = unpack("C$countVisibAttr", $result);
  1214. if(scalar(@heatpump_visibility) != $countVisibAttr) {
  1215. LUXTRONIK2_Log $name, 2, "Unpacking problem by visibility attributes: ".scalar(@heatpump_visibility)." instead of ".$countVisibAttr;
  1216. $socket->close();
  1217. return (0, "Unpacking problem of visibility attributes");
  1218. }
  1219. LUXTRONIK2_Log $name, 5, "$countVisibAttr visibility attributs received";
  1220. ####################################
  1221. LUXTRONIK2_Log $name, 5, "Closing connection to host $host";
  1222. $socket->close();
  1223. my $readingEndTime = time();
  1224. #return all readings for further processing
  1225. return ( 1, "OK", \@heatpump_values, \@heatpump_parameters, \@heatpump_visibility);
  1226. }
  1227. sub ########################################
  1228. LUXTRONIK2_CalcTemp($)
  1229. {
  1230. my ($temp) = @_;
  1231. #change unsigned into signed
  1232. if ($temp > 2147483648) {$temp = $temp-4294967296;}
  1233. $temp /= 10;
  1234. return sprintf ("%.1f", $temp);
  1235. }
  1236. ########################################
  1237. sub LUXTRONIK2_FormatDuration($)
  1238. {
  1239. my ($value) = @_;
  1240. my $returnstr;
  1241. $returnstr = sprintf "%01dd ", int($value/86400)
  1242. if $value >= 86400;
  1243. $value %= 86400;
  1244. $returnstr .= sprintf "%02d:", int($value/3600);
  1245. $value %= 3600;
  1246. $returnstr .= sprintf "%02d:", int($value/60);
  1247. $value %= 60;
  1248. $returnstr .= sprintf "%02d", $value;
  1249. return $returnstr;
  1250. }
  1251. ########################################
  1252. sub LUXTRONIK2_SetParameter ($$$)
  1253. {
  1254. my ($hash, $parameterName, $realValue) = @_;
  1255. my $setParameter = 0;
  1256. my $setValue = 0;
  1257. my $result;
  1258. my $buffer;
  1259. my $host = $hash->{HOST};
  1260. my $port = $hash->{PORT};
  1261. my $name = $hash->{NAME};
  1262. my %opMode = ( "Auto" => 0,
  1263. "Party" => 2,
  1264. "Off" => 4);
  1265. if(AttrVal($name, "allowSetParameter", 0) != 1) {
  1266. return $name." Error: Setting of parameters not allowed. Please set attribut 'allowSetParameter' to 1";
  1267. }
  1268. if ($parameterName eq "hotWaterTemperatureTarget") {
  1269. #parameter number
  1270. $setParameter = 2;
  1271. #limit temperature range
  1272. $realValue = 30 if( $realValue < 30 );
  1273. $realValue = 65 if( $realValue > 65 );
  1274. #Allow only integer temperatures with decimal .1
  1275. $setValue = int($realValue * 10);
  1276. $realValue = $setValue / 10;
  1277. }
  1278. elsif ($parameterName eq "heatingCurveEndPoint") {
  1279. #parameter number
  1280. $setParameter = 11;
  1281. #limit temperature range
  1282. $realValue = 20 if( $realValue < 20.0 );
  1283. $realValue = 70 if( $realValue > 70.0 );
  1284. #Allow only integer temperatures
  1285. $setValue = int($realValue * 10);
  1286. $realValue = $setValue / 10;
  1287. }
  1288. elsif ($parameterName eq "heatingCurveOffset") {
  1289. #parameter number
  1290. $setParameter = 12;
  1291. #limit temperature range
  1292. $realValue = 5 if( $realValue < 5.0 );
  1293. $realValue = 35 if( $realValue > 35.0 );
  1294. #Allow only integer temperatures
  1295. $setValue = int($realValue * 10);
  1296. $realValue = $setValue / 10;
  1297. }
  1298. elsif ($parameterName eq "heatSourceDefrostAirEnd") {
  1299. #parameter number
  1300. $setParameter = 98;
  1301. #limit temperature range
  1302. $realValue = 1 if( $realValue < 1.0 );
  1303. $realValue = 24 if( $realValue > 24.0 );
  1304. #Allow only integer temperatures
  1305. $setValue = int($realValue * 10);
  1306. $realValue = $setValue / 10;
  1307. }
  1308. elsif ($parameterName eq "heatSourceDefrostAirThreshold") {
  1309. #parameter number
  1310. $setParameter = 44;
  1311. #limit temperature range
  1312. $realValue = 1.5 if( $realValue < 1.5 );
  1313. $realValue = 20 if( $realValue > 20.0 );
  1314. #Allow only integer temperatures
  1315. $setValue = int($realValue * 10);
  1316. $realValue = $setValue / 10;
  1317. }
  1318. elsif ($parameterName eq "opModeHotWater") {
  1319. if (! exists($opMode{$realValue})) {
  1320. return "$name Error: Wrong parameter given for opModeHotWater, use Automatik,Party,Off"
  1321. }
  1322. $setParameter = 4;
  1323. $setValue = $opMode{$realValue};
  1324. }
  1325. elsif ($parameterName eq "returnTemperatureHyst") {
  1326. #parameter number
  1327. $setParameter = 88;
  1328. #limit temperature range
  1329. $realValue = 0.5 if( $realValue < 0.5 );
  1330. $realValue = 3.0 if( $realValue > 3.0 );
  1331. #Allow only temperatures with decimal .1
  1332. $setValue = int($realValue * 10);
  1333. $realValue = $setValue / 10;
  1334. }
  1335. elsif ($parameterName eq "returnTemperatureSetBack") {
  1336. #parameter number
  1337. $setParameter = 1;
  1338. #limit temperature range
  1339. $realValue = -5 if( $realValue < -5 );
  1340. $realValue = 5 if( $realValue > 5 );
  1341. #Allow only temperatures with decimal .1
  1342. $setValue = int($realValue * 10);
  1343. $realValue = $setValue / 10;
  1344. }
  1345. elsif ($parameterName eq "heatingSystemCircPumpDeaerate") { #isVisible(161)
  1346. $setParameter = 678;
  1347. $setValue = $realValue eq "on" ? 1 : 0;
  1348. }
  1349. elsif ($parameterName eq "hotWaterCircPumpDeaerate") { #isVisible(167)
  1350. $setParameter = 684;
  1351. $setValue = $realValue eq "on" ? 1 : 0;
  1352. }
  1353. elsif ($parameterName eq "runDeaerate") {
  1354. $setParameter = 158;
  1355. $setValue = $realValue;
  1356. }
  1357. else {
  1358. return "$name LUXTRONIK2_SetParameter-Error: unknown parameter $parameterName";
  1359. }
  1360. ############################
  1361. # Send new parameter to host
  1362. ############################
  1363. if ($setParameter != 0) {
  1364. LUXTRONIK2_Log $name, 5, "Opening connection to host ".$host;
  1365. my $socket = new IO::Socket::INET ( PeerAddr => $host,
  1366. PeerPort => $port,
  1367. Proto => 'tcp'
  1368. );
  1369. # Socket error
  1370. if (!$socket) {
  1371. LUXTRONIK2_Log $name, 1, "Could not open connection to host ".$host;
  1372. return "$name Error: Could not open connection to host ".$host;
  1373. }
  1374. $socket->autoflush(1);
  1375. LUXTRONIK2_Log $name, 5, "Set parameter $parameterName ($setParameter) = $realValue ($setValue)";
  1376. $socket->send( pack( "N3", (3002, $setParameter, $setValue) ) );
  1377. LUXTRONIK2_Log $name, 5, "Receive confirmation";
  1378. #read first 4 bytes of response -> should be request_echo = 3002
  1379. $socket->recv($buffer,4, MSG_WAITALL );
  1380. $result = unpack("N", $buffer);
  1381. if($result != 3002) {
  1382. LUXTRONIK2_Log $name, 2, "Set parameter $parameterName - wrong echo of request: $result instead of 3002";
  1383. $socket->close();
  1384. return "$name Error: Host did not confirm parameter setting";
  1385. }
  1386. #Read next 4 bytes of response -> should be setParameter
  1387. $socket->recv($buffer,4, MSG_WAITALL );
  1388. $result = unpack("N", $buffer);
  1389. if($result !=$setParameter) {
  1390. LUXTRONIK2_Log $name, 2, "Set parameter $parameterName - missing confirmation: $result instead of $setParameter";
  1391. $socket->close();
  1392. return "$name Error: Host did not confirm parameter setting";
  1393. }
  1394. LUXTRONIK2_Log $name, 5, "Parameter setting confirmed";
  1395. $socket->close();
  1396. readingsSingleUpdate($hash,$parameterName,$realValue,0) unless $parameterName eq "runDeaerate";
  1397. return undef;
  1398. }
  1399. }
  1400. ########################################
  1401. sub LUXTRONIK2_synchronizeClock (@)
  1402. {
  1403. my ($hash,$maxDelta) = @_;
  1404. my $host = $hash->{HOST};
  1405. my $name = $hash->{NAME};
  1406. my $delay = 0;
  1407. my $returnStr = "";
  1408. $maxDelta = 60 unless defined $maxDelta;
  1409. $maxDelta = 60 unless $maxDelta >= 0;
  1410. $maxDelta = 600 unless $maxDelta <= 600;
  1411. LUXTRONIK2_Log $name, 5, "Open telnet connection to $host";
  1412. my $telnet = new Net::Telnet ( host=>$host, port => 23, timeout=>10, errmode=>'return');
  1413. if (!$telnet) {
  1414. my $msg = "Could not open telnet connection to $host: $!";
  1415. LUXTRONIK2_Log $name, 1, $msg;
  1416. return "$name synchronizeDeviceClock-Error: ".$msg;
  1417. }
  1418. LUXTRONIK2_Log $name, 5, "Log into $host";
  1419. if (!$telnet->login('root', '')) {
  1420. LUXTRONIK2_Log $name, 1, $telnet->errmsg;
  1421. return "$name synchronizeDeviceClock-Error: ".$telnet->errmsg;
  1422. }
  1423. LUXTRONIK2_Log $name, 5, "Read current time of host";
  1424. my @output = $telnet->cmd('date +%s');
  1425. $delay = sprintf("%.1f",time() - $output[0]);
  1426. LUXTRONIK2_Log $name, 5, "Current time is ".localtime($output[0])." Delay is $delay seconds.";
  1427. if (abs($delay)>$maxDelta && $maxDelta!=0) {
  1428. $returnStr = "Do not dare to synchronize. Device clock of host $host differs by $delay seconds (max. is $maxDelta).";
  1429. } elsif ($delay == 0) {
  1430. $returnStr = "Internal clock of host $host has no delay. -> not synchronized";
  1431. } else {
  1432. my $newTime = strftime "%m%d%H%M%Y.%S", localtime();
  1433. LUXTRONIK2_Log $name, 5, "Run command 'date ".$newTime."'";
  1434. @output=$telnet->cmd('date '.$newTime);
  1435. $returnStr = "Internal clock of host $host corrected by $delay seconds. -> ".$output[0];
  1436. readingsSingleUpdate($hash,"deviceTimeLastSync",TimeNow,1);
  1437. }
  1438. LUXTRONIK2_Log $name, 5, "Close telnet connection.";
  1439. $telnet->close;
  1440. return $returnStr;
  1441. }
  1442. ########################################
  1443. sub LUXTRONIK2_boostHotWater_Start ($$)
  1444. { my ($hash, $temperature) = @_;
  1445. my $name = $hash->{NAME};
  1446. return "boostHotWater not implemented yet";
  1447. return "$temperature is not a number." if defined $temperature && $temperature !~ /^\d*\.?\d*$/;
  1448. my $currTarget = $hash->{READINGS}{hotWaterTemperatureTarget}{VAL};
  1449. return "Could not determine current hotWaterTemperatureTarget." unless defined $currTarget;
  1450. readingsSingleUpdate($hash,"bhwLastTarget",$currTarget, 0) unless $hash->{READINGS}{bhwLastTarget}{VAL};
  1451. my $currMode = $hash->{READINGS}{opModeHotWater}{VAL};
  1452. return "Could not determine current opModeHotWater." unless defined $currMode;
  1453. readingsSingleUpdate($hash,"bhwLastMode",$currMode, 0) unless $hash->{READINGS}{bhwLastMode}{VAL};
  1454. my $currState = $hash->{READINGS}{opStateHotWater}{VAL};
  1455. return "Could not determine current opStateHotWater." unless defined $currState;
  1456. $hash->{boostHotWater} = 1;
  1457. if ( defined $temperature ) {
  1458. LUXTRONIK2_Log $name, 4, "set 'hotWaterTemperatureTarget' temporarly to ".$temperature;
  1459. LUXTRONIK2_SetParameter($hash, "hotWaterTemperatureTarget", $temperature);
  1460. }
  1461. if ( $currState !~ /Aufheizen|Temp. OK/) {
  1462. LUXTRONIK2_Log $name, 4, "set 'opModeHotWater' temporarly to 'Party'";
  1463. LUXTRONIK2_SetParameter($hash, "opModeHotWater", "Party");
  1464. }
  1465. }
  1466. ########################################
  1467. sub LUXTRONIK2_calcHeatingCurveParameter ($$$$$)
  1468. { my ($hash, $aussen_1, $rtSoll_1, $aussen_2, $rtSoll_2) = @_;
  1469. if ($aussen_1 > $aussen_2) {
  1470. my $temp= $aussen_1;
  1471. $aussen_1=$aussen_2;
  1472. $aussen_2=$temp;
  1473. $temp= $rtSoll_1;
  1474. $rtSoll_1=$rtSoll_2;
  1475. $rtSoll_2=$temp;
  1476. }
  1477. my $endPoint_Ist = $hash->{READINGS}{heatingCurveEndPoint}{VAL};
  1478. my $endPoint = $endPoint_Ist;
  1479. my $offset_Ist = $hash->{READINGS}{heatingCurveOffset}{VAL};
  1480. my $offset = $offset_Ist;
  1481. my $rtIst_1 = LUXTRONIK2_getHeatingCurveReturnTemperature ( $hash, $aussen_1, $endPoint, $offset);
  1482. my $rtIst_2 = LUXTRONIK2_getHeatingCurveReturnTemperature ( $hash, $aussen_2, $endPoint, $offset);
  1483. my $delta_1; my $delta_2;
  1484. my $msg; my $i;
  1485. #get Heizung heatingCurveParameter 0 27 10 25
  1486. for ( $i=0; $i<1000; $i++ ) {
  1487. $delta_1 = LUXTRONIK2_getHeatingCurveReturnTemperature ( $hash, $aussen_1, $endPoint, $offset) - $rtSoll_1;
  1488. $delta_1 = int(10.0 * $delta_1 + 0.5) / 10.0;
  1489. $delta_2 = LUXTRONIK2_getHeatingCurveReturnTemperature ( $hash, $aussen_2, $endPoint, $offset) - $rtSoll_2;
  1490. $delta_2 = int(10.0 * $delta_2 + 0.5) / 10.0;
  1491. $msg = "Calculate loop $i: hcEndPoint=$endPoint, hcOffset=$offset, delta($aussen_1)=$delta_1, delta($aussen_2)=$delta_2)\n";
  1492. LUXTRONIK2_Log $hash, 4, $msg;
  1493. last if $delta_1 == 0 && $delta_2 == 0;
  1494. if ($delta_2 > 0) {
  1495. $offset -= 0.1;
  1496. }
  1497. elsif ($delta_2 < 0) {
  1498. $offset += 0.1;
  1499. }
  1500. elsif ($delta_1 > 0) {
  1501. $endPoint -= 0.1;
  1502. }
  1503. elsif ($delta_1 < 0) {
  1504. $endPoint += 0.1;
  1505. }
  1506. $endPoint = int(10.0 * $endPoint + 0.5) / 10.0;
  1507. $offset = int(10.0 * $offset + 0.5) / 10.0;
  1508. }
  1509. LUXTRONIK2_Log $hash, 3, "Heating-Curve-Parameter calculated in $i loops.";
  1510. $msg = "New Values: heatingCurveEndPoint=$endPoint heatingCurveOffset=$offset\n";
  1511. $msg .= "Old Values: heatingCurveEndPoint=$endPoint_Ist heatingCurveOffset=$offset_Ist\n\n";
  1512. $msg .= "New Heating-Curve: returnTemp($aussen_1)=".($delta_1+$rtSoll_1)." and returnTemp($aussen_2)=".($delta_2+$rtSoll_2)."\n";
  1513. $msg .= "Old Heating-Curve: returnTemp($aussen_1)=".($rtIst_1)." and returnTemp($aussen_2)=".($rtIst_2)."\n";
  1514. $msg .= "calculated in $i loops\n";
  1515. return $msg;
  1516. }
  1517. ########################################
  1518. sub LUXTRONIK2_getHeatingCurveReturnTemperature ($$$$)
  1519. { my ($hash, $aussen, $endPoint, $offset) = @_;
  1520. LUXTRONIK2_Log $hash, 5, "Calculate return-temperature at $aussen with heating curve ($endPoint, $offset)";
  1521. my $result = $offset + ($endPoint - 20.0) * ($offset - $aussen) / (20.0 - ($aussen - $offset) / 2);
  1522. $result = int(10.0 * $result + 0.5) / 10.0;
  1523. return $result;
  1524. }
  1525. ########################################
  1526. sub LUXTRONIK2_checkFirmware ($)
  1527. {
  1528. my ($myFirmware) = @_;
  1529. #Firmware not tested
  1530. if (index($testedFirmware,"#".$myFirmware."#") == -1) {
  1531. return "fwNotTested";
  1532. #Firmware tested but not compatible
  1533. } elsif (index($compatibleFirmware,"#".$myFirmware."#") == -1) {
  1534. return "fwNotCompatible";
  1535. #Firmware compatible
  1536. } else {
  1537. return "fwCompatible";
  1538. }
  1539. }
  1540. # Calculate heat-up gradients of boiler based on hotWaterTemperature and counterHeatQHeating
  1541. sub ########################################
  1542. LUXTRONIK2_doStatisticThermalPower ($$$$$$$$$)
  1543. {
  1544. my ($hash, $MonitoredOpState, $currOpState, $currHeatQuantity, $currOpHours, $currAmbTemp, $currHeatSourceIn, $targetTemp, $electricalPower) = @_;
  1545. my @last = split / /, $hash->{fhem}{"statThermalPowerOpState_".$MonitoredOpState} || "1";
  1546. my $returnStr = "";
  1547. my $value1;
  1548. my $value2;
  1549. my $value3;
  1550. my $save = 0;
  1551. if ( $last[0] != $MonitoredOpState && $currOpState == $MonitoredOpState ) {
  1552. # Save start values at the beginning of the monitored operation (5=Hot Water, 0=Heating)
  1553. $save = 1;
  1554. $last[0] = $currOpState;
  1555. $last[1] = $currHeatQuantity;
  1556. $last[2] = $currOpHours;
  1557. $last[3] = $currAmbTemp;
  1558. $last[4] = $currHeatSourceIn;
  1559. $last[5] = 1;
  1560. $last[6] = $targetTemp;
  1561. $last[7] = $electricalPower;
  1562. } elsif ($last[0] == $MonitoredOpState && ($currOpState == $MonitoredOpState || $currOpState == 16) ) { #16=Durchflussüberwachung
  1563. # Store intermediate values as long as the correct opMode runs
  1564. $save = 1;
  1565. $last[3] += $currAmbTemp;
  1566. $last[4] += $currHeatSourceIn;
  1567. $last[5]++;
  1568. $last[7] += $electricalPower;
  1569. } elsif ($last[0] == $MonitoredOpState && $currOpState != $MonitoredOpState && $currOpState != 16 ) { #16=Durchflussüberwachung
  1570. # Do statistics at the end of the monitored operation if it run at least 9.5 minutes
  1571. $save = 1;
  1572. $last[0] = $currOpState;
  1573. $value2 = ($currOpHours - $last[2])/60;
  1574. if ($value2 >= 6) {
  1575. $returnStr = sprintf "aT: %.1f iT: %.1f tT: %.1f", $last[3]/$last[5], $last[4]/$last[5], $targetTemp;
  1576. $value1 = $currHeatQuantity - $last[1];
  1577. $value3 = $value1 * 60 / $value2;
  1578. $returnStr .= sprintf " thP: %.1f DQ: %.1f t: %.0f", $value3, $value1, $value2;
  1579. if ($last[7]>0) {
  1580. $value1 = $value3 *1000 / $last[7] * $last[5];;
  1581. $returnStr .= sprintf " COP: %.2f", $value1;
  1582. }
  1583. if ($last[6] > $targetTemp) { $returnStr .= " tTStart: " . $last[6]; }
  1584. }
  1585. }
  1586. if ($save == 1) { $hash->{fhem}{"statThermalPowerOpState_".$MonitoredOpState} = join( " ", @last);}
  1587. return $returnStr;
  1588. }
  1589. # Calculate heat-up gradients of boiler based on hotWaterTemperature and counterHeatQHeating
  1590. sub ########################################
  1591. LUXTRONIK2_doStatisticBoilerHeatUp ($$$$$$)
  1592. {
  1593. my ($hash, $currOpHours, $currHQ, $currTemp, $opState, $target) = @_;
  1594. my $name = $hash->{NAME};
  1595. my $step = $hash->{fhem}{statBoilerHeatUpStep};
  1596. my $minTemp = $hash->{fhem}{statBoilerHeatUpMin};
  1597. my $maxTemp = $hash->{fhem}{statBoilerHeatUpMax};
  1598. my $lastHQ = $hash->{fhem}{statBoilerHeatUpHQ};
  1599. my $lastOpHours = $hash->{fhem}{statBoilerHeatUpOpHours};
  1600. my $value1 = 0;
  1601. my $value2 = 0;
  1602. my $value3 = 0;
  1603. my $returnStr = "";
  1604. # step 0 = Initialize - if hot water preparation is off
  1605. if ($step == 0) {
  1606. if ($opState != 5) { # wait till hot water preparation stopped
  1607. LUXTRONIK2_Log $name, 4, "Statistic Boiler Heat-Up step 0->1: Initializing Measurment";
  1608. $step = 1;
  1609. $lastOpHours = $currOpHours;
  1610. $lastHQ = $currHQ;
  1611. $minTemp = $currTemp;
  1612. }
  1613. # step 1 = wait till hot water preparation starts -> monitor Tmin, take previous HQ and previous operating hours
  1614. } elsif ($step == 1) {
  1615. if ($currTemp < $minTemp) { # monitor minimum temperature
  1616. LUXTRONIK2_Log $name, 4, "Statistic Boiler Heat-Up step 1: Monitor minimum temperature ($minTemp -> $currTemp)";
  1617. $minTemp = $currTemp;
  1618. }
  1619. if ($opState != 5) { # wait -> update operating hours and HQ to be used as start value in calculations
  1620. $lastOpHours = $currOpHours;
  1621. $lastHQ = $currHQ;
  1622. } else { # go to step 2 - if hot water preparation running
  1623. LUXTRONIK2_Log $name, 4, "Statistic Boiler Heat-Up step 1->2: Hot water preparation started ".($currOpHours-$lastOpHours)." s ago";
  1624. $step = 2;
  1625. $maxTemp = $currTemp;
  1626. }
  1627. # step 2 = wait till hot water preparation done and target reached
  1628. } elsif ($step == 2) {
  1629. if ($currTemp < $minTemp) { # monitor minimal temperature
  1630. LUXTRONIK2_Log $name, 4, "Statistic Boiler Heat-Up step 2: Boiler temperature still decreasing ($minTemp -> $currTemp)";
  1631. $minTemp = $currTemp;
  1632. }
  1633. if ($currTemp > $maxTemp) { # monitor maximal temperature
  1634. LUXTRONIK2_Log $name, 4, "Statistic Boiler Heat-Up step 2: Boiler temperature increasing ($maxTemp -> $currTemp)";
  1635. $maxTemp = $currTemp;
  1636. }
  1637. if ($opState != 5) { # wait till hot water preparation stopped
  1638. if ($currTemp >= $target) {
  1639. LUXTRONIK2_Log $name, 4, "Statistic Boiler Heat-Up step 2->3: Hot water preparation stopped";
  1640. $step = 3;
  1641. } else {
  1642. LUXTRONIK2_Log $name, 4, "Statistic Boiler Heat-Up step 2->1: Measurement cancelled (hot water preparation stopped but target not reached, $currTemp < $target)";
  1643. $step = 1;
  1644. $lastOpHours = $currOpHours;
  1645. $lastHQ = $currHQ;
  1646. $minTemp = $currTemp;
  1647. }
  1648. }
  1649. # step 3 = wait with calculation till temperature maximum reached once
  1650. } elsif ($step == 3) {
  1651. # cancel measurement - if hot water preparation has restarted
  1652. if ($opState == 5) {
  1653. LUXTRONIK2_Log $name, 4, "Statistic Boiler Heat-Up step 3->0: Measurement cancelled (hot water preparation restarted before maximum reached)";
  1654. $step = 0;
  1655. # monitor maximal temperature
  1656. } elsif ($currTemp > $maxTemp) {
  1657. LUXTRONIK2_Log $name, 4, "Statistic Boiler Heat-Up step 3: Temperature still increasing ($maxTemp -> $currTemp)";
  1658. $maxTemp = $currTemp;
  1659. # else calculate temperature gradient
  1660. } else {
  1661. LUXTRONIK2_Log $name, 4, "Statistic Boiler Heat-Up step 3->1: Boiler heat-up measurement finished";
  1662. $value1 = ( int(10 * $maxTemp) - int(10 * $minTemp) ) / 10; # delta hot water temperature
  1663. $value2 = ( $currOpHours - $lastOpHours ) / 60; # delta time (minutes)
  1664. $value3 = $currHQ - $lastHQ; # delta heat quantity, average thermal power
  1665. $returnStr = sprintf "DT/min: %.2f DT: %.2f Dmin: %.0f DQ: %.1f thP: %.1f", $value1/$value2, $value1, $value2, $value3, $value3*60/$value2;
  1666. #real (mixed) Temperature-Difference
  1667. my $boilerVolumn = AttrVal($name, "boilerVolumn", 0);
  1668. if ($boilerVolumn >0 ) {
  1669. # (delta T) [K] = Wärmemenge [kWh] / #Volumen [l] * ( 3.600 [kJ/kWh] / ( 4,179 [kJ/(kg*K)] (H2O Wärmekapazität bei 40°C) * 0,992 [kg/l] (H2O Dichte bei 40°C) ) [K/(kWh*l)] )
  1670. $value2 = 868.4 * $value3 / $boilerVolumn ;
  1671. $returnStr .= sprintf " realDT: %.0f", $value2;
  1672. }
  1673. $step = 1;
  1674. $lastOpHours = $currOpHours;
  1675. $lastHQ = $currHQ;
  1676. $minTemp = $currTemp;
  1677. }
  1678. }
  1679. $hash->{fhem}{statBoilerHeatUpStep} = $step;
  1680. $hash->{fhem}{statBoilerHeatUpMin} = $minTemp;
  1681. $hash->{fhem}{statBoilerHeatUpMax} = $maxTemp;
  1682. $hash->{fhem}{statBoilerHeatUpHQ} = $lastHQ;
  1683. $hash->{fhem}{statBoilerHeatUpOpHours} = $lastOpHours;
  1684. return $returnStr;
  1685. }
  1686. # Calculate heat loss gradients of boiler based on hotWaterTemperature and counterHeatQHeating
  1687. sub ########################################
  1688. LUXTRONIK2_doStatisticBoilerCoolDown ($$$$$$)
  1689. {
  1690. my ($hash, $time, $currTemp, $opState, $target, $threshold) = @_;
  1691. my $name = $hash->{NAME};
  1692. my $step = $hash->{fhem}{statBoilerCoolDownStep};
  1693. my $maxTemp = $hash->{fhem}{statBoilerCoolDownMax};
  1694. my $startTime = $hash->{fhem}{statBoilerCoolDownStartTime};
  1695. my $lastTime = $hash->{fhem}{statBoilerCoolDownLastTime};
  1696. my $lastTemp = $hash->{fhem}{statBoilerCoolDownLastTemp};
  1697. my $value1 = 0;
  1698. my $value2 = 0;
  1699. my $value3 = 0;
  1700. my $returnStr = "";
  1701. # step 0 = Initialize - if hot water preparation is off and target reached,
  1702. if ($step == 0) {
  1703. if ($opState == 5 || $currTemp < $target) { # -> stay step 0
  1704. # LUXTRONIK2_Log $name, 4, "Statistic Boiler Cool-Down step 0: Wait till hot water preparation stops and target is reached ($currTemp < $target)";
  1705. } else {
  1706. LUXTRONIK2_Log $name, 4, "Statistic Boiler Cool-Down step 0->1: Initializing, target reached ($currTemp >= $target)";
  1707. $step = 1;
  1708. $startTime = $time;
  1709. $maxTemp = $currTemp;
  1710. }
  1711. # step 1 = wait till threshold is reached -> do calculation, monitor maximal temperature
  1712. } elsif ($step == 1) {
  1713. if ($currTemp > $maxTemp) { # monitor maximal temperature
  1714. LUXTRONIK2_Log $name, 4, "Statistic Boiler Cool-Down step 1: Temperature still increasing ($currTemp > $maxTemp)";
  1715. $maxTemp = $currTemp;
  1716. $startTime = $time;
  1717. }
  1718. if ($opState == 5 || $currTemp <= $threshold) {
  1719. if ($opState == 5) {
  1720. LUXTRONIK2_Log $name, 4, "Statistic Boiler Cool-Down step 1->0: Heat-up started, measurement finished";
  1721. $value1 = $lastTemp - $maxTemp; # delta hot water temperature
  1722. $value2 = ( $lastTime - $startTime ) / 3600; # delta time (hours)
  1723. } elsif ($currTemp <= $threshold) {
  1724. LUXTRONIK2_Log $name, 4, "Statistic Boiler Cool-Down step 1->0: Measurement finished, threshold reached ($currTemp <= $threshold)";
  1725. $value1 = $currTemp - $maxTemp; # delta hot water temperature
  1726. $value2 = ( $time - $startTime ) / 3600; # delta time (hours)
  1727. }
  1728. $returnStr = sprintf "DT/h: %.2f DT: %.1f Dh: %.2f", $value1/$value2, $value1, $value2;
  1729. $step = 0;
  1730. }
  1731. }
  1732. $hash->{fhem}{statBoilerCoolDownStep} = $step;
  1733. $hash->{fhem}{statBoilerCoolDownMax} = $maxTemp;
  1734. $hash->{fhem}{statBoilerCoolDownStartTime} = $startTime;
  1735. $hash->{fhem}{statBoilerCoolDownLastTime} = $time;
  1736. $hash->{fhem}{statBoilerCoolDownLastTemp} = $currTemp;
  1737. return $returnStr;
  1738. }
  1739. # Calculates single MaxMin Values and informs about end of day and month
  1740. ########################################
  1741. sub LUXTRONIK2_doStatisticMinMax ($$$)
  1742. {
  1743. my ($hash, $readingName, $value) = @_;
  1744. my $dummy;
  1745. my $saveLast;
  1746. my $statReadingName;
  1747. my $lastReading;
  1748. my $lastSums;
  1749. my @newReading;
  1750. my $yearLast;
  1751. my $monthLast;
  1752. my $dayLast;
  1753. my $dayNow;
  1754. my $monthNow;
  1755. my $yearNow;
  1756. # Determine date of last and current reading
  1757. if (exists($hash->{READINGS}{$readingName."Day"}{TIME})) {
  1758. ($yearLast, $monthLast, $dayLast) = $hash->{READINGS}{$readingName."Day"}{TIME} =~ /^(\d\d\d\d)-(\d\d)-(\d\d)/;
  1759. } else {
  1760. ($dummy, $dummy, $dummy, $dayLast, $monthLast, $yearLast) = localtime;
  1761. $yearLast += 1900;
  1762. $monthLast ++;
  1763. }
  1764. ($dummy, $dummy, $dummy, $dayNow, $monthNow, $yearNow) = localtime;
  1765. $yearNow += 1900;
  1766. $monthNow ++;
  1767. # Daily Statistic
  1768. $saveLast = ($dayNow != $dayLast);
  1769. $statReadingName = $readingName."Day";
  1770. LUXTRONIK2_doStatisticMinMaxSingle $hash, $statReadingName, $value, $saveLast;
  1771. # Monthly Statistic
  1772. $saveLast = ($monthNow != $monthLast);
  1773. $statReadingName = $readingName."Month";
  1774. LUXTRONIK2_doStatisticMinMaxSingle $hash, $statReadingName, $value, $saveLast;
  1775. # Yearly Statistic
  1776. $saveLast = ($yearNow != $yearLast);
  1777. $statReadingName = $readingName."Year";
  1778. LUXTRONIK2_doStatisticMinMaxSingle $hash, $statReadingName, $value, $saveLast;
  1779. return ;
  1780. }
  1781. # Calculates single MaxMin Values and informs about end of day and month
  1782. sub ########################################
  1783. LUXTRONIK2_doStatisticMinMaxSingle ($$$$)
  1784. {
  1785. my ($hash, $readingName, $value, $saveLast) = @_;
  1786. my $result;
  1787. my $lastReading = $hash->{READINGS}{$readingName}{VAL} || "";
  1788. # Initializing
  1789. if ( $lastReading eq "" ) {
  1790. my $since = strftime "%Y-%m-%d_%H:%M:%S", localtime();
  1791. $result = "Count: 1 Sum: $value ShowDate: 1";
  1792. readingsBulkUpdate($hash, ".".$readingName, $result);
  1793. $result = "Min: $value Avg: $value Max: $value (since: $since )";
  1794. readingsBulkUpdate($hash, $readingName, $result);
  1795. # Calculations
  1796. } else {
  1797. my @a = split / /, $hash->{READINGS}{"." . $readingName}{VAL}; # Internal values
  1798. my @b = split / /, $lastReading;
  1799. # Do calculations
  1800. $a[1]++; # Count
  1801. $a[3] += $value; # Sum
  1802. if ($value < $b[1]) { $b[1]=$value; } # Min
  1803. if ($a[1]>0) {$b[3] = sprintf "%.1f" , $a[3] / $a[1] ;} # Avg
  1804. if ($value > $b[5]) { $b[5]=$value; } # Max
  1805. # in case of period change, save "last" values and reset counters
  1806. if ($saveLast) {
  1807. $result = "Min: $b[1] Avg: $b[3] Max: $b[5]";
  1808. if ($a[5] == 1) { $result .= " (since: $b[7] )"; }
  1809. readingsBulkUpdate($hash, $readingName . "Last", $lastReading);
  1810. $a[1] = 1; $a[3] = $value; $a[5] = 0;
  1811. $b[1] = $value; $b[3] = $value; $b[5] = $value;
  1812. }
  1813. # Store internal calculation values
  1814. $result = "Count: $a[1] Sum: $a[3] ShowDate: $a[5]";
  1815. readingsBulkUpdate($hash, ".".$readingName, $result);
  1816. # Store visible Reading
  1817. if ($a[5] == 1) {
  1818. $result = "Min: $b[1] Avg: $b[3] Max: $b[5] (since: $b[7] )";
  1819. } else {
  1820. $result = "Min: $b[1] Avg: $b[3] Max: $b[5]";
  1821. }
  1822. readingsBulkUpdate($hash, $readingName, $result);
  1823. }
  1824. return;
  1825. }
  1826. ########################################
  1827. sub LUXTRONIK2_storeReadings($$$$$$)
  1828. {
  1829. my ($hash, $readingName, $value, $factor, $doStatistic, $electricalPower) = @_;
  1830. if ($value eq "no" || $value == 0 ) { return; }
  1831. readingsBulkUpdate($hash, $readingName, sprintf("%.1f", $value / $factor));
  1832. $readingName =~ s/counter//;
  1833. # LUXTRONIK2_doStatisticDelta: $hash, $readingName, $value, $factor, $electricalPower
  1834. if ( $doStatistic == 1) { LUXTRONIK2_doStatisticDelta $hash, "stat".$readingName, $value, $factor, $electricalPower; }
  1835. }
  1836. # Calculates deltas for day, month and year
  1837. ########################################
  1838. sub LUXTRONIK2_doStatisticDelta ($$$$$)
  1839. {
  1840. my ($hash, $readingName, $value, $factor, $electricalPower) = @_;
  1841. my $name = $hash->{NAME};
  1842. my $dummy;
  1843. my $result;
  1844. my $deltaValue;
  1845. my $previousTariff;
  1846. my $showDate;
  1847. # Determine if time period switched (day, month, year)
  1848. # Get deltaValue and Tariff of previous call
  1849. my $periodSwitch = 0;
  1850. my $yearLast; my $monthLast; my $dayLast; my $dayNow; my $monthNow; my $yearNow;
  1851. if (exists($hash->{READINGS}{"." . $readingName . "Before"})) {
  1852. ($yearLast, $monthLast, $dayLast) = ($hash->{READINGS}{"." . $readingName . "Before"}{TIME} =~ /^(\d\d\d\d)-(\d\d)-(\d\d)/);
  1853. $yearLast -= 1900;
  1854. $monthLast --;
  1855. ($dummy, $deltaValue, $dummy, $previousTariff, $dummy, $showDate) = split / /, $hash->{READINGS}{"." . $readingName . "Before"}{VAL} || "";
  1856. $deltaValue = $value - $deltaValue;
  1857. } else {
  1858. ($dummy, $dummy, $dummy, $dayLast, $monthLast, $yearLast) = localtime;
  1859. $deltaValue = 0;
  1860. $previousTariff = 0;
  1861. $showDate = 6;
  1862. }
  1863. ($dummy, $dummy, $dummy, $dayNow, $monthNow, $yearNow) = localtime;
  1864. if ($yearNow != $yearLast) { $periodSwitch = 3; }
  1865. elsif ($monthNow != $monthLast) { $periodSwitch = 2; }
  1866. elsif ($dayNow != $dayLast) { $periodSwitch = 1; }
  1867. # Determine if "since" value has to be shown in current and last reading
  1868. if ($periodSwitch == 3) {
  1869. if ($showDate == 1) { $showDate = 0; } # Do not show the "since:" value for year changes anymore
  1870. if ($showDate >= 2) { $showDate = 1; } # Shows the "since:" value for the first year change
  1871. }
  1872. if ($periodSwitch >= 2){
  1873. if ($showDate == 3) { $showDate = 2; } # Do not show the "since:" value for month changes anymore
  1874. if ($showDate >= 4) { $showDate = 3; } # Shows the "since:" value for the first month change
  1875. }
  1876. if ($periodSwitch >= 1){
  1877. if ($showDate == 5) { $showDate = 4; } # Do not show the "since:" value for day changes anymore
  1878. if ($showDate >= 6) { $showDate = 5; } # Shows the "since:" value for the first day change
  1879. }
  1880. # LUXTRONIK2_doStatisticDeltaSingle; $hash, $readingName, $deltaValue, $periodSwitch, $showDate, $firstCall
  1881. LUXTRONIK2_doStatisticDeltaSingle ($hash, $readingName, $deltaValue, $factor, $periodSwitch, $showDate, 0);
  1882. my $activeTariff = ReadingsVal($name,"activeTariff",0);
  1883. if ( $electricalPower >=0 ) {
  1884. my $readingNamePower = $readingName;
  1885. $readingNamePower =~ s/Hours/Electricity/ ;
  1886. if ($activeTariff > 0) {
  1887. foreach (1,2,3,4,5,6,7,8,9) {
  1888. if ( $previousTariff == $_ ) {
  1889. LUXTRONIK2_doStatisticDeltaSingle ($hash, $readingNamePower."Tariff".$_, $deltaValue * $electricalPower, $factor, $periodSwitch, $showDate, 1);
  1890. } elsif ($activeTariff == $_ || ($periodSwitch > 0 && exists($hash->{READINGS}{$readingNamePower . "Tariff".$_}))) {
  1891. LUXTRONIK2_doStatisticDeltaSingle ($hash, $readingNamePower."Tariff".$_, 0, $factor, $periodSwitch, $showDate, 1);
  1892. }
  1893. }
  1894. } else {
  1895. LUXTRONIK2_doStatisticDeltaSingle ($hash, $readingNamePower, $deltaValue * $electricalPower, $factor, $periodSwitch, $showDate, 1);
  1896. }
  1897. }
  1898. # Hidden storage of current values for next call(before values)
  1899. $result = "Value: $value Tariff: $activeTariff ShowDate: $showDate";
  1900. readingsBulkUpdate($hash, ".".$readingName."Before", $result);
  1901. return ;
  1902. }
  1903. sub ########################################
  1904. LUXTRONIK2_doStatisticDeltaSingle ($$$$$$$)
  1905. {
  1906. my ($hash, $readingName, $deltaValue, $factor, $periodSwitch, $showDate, $specMonth) = @_;
  1907. my $dummy;
  1908. my $result;
  1909. # get existing statistic reading
  1910. my @curr;
  1911. if (exists($hash->{READINGS}{".".$readingName}{VAL})) {
  1912. @curr = split / /, $hash->{READINGS}{".".$readingName}{VAL} || "";
  1913. } else {
  1914. $curr[1] = 0; $curr[3] = 0; $curr[5] = 0;
  1915. if ($showDate>5) {$curr[7] = strftime "%Y-%m-%d_%H:%M:%S", localtime();} # start
  1916. else {$curr[7] = strftime "%Y-%m-%d", localtime();} # start
  1917. }
  1918. # get statistic values of previous period
  1919. my @last;
  1920. if ($periodSwitch >= 1) {
  1921. if (exists ($hash->{READINGS}{$readingName."Last"})) {
  1922. @last = split / /, $hash->{READINGS}{$readingName."Last"}{VAL};
  1923. } else {
  1924. @last = split / /, "Day: - Month: - Year: -";
  1925. }
  1926. }
  1927. # Do statistic
  1928. $curr[1] += $deltaValue;
  1929. $curr[3] += $deltaValue;
  1930. $curr[5] += $deltaValue;
  1931. # If change of year, change yearly statistic
  1932. if ($periodSwitch == 3){
  1933. if ($specMonth) { $last[5] = sprintf("%.3f",$curr[5] / $factor/ 1000); }
  1934. else {$last[5] = sprintf("%.0f",$curr[5] / $factor);}
  1935. $curr[5] = 0;
  1936. if ($showDate == 1) { $last[7] = $curr[7]; }
  1937. }
  1938. # If change of month, change monthly statistic
  1939. if ($periodSwitch >= 2){
  1940. if ($specMonth) { $last[3] = sprintf("%.3f",$curr[3] / $factor/ 1000); }
  1941. else {$last[3] = sprintf("%.0f",$curr[3] / $factor);}
  1942. $curr[3] = 0;
  1943. if ($showDate == 3) { $last[7] = $curr[7];}
  1944. }
  1945. # If change of day, change daily statistic
  1946. if ($periodSwitch >= 1){
  1947. $last[1] = sprintf("%.1f",$curr[1] / $factor);
  1948. $curr[1] = 0;
  1949. if ($showDate == 5) {
  1950. $last[7] = $curr[7];
  1951. # Next monthly and yearly values start at 00:00 and show only date (no time)
  1952. $curr[3] = 0;
  1953. $curr[5] = 0;
  1954. $curr[7] = strftime "%Y-%m-%d", localtime(); # start
  1955. }
  1956. }
  1957. # Store hidden statistic readings (delta values)
  1958. $result = "Day: $curr[1] Month: $curr[3] Year: $curr[5]";
  1959. if ( $showDate >=2 ) { $result .= " (since: $curr[7] )"; }
  1960. readingsBulkUpdate($hash,".".$readingName,$result);
  1961. # Store visible statistic readings (delta values)
  1962. if ($specMonth) { $result = sprintf "Day: %.1f Month: %.3f Year: %.3f", $curr[1]/$factor, $curr[3]/$factor/1000, $curr[5]/$factor/1000; }
  1963. else { $result = sprintf "Day: %.1f Month: %.0f Year: %.0f", $curr[1]/$factor, $curr[3]/$factor, $curr[5]/$factor; }
  1964. if ( $showDate >=2 ) { $result .= " (since: $curr[7] )"; }
  1965. readingsBulkUpdate($hash,$readingName,$result);
  1966. # if changed, store previous visible statistic (delta) values
  1967. if ($periodSwitch >= 1) {
  1968. $result = "Day: $last[1] Month: $last[3] Year: $last[5]";
  1969. if ( $showDate =~ /1|3|5/ ) { $result .= " (since: $last[7] )";}
  1970. readingsBulkUpdate($hash,$readingName."Last",$result);
  1971. }
  1972. }
  1973. 1;
  1974. =pod
  1975. =item device
  1976. =item summary Connects with a Luxtronik 2.0 controller for heat pumps.
  1977. =item summary_DE Verbindet mit einer Luxtronik 2.0 Heizungssteuerung für Wärmepumpen.
  1978. =begin html
  1979. <a name="LUXTRONIK2"></a>
  1980. <h3>LUXTRONIK2</h3>
  1981. <div>
  1982. <ul>
  1983. Luxtronik 2.0 and 2.1 is a heating controller from <a href="http://www.alpha-innotec.de">Alpha InnoTec (AIT)</a> used in heat pumps of Alpha InnoTec, Buderus (Logamatic HMC20, HMC20 Z), CTA All-In-One (Aeroplus), Elco, Nibe (AP-AW10), Roth (ThermoAura&reg;, ThermoTerra), Novelan (WPR NET) and Wolf Heiztechnik (BWL/BWS).<br>
  1984. It has a built-in Ethernet (RJ45) port, so it can be directly integrated into a local area network (LAN).
  1985. <br>
  1986. <i>The module is reported to work with firmware: V1.51, V1.54C, V1.60, V1.64, V1.69, V1.70, V1.73, V1.77, V1.80, V1.81.</i>
  1987. <br>
  1988. More Info on the particular <a href="http://www.fhemwiki.de/wiki/Luxtronik_2.0">page of FHEM-Wiki</a> (in German).
  1989. <br>
  1990. &nbsp;
  1991. <br>
  1992. <a name="LUXTRONIK2define"></a>
  1993. <b>Define</b>
  1994. <ul>
  1995. <code>define &lt;name&gt; LUXTRONIK2 &lt;IP-address[:Port]&gt; [poll-interval]</code><br>
  1996. If the pool interval is omitted, it is set to 300 (seconds). Smallest possible value is 10.
  1997. <br>
  1998. Usually, the port needs not to be defined.
  1999. <br>
  2000. Example: <code>define Heizung LUXTRONIK2 192.168.0.12 600</code>
  2001. </ul>
  2002. <br>
  2003. <a name="LUXTRONIK2set"></a>
  2004. <b>Set</b>
  2005. <ul>A firmware check assures before each set operation that a heat pump with untested firmware is not damaged accidentally.
  2006. <li><code>activeTariff &lt; 0 - 9 &gt;</code>
  2007. <br>
  2008. Allows the separate measurement of the consumption (doStatistics = 1 or 2) within different tariffs.<br>
  2009. This value must be set at the correct point of time in accordance to the existing or planned tariff <b>by the FHEM command "at"</b>.<br>
  2010. 0 = without separate tariffs
  2011. </li><br>
  2012. <li><code>INTERVAL &lt;polling interval&gt;</code><br>
  2013. Polling interval in seconds
  2014. </li><br>
  2015. <li><code>heatingCurveEndPoint &lt;Temperature&gt;</code><br>
  2016. Sets the heating curve parameter. Adjustable in 0.1 steps.
  2017. </li><br>
  2018. <li><code>heatingCurveOffset &lt;Temperature&gt;</code><br>
  2019. Sets the heating curve parameter. Adjustable in 0.1 steps.
  2020. </li><br>
  2021. <li><code>heatingSystemCircPumpDeaerate &lt;on | off&gt;</code><br>
  2022. Switches the heating circuit circulation pump on or off. So, also in summer all (open) heating circuits have the same temperature. So, heat and coolness spread slightly between rooms.
  2023. <br>
  2024. NOTE! It uses the deaerate function of the controller. So, the pump alternates always 5 minutes on and 5 minutes off.
  2025. </li><br>
  2026. <li><code>hotWaterCircPumpDeaerate &lt;on | off&gt;</code><br>
  2027. Switches the external circulation pump for the hot water on or off. The circulation prevents a cool down of the hot water in the pipes but increases the heat consumption drastically.
  2028. <br>
  2029. NOTE! It uses the deaerate function of the controller. So, the pump alternates always 5 minutes on and 5 minutes off.
  2030. </li><br>
  2031. <li><code>hotWaterTemperatureTarget &lt;temperature&gt;</code><br>
  2032. Target temperature of domestic hot water boiler in °C
  2033. </li><br>
  2034. <li><code>opModeHotWater &lt;Mode&gt;</code><br>
  2035. Operating Mode of domestic hot water boiler (Auto | Party | Off)
  2036. </li><br>
  2037. <li><code>resetStatistics &lt;statReadings&gt;</code>
  2038. <br>
  2039. Deletes the selected statistic values <i>all, statBoilerGradientCoolDownMin, statAmbientTemp..., statElectricity..., statHours..., statHeatQ...</i>
  2040. </li><br>
  2041. <li><code>returnTemperatureHyst &lt;Temperature&gt;</code>
  2042. <br>
  2043. Hysteresis of the returnTemperatureTarget of the heating controller. 0.5 K till 3 K. Adjustable in 0.1 steps.
  2044. </li><br>
  2045. <li><code>returnTemperatureSetBack &lt;Temperature&gt;</code>
  2046. <br>
  2047. Decreasing or increasing of the returnTemperatureTarget by -5 K till + 5 K. Adjustable in 0.1 steps.
  2048. </li><br>
  2049. <li><code>statusRequest</code><br>
  2050. Update device information
  2051. </li><br>
  2052. <li><code>synchClockHeatPump</code><br>
  2053. Synchronizes controller clock with FHEM time. <b>!! This change is lost in case of controller power off!!</b></li>
  2054. </ul>
  2055. <br>
  2056. <a name="LUXTRONIK2get"></a>
  2057. <b>Get</b>
  2058. <ul>
  2059. <li><code>heatingCurveParameter &lt;OutsideTemp1 SetTemp1 OutsideTemp2 SetTemp2&gt;</code>
  2060. <br>
  2061. Determines based on two points on the heating curve the respective heat curve parameter <i>heatingCurveEndPoint</i> and <i>heatingCurveOffset</i>.<br>
  2062. These parameter can be set via the respective set commands.
  2063. </li>
  2064. <br>
  2065. <li><code>rawData</code>
  2066. <br>
  2067. Shows a table with all parameter and operational values returned by the controller.<br>
  2068. They can be assigned to device readings via the attributes <i>userHeatpumpParameters</i> und <i>userHeatpumpValues</i>.
  2069. </li><br>
  2070. </ul>
  2071. <br>
  2072. <a name="LUXTRONIK2attr"></a>
  2073. <b>Attributes</b>
  2074. <ul>
  2075. <li><code>allowSetParameter &lt; 0 | 1 &gt;</code>
  2076. <br>
  2077. The <a href="#LUXTRONIK2set">parameters</a> of the heat pump controller can only be changed if this attribute is set to 1.
  2078. </li><br>
  2079. <li><code>autoSynchClock &lt;delay&gt;</code>
  2080. <br>
  2081. Corrects the clock of the heatpump automatically if a certain <i>delay</i> (10 s - 600 s) against the FHEM time is exceeded. Does a firmware check before.
  2082. <br>
  2083. <i>(A 'delayDeviceTimeCalc' &lt;= 2 s can be caused by the internal calculation interval of the heat pump controller.)</i>
  2084. </li><br>
  2085. <li><code>compressor2ElectricalPowerWatt</code><br>
  2086. Electrical power of the 2nd compressor to calculated the COP and estimate electrical consumption (calculations not implemented yet)
  2087. </li><br>
  2088. <li><code>doStatistics &lt; 0 | 1 | 2 &gt;</code>
  2089. <br>
  2090. 1 or 2: Calculates statistic values: <i>statBoilerGradientHeatUp, statBoilerGradientCoolDown, statBoilerGradientCoolDownMin (boiler heat loss)</i>
  2091. <br>
  2092. 1: Builds daily, monthly and yearly statistics for certain readings (average/min/max or cumulated values).
  2093. <br>
  2094. Logging and visualization of the statistic should be done with readings of type 'stat<i>ReadingName</i><b>Last</b>'.
  2095. </li><br>
  2096. <li><code>heatPumpElectricalPowerWatt</code><br>
  2097. Electrical power of the heat pump by a flow temperature of 35°C to calculated efficiency factor and estimate electrical consumption
  2098. </li><br>
  2099. <li><code>heatPumpElectricalPowerFactor</code><br>
  2100. Change of electrical power consumption per 1 K flow temperature difference to 35°C (e.g. 2% per 1 K = 0,02)
  2101. </li><br>
  2102. <li><code>heatRodElectricalPowerWatt</code><br>
  2103. Electrical power of the heat rods (2nd heat source) to estimate electrical consumption
  2104. </li><br>
  2105. <li><code>ignoreFirmwareCheck &lt; 0 | 1 &gt;</code>
  2106. <br>
  2107. A firmware check assures before each set operation that a heatpump controller with untested firmware is not damaged accidentally.
  2108. <br>
  2109. If this attribute is set to 1, the firmware check is ignored and new firmware can be tested for compatibility.
  2110. </li><br>
  2111. <li><code>statusHTML</code>
  2112. <br>
  2113. If set, a HTML-formatted reading named "floorplanHTML" is created. It can be used with the <a href="#FLOORPLAN">FLOORPLAN</a> module.
  2114. <br>
  2115. Currently, if the value of this attribute is not NULL, the corresponding reading consists of the current status of the heat pump and the temperature of the water.
  2116. </li><br>
  2117. <li><code>userHeatpumpParameters &lt;Index [Name][,Index2 [Name2],Index3 [Name3] ...]&gt;</code>
  2118. <br>
  2119. Allows to continuously read the value of certain controller parameters. The index number of the parameter can be determined with the get command <i>rawData</i><br>
  2120. In the attribute definition, a name can be written behind the index number separated by a space. The respective parameter value will either be shown with the prefix "userParameter..." or under the given name. <br>
  2121. Multiple indexes are separated by a comma.<br>
  2122. If the readings are not used anymore the can be deleted with the FHEM command <a href="#deletereading">deleteReading</a>.
  2123. </li><br>
  2124. <li><code>userHeatpumpValues &lt;Index Name[,Index2 Name2,Index3 Name3 ...]&gt;</code>
  2125. <br>
  2126. Allows to read out specific operational values. Proceed as with <i>userHeatpumpParameters</i>.
  2127. </li><br>
  2128. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  2129. </ul>
  2130. </ul>
  2131. </div>
  2132. =end html
  2133. =begin html_DE
  2134. <a name="LUXTRONIK2"></a>
  2135. <h3>LUXTRONIK2</h3>
  2136. <div>
  2137. <ul>
  2138. Die Luxtronik 2.0 and 2.1 ist eine Heizungssteuerung der Firma <a href="http://www.alpha-innotec.de">Alpha InnoTec AIT</a>, welche in Wärmepumpen von Alpha InnoTec, Buderus (Logamatic HMC20, HMC20 Z), CTA All-In-One (Aeroplus), Elco, Nibe (AP-AW10), Roth (ThermoAura&reg;, ThermoTerra), Novelan (WPR NET) und Wolf Heiztechnik (BWL/BWS) verbaut ist. Sie besitzt einen Ethernet (RJ45) Anschluss, so dass sie direkt in lokale Netzwerke (LAN) integriert werden kann.
  2139. <br>
  2140. <i>Das Modul wurde bisher mit folgender Steuerung-Firmware getestet: V1.51, V1.54C, V1.60, V1.64, V1.69, V1.70, V1.73, V1.77, V1.80, V1.81.</i>
  2141. <br>
  2142. Mehr Infos im entsprechenden <u><a href="http://www.fhemwiki.de/wiki/Luxtronik_2.0">Artikel der FHEM-Wiki</a></u>.
  2143. <br>&nbsp;
  2144. <br>
  2145. <a name="LUXTRONIK2define"></a>
  2146. <b>Define</b>
  2147. <ul>
  2148. <code>define &lt;name&gt; LUXTRONIK2 &lt;IP-Adresse[:Port]&gt; [Abfrageintervall]</code>
  2149. <br>
  2150. Wenn das Abfrage-Interval nicht angegeben ist, wird es auf 300 (Sekunden) gesetzt. Der kleinste mögliche Wert ist 10.
  2151. <br>
  2152. Die Angabe des Portes kann gewöhnlich entfallen.
  2153. <br>
  2154. Beispiel: <code>define Heizung LUXTRONIK2 192.168.0.12 600</code>
  2155. </ul>
  2156. <br>
  2157. <a name="LUXTRONIK2set"></a>
  2158. <b>Set</b><br>
  2159. <ul>
  2160. Durch einen Firmware-Test wird vor jeder Set-Operation sichergestellt, dass Wärmepumpen mit ungetesteter Firmware nicht unabsichtlich beschädigt werden.
  2161. <br>&nbsp;
  2162. <li><code>activeTariff &lt; 0 - 9 &gt;</code>
  2163. <br>
  2164. Erlaubt die gezielte, separate Erfassung der statistischen Verbrauchswerte (doStatistics = 1) für verschiedene Tarife (Doppelstromzähler)<br>
  2165. Dieser Wert muss entsprechend des vorhandenen oder geplanten Tarifes zum jeweiligen Zeitpunkt z.B. durch den FHEM-Befehl "at" gesetzt werden.<br>
  2166. 0 = tariflos
  2167. </li><br>
  2168. <li><code>heatingCurveEndPoint &lt;Temperatur&gt;</code><br>
  2169. Einstellung des Heizkurven-Parameters. In 0.1er Schritten einstellbar.
  2170. </li><br>
  2171. <li><code>heatingCurveOffset &lt;Temperatur&gt;</code><br>
  2172. Einstellung des Heizkurven-Parameters. In 0.1er Schritten einstellbar.
  2173. </li><br>
  2174. <li><code>heatingSystemCircPumpDeaerate &lt;on | off&gt;</code><br>
  2175. Schaltet die Umwälzpumpe des Heizkreislaufes an oder aus. Damit werden auch im Sommer alle Heizkreise auf gleicher Temperatur gehalten und es findet eine geringfügige Umverteilung von Wärme und Kühle statt.
  2176. <br>
  2177. Achtung! Es wird die Entlüftungsfunktion der Steuerung genutzt. Dadurch taktet die Pumpe jeweils 5 Minuten ein und 5 Minuten aus.
  2178. </li><br>
  2179. <li><code>hotWaterCircPumpDeaerate &lt;on | off&gt;</code><br>
  2180. Schaltet die externe Warmwasser-Zirkulationspumpe an oder aus. Durch die Zirkulation wird das Abkühlen des Warmwassers in den Hausleitungen verhindert. Der Wärmeverbrauch steigt jedoch drastisch.
  2181. <br>
  2182. Achtung! Es wird die Entlüftungsfunktion der Steuerung genutzt. Dadurch taktet die Pumpe jeweils 5 Minuten ein und 5 Minuten aus.
  2183. </li><br>
  2184. <li><code>hotWaterTemperatureTarget &lt;Temperatur&gt;</code>
  2185. <br>
  2186. Soll-Temperatur des Heißwasserspeichers in °C
  2187. </li><br>
  2188. <li><code>opModeHotWater &lt;Betriebsmodus&gt;</code>
  2189. <br>
  2190. Betriebsmodus des Heißwasserspeichers ( Auto | Party | Off )
  2191. </li><br>
  2192. <li><code>resetStatistics &lt;statWerte&gt;</code>
  2193. <br>
  2194. Löscht die ausgewählten statistischen Werte: <i>all, statBoilerGradientCoolDownMin, statAmbientTemp..., statElectricity..., statHours..., statHeatQ...</i>
  2195. </li><br>
  2196. <li><code>returnTemperatureHyst &lt;Temperatur&gt;</code>
  2197. <br>
  2198. Sollwert-Hysterese der Heizungsregelung. 0.5 K bis 3 K. In 0.1er Schritten einstellbar.
  2199. </li><br>
  2200. <li><code>returnTemperatureSetBack &lt;Temperatur&gt;</code>
  2201. <br>
  2202. Absenkung oder Anhebung der Rücklauftemperatur von -5 K bis + 5K. In 0.1er Schritten einstellbar.
  2203. </li><br>
  2204. <li><code>INTERVAL &lt;Sekunden&gt;</code>
  2205. <br>
  2206. Abfrageintervall in Sekunden
  2207. </li><br>
  2208. <li><code>statusRequest</code>
  2209. <br>
  2210. Aktualisieren der Gerätewerte
  2211. </li><br>
  2212. <li><code>synchClockHeatPump</code>
  2213. <br>
  2214. Abgleich der Uhr der Steuerung mit der FHEM Zeit. <b>Diese Änderung geht verloren, sobald die Steuerung ausgeschaltet wird!!</b></li>
  2215. </ul>
  2216. <br>
  2217. <a name="LUXTRONIK2get"></a>
  2218. <b>Get</b>
  2219. <ul>
  2220. <li><code>heatingCurveParameter &lt;Aussentemp1 Solltemp1 Aussentemp2 Solltemp2&gt;</code>
  2221. <br>
  2222. Ermittelt rekursiv anhand zweier Punkte auf der Heizkurve die entsprechenden Heizkurven-Parameter <i>heatingCurveEndPoint</i> und <i>heatingCurveOffset</i>.<br>
  2223. Diese können dann über die entsprechenden set-Befehl einstellt werden.
  2224. </li>
  2225. <br>
  2226. <li><code>rawData</code>
  2227. <br>
  2228. Zeigt alle von der Steuerung auslesbaren Parameter und Betriebswerte an.<br>
  2229. Diese können dann mit den Attributen <i>userHeatpumpParameters</i> und <i>userHeatpumpValues</i> einem Gerätewert zugeordnet werden.
  2230. </li><br>
  2231. </ul>
  2232. <br>
  2233. <a name="LUXTRONIK2attr"></a>
  2234. <b>Attribute</b>
  2235. <ul>
  2236. <li><code>allowSetParameter &lt; 0 | 1 &gt;</code>
  2237. <br>
  2238. Die internen <a href="#LUXTRONIK2set">Parameter</a> der Wärmepumpensteuerung können
  2239. nur geändert werden, wenn dieses Attribut auf 1 gesetzt ist.
  2240. </li><br>
  2241. <li><code>autoSynchClock &lt;Zeitunterschied&gt;</code>
  2242. <br>
  2243. Die Uhr der Wärmepumpe wird automatisch korrigiert, wenn ein gewisser <i>Zeitunterschied</i> (10 s - 600 s)
  2244. gegenüber der FHEM Zeit erreicht ist. Zuvor wird die Kompatibilität der Firmware überprüft.<br>
  2245. <i>(Ein Gerätewert 'delayDeviceTimeCalc' &lt;= 2 s ist auf die internen Berechnungsintervalle der
  2246. Wärmepumpensteuerung zurückzuführen.)</i>
  2247. </li><br>
  2248. <li><code>compressor2ElectricalPowerWatt</code><br>
  2249. Betriebsleistung des zweiten Kompressors zur Berechnung der Arbeitszahl (erzeugte Wärme pro elektrische Energieeinheit)
  2250. und Abschätzung des elektrischen Verbrauches (Auswertungen noch nicht implementiert)
  2251. </li><br>
  2252. <li><code>doStatistics &lt; 0 | 1 | 2 &gt;</code>
  2253. <br>
  2254. Berechnet statistische Werte: <i>statBoilerGradientHeatUp, statBoilerGradientCoolDown,
  2255. statBoilerGradientCoolDownMin (Wärmeverlust des Boilers)</i>
  2256. <br>
  2257. Bildet tägliche, monatliche und jährliche Statistiken bestimmter Gerätewerte.<br>
  2258. Für grafische Auswertungen können die Werte der Form 'stat<i>ReadingName</i><b>Last</b>' genutzt werden.
  2259. </li><br>
  2260. <li><code>heatPumpElectricalPowerWatt &lt;E-Leistung in Watt&gt;</code><br>
  2261. Elektrische Leistungsaufnahme der Wärmepumpe in Watt bei einer Vorlauftemperatur von 35°C zur Berechnung der Arbeitszahl (erzeugte Wärme pro elektrische Energieeinheit)
  2262. und Abschätzung des elektrischen Verbrauches
  2263. </li><br>
  2264. <li><code>heatPumpElectricalPowerFactor</code><br>
  2265. Änderung der elektrischen Leistungsaufnahme pro 1 K Vorlauf-Temperaturdifferenz zu 35°C
  2266. <br>
  2267. (z.B. 2% pro 1 K = 0,02)
  2268. </li><br>
  2269. <li><code>heatRodElectricalPowerWatt &lt;E-Leistung in Watt&gt;</code><br>
  2270. Elektrische Leistungsaufnahme der Heizstäbe in Watt zur Abschätzung des elektrischen Verbrauches
  2271. </li><br>
  2272. <li><code>ignoreFirmwareCheck &lt; 0 | 1 &gt;</code>
  2273. <br>
  2274. Durch einen Firmware-Test wird vor jeder Set-Operation sichergestellt, dass Wärmepumpen
  2275. mit ungetesteter Firmware nicht unabsichtlich beschädigt werden. Wenn dieses Attribute auf 1
  2276. gesetzt ist, dann wird der Firmware-Test ignoriert und neue Firmware kann getestet werden.
  2277. Dieses Attribut wird jedoch ignoriert, wenn die Steuerung-Firmware bereits als nicht kompatibel berichtet wurde.
  2278. </li><br>
  2279. <li><code>statusHTML</code>
  2280. <br>
  2281. Wenn gesetzt, dann wird ein HTML-formatierter Wert "floorplanHTML" erzeugt,
  2282. welcher vom Modul <a href="#FLOORPLAN">FLOORPLAN</a> genutzt werden kann.<br>
  2283. Momentan wird nur geprüft, ob der Wert dieses Attributes ungleich NULL ist,
  2284. der entsprechende Gerätewerte besteht aus dem aktuellen Wärmepumpenstatus und der Warmwassertemperatur.
  2285. </li><br>
  2286. <li><code>userHeatpumpParameters &lt;Index [Name][,Index2 [Name2],Index3 [Name3] ...]&gt;</code>
  2287. <br>
  2288. Erlaubt das Auslesen der Werte benutzerspezifischer Parameter. Die Indizes der verfügbaren Parameterwerte können mit dem get-Befehl <i>rawData</i> ermittelt werden.<br>
  2289. In der Attributdefinition kann der Name hinter den Index getrennt durch ein Leerzeichen geschrieben werden. Der jeweilige Parameter-Wert wird entweder mit dem Präfix "userParameter..." oder unter dem angegebenen Namen angezeigt. <br>
  2290. Mehrere Indizes werden durch Kommas getrennt.<br>
  2291. Nicht mehr benötigte Gerätewerte können mit dem FHEM-Befehl <a href="#deletereading">deleteReading</a> gelöscht werden.
  2292. </li><br>
  2293. <li><code>userHeatpumpValues &lt;Index Name[,Index2 Name2,Index3 Name3 ...]&gt;</code>
  2294. <br>
  2295. Erlaubt das Auslesen benutzerspezifische Betriebswerte. Vorgehen wie bei <i>userHeatpumpParameters</i>.
  2296. </li><br>
  2297. <li><a href="#readingFnAttributes">readingFnAttributes</a>
  2298. </li><br>
  2299. </ul>
  2300. </ul>
  2301. </div>
  2302. =end html_DE
  2303. =cut