00_THZ.pm 138 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436
  1. ##############################################
  2. # 00_THZ
  3. # $Id: 00_THZ.pm 16208 2018-02-18 09:38:31Z immi $
  4. # by immi 1/2018
  5. my $thzversion = "0.178";
  6. # this code is based on the hard work of Robert; I just tried to port it
  7. # http://robert.penz.name/heat-pump-lwz/
  8. ########################################################################################
  9. #
  10. # This programm is free software; you can redistribute it and/or modify
  11. # it under the terms of the GNU General Public License as published by
  12. # the Free Software Foundation; either version 2 of the License, or
  13. # (at your option) any later version.
  14. #
  15. # The GNU General Public License can be found at
  16. # http://www.gnu.org/copyleft/gpl.html.
  17. # A copy is found in the textfile GPL.txt and important notices to the license
  18. # from the author is found in LICENSE.txt distributed with these scripts.
  19. #
  20. # This script is distributed in the hope that it will be useful,
  21. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. # GNU General Public License for more details.
  24. #
  25. ########################################################################################
  26. package main;
  27. use strict;
  28. use warnings;
  29. use Time::HiRes qw(gettimeofday);
  30. use feature ":5.10";
  31. use SetExtensions;
  32. use Blocking;
  33. sub THZ_Read($);
  34. sub THZ_ReadAnswer($);
  35. sub THZ_Ready($);
  36. sub THZ_Write($$);
  37. sub THZ_Parse1($$);
  38. sub THZ_checksum($);
  39. sub THZ_replacebytes($$$);
  40. sub THZ_decode($);
  41. sub THZ_overwritechecksum($);
  42. sub THZ_encodecommand($$);
  43. sub hex2int($);
  44. sub quaters2time($);
  45. sub time2quaters($);
  46. sub THZ_debugread($);
  47. sub THZ_GetRefresh($);
  48. sub THZ_Refresh_all_gets($);
  49. sub THZ_Get_Comunication($$);
  50. sub THZ_PrintcurveSVG;
  51. sub THZ_RemoveInternalTimer($);
  52. sub THZ_Set($@);
  53. sub function_heatSetTemp($$);
  54. sub THZ_Get($@);
  55. ########################################################################################
  56. #
  57. # %parsinghash - known type of message structure
  58. #
  59. ########################################################################################
  60. my %parsinghash = (
  61. #msgtype => parsingrule
  62. "01pxx206" => [["p37Fanstage1AirflowInlet: ", 4, 4, "hex", 1], [" p38Fanstage2AirflowInlet: ", 8, 4, "hex", 1], [" p39Fanstage3AirflowInlet: ", 12, 4, "hex", 1],
  63. [" p40Fanstage1AirflowOutlet: ", 16, 4, "hex", 1], [" p41Fanstage2AirflowOutlet: ", 20, 4, "hex", 1], [" p42Fanstage3AirflowOutlet: ", 24, 4, "hex", 1],
  64. [" p43UnschedVent3: ", 28, 4, "hex", 1], [" p44UnschedVent2: ", 32, 4, "hex", 1], [" p45UnschedVent1: ", 36, 4, "hex", 1],
  65. [" p46UnschedVent0: ", 40, 4, "hex", 1], [" p75PassiveCooling: ", 44, 4, "hex", 1]
  66. ],
  67. "01pxx214" => [["p37Fanstage1AirflowInlet: ", 4, 2, "hex", 1],[" p38Fanstage2AirflowInlet: ", 6, 2, "hex", 1], [" p39Fanstage3AirflowInlet: ", 8, 2, "hex", 1],
  68. [" p40Fanstage1AirflowOutlet: ", 10, 2, "hex", 1], [" p41Fanstage2AirflowOutlet: ", 12, 2, "hex", 1], [" p42Fanstage3AirflowOutlet: ", 14, 2, "hex", 1],
  69. [" p43UnschedVent3: ", 16, 4, "hex", 1], [" p44UnschedVent2: ", 20, 4, "hex", 1], [" p45UnschedVent1: ", 24, 4, "hex", 1],
  70. [" p46UnschedVent0: ", 28, 4, "hex", 1], [" p75PassiveCooling: ", 32, 2, "hex", 1]
  71. ],
  72. "03pxx206" => [["UpTempLimitDefrostEvaporatorEnd: ", 4, 4, "hex", 10], [" MaxTimeDefrostEvaporator: ", 8, 4, "hex", 1], [" LimitTempCondenserElectBoost: ", 12, 4, "hex", 10],
  73. [" LimitTempCondenserDefrostTerm: ", 16, 4, "hex", 10], [" p47CompressorRestartDelay: ", 20, 2, "hex", 1], [" p48MainFanSpeed: ", 22, 2, "hex", 1]
  74. ],
  75. "04pxx206" => [["MaxDefrostDurationAAExchenger: ", 4, 2, "hex", 1], [" DefrostStartThreshold: ", 6, 4, "hex", 10], [" VolumeFlowFilterReplacement: ", 10, 4, "hex", 1]
  76. ],
  77. "05pxx206" => [["p13GradientHC1: ", 4, 4, "hex", 10], [" p14LowEndHC1: ", 8, 4, "hex", 10], [" p15RoomInfluenceHC1: ", 12, 2, "hex", 10],
  78. [" p16GradientHC2: ", 14, 4, "hex", 10], [" p17LowEndHC2: ", 18, 4, "hex", 10], [" p18RoomInfluenceHC2: ", 22, 2, "hex", 10],
  79. [" p19FlowProportionHC1: ", 24, 4, "hex", 1], [" p20FlowProportionHC2: ", 28, 4, "hex", 1], [" MaxSetHeatFlowTempHC1: ", 32, 4, "hex", 10],
  80. [" MinSetHeatFlowTempHC1: ", 36, 4, "hex", 10], [" MaxSetHeatFlowTempHC2: ", 40, 4, "hex", 10], [" MinSetHeatFlowTempHC2: ", 44, 4, "hex", 10],
  81. ],
  82. "06pxx206" => [["p21Hyst1: ", 4, 2, "hex", 10], [" p22Hyst2: ", 6, 2, "hex", 10], [" p23Hyst3: ", 8, 2, "hex", 10],
  83. [" p24Hyst4: ", 10, 2, "hex", 10], [" p25Hyst5: ", 12, 2, "hex", 10], [" p26Hyst6: ", 14, 2, "hex", 10],
  84. [" p27Hyst7: ", 16, 2, "hex", 10], [" p28Hyst8: ", 18, 2, "hex", 10], [" p29HystAsymmetry: ", 20, 2, "hex", 1],
  85. [" p30integralComponent: ", 22, 4, "hex", 1], [" p31MaxBoostStages: ", 26, 2, "hex", 1], [" MaxHeatFlowTemp: ", 28, 4, "hex", 10],
  86. [" p49SummerModeTemp: ", 32, 4, "hex", 10], [" p50SummerModeHysteresis: ", 36, 4, "hex", 10], [" p77OutTempFilterTime: ", 40, 4, "hex", 1],
  87. [" p78DualModePoint: ", 44, 4, "hex2int", 10],[" p79BoosterTimeoutHC: ", 48, 2, "hex", 1]
  88. ],
  89. "07pxx206" => [["p32HystDHW: ", 4, 2, "hex", 10], [" p33BoosterTimeoutDHW: ", 6, 2, "hex", 1], [" p34TempLimitBoostDHW: ", 8, 4, "hex2int", 10], [" p35PasteurisationInterval: ", 12, 2, "hex", 1],
  90. [" p36MaxDurationDHWLoad: ", 14, 2, "hex", 1], [" pasteurisationTemp: ", 16, 4, "hex", 10], [" maxBoostStagesDHW: ", 20, 2, "hex", 1],
  91. [" p84EnableDHWBuffer: ", 22, 2, "hex", 1]
  92. ],
  93. "08pxx206" => [["p80EnableSolar: ", 4, 2, "hex", 1], [" p81DiffTempSolarLoading: ", 6, 4, "hex", 10], [" p82DelayCompStartSolar: ", 10, 2, "hex", 1],
  94. [" p84DHWTempSolarMode: ", 12, 4, "hex", 10], [" HystDiffTempSolar: ", 16, 4, "hex", 10], [" CollectLimitTempSolar: ", 20, 4, "hex", 10]
  95. ],
  96. "09his" => [["compressorHeating: ", 4, 4, "hex", 1], [" compressorCooling: ", 8, 4, "hex", 1],
  97. [" compressorDHW: ", 12, 4, "hex", 1], [" boosterDHW: ", 16, 4, "hex", 1],
  98. [" boosterHeating: ", 20, 4, "hex", 1]
  99. ],
  100. "09his206" => [["operatingHours1: ", 4, 4, "hex", 1], [" operatingHours2: ", 8, 4, "hex", 1],
  101. [" heatingHours: ", 12, 4, "hex", 1], [" DHWhours: ", 16, 4, "hex", 1],
  102. [" coolingHours: ", 20, 4, "hex", 1]
  103. ],
  104. "0Apxx206" => [["p54MinPumpCycles: ", 4, 2, "hex", 1], [" p55MaxPumpCycles: ", 6, 4, "hex", 1], [" p56OutTempMaxPumpCycles: ", 10, 4, "hex", 10],
  105. [" p57OutTempMinPumpCycles: ", 14, 4, "hex", 10], [" p58SuppressTempCaptPumpStart: ", 18, 4, "hex", 1]
  106. ],
  107. "0Bpxx206" => [["progHC1StartTime: ", 4, 4, "hex2time", 1], [" progHC1EndTime: ", 8, 4, "hex2time", 1],
  108. [" progHC1Monday: ", 13, 1, "bit0", 1], [" progHC1Tuesday: ", 13, 1, "bit1", 1],
  109. [" progHC1Wednesday: ", 13, 1, "bit2", 1], [" progHC1Thursday: ", 13, 1, "bit3", 1],
  110. [" progHC1Friday: ", 12, 1, "bit0", 1], [" progHC1Saturday: ", 12, 1, "bit1", 1],
  111. [" progHC1Sunday: ", 12, 1, "bit2", 1], [" progHC1Enable: ", 14, 2, "hex", 1],
  112. [" progHC2StartTime: ", 16, 4, "hex2time", 1], [" progHC2EndTime: ", 20, 4, "hex2time", 1],
  113. [" progHC2Monday: ", 25, 1, "bit0", 1], [" progHC2Tuesday: ", 25, 1, "bit1", 1],
  114. [" progHC2Wednesday: ", 25, 1, "bit2", 1], [" progHC2Thursday: ", 25, 1, "bit3", 1],
  115. [" progHC2Friday: ", 24, 1, "bit0", 1], [" progHC2Saturday: ", 24, 1, "bit1", 1],
  116. [" progHC2Sunday: ", 24, 1, "bit2", 1], [" progHC2Enable: ", 26, 2, "hex", 1]
  117. ],
  118. "0Cpxx206" => [["progDHWStartTime: ", 4, 4, "hex2time", 1], [" progDHWEndTime: ", 8, 4, "hex2time", 1],
  119. [" progDHWMonday: ", 13, 1, "bit0", 1], [" progDHWTuesday: ", 13, 1, "bit1", 1],
  120. [" progDHWWednesday: ", 13, 1, "bit2", 1], [" progDHWThursday: ", 13, 1, "bit3", 1],
  121. [" progDHWFriday: ", 12, 1, "bit0", 1], [" progDHWSaturday: ", 12, 1, "bit1", 1],
  122. [" progDHWSunday: ", 12, 1, "bit2", 1], [" progDHWEnable: ", 14, 2, "hex", 1],
  123. ],
  124. "0Dpxx206" => [["progFAN1StartTime: ", 4, 4, "hex2time", 1], [" progFAN1EndTime: ", 8, 4, "hex2time", 1],
  125. [" progFAN1Monday: ", 13, 1, "bit0", 1], [" progFAN1Tuesday: ", 13, 1, "bit1", 1],
  126. [" progFAN1Wednesday: ", 13, 1, "bit2", 1], [" progFAN1Thursday: ", 13, 1, "bit3", 1],
  127. [" progFAN1Friday: ", 12, 1, "bit0", 1], [" progFAN1Saturday: ", 12, 1, "bit1", 1],
  128. [" progFAN1Sunday: ", 12, 1, "bit2", 1], [" progFAN1Enable: ", 14, 2, "hex", 1],
  129. [" progFAN2StartTime: ", 16, 4, "hex2time", 1], [" progFAN2EndTime: ", 20, 4, "hex2time", 1],
  130. [" progFAN2Monday: ", 25, 1, "bit0", 1], [" progFAN2Tuesday: ", 25, 1, "bit1", 1],
  131. [" progFAN2Wednesday: ", 25, 1, "bit2", 1], [" progFAN2Thursday: ", 25, 1, "bit3", 1],
  132. [" progFAN2Friday: ", 24, 1, "bit0", 1], [" progFAN2Saturday: ", 24, 1, "bit1", 1],
  133. [" progFAN2Sunday: ", 24, 1, "bit2", 1], [" progFAN2Enable: ", 26, 2, "hex", 1]
  134. ],
  135. "0Epxx206" => [["p59RestartBeforeSetbackEnd: ", 4, 4, "hex", 1]
  136. ],
  137. "0Fpxx206" => [["pA0DurationUntilAbsenceStart: ", 4, 4, "hex", 10], [" pA0AbsenceDuration: ", 8, 4, "hex", 10], [" pA0EnableAbsenceProg: ", 12, 2, "hex", 1]
  138. ],
  139. "10pxx206" => [["p70StartDryHeat: ", 4, 2, "hex", 1], [" p71BaseTemp: ", 6, 4, "hex", 10], [" p72PeakTemp: ", 10, 4, "hex", 10],
  140. [" p73TempDuration: ", 14, 4, "hex", 1], [" p74TempIncrease: ", 18, 4, "hex", 10]
  141. ],
  142. "16sol" => [["collectorTemp: ", 4, 4, "hex2int", 10], [" dhwTemp: ", 8, 4, "hex2int", 10],
  143. [" flowTemp: ", 12, 4, "hex2int", 10], [" edSolPump: ", 16, 2, "hex2int", 1],
  144. [" out: ", 26, 4, "raw", 1], [" status: ", 30, 2, "raw", 1]
  145. ],
  146. "17pxx206" => [["p01RoomTempDay: ", 4, 4, "hex", 10], [" p02RoomTempNight: ", 8, 4, "hex", 10],
  147. [" p03RoomTempStandby: ", 12, 4, "hex", 10], [" p04DHWsetTempDay: ", 16, 4, "hex", 10],
  148. [" p05DHWsetTempNight: ", 20, 4, "hex", 10], [" p06DHWsetTempStandby: ", 24, 4, "hex", 10],
  149. [" p07FanStageDay: ", 28, 2, "hex", 1], [" p08FanStageNight: ", 30, 2, "hex", 1],
  150. [" p09FanStageStandby: ", 32, 2, "hex", 1], [" p10HCTempManual: ", 34, 4, "hex", 10],
  151. [" p11DHWsetTempManual: ", 38, 4, "hex", 10], [" p12FanStageManual: ", 42, 2, "hex", 1],
  152. ],
  153. "D1last" => [["number_of_faults: ", 4, 2, "hex", 1],
  154. [" fault0CODE: ", 8, 2, "faultmap", 1], [" fault0TIME: ", 12, 4, "turnhex2time", 1], [" fault0DATE: ", 16, 4, "turnhexdate", 1],
  155. [" fault1CODE: ", 20, 2, "faultmap", 1], [" fault1TIME: ", 24, 4, "turnhex2time", 1], [" fault1DATE: ", 28, 4, "turnhexdate", 1],
  156. [" fault2CODE: ", 32, 2, "faultmap", 1], [" fault2TIME: ", 36, 4, "turnhex2time", 1], [" fault2DATE: ", 40, 4, "turnhexdate", 1],
  157. [" fault3CODE: ", 44, 2, "faultmap", 1], [" fault3TIME: ", 48, 4, "turnhex2time", 1], [" fault3DATE: ", 52, 4, "turnhexdate", 1]
  158. ],
  159. "D1last206" => [["number_of_faults: ", 4, 2, "hex", 1],
  160. [" fault0CODE: ", 8, 4, "faultmap", 1], [" fault0TIME: ", 12, 4, "hex2time", 1], [" fault0DATE: ", 16, 4, "hexdate", 1],
  161. [" fault1CODE: ", 20, 4, "faultmap", 1], [" fault1TIME: ", 24, 4, "hex2time", 1], [" fault1DATE: ", 28, 4, "hexdate", 1],
  162. [" fault2CODE: ", 32, 4, "faultmap", 1], [" fault2TIME: ", 36, 4, "hex2time", 1], [" fault2DATE: ", 40, 4, "hexdate", 1],
  163. [" fault3CODE: ", 44, 4, "faultmap", 1], [" fault3TIME: ", 48, 4, "hex2time", 1], [" fault3DATE: ", 52, 4, "hexdate", 1]
  164. ],
  165. "E8fan" => [[" inputFanSpeed: ", 58, 2, "hex", 1], # like in sGlobal
  166. [" outputFanSpeed: ", 60, 2, "hex", 1], # like in sGlobal
  167. [" pFanstageXAirflowInlet: ", 62, 4, "hex", 1], # m3/h corresponding to p37Fanstage1AirflowInlet or p38Fanstage2AirflowInlet
  168. [" pFanstageXAirflowOutlet: ", 66, 4, "hex", 1], # m3/h corresponding to p40Fanstage1AirflowOutlet or p41Fanstage2AirflowOutlet
  169. [" inputFanPower: ", 70, 2, "hex", 1], # like in sGlobal
  170. [" outputFanPower: ", 72, 2, "hex", 1], # like in sGlobal
  171. ],
  172. "E8fan206" => [["statusAFC: ", 4, 4, "hex", 1], # 0=init air flow calibration (16:00) 4=normal fan operation
  173. [" supplyFanSpeedCAL: ", 8, 4, "hex", 60], # calibration speed
  174. [" exhaustFanSpeedCAL: ", 12, 4, "hex", 60],
  175. [" supplyFanAirflowCAL: ", 16, 4, "hex", 100], # calibration air flow volume
  176. [" exhaustFanAirflowCAL: ", 20, 4, "hex", 100],
  177. [" supplyFanSpeed: ", 24, 4, "hex", 1], # actual fan speed in 1/s
  178. [" exhaustFanSpeed: ", 28, 4, "hex", 1],
  179. [" supplyFanAirflowSet: ", 32, 4, "hex", 1], # actual air flow volume setting in m3/h
  180. [" exhaustFanAirflowSet: ", 36, 4, "hex", 1],
  181. [" supplyFanSpeedTarget: ", 40, 4, "hex", 1], # target fan speed in %
  182. [" exhaustFanSpeedTarget: ", 44, 4, "hex", 1],
  183. [" supplyFanSpeed0: ", 48, 4, "hex", 10],
  184. [" exhaustFanSpeed0: ", 52, 4, "hex", 10],
  185. [" supplyFanSpeed200: ", 56, 4, "hex", 10],
  186. [" exhaustFanSpeed200: ", 60, 4, "hex", 10],
  187. [" airflowTolerance: ", 64, 2, "hex", 1],
  188. [" airflowCalibrationInterval: ", 66, 2, "hex", 1], # calibration interval
  189. [" timeToCalibration: ", 68, 2, "hex", 1] # days to next calibration
  190. ],
  191. "EEprg206" => [["opMode: ", 4, 2, "opmode2", 1], [" ProgStateHC: ", 10, 2, "opmodehc", 1], [" ProgStateDHW: ", 12, 2, "opmodehc", 1],
  192. [" ProgStateFAN: ", 14, 2, "opmodehc", 1], [" BaseTimeAP0: ", 16, 8, "hex", 1], [" StatusAP0: ", 24, 2, "hex", 1],
  193. [" StartTimeAP0: ", 26, 8, "hex", 1], [" EndTimeAP0: ", 34, 8, "hex", 1]
  194. ],
  195. "F2ctrl" => [["heatRequest: ", 4, 2, "hex", 1], # 0=DHW 2=heat 5=off 6=defrostEva
  196. [" heatRequest2: ", 6, 2, "hex", 1], # same as heatRequest
  197. [" hcStage: ", 8, 2, "hex", 1], # 0=off 1=solar 2=heatPump 3=boost1 4=boost2 5=boost3
  198. [" dhwStage: ", 10, 2, "hex", 1], # 0=off, 1=solar, 2=heatPump 3=boostMax
  199. [" heatStageControlModul: ", 12, 2, "hex", 1], # either hcStage or dhwStage depending from heatRequest
  200. [" compBlockTime: ", 14, 4, "hex2int", 1], # remaining compressor block time
  201. [" pasteurisationMode: ", 18, 2, "hex", 1], # 0=off 1=on
  202. [" defrostEvaporator: ", 20, 2, "raw", 1], # 10=off 30=defrostEva
  203. [" boosterStage2: ", 22, 1, "bit3", 1], # booster 2
  204. [" solarPump: ", 22, 1, "bit2", 1], # solar pump
  205. [" boosterStage1: ", 22, 1, "bit1", 1], # booster 1
  206. [" compressor: ", 22, 1, "bit0", 1], # compressor
  207. [" heatPipeValve: ", 23, 1, "bit3", 1], # heat pipe valve
  208. [" diverterValve: ", 23, 1, "bit2", 1], # diverter valve
  209. [" dhwPump: ", 23, 1, "bit1", 1], # dhw pump
  210. [" heatingCircuitPump: ", 23, 1, "bit0", 1], # hc pump
  211. [" mixerOpen: ", 25, 1, "bit1", 1], # mixer open
  212. [" mixerClosed: ", 25, 1, "bit0", 1], # mixer closed
  213. [" sensorBits1: ", 26, 2, "raw", 1], # sensor condenser temperature ??
  214. [" sensorBits2: ", 28, 2, "raw", 1], # sensor low pressure ??
  215. [" boostBlockTimeAfterPumpStart: ", 30, 4, "hex2int", 1], # after each pump start (dhw or heat circuit)
  216. [" boostBlockTimeAfterHD: ", 34, 4, "hex2int", 1] # ??
  217. ],
  218. "F3dhw" => [["dhwTemp: ", 4, 4, "hex2int", 10], [" outsideTemp: ", 8, 4, "hex2int", 10],
  219. [" dhwSetTemp: ", 12, 4, "hex2int", 10], [" compBlockTime: ", 16, 4, "hex2int", 1],
  220. [" out: ", 20, 4, "raw", 1], [" heatBlockTime: ", 24, 4, "hex2int", 1],
  221. [" dhwBoosterStage: ", 28, 2, "hex", 1], [" pasteurisationMode: ", 32, 2, "hex", 1],
  222. [" dhwOpMode: ", 34, 2, "opmodehc", 1], [" x36: ", 36, 4, "raw", 1]
  223. ],
  224. "F4hc1" => [["outsideTemp: ", 4, 4, "hex2int", 10], [" x08: ", 8, 4, "hex2int", 10],
  225. [" returnTemp: ", 12, 4, "hex2int", 10], [" integralHeat: ", 16, 4, "hex2int", 1],
  226. [" flowTemp: ", 20, 4, "hex2int", 10], [" heatSetTemp: ", 24, 4, "hex2int", 10],
  227. [" heatTemp: ", 28, 4, "hex2int", 10],
  228. [" seasonMode: ", 38, 2, "somwinmode", 1], #[" x40: ", 40, 4, "hex2int", 1],
  229. [" integralSwitch: ", 44, 4, "hex2int", 1], [" hcOpMode: ", 48, 2, "opmodehc", 1],
  230. #[" x52: ", 52, 4, "hex2int", 1],
  231. [" roomSetTemp: ", 56, 4, "hex2int", 10], [" x60: ", 60, 4, "hex2int", 10],
  232. [" x64: ", 64, 4, "hex2int", 10], [" insideTempRC: ", 68, 4, "hex2int", 10],
  233. [" x72: ", 72, 4, "hex2int", 10], [" x76: ", 76, 4, "hex2int", 10],
  234. [" onHysteresisNo: ", 32, 2, "hex", 1], [" offHysteresisNo: ", 34, 2, "hex", 1],
  235. [" hcBoosterStage: ", 36, 2, "hex", 1]
  236. ],
  237. "F4hc1214" => [["outsideTemp: ", 4, 4, "hex2int", 10], [" x08: ", 8, 4, "raw", 1],
  238. [" returnTemp: ", 12, 4, "hex2int", 10], [" integralHeat: ", 16, 4, "hex2int", 1],
  239. [" flowTemp: ", 20, 4, "hex2int", 10], [" heatSetTemp: ", 24, 4, "hex2int", 10],
  240. [" heatTemp: ", 28, 4, "hex2int", 10],
  241. [" seasonMode: ", 38, 2, "somwinmode", 1],
  242. [" integralSwitch: ", 44, 4, "hex2int", 1], [" hcOpMode: ", 48, 2, "opmodehc", 1],
  243. [" roomSetTemp: ", 62, 4, "hex2int", 10], [" x60: ", 60, 4, "hex2int", 10],
  244. [" x64: ", 64, 4, "raw", 1], [" insideTempRC: ", 68, 4, "hex2int", 10],
  245. [" x72: ", 72, 4, "raw", 1], [" x76: ", 76, 4, "raw", 1],
  246. [" onHysteresisNo: ", 32, 2, "hex", 1], [" offHysteresisNo: ", 34, 2, "hex", 1],
  247. [" hcBoosterStage: ", 36, 2, "hex", 1]
  248. ],
  249. "F5hc2" => [["outsideTemp: ", 4, 4, "hex2int", 10], [" returnTemp: ", 8, 4, "hex2int", 10],
  250. [" vorlaufTemp: ", 12, 4, "hex2int", 10], [" heatSetTemp: ", 16, 4, "hex2int", 10],
  251. [" heatTemp: ", 20, 4, "hex2int", 10], [" stellgroesse: ", 24, 4, "hex2int", 10],
  252. [" seasonMode: ", 30, 2, "somwinmode",1], [" hcOpMode: ", 36, 2, "opmodehc", 1]
  253. ],
  254. "F6sys206" => [["userSetFanStage: ", 30, 2, "hex", 1], [" userSetFanRemainingTime: ", 36, 4, "hex", 1],
  255. [" lastErrors: ", 4, 8, "hex2error", 1],
  256. ],
  257. "FBglob" => [["outsideTemp: ", 8, 4, "hex2int", 10], [" flowTemp: ", 12, 4, "hex2int", 10],
  258. [" returnTemp: ", 16, 4, "hex2int", 10], [" hotGasTemp: ", 20, 4, "hex2int", 10],
  259. [" dhwTemp: ", 24, 4, "hex2int", 10], [" flowTempHC2: ", 28, 4, "hex2int", 10],
  260. [" evaporatorTemp: ", 36, 4, "hex2int", 10], [" condenserTemp: ", 40, 4, "hex2int", 10],
  261. [" mixerOpen: ", 45, 1, "bit0", 1], [" mixerClosed: ", 45, 1, "bit1", 1],
  262. [" heatPipeValve: ", 45, 1, "bit2", 1], [" diverterValve: ", 45, 1, "bit3", 1],
  263. [" dhwPump: ", 44, 1, "bit0", 1], [" heatingCircuitPump: ", 44, 1, "bit1", 1],
  264. [" solarPump: ", 44, 1, "bit3", 1], [" compressor: ", 47, 1, "bit3", 1],
  265. [" boosterStage3: ", 46, 1, "bit0", 1], [" boosterStage2: ", 46, 1, "bit1", 1],
  266. [" boosterStage1: ", 46, 1, "bit2", 1], [" highPressureSensor: ", 49, 1, "nbit0", 1],
  267. [" lowPressureSensor: ", 49, 1, "nbit1", 1], [" evaporatorIceMonitor: ", 49, 1, "bit2", 1],
  268. [" signalAnode: ", 49, 1, "bit3", 1], [" evuRelease: ", 48, 1, "bit0", 1],
  269. [" ovenFireplace: ", 48, 1, "bit1", 1], [" STB: ", 48, 1, "bit2", 1],
  270. [" outputVentilatorPower: ",50, 4, "hex", 10], [" inputVentilatorPower: ", 54, 4, "hex", 10], [" mainVentilatorPower: ", 58, 4, "hex", 10],
  271. [" outputVentilatorSpeed: ",62, 4, "hex", 1], [" inputVentilatorSpeed: ", 66, 4, "hex", 1], [" mainVentilatorSpeed: ", 70, 4, "hex", 1],
  272. [" outside_tempFiltered: ",74, 4, "hex2int", 10], [" relHumidity: ", 78, 4, "hex2int", 10],
  273. [" dewPoint: ", 82, 4, "hex2int", 10],
  274. [" P_Nd: ", 86, 4, "hex2int", 100], [" P_Hd: ", 90, 4, "hex2int", 100],
  275. [" actualPower_Qc: ", 94, 8, "esp_mant", 1], [" actualPower_Pel: ", 102, 8, "esp_mant", 1],
  276. [" collectorTemp: ", 4, 4, "hex2int", 10], [" insideTemp: ", 32, 4, "hex2int", 10]
  277. ],
  278. "FBglob214" => [["outsideTemp: ", 8, 4, "hex2int", 10], [" flowTemp: ", 12, 4, "hex2int", 10],
  279. [" returnTemp: ", 16, 4, "hex2int", 10], [" hotGasTemp: ", 20, 4, "hex2int", 10],
  280. [" dhwTemp: ", 24, 4, "hex2int", 10], [" flowTempHC2: ", 28, 4, "hex2int", 10],
  281. [" evaporatorTemp: ", 36, 4, "hex2int", 10], [" condenserTemp: ", 40, 4, "hex2int", 10],
  282. [" mixerOpen: ", 47, 1, "bit1", 1], [" mixerClosed: ", 47, 1, "bit0", 1],
  283. [" heatPipeValve: ", 45, 1, "bit3", 1], [" diverterValve: ", 45, 1, "bit2", 1],
  284. [" dhwPump: ", 45, 1, "bit1", 1], [" heatingCircuitPump: ", 45, 1, "bit0", 1],
  285. [" solarPump: ", 44, 1, "bit2", 1], [" compressor: ", 44, 1, "bit0", 1],
  286. [" boosterStage2: ", 44, 1, "bit3", 1], [" boosterStage3: ", 44, 1, "n.a.", 1],
  287. [" boosterStage1: ", 44, 1, "bit1", 1], [" highPressureSensor: ", 54, 1, "bit3", 1],
  288. [" lowPressureSensor: ", 54, 1, "bit2", 1], [" evaporatorIceMonitor: ", 55, 1, "bit3", 1],
  289. [" signalAnode: ", 54, 1, "bit1", 1], [" evuRelease: ", 48, 1, "n.a.", 1],
  290. [" ovenFireplace: ", 54, 1, "bit0", 1], [" STB: ", 48, 1, "n.a.", 1],
  291. [" outputVentilatorPower: ",48, 2, "hex", 1], [" inputVentilatorPower: ", 50, 2, "hex", 1], [" mainVentilatorPower: ", 52, 2, "hex", 255/100],
  292. [" outputVentilatorSpeed: ",56, 2, "hex", 1], [" inputVentilatorSpeed: ", 58, 2, "hex", 1], [" mainVentilatorSpeed: ", 60, 2, "hex", 1],
  293. [" outsideTempFiltered: ",64, 4, "hex2int", 10], [" relHumidity: ", 70, 4, "n.a.", 1],
  294. [" dewPoint: ", 5, 4, "n.a.", 1],
  295. [" P_Nd: ", 5, 4, "n.a.", 1], [" P_Hd: ", 5, 4, "n.a.", 1],
  296. [" actualPower_Qc: ", 5, 8, "n.a.", 1], [" actualPower_Pel: ", 5, 8, "n.a.", 1],
  297. [" collectorTemp: ", 4, 4, "hex2int", 10], [" insideTemp: ", 32, 4, "hex2int", 10]
  298. ],
  299. "FBglob206" => [["outsideTemp: ", 8, 4, "hex2int", 10], [" flowTemp: ", 12, 4, "hex2int", 10],
  300. [" returnTemp: ", 16, 4, "hex2int", 10], [" hotGasTemp: ", 20, 4, "hex2int", 10],
  301. [" dhwTemp: ", 24, 4, "hex2int", 10], [" flowTempHC2: ", 28, 4, "hex2int", 10],
  302. [" evaporatorTemp: ", 36, 4, "hex2int", 10], [" condenserTemp: ", 40, 4, "hex2int", 10],
  303. [" mixerOpen: ", 47, 1, "bit1", 1], [" mixerClosed: ", 47, 1, "bit0", 1],
  304. [" heatPipeValve: ", 45, 1, "bit3", 1], [" diverterValve: ", 45, 1, "bit2", 1],
  305. [" dhwPump: ", 45, 1, "bit1", 1], [" heatingCircuitPump: ", 45, 1, "bit0", 1],
  306. [" solarPump: ", 44, 1, "n.a", 1], [" compressor: ", 44, 1, "bit0", 1],
  307. [" boosterStage3: ", 44, 1, "bit3", 1], [" boosterStage2: ", 44, 1, "bit2", 1],
  308. [" boosterStage1: ", 44, 1, "bit1", 1], [" highPressureSensor: ", 54, 1, "bit3", 1],
  309. [" lowPressureSensor: ", 54, 1, "bit2", 1], [" evaporatorIceMonitor: ", 55, 1, "bit3", 1],
  310. [" signalAnode: ", 54, 1, "bit1", 1], [" evuRelease: ", 48, 1, "n.a.", 1],
  311. [" ovenFireplace: ", 54, 1, "bit0", 1], [" STB: ", 48, 1, "n.a.", 1],
  312. [" outputVentilatorPower: ",48, 2, "hex", 1], [" inputVentilatorPower: ", 50, 2, "hex", 1], [" mainVentilatorPower: ", 52, 2, "hex", 255/100],
  313. [" outputVentilatorSpeed: ",56, 2, "hex", 1], [" inputVentilatorSpeed: ", 58, 2, "hex", 1], [" mainVentilatorSpeed: ", 60, 2, "hex", 1],
  314. [" outsideTempFiltered: ",64, 4, "hex2int", 10], [" relHumidity: ", 70, 4, "n.a.", 1],
  315. [" dewPoint: ", 5, 4, "n.a.", 1],
  316. [" P_Nd: ", 5, 4, "n.a.", 1], [" P_Hd: ", 5, 4, "n.a.", 1],
  317. [" actualPower_Qc: ", 5, 8, "n.a.", 1], [" actualPower_Pel: ", 5, 8, "n.a.", 1],
  318. [" collectorTemp: ", 4, 4, "hex2int", 10], [" insideTemp: ", 32, 4, "hex2int", 10]
  319. ],
  320. "FCtime" => [["Weekday: ", 5, 1, "weekday", 1], [" Hour: ", 6, 2, "hex", 1],
  321. [" Min: ", 8, 2, "hex", 1], [" Sec: ", 10, 2, "hex", 1],
  322. [" Date: ", 12, 2, "year", 1], ["/", 14, 2, "hex", 1],
  323. ["/", 16, 2, "hex", 1]
  324. ],
  325. "FCtime206" => [["Weekday: ", 7, 1, "weekday", 1], [" pClockHour: ", 8, 2, "hex", 1],
  326. [" pClockMinutes: ", 10, 2, "hex", 1], [" Sec: ", 12, 2, "hex", 1],
  327. [" pClockYear: ", 14, 2, "hex", 1], [" pClockMonth: ", 18, 2, "hex", 1],
  328. [" pClockDay: ", 20, 2, "hex", 1]
  329. ],
  330. "FDfirm" => [["version: ", 4, 4, "hexdate", 1]
  331. ],
  332. "FEfirmId" => [[" HW: ", 30, 2, "hex", 1], [" SW: ", 32, 4, "swver", 1],
  333. [" Date: ", 36, 22, "hex2ascii", 1]
  334. ],
  335. "0A0176Dis" => [[" switchingProg: ", 11, 1, "bit0", 1], [" compressor: ", 11, 1, "bit1", 1],
  336. [" heatingHC: ", 11, 1, "bit2", 1], [" heatingDHW: ", 10, 1, "bit0", 1],
  337. [" boosterHC: ", 10, 1, "bit1", 1], [" filterBoth: ", 9, 1, "bit0", 1],
  338. [" ventStage: ", 9, 1, "bit1", 1], [" pumpHC: ", 9, 1, "bit2", 1],
  339. [" defrost: ", 9, 1, "bit3", 1], [" filterUp: ", 8, 1, "bit0", 1],
  340. [" filterDown: ", 8, 1, "bit1", 1], [" cooling: ", 11, 1, "bit3", 1],
  341. [" service: ", 10, 1, "bit2", 1]
  342. ],
  343. "0clean" => [["", 8, 2, "hex", 1]
  344. ],
  345. "1clean" => [["", 8, 4, "hex", 1]
  346. ],
  347. "2opmode" => [["", 8, 2, "opmode", 1]
  348. ],
  349. "4temp" => [["", 8, 4, "hex2int",2560]
  350. ],
  351. "5temp" => [["", 8, 4, "hex2int",10]
  352. ],
  353. "6gradient" => [["", 8, 4, "hex", 100]
  354. ],
  355. "7prog" => [["", 8, 2, "quater", 1], ["--", 10, 2, "quater", 1]
  356. ],
  357. "8party" => [["", 10, 2, "quater", 1], ["--", 8, 2, "quater", 1]
  358. ],
  359. "9holy" => [["", 10, 2, "quater", 1]
  360. ]
  361. );
  362. ########################################################################################
  363. #
  364. # %sets - all supported protocols are listed 59E
  365. #
  366. ########################################################################################
  367. my %sets439technician =(
  368. # "zResetLast10errors" => {cmd2=>"D1", argMin => "0", argMax => "0", type =>"0clean", unit =>""},
  369. # "zPassiveCoolingtrigger" => {cmd2=>"0A0597", argMin => "0", argMax => "50", type =>"1clean", unit =>""},
  370. "zPumpHC" => {cmd2=>"0A0052", argMin => "0", argMax => "1", type =>"0clean", unit =>""},
  371. "zPumpDHW" => {cmd2=>"0A0056", argMin => "0", argMax => "1", type =>"0clean", unit =>""}
  372. );
  373. my %sets439539common = (
  374. "pOpMode" => {cmd2=>"0A0112", type => "2opmode"}, # 1 Standby bereitschaft; 11 in Automatic; 3 DAYmode; SetbackMode; DHWmode; Manual; Emergency
  375. "p01RoomTempDayHC1" => {cmd2=>"0B0005", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  376. "p02RoomTempNightHC1" => {cmd2=>"0B0008", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  377. "p03RoomTempStandbyHC1" => {cmd2=>"0B013D", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  378. "p01RoomTempDayHC1SummerMode" => {cmd2=>"0B0569", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  379. "p02RoomTempNightHC1SummerMode" => {cmd2=>"0B056B", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  380. "p03RoomTempStandbyHC1SummerMode" => {cmd2=>"0B056A", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  381. "p13GradientHC1" => {cmd2=>"0B010E", argMin => "0.1", argMax => "5", type =>"6gradient", unit =>""}, # 0..5 rappresentato/100
  382. "p14LowEndHC1" => {cmd2=>"0B059E", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"}, #in °K 0..20°K rappresentato/10
  383. "p15RoomInfluenceHC1" => {cmd2=>"0B010F", argMin => "0", argMax => "100", type =>"0clean", unit =>" %"},
  384. "p19FlowProportionHC1" => {cmd2=>"0B059D", argMin => "0", argMax => "100", type =>"1clean", unit =>" %"}, #in % 0..100%
  385. "p01RoomTempDayHC2" => {cmd2=>"0C0005", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  386. "p02RoomTempNightHC2" => {cmd2=>"0C0008", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  387. "p03RoomTempStandbyHC2" => {cmd2=>"0C013D", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  388. "p01RoomTempDayHC2SummerMode" => {cmd2=>"0C0569", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  389. "p02RoomTempNightHC2SummerMode" => {cmd2=>"0C056B", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  390. "p03RoomTempStandbyHC2SummerMode" => {cmd2=>"0C056A", argMin => "12", argMax => "28", type =>"5temp", unit =>" °C"},
  391. "p16GradientHC2" => {cmd2=>"0C010E", argMin => "0.1", argMax => "5", type =>"6gradient", unit =>""}, # /100
  392. "p17LowEndHC2" => {cmd2=>"0C059E", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"},
  393. "p18RoomInfluenceHC2" => {cmd2=>"0C010F", argMin => "0", argMax => "100", type =>"0clean", unit =>" %"},
  394. "p04DHWsetDayTemp" => {cmd2=>"0A0013", argMin => "10", argMax => "55", type =>"5temp", unit =>" °C"},
  395. "p05DHWsetNightTemp" => {cmd2=>"0A05BF", argMin => "10", argMax => "55", type =>"5temp", unit =>" °C"},
  396. "p83DHWsetSolarTemp" => {cmd2=>"0A05BE", argMin => "10", argMax => "75", type =>"5temp", unit =>" °C"},
  397. "p06DHWsetStandbyTemp" => {cmd2=>"0A0581", argMin => "10", argMax => "55", type =>"5temp", unit =>" °C"},
  398. "p11DHWsetManualTemp" => {cmd2=>"0A0580", argMin => "10", argMax => "55", type =>"5temp", unit =>" °C"},
  399. "p36DHWMaxTime" => {cmd2=>"0A0180", argMin => "6", argMax => "12", type =>"1clean", unit =>""},
  400. "p07FanStageDay" => {cmd2=>"0A056C", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
  401. "p08FanStageNight" => {cmd2=>"0A056D", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
  402. "p09FanStageStandby" => {cmd2=>"0A056F", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
  403. "p99FanStageParty" => {cmd2=>"0A0570", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
  404. "p21Hyst1" => {cmd2=>"0A05C0", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"},
  405. "p22Hyst2" => {cmd2=>"0A05C1", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"},
  406. "p23Hyst3" => {cmd2=>"0A05C2", argMin => "0", argMax => "5", type =>"5temp", unit =>" K"},
  407. "p24Hyst4" => {cmd2=>"0A05C3", argMin => "0", argMax => "5", type =>"5temp", unit =>" K"},
  408. "p25Hyst5" => {cmd2=>"0A05C4", argMin => "0", argMax => "5", type =>"5temp", unit =>" K"},
  409. "p29HystAsymmetry" => {cmd2=>"0A05C5", argMin => "1", argMax => "5", type =>"1clean", unit =>""},
  410. "p30integralComponent" => {cmd2=>"0A0162", argMin => "10", argMax => "999", type =>"1clean", unit =>" Kmin"},
  411. "p32HystDHW" => {cmd2=>"0A0140", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"},
  412. "p33BoosterTimeoutDHW" => {cmd2=>"0A0588", argMin => "0", argMax => "200", type =>"1clean", unit =>" min"}, #during DHW heating
  413. "p79BoosterTimeoutHC" => {cmd2=>"0A05A0", argMin => "0", argMax => "60", type =>"1clean", unit =>" min"}, #delayed enabling of booster heater
  414. "p46UnschedVent0" => {cmd2=>"0A0571", argMin => "0", argMax => "1000", type =>"1clean", unit =>" min"}, #in min
  415. "p45UnschedVent1" => {cmd2=>"0A0572", argMin => "0", argMax => "1000", type =>"1clean", unit =>" min"}, #in min
  416. "p44UnschedVent2" => {cmd2=>"0A0573", argMin => "0", argMax => "1000", type =>"1clean", unit =>" min"}, #in min
  417. "p43UnschedVent3" => {cmd2=>"0A0574", argMin => "0", argMax => "1000", type =>"1clean", unit =>" min"}, #in min
  418. "p37Fanstage1AirflowInlet" => {cmd2=>"0A0576", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #zuluft
  419. "p38Fanstage2AirflowInlet" => {cmd2=>"0A0577", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #zuluft
  420. "p39Fanstage3AirflowInlet" => {cmd2=>"0A0578", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #zuluft
  421. "p40Fanstage1AirflowOutlet" => {cmd2=>"0A0579", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #abluft extrated
  422. "p41Fanstage2AirflowOutlet" => {cmd2=>"0A057A", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #abluft extrated
  423. "p42Fanstage3AirflowOutlet" => {cmd2=>"0A057B", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #abluft extrated
  424. "p49SummerModeTemp" => {cmd2=>"0A0116", argMin => "10", argMax => "24", type =>"5temp", unit =>" °C"}, #threshold for summer mode !!
  425. "p50SummerModeHysteresis" => {cmd2=>"0A05A2", argMin => "0.5", argMax => "5", type =>"5temp", unit =>" K"}, #Hysteresis for summer mode !!
  426. "p78DualModePoint" => {cmd2=>"0A01AC", argMin => "-10", argMax => "20", type =>"5temp", unit =>" °C"},
  427. "p54MinPumpCycles" => {cmd2=>"0A05B8", argMin => "1", argMax => "24", type =>"1clean", unit =>""},
  428. "p55MaxPumpCycles" => {cmd2=>"0A05B7", argMin => "25", argMax => "200", type =>"1clean", unit =>""},
  429. "p56OutTempMaxPumpCycles" => {cmd2=>"0A05B9", argMin => "0", argMax => "20", type =>"5temp", unit =>" °C"},
  430. "p57OutTempMinPumpCycles" => {cmd2=>"0A05BA", argMin => "0", argMax => "25", type =>"5temp", unit =>" °C"},
  431. "p58SuppressTempCaptPumpStart" => {cmd2=>"0A0611", argMin => "0", argMax => "120", type =>"1clean", unit =>" s"},
  432. "p76RoomThermCorrection" => {cmd2=>"0A0109", argMin => "-5", argMax => "5", type =>"4temp", unit =>" K"},
  433. "p77OutThermFilterTime" => {cmd2=>"0A010C", argMin => "1", argMax => "24", type =>"0clean", unit =>" h"},
  434. "p35PasteurisationInterval" => {cmd2=>"0A0586", argMin => "1", argMax => "30", type =>"1clean", unit =>""},
  435. "p35PasteurisationTemp" => {cmd2=>"0A0587", argMin => "10", argMax => "65", type =>"5temp", unit =>" °C"},
  436. "p34BoosterDHWTempAct" => {cmd2=>"0A0589", argMin => "-10", argMax => "10", type =>"5temp", unit =>" °C"},
  437. "p99DHWmaxFlowTemp" => {cmd2=>"0A058C", argMin => "10", argMax => "75", type =>"5temp", unit =>" °C"},
  438. "p99HC1maxFlowTemp" => {cmd2=>"0A0027", argMin => "10", argMax => "75", type =>"5temp", unit =>" °C"},
  439. "p89DHWeco" => {cmd2=>"0A058D", argMin => "0", argMax => "1", type =>"1clean", unit =>""},
  440. "p99startUnschedVent" => {cmd2=>"0A05DD", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
  441. "p99FrostProtectionBoost" => {cmd2=>"0A05B3", argMin => "10", argMax => "30", type =>"5temp", unit =>" °C"}, #added by TheTrumpeter __EINFRIERSCHUTZ NE
  442. "p99FrostProtectionCancel" => {cmd2=>"0A05B4", argMin => "0", argMax => "20", type =>"5temp", unit =>" °C"}, #added by TheTrumpeter __ABTAUABBR.
  443. "pClockDay" => {cmd2=>"0A0122", argMin => "1", argMax => "31", type =>"0clean", unit =>""},
  444. "pClockMonth" => {cmd2=>"0A0123", argMin => "1", argMax => "12", type =>"0clean", unit =>""},
  445. "pClockYear" => {cmd2=>"0A0124", argMin => "12", argMax => "20", type =>"0clean", unit =>""},
  446. "pClockHour" => {cmd2=>"0A0125", argMin => "0", argMax => "23", type =>"0clean", unit =>""},
  447. "pClockMinutes" => {cmd2=>"0A0126", argMin => "0", argMax => "59", type =>"0clean", unit =>""},
  448. "pHolidayBeginDay" => {cmd2=>"0A011B", argMin => "1", argMax => "31", type =>"0clean", unit =>""},
  449. "pHolidayBeginMonth" => {cmd2=>"0A011C", argMin => "1", argMax => "12", type =>"0clean", unit =>""},
  450. "pHolidayBeginYear" => {cmd2=>"0A011D", argMin => "12", argMax => "20", type =>"0clean", unit =>""},
  451. "pHolidayBeginTime" => {cmd2=>"0A05D3", argMin => "00:00", argMax => "23:59", type =>"9holy", unit =>""},
  452. "pHolidayEndDay" => {cmd2=>"0A011E", argMin => "1", argMax => "31", type =>"0clean", unit =>""},
  453. "pHolidayEndMonth" => {cmd2=>"0A011F", argMin => "1", argMax => "12", type =>"0clean", unit =>""},
  454. "pHolidayEndYear" => {cmd2=>"0A0120", argMin => "12", argMax => "20", type =>"0clean", unit =>""},
  455. "pHolidayEndTime" => {cmd2=>"0A05D4", argMin => "00:00", argMax => "23:59", type =>"9holy", unit =>""}, # the answer look like 0A05D4-0D0A05D40029 for year 41 which is 10:15
  456. #"party-time" => {cmd2=>"0A05D1", argMin => "00:00", argMax => "23:59", type =>"8party", unit =>""}, # value 1Ch 28dec is 7 ; value 1Eh 30dec is 7:30
  457. "programHC1_Mo_0" => {cmd2=>"0B1410", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""}, #1 is monday 0 is first prog; start and end; value 1Ch 28dec is 7 ; value 1Eh 30dec is 7:30
  458. "programHC1_Mo_1" => {cmd2=>"0B1411", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  459. "programHC1_Mo_2" => {cmd2=>"0B1412", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  460. "programHC1_Tu_0" => {cmd2=>"0B1420", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  461. "programHC1_Tu_1" => {cmd2=>"0B1421", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  462. "programHC1_Tu_2" => {cmd2=>"0B1422", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  463. "programHC1_We_0" => {cmd2=>"0B1430", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  464. "programHC1_We_1" => {cmd2=>"0B1431", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  465. "programHC1_We_2" => {cmd2=>"0B1432", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  466. "programHC1_Th_0" => {cmd2=>"0B1440", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  467. "programHC1_Th_1" => {cmd2=>"0B1441", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  468. "programHC1_Th_2" => {cmd2=>"0B1442", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  469. "programHC1_Fr_0" => {cmd2=>"0B1450", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  470. "programHC1_Fr_1" => {cmd2=>"0B1451", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  471. "programHC1_Fr_2" => {cmd2=>"0B1452", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  472. "programHC1_Sa_0" => {cmd2=>"0B1460", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  473. "programHC1_Sa_1" => {cmd2=>"0B1461", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  474. "programHC1_Sa_2" => {cmd2=>"0B1462", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  475. "programHC1_So_0" => {cmd2=>"0B1470", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  476. "programHC1_So_1" => {cmd2=>"0B1471", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  477. "programHC1_So_2" => {cmd2=>"0B1472", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  478. "programHC1_Mo-Fr_0" => {cmd2=>"0B1480", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  479. "programHC1_Mo-Fr_1" => {cmd2=>"0B1481", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  480. "programHC1_Mo-Fr_2" => {cmd2=>"0B1482", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  481. "programHC1_Sa-So_0" => {cmd2=>"0B1490", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  482. "programHC1_Sa-So_1" => {cmd2=>"0B1491", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  483. "programHC1_Sa-So_2" => {cmd2=>"0B1492", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  484. "programHC1_Mo-So_0" => {cmd2=>"0B14A0", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  485. "programHC1_Mo-So_1" => {cmd2=>"0B14A1", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  486. "programHC1_Mo-So_2" => {cmd2=>"0B14A2", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  487. "programHC2_Mo_0" => {cmd2=>"0C1510", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""}, #1 is monday 0 is first prog; start and end; value 1Ch 28dec is 7 ; value 1Eh 30dec is 7:30
  488. "programHC2_Mo_1" => {cmd2=>"0C1511", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  489. "programHC2_Mo_2" => {cmd2=>"0C1512", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  490. "programHC2_Tu_0" => {cmd2=>"0C1520", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  491. "programHC2_Tu_1" => {cmd2=>"0C1521", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  492. "programHC2_Tu_2" => {cmd2=>"0C1522", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  493. "programHC2_We_0" => {cmd2=>"0C1530", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  494. "programHC2_We_1" => {cmd2=>"0C1531", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  495. "programHC2_We_2" => {cmd2=>"0C1532", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  496. "programHC2_Th_0" => {cmd2=>"0C1540", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  497. "programHC2_Th_1" => {cmd2=>"0C1541", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  498. "programHC2_Th_2" => {cmd2=>"0C1542", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  499. "programHC2_Fr_0" => {cmd2=>"0C1550", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  500. "programHC2_Fr_1" => {cmd2=>"0C1551", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  501. "programHC2_Fr_2" => {cmd2=>"0C1552", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  502. "programHC2_Sa_0" => {cmd2=>"0C1560", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  503. "programHC2_Sa_1" => {cmd2=>"0C1561", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  504. "programHC2_Sa_2" => {cmd2=>"0C1562", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  505. "programHC2_So_0" => {cmd2=>"0C1570", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  506. "programHC2_So_1" => {cmd2=>"0C1571", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  507. "programHC2_So_2" => {cmd2=>"0C1572", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  508. "programHC2_Mo-Fr_0" => {cmd2=>"0C1580", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  509. "programHC2_Mo-Fr_1" => {cmd2=>"0C1581", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  510. "programHC2_Mo-Fr_2" => {cmd2=>"0C1582", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  511. "programHC2_Sa-So_0" => {cmd2=>"0C1590", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  512. "programHC2_Sa-So_1" => {cmd2=>"0C1591", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  513. "programHC2_Sa-So_2" => {cmd2=>"0C1592", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  514. "programHC2_Mo-So_0" => {cmd2=>"0C15A0", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  515. "programHC2_Mo-So_1" => {cmd2=>"0C15A1", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  516. "programHC2_Mo-So_2" => {cmd2=>"0C15A2", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  517. "programDHW_Mo_0" => {cmd2=>"0A1710", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  518. "programDHW_Mo_1" => {cmd2=>"0A1711", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  519. "programDHW_Mo_2" => {cmd2=>"0A1712", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  520. "programDHW_Tu_0" => {cmd2=>"0A1720", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  521. "programDHW_Tu_1" => {cmd2=>"0A1721", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  522. "programDHW_Tu_2" => {cmd2=>"0A1722", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  523. "programDHW_We_0" => {cmd2=>"0A1730", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  524. "programDHW_We_1" => {cmd2=>"0A1731", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  525. "programDHW_We_2" => {cmd2=>"0A1732", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  526. "programDHW_Th_0" => {cmd2=>"0A1740", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  527. "programDHW_Th_1" => {cmd2=>"0A1741", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  528. "programDHW_Th_2" => {cmd2=>"0A1742", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  529. "programDHW_Fr_0" => {cmd2=>"0A1750", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  530. "programDHW_Fr_1" => {cmd2=>"0A1751", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  531. "programDHW_Fr_2" => {cmd2=>"0A1752", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  532. "programDHW_Sa_0" => {cmd2=>"0A1760", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  533. "programDHW_Sa_1" => {cmd2=>"0A1761", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  534. "programDHW_Sa_2" => {cmd2=>"0A1762", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  535. "programDHW_So_0" => {cmd2=>"0A1770", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  536. "programDHW_So_1" => {cmd2=>"0A1771", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  537. "programDHW_So_2" => {cmd2=>"0A1772", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  538. "programDHW_Mo-Fr_0" => {cmd2=>"0A1780", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  539. "programDHW_Mo-Fr_1" => {cmd2=>"0A1781", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  540. "programDHW_Mo-Fr_2" => {cmd2=>"0A1782", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  541. "programDHW_Sa-So_0" => {cmd2=>"0A1790", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  542. "programDHW_Sa-So_1" => {cmd2=>"0A1791", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  543. "programDHW_Sa-So_2" => {cmd2=>"0A1792", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  544. "programDHW_Mo-So_0" => {cmd2=>"0A17A0", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  545. "programDHW_Mo-So_1" => {cmd2=>"0A17A1", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  546. "programDHW_Mo-So_2" => {cmd2=>"0A17A2", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  547. "programFan_Mo_0" => {cmd2=>"0A1D10", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  548. "programFan_Mo_1" => {cmd2=>"0A1D11", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  549. "programFan_Mo_2" => {cmd2=>"0A1D12", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  550. "programFan_Tu_0" => {cmd2=>"0A1D20", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  551. "programFan_Tu_1" => {cmd2=>"0A1D21", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  552. "programFan_Tu_2" => {cmd2=>"0A1D22", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  553. "programFan_We_0" => {cmd2=>"0A1D30", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  554. "programFan_We_1" => {cmd2=>"0A1D31", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  555. "programFan_We_2" => {cmd2=>"0A1D32", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  556. "programFan_Th_0" => {cmd2=>"0A1D40", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  557. "programFan_Th_1" => {cmd2=>"0A1D41", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  558. "programFan_Th_2" => {cmd2=>"0A1D42", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  559. "programFan_Fr_0" => {cmd2=>"0A1D50", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  560. "programFan_Fr_1" => {cmd2=>"0A1D51", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  561. "programFan_Fr_2" => {cmd2=>"0A1D52", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  562. "programFan_Sa_0" => {cmd2=>"0A1D60", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  563. "programFan_Sa_1" => {cmd2=>"0A1D61", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  564. "programFan_Sa_2" => {cmd2=>"0A1D62", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  565. "programFan_So_0" => {cmd2=>"0A1D70", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  566. "programFan_So_1" => {cmd2=>"0A1D71", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  567. "programFan_So_2" => {cmd2=>"0A1D72", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  568. "programFan_Mo-Fr_0" => {cmd2=>"0A1D80", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  569. "programFan_Mo-Fr_1" => {cmd2=>"0A1D81", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  570. "programFan_Mo-Fr_2" => {cmd2=>"0A1D82", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  571. "programFan_Sa-So_0" => {cmd2=>"0A1D90", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  572. "programFan_Sa-So_1" => {cmd2=>"0A1D91", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  573. "programFan_Sa-So_2" => {cmd2=>"0A1D92", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  574. "programFan_Mo-So_0" => {cmd2=>"0A1DA0", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  575. "programFan_Mo-So_1" => {cmd2=>"0A1DA1", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  576. "programFan_Mo-So_2" => {cmd2=>"0A1DA2", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""}
  577. );
  578. my %sets439only =(
  579. "p75passiveCooling" => {cmd2=>"0A0575", argMin => "0", argMax => "2", type =>"1clean", unit =>""}
  580. );
  581. my %sets539only =(
  582. "p75passiveCooling" => {cmd2=>"0A0575", argMin => "0", argMax => "4", type =>"1clean", unit =>""},
  583. "p99PumpRateHC" => {cmd2=>"0A02CB", argMin => "0", argMax => "100", type =>"5temp", unit =>" %"},
  584. "p99PumpRateDHW" => {cmd2=>"0A02CC", argMin => "0", argMax => "100", type =>"5temp", unit =>" %"} ,
  585. "p99CoolingHC1Switch" => {cmd2=>"0B0287", argMin => "0", argMax => "1", type =>"1clean", unit =>""},
  586. "p99CoolingHC1SetTemp" => {cmd2=>"0B0582", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"}, #suggested by TheTrumpeter
  587. "p99CoolingHC1HystersisFlowTemp" => {cmd2=>"0B0583", argMin => "0.5", argMax => "5", type =>"5temp", unit =>" K"}, #suggested by TheTrumpeter
  588. "p99CoolingHC1HystersisRoomTemp" => {cmd2=>"0B0584", argMin => "0.5", argMax => "3", type =>"5temp", unit =>" K"} #suggested by TheTrumpeter
  589. );
  590. my %sets206 = (
  591. "p01RoomTempDay" => {parent=>"p01-p12", argMin => "10", argMax => "30", type =>"pclean", unit =>" °C"},
  592. "p02RoomTempNight" => {parent=>"p01-p12", argMin => "10", argMax => "30", type =>"pclean", unit =>" °C"},
  593. "p03RoomTempStandby" => {parent=>"p01-p12", argMin => "10", argMax => "30", type =>"pclean", unit =>" °C"},
  594. "p04DHWsetTempDay" => {parent=>"p01-p12", argMin => "10", argMax => "55", type =>"pclean", unit =>" °C"},
  595. "p05DHWsetTempNight" => {parent=>"p01-p12", argMin => "10", argMax => "55", type =>"pclean", unit =>" °C"},
  596. "p06DHWsetTempStandby" => {parent=>"p01-p12", argMin => "10", argMax => "55", type =>"pclean", unit =>" °C"},
  597. "p07FanStageDay" => {parent=>"p01-p12", argMin => "0", argMax => "3", type =>"pclean", unit =>""},
  598. "p08FanStageNight" => {parent=>"p01-p12", argMin => "0", argMax => "3", type =>"pclean", unit =>""},
  599. "p09FanStageStandby" => {parent=>"p01-p12", argMin => "0", argMax => "3", type =>"pclean", unit =>""},
  600. "p10HCTempManual" => {parent=>"p01-p12", argMin => "10", argMax => "65", type =>"pclean", unit =>" °C"},
  601. "p11DHWsetTempManual" => {parent=>"p01-p12", argMin => "10", argMax => "65", type =>"pclean", unit =>" °C"},
  602. "p12FanStageManual" => {parent=>"p01-p12", argMin => "0", argMax => "3", type =>"pclean", unit =>""},
  603. "p13GradientHC1" => {parent=>"pHeat1", argMin => "0", argMax => "5", type =>"pclean", unit =>""},
  604. "p14LowEndHC1" => {parent=>"pHeat1", argMin => "0", argMax => "20", type =>"pclean", unit =>" K"},
  605. "p15RoomInfluenceHC1" => {parent=>"pHeat1", argMin => "0", argMax => "10", type =>"pclean", unit =>""},
  606. "p16GradientHC2" => {parent=>"pHeat1", argMin => "0", argMax => "5", type =>"pclean", unit =>""},
  607. "p17LowEndHC2" => {parent=>"pHeat1", argMin => "0", argMax => "10", type =>"pclean", unit =>" K"},
  608. "p18RoomInfluenceHC2" => {parent=>"pHeat1", argMin => "0", argMax => "10", type =>"pclean", unit =>""},
  609. "p19FlowProportionHC1" => {parent=>"pHeat1", argMin => "0", argMax => "100", type =>"pclean", unit =>" %"},
  610. "p20FlowProportionHC2" => {parent=>"pHeat1", argMin => "0", argMax => "100", type =>"pclean", unit =>" %"},
  611. "p21Hyst1" => {parent=>"pHeat2", argMin => "0", argMax => "10", type =>"pclean", unit =>" K"},
  612. "p22Hyst2" => {parent=>"pHeat2", argMin => "0", argMax => "10", type =>"pclean", unit =>" K"},
  613. "p23Hyst3" => {parent=>"pHeat2", argMin => "0", argMax => "5", type =>"pclean", unit =>" K"},
  614. "p24Hyst4" => {parent=>"pHeat2", argMin => "0", argMax => "5", type =>"pclean", unit =>" K"},
  615. "p25Hyst5" => {parent=>"pHeat2", argMin => "0", argMax => "5", type =>"pclean", unit =>" K"},
  616. "p29HystAsymmetry" => {parent=>"pHeat2", argMin => "1", argMax => "5", type =>"pclean", unit =>""},
  617. "p30integralComponent" => {parent=>"pHeat2", argMin => "10", argMax => "999", type =>"pclean", unit =>" Kmin"},
  618. "p32HystDHW" => {parent=>"pDHW", argMin => "2", argMax => "10", type =>"pclean", unit =>" K"},
  619. "p33BoosterTimeoutDHW" => {parent=>"pDHW", argMin => "0", argMax => "240", type =>"pclean", unit =>" min"},
  620. "p34TempLimitBoostDHW" => {parent=>"pDHW", argMin => "-10", argMax => "10", type =>"pclean", unit =>" °C"},
  621. "p35PasteurisationInterval" => {parent=>"pDHW", argMin => "3", argMax => "30", type =>"pclean", unit =>" Days"},
  622. "p36MaxDurationDHWLoad" => {parent=>"pDHW", argMin => "6", argMax => "12", type =>"pclean", unit =>" h"},
  623. "p37Fanstage1AirflowInlet" => {parent=>"pFan", argMin => "60", argMax => "250", type =>"pclean", unit =>" m3/h"},
  624. "p38Fanstage2AirflowInlet" => {parent=>"pFan", argMin => "60", argMax => "250", type =>"pclean", unit =>" m3/h"},
  625. "p39Fanstage3AirflowInlet" => {parent=>"pFan", argMin => "60", argMax => "250", type =>"pclean", unit =>" m3/h"},
  626. "p40Fanstage1AirflowOutlet" => {parent=>"pFan", argMin => "60", argMax => "250", type =>"pclean", unit =>" m3/h"},
  627. "p41Fanstage2AirflowOutlet" => {parent=>"pFan", argMin => "60", argMax => "250", type =>"pclean", unit =>" m3/h"},
  628. "p42Fanstage3AirflowOutlet" => {parent=>"pFan", argMin => "60", argMax => "250", type =>"pclean", unit =>" m3/h"},
  629. "p43UnschedVent3" => {parent=>"pFan", argMin => "0", argMax => "1000", type =>"pclean", unit =>" min"},
  630. "p44UnschedVent2" => {parent=>"pFan", argMin => "0", argMax => "1000", type =>"pclean", unit =>" min"},
  631. "p45UnschedVent1" => {parent=>"pFan", argMin => "0", argMax => "1000", type =>"pclean", unit =>" min"},
  632. "p46UnschedVent0" => {parent=>"pFan", argMin => "0", argMax => "1000", type =>"pclean", unit =>" min"},
  633. "p47CompressorRestartDelay" => {parent=>"pDefrostEva", argMin => "0", argMax => "20", type =>"pclean", unit =>" min"},
  634. "p48MainFanSpeed" => {parent=>"pDefrostEva", argMin => "0", argMax => "100", type =>"pclean", unit =>" %"},
  635. "p49SummerModeTemp" => {parent=>"pHeat2", argMin => "10", argMax => "24", type =>"pclean", unit =>" °C"},
  636. "p50SummerModeHysteresis" => {parent=>"pHeat2", argMin => "1", argMax => "5", type =>"pclean", unit =>" K"},
  637. "p54MinPumpCycles" => {parent=>"pCircPump", argMin => "1", argMax => "24", type =>"pclean", unit =>" /Day"},
  638. "p55MaxPumpCycles" => {parent=>"pCircPump", argMin => "25", argMax => "288", type =>"pclean", unit =>" /Day"},
  639. "p56OutTempMaxPumpCycles" => {parent=>"pCircPump", argMin => "0", argMax => "20", type =>"pclean", unit =>" °C"},
  640. "p57OutTempMinPumpCycles" => {parent=>"pCircPump", argMin => "0", argMax => "25", type =>"pclean", unit =>" °C"},
  641. "p58SuppressTempCaptPumpStart"=> {parent=>"pCircPump", argMin => "0", argMax => "120", type =>"pclean", unit =>" s"},
  642. "p75PassiveCooling" => {parent=>"pFan", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  643. "p77OutTempFilterTime" => {parent=>"pHeat2", argMin => "0", argMax => "24", type =>"pclean", unit =>" h"},
  644. "p78DualModePoint" => {parent=>"pHeat2", argMin => "-10", argMax => "20", type =>"pclean", unit =>" °C"},
  645. "p79BoosterTimeoutHC" => {parent=>"pHeat2", argMin => "0", argMax => "60", type =>"pclean", unit =>" min"},
  646. "p80EnableSolar" => {parent=>"pSolar", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  647. "pClockDay" => {parent=>"sTimedate", argMin => "1", argMax => "31", type =>"pclean", unit =>""},
  648. "pClockMonth" => {parent=>"sTimedate", argMin => "1", argMax => "12", type =>"pclean", unit =>""},
  649. "pClockYear" => {parent=>"sTimedate", argMin => "12", argMax => "20", type =>"pclean", unit =>""},
  650. "pClockHour" => {parent=>"sTimedate", argMin => "0", argMax => "23", type =>"pclean", unit =>""},
  651. "pClockMinutes" => {parent=>"sTimedate", argMin => "0", argMax => "59", type =>"pclean", unit =>""},
  652. "progDHWStartTime" => {parent=>"pDHWProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
  653. "progDHWEndTime" => {parent=>"pDHWProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
  654. "progDHWEnable" => {parent=>"pDHWProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  655. "progDHWMonday" => {parent=>"pDHWProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  656. "progDHWTuesday" => {parent=>"pDHWProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  657. "progDHWWednesday" => {parent=>"pDHWProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  658. "progDHWThursday" => {parent=>"pDHWProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  659. "progDHWFriday" => {parent=>"pDHWProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  660. "progDHWSaturday" => {parent=>"pDHWProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  661. "progDHWSunday" => {parent=>"pDHWProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  662. "progHC1StartTime" => {parent=>"pHeatProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
  663. "progHC1EndTime" => {parent=>"pHeatProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
  664. "progHC1Enable" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  665. "progHC1Monday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  666. "progHC1Tuesday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  667. "progHC1Wednesday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  668. "progHC1Thursday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  669. "progHC1Friday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  670. "progHC1Saturday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  671. "progHC1Sunday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  672. "progHC2StartTime" => {parent=>"pHeatProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
  673. "progHC2EndTime" => {parent=>"pHeatProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
  674. "progHC2Enable" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  675. "progHC2Monday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  676. "progHC2Tuesday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  677. "progHC2Wednesday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  678. "progHC2Thursday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  679. "progHC2Friday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  680. "progHC2Saturday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  681. "progHC2Sunday" => {parent=>"pHeatProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  682. "progFAN1StartTime" => {parent=>"pFanProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
  683. "progFAN1EndTime" => {parent=>"pFanProg", argMin => "00:00", argMax => "23:59", type =>"ütime", unit =>""},
  684. "progFAN1Enable" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  685. "progFAN1Monday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  686. "progFAN1Tuesday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  687. "progFAN1Wednesday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  688. "progFAN1Thursday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  689. "progFAN1Friday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  690. "progFAN1Saturday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  691. "progFAN1Sunday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  692. "progFAN2StartTime" => {parent=>"pFanProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
  693. "progFAN2EndTime" => {parent=>"pFanProg", argMin => "00:00", argMax => "23:59", type =>"ptime", unit =>""},
  694. "progFAN2Enable" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  695. "progFAN2Monday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  696. "progFAN2Tuesday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  697. "progFAN2Wednesday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  698. "progFAN2Thursday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  699. "progFAN2Friday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  700. "progFAN2Saturday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""},
  701. "progFAN2Sunday" => {parent=>"pFanProg", argMin => "0", argMax => "1", type =>"pclean", unit =>""}
  702. );
  703. my %setsonly214 = (
  704. "ResetErrors" => {cmd2=>"F8", argMin => "0", argMax => "0", type =>"0clean", unit =>""}
  705. );
  706. ########################################################################################
  707. #
  708. # %gets - all supported protocols are listed without header and footer
  709. #
  710. ########################################################################################
  711. my %getsonly439 = (
  712. #"debug_read_raw_register_slow" => { },
  713. "sSol" => {cmd2=>"16", type =>"16sol", unit =>""},
  714. "sHistory" => {cmd2=>"09", type =>"09his", unit =>""},
  715. "sLast10errors" => {cmd2=>"D1", type =>"D1last", unit =>""},
  716. "sFan" => {cmd2=>"E8", type =>"E8fan", unit =>""},
  717. "sDHW" => {cmd2=>"F3", type =>"F3dhw", unit =>""},
  718. "sHC1" => {cmd2=>"F4", type =>"F4hc1", unit =>""},
  719. "sHC2" => {cmd2=>"F5", type =>"F5hc2", unit =>""},
  720. "sControl" => {cmd2=>"F2", type =>"F2ctrl", unit =>""},
  721. "sGlobal" => {cmd2=>"FB", type =>"FBglob", unit =>""}, #allFB
  722. "sTimedate" => {cmd2=>"FC", type =>"FCtime", unit =>""},
  723. "sFirmware" => {cmd2=>"FD", type =>"FDfirm", unit =>""},
  724. "sFirmware-Id" => {cmd2=>"FE", type =>"FEfirmId", unit =>""},
  725. "sDisplay" => {cmd2=>"0A0176", type =>"0A0176Dis", unit =>""},
  726. "sBoostDHWTotal" => {cmd2=>"0A0924", cmd3=>"0A0925", type =>"1clean", unit =>" kWh"},
  727. "sBoostHCTotal" => {cmd2=>"0A0928", cmd3=>"0A0929", type =>"1clean", unit =>" kWh"},
  728. "sHeatRecoveredDay" => {cmd2=>"0A03AE", cmd3=>"0A03AF", type =>"1clean", unit =>" Wh"},
  729. "sHeatRecoveredTotal" => {cmd2=>"0A03B0", cmd3=>"0A03B1", type =>"1clean", unit =>" kWh"},
  730. "sHeatDHWDay" => {cmd2=>"0A092A", cmd3=>"0A092B", type =>"1clean", unit =>" Wh"},
  731. "sHeatDHWTotal" => {cmd2=>"0A092C", cmd3=>"0A092D", type =>"1clean", unit =>" kWh"},
  732. "sHeatHCDay" => {cmd2=>"0A092E", cmd3=>"0A092F", type =>"1clean", unit =>" Wh"},
  733. "sHeatHCTotal" => {cmd2=>"0A0930", cmd3=>"0A0931", type =>"1clean", unit =>" kWh"},
  734. "sElectrDHWDay" => {cmd2=>"0A091A", cmd3=>"0A091B", type =>"1clean", unit =>" Wh"},
  735. "sElectrDHWTotal" => {cmd2=>"0A091C", cmd3=>"0A091D", type =>"1clean", unit =>" kWh"},
  736. "sElectrHCDay" => {cmd2=>"0A091E", cmd3=>"0A091F", type =>"1clean", unit =>" Wh"},
  737. "sElectrHCTotal" => {cmd2=>"0A0920", cmd3=>"0A0921", type =>"1clean", unit =>" kWh"},
  738. "party-time" => {cmd2=>"0A05D1", argMin => "00:00", argMax => "23:59", type =>"8party", unit =>""} # value 1Ch 28dec is 7 ; value 1Eh 30dec is 7:30
  739. );
  740. my %getsonly539 = ( #info from belu and godmorgon
  741. "sFlowRate" => {cmd2=>"0A033B", type =>"1clean", unit =>" cl/min"},
  742. "sHumMaskingTime" => {cmd2=>"0A064F", type =>"1clean", unit =>" min"},
  743. "sHumThreshold" => {cmd2=>"0A0650", type =>"1clean", unit =>" %"},
  744. "sOutputReduction" => {cmd2=>"0A06A4", type =>"1clean", unit =>" %"},
  745. "sOutputIncrease" => {cmd2=>"0A06A5", type =>"1clean", unit =>" %"},
  746. "sHumProtection" => {cmd2=>"0A09D1", type =>"1clean", unit =>""},
  747. "sSetHumidityMin" => {cmd2=>"0A09D2", type =>"1clean", unit =>" %"},
  748. "sSetHumidityMax" => {cmd2=>"0A09D3", type =>"1clean", unit =>" %"},
  749. "sCoolHCTotal" => {cmd2=>"0A0648", cmd3 =>"0A0649", type =>"1clean", unit =>" kWh"},
  750. "sDewPointHC1" => {cmd2=>"0B0264", type =>"5temp", unit =>" °C"}
  751. );
  752. %getsonly539=(%getsonly539, %getsonly439);
  753. my %getsonly2xx = (
  754. "pDefrostEva" => {cmd2=>"03", type =>"03pxx206", unit =>""},
  755. "pDefrostAA" => {cmd2=>"04", type =>"04pxx206", unit =>""},
  756. "pHeat1" => {cmd2=>"05", type =>"05pxx206", unit =>""},
  757. "pHeat2" => {cmd2=>"06", type =>"06pxx206", unit =>""},
  758. "pDHW" => {cmd2=>"07", type =>"07pxx206", unit =>""},
  759. "pSolar" => {cmd2=>"08", type =>"08pxx206", unit =>""},
  760. "sHistory" => {cmd2=>"09", type =>"09his206", unit =>""},
  761. "pCircPump" => {cmd2=>"0A", type =>"0Apxx206", unit =>""},
  762. "pHeatProg" => {cmd2=>"0B", type =>"0Bpxx206", unit =>""},
  763. "pDHWProg" => {cmd2=>"0C", type =>"0Cpxx206", unit =>""},
  764. "pFanProg" => {cmd2=>"0D", type =>"0Dpxx206", unit =>""},
  765. "pRestart" => {cmd2=>"0E", type =>"0Epxx206", unit =>""},
  766. "pAbsence" => {cmd2=>"0F", type =>"0Fpxx206", unit =>""},
  767. "pDryHeat" => {cmd2=>"10", type =>"10pxx206", unit =>""},
  768. "sSol" => {cmd2=>"16", type =>"16sol", unit =>""},
  769. "p01-p12" => {cmd2=>"17", type =>"17pxx206", unit =>""},
  770. "sProgram" => {cmd2=>"EE", type =>"EEprg206", unit =>""},
  771. "sFan" => {cmd2=>"E8", type =>"E8fan206", unit =>""},
  772. "sControl" => {cmd2=>"F2", type =>"F2ctrl", unit =>""},
  773. "sDHW" => {cmd2=>"F3", type =>"F3dhw", unit =>""},
  774. "sHC2" => {cmd2=>"F5", type =>"F5hc2", unit =>""},
  775. "sSystem" => {cmd2=>"F6", type =>"F6sys206", unit =>""},
  776. "sTimedate" => {cmd2=>"FC", type =>"FCtime206", unit =>""},
  777. "inputVentilatorSpeed"=> {parent=>"sGlobal", unit =>" %"},
  778. "outputVentilatorSpeed"=>{parent=>"sGlobal", unit =>" %"},
  779. "mainVentilatorSpeed" => {parent=>"sGlobal", unit =>" %"},
  780. "inputVentilatorPower"=> {parent=>"sGlobal", unit =>" %"},
  781. "outputVentilatorPower"=>{parent=>"sGlobal", unit =>" %"},
  782. "mainVentilatorPower" => {parent=>"sGlobal", unit =>" %"},
  783. );
  784. my %getsonly206 = (
  785. "sHC1" => {cmd2=>"F4", type =>"F4hc1", unit =>""},
  786. "pFan" => {cmd2=>"01", type =>"01pxx206", unit =>""},
  787. "sLast10errors" => {cmd2=>"D1", type =>"D1last206", unit =>""},
  788. "sFirmware" => {cmd2=>"FD", type =>"FDfirm", unit =>""},
  789. "sGlobal" => {cmd2=>"FB", type =>"FBglob206", unit =>""}
  790. );
  791. my %getsonly214 = (
  792. "pFan" => {cmd2=>"01", type =>"01pxx214", unit =>""},
  793. "pExpert" => {cmd2=>"02", type =>"02pxx206", unit =>""},
  794. "sControl" => {cmd2=>"F2", type =>"F2type", unit =>""},
  795. "sHC1" => {cmd2=>"F4", type =>"F4hc1214", unit =>""},
  796. #"sLVR" => {cmd2=>"E8", type =>"E8tyype", unit =>""},
  797. #"sF0" => {cmd2=>"F0", type =>"F0type", unit =>""},
  798. #"sF1" => {cmd2=>"F1", type =>"F1type", unit =>""},
  799. #"sEF" => {cmd2=>"EF", type =>"EFtype", unit =>""},
  800. "sGlobal" => {cmd2=>"FB", type =>"FBglob214", unit =>""}
  801. );
  802. my %sets= (%sets439539common, %sets439only);
  803. my %gets= (%getsonly439, %sets);
  804. my %OpMode= ("1" =>"standby", "11" => "automatic", "3" =>"DAYmode", "4" =>"setback", "5" =>"DHWmode", "14" =>"manual", "0" =>"emergency");
  805. my %Rev_OpMode= reverse %OpMode;
  806. my %OpModeHC= ("1" =>"normal", "2" => "setback", "3" =>"standby", "4" =>"restart", "5" =>"restart");
  807. my %opMode2= ("0" =>"manual", "1" => "automatic");
  808. my %SomWinMode= ("01" =>"winter", "02" => "summer");
  809. my %weekday= ("0" =>"Monday", "1" => "Tuesday", "2" =>"Wednesday", "3" => "Thursday", "4" => "Friday", "5" =>"Saturday", "6" => "Sunday" );
  810. #my %weekdaymap= ( "1" =>"Mon", "2" => "Tue", "3" =>"Wed", "4" => "Thu", "5" => "Fri", "6" =>"Sat", "7" => "Sun" );
  811. my %faultmap= ( "0" =>"n.a.", "1" => "F01_AnodeFault", "2" => "F02_SafetyTempDelimiterEngaged", "3" => "F03_HighPreasureGuardFault", "4" => "F04_LowPreasureGuardFault", "5" => "F05_OutletFanFault", "6" => "F06_InletFanFault", "7" => "F07_MainOutputFanFault", "11" => "F11_LowPreasureSensorFault", "12"=> "F12_HighPreasureSensorFault", "15" => "F15_DHW_TemperatureFault", "17" => "F17_DefrostingDurationExceeded", "20" => "F20_SolarSensorFault", "21" => "F21_OutsideTemperatureSensorFault", "22" => "F22_HotGasTemperatureFault", "23" => "F23_CondenserTemperatureSensorFault", "24" => "F24_EvaporatorTemperatureSensorFault", "26" => "F26_ReturnTemperatureSensorFault", "28" => "F28_FlowTemperatureSensorFault", "29" => "F29_DHW_TemperatureSensorFault", "30" => "F30_SoftwareVersionFault", "31" => "F31_RAMfault", "32" => "F32_EEPromFault", "33" => "F33_ExtractAirHumiditySensor", "34" => "F34_FlowSensor", "35" => "F35_minFlowCooling", "36" => "F36_MinFlowRate", "37" => "F37_MinWaterPressure", "40" => "F40_FloatSwitch", "50" => "F50_SensorHeatPumpReturn", "51" => "F51_SensorHeatPumpFlow", "52" => "F52_SensorCondenserOutlet" );
  812. my $firstLoadAll= 0;
  813. my $noanswerreceived= 0;
  814. my $internalHash;
  815. ########################################################################################
  816. #
  817. # THZ_Initialize($)
  818. #
  819. # Parameter hash
  820. #
  821. ########################################################################################
  822. sub THZ_Initialize($) {
  823. my ($hash) = @_;
  824. require "$attr{global}{modpath}/FHEM/DevIo.pm";
  825. # Provider
  826. $hash->{ReadFn} = "THZ_Read";
  827. $hash->{WriteFn} = "THZ_Write";
  828. $hash->{ReadyFn} = "THZ_Ready";
  829. # Normal devices
  830. $hash->{DefFn} = "THZ_Define";
  831. $hash->{UndefFn} = "THZ_Undef";
  832. $hash->{GetFn} = "THZ_Get";
  833. $hash->{SetFn} = "THZ_Set";
  834. $hash->{AttrFn} = "THZ_Attr";
  835. $hash->{FW_detailFn} ="THZ_detailFn";
  836. $hash->{AttrList}= "IODev do_not_notify:1,0 ignore:0,1 dummy:1,0 showtime:1,0 "
  837. ."interval_sGlobal:0,60,120,180,300,600,3600,7200,43200,86400 "
  838. ."interval_sSol:0,60,120,180,300,600,3600,7200,43200,86400 "
  839. ."interval_sDHW:0,60,120,180,300,600,3600,7200,43200,86400 "
  840. ."interval_sHC1:0,60,120,180,300,600,3600,7200,43200,86400 "
  841. ."interval_sHC2:0,60,120,180,300,600,3600,7200,43200,86400 "
  842. ."interval_sHistory:0,3600,7200,28800,43200,86400 "
  843. ."interval_sLast10errors:0,3600,7200,28800,43200,86400 "
  844. ."interval_sHeatRecoveredDay:0,1200,3600,7200,28800,43200,86400 "
  845. ."interval_sHeatRecoveredTotal:0,3600,7200,28800,43200,86400 "
  846. ."interval_sHeatDHWDay:0,1200,3600,7200,28800,43200,86400 "
  847. ."interval_sHeatDHWTotal:0,3600,7200,28800,43200,86400 "
  848. ."interval_sHeatHCDay:0,1200,3600,7200,28800,43200,86400 "
  849. ."interval_sHeatHCTotal:0,3600,7200,28800,43200,86400 "
  850. ."interval_sElectrDHWDay:0,1200,3600,7200,28800,43200,86400 "
  851. ."interval_sElectrDHWTotal:0,3600,7200,28800,43200,86400 "
  852. ."interval_sElectrHCDay:0,1200,3600,7200,28800,43200,86400 "
  853. ."interval_sElectrHCTotal:0,3600,7200,28800,43200,86400 "
  854. ."interval_sBoostDHWTotal:0,3600,7200,28800,43200,86400 "
  855. ."interval_sBoostHCTotal:0,3600,7200,28800,43200,86400 "
  856. ."interval_sFlowRate:0,3600,7200,28800,43200,86400 "
  857. ."interval_sDisplay:0,60,120,180,300 "
  858. ."firmware:4.39,2.06,2.14,5.39,4.39technician "
  859. ."interval_sDewPointHC1:0,60,120,180,300 "
  860. ."simpleReadTimeout:0.25,0.5,1,2,3,4,5,6,7,8,9,10 " #standard has been 0.5 since msg468515 If blocking attribut is NOT enabled then set the timeout value to a maximum value of 0.5 sec.
  861. ."nonblocking:0,1 "
  862. . $readingFnAttributes;
  863. $data{FWEXT}{"/THZ_PrintcurveSVG"}{FUNC} = "THZ_PrintcurveSVG";
  864. }
  865. ########################################################################################
  866. #
  867. # THZ_define
  868. #
  869. # Parameter hash and configuration
  870. #
  871. ########################################################################################
  872. sub THZ_Define($$) {
  873. my ($hash, $def) = @_;
  874. my @a = split("[ \t][ \t]*", $def);
  875. my $name = $a[0];
  876. $hash->{VERSION} = $thzversion;
  877. return "wrong syntax. Correct is: define <name> THZ ".
  878. "{devicename[\@baudrate]|ip:port}"
  879. if(@a != 3);
  880. DevIo_CloseDev($hash);
  881. my $dev = $a[2];
  882. if($dev eq "none") {
  883. Log3 $name, 2, "$name device is none, commands will be echoed only";
  884. $attr{$name}{dummy} = 1;
  885. return undef;
  886. }
  887. $hash->{DeviceName} = $dev;
  888. $attr{$name}{devStateIcon} = 'opened:10px-kreis-gruen disconnected:10px-kreis-rot';
  889. my $ret = DevIo_OpenDev($hash, 0, "THZ_Refresh_all_gets");
  890. #THZ_Testloopapproach($hash);
  891. return $ret;
  892. }
  893. ########################################################################################
  894. #
  895. # THZ_Refresh_all_gets - Called once refreshes current reading for all gets and initializes the regular interval calls
  896. #
  897. # Parameter $hash
  898. #
  899. ########################################################################################
  900. sub THZ_Refresh_all_gets($) {
  901. my ($hash) = @_;
  902. RemoveInternalTimer(0, "THZ_GetRefresh");
  903. #THZ_RemoveInternalTimer("THZ_GetRefresh"); not needed since https://svn.fhem.de/trac/changeset/15667/ because now there is a second parameter for the function
  904. Log3 $hash->{NAME}, 5, "thzversion = $thzversion ";
  905. my $timedelay= 15; #5 seconds were ok but considering winter 2017/2018 I prefer to increase
  906. foreach my $cmdhash (keys %gets) {
  907. my %par = ( hash => $hash, command => $cmdhash );
  908. #RemoveInternalTimer(\%par); #commented out in v.0161 because appearently redundant; THZ_RemoveInternalTimer is more efficient and both are not needed
  909. InternalTimer(gettimeofday() + ($timedelay) , "THZ_GetRefresh", \%par, 0); #increment 0.6 $timedelay++
  910. $timedelay += 1.6; #0.6 seconds were ok but considering winter 2017/2018 I prefer to increase
  911. } #refresh all registers; the register with interval_command ne 0 will keep on refreshing
  912. }
  913. ########################################################################################
  914. #
  915. # THZ_GetRefresh - Called in regular intervals to obtain current reading
  916. #
  917. # Parameter (hash => $hash, command => "allFB" )
  918. # it get the intervall directly from a attribute; the register with interval_command ne 0 will keep on refreshing
  919. ########################################################################################
  920. sub THZ_GetRefresh($) {
  921. my ($par)=@_;
  922. my $hash=$par->{hash};
  923. my $command=$par->{command};
  924. my $name =$hash->{NAME};
  925. my $interval = AttrVal($name, ("interval_".$command), 0);
  926. if (AttrVal($name, "nonblocking" , "0") =~ /1/ ) {
  927. if (!(exists($hash->{helper}{RUNNING_PID}))) {
  928. DevIo_CloseDev($hash); #close device in parent process
  929. #$hash->{STATE}="disconnected";
  930. my $bctimeout = (AttrVal($name, "simpleReadTimeout", "0.5"))*2 +1;
  931. my $dev = $hash->{DeviceName};
  932. #$hash->{connection} =$hash->{STATE} ."||". $hash->{USBDev} ."||". $hash->{TCPDev} ."||". $hash->{conn} ."||". $hash->{FD} ."||". $selectlist{"$name.$dev"} ;
  933. $hash->{connection} =$hash->{STATE} ."||". $hash->{TCPDev} ."||". $hash->{FD} ."||". $selectlist{"$name.$dev"} ;
  934. Log3 $hash, 3, $hash->{connection};
  935. $hash->{helper}{RUNNING_PID} = BlockingCall("THZ_GetNB", $name."|".$command, "THZ_GetNBDone", $bctimeout, "THZ_GetNBAbort", $hash);
  936. Log3 $hash, 3, "[$name] THZ_GetRefresh($command) BlockingCall started";
  937. }
  938. else {
  939. Log3 $hash, 3, "[$name] THZ_GetRefresh($command) rescheduled (Blocking Call is still running)";
  940. InternalTimer(gettimeofday() + 2, "THZ_GetRefresh", $par, 1);
  941. return;
  942. }
  943. }
  944. else {
  945. THZ_Get($hash, $hash->{NAME}, $command) if ($hash->{STATE} ne "disconnected");
  946. }
  947. if ($interval) {
  948. $interval = 60 if ($interval < 60); #do not allow intervall <60 sec
  949. InternalTimer(gettimeofday()+ $interval, "THZ_GetRefresh", $par, 1) ;
  950. }
  951. if ($command =~ "sFirmware") { # model summary for statistics
  952. my $sFirmwareId = join('', (split(/ |:/, ReadingsVal($name,"sFirmware-Id"," : : : ")))[0..6]);
  953. my $sFirmware= (split(/ /, ReadingsVal($name,"sFirmware"," ")))[1];
  954. $hash->{model}= sprintf("%.5s%s%s", AttrVal($name,"firmware","n.a.")."______", $sFirmware, $sFirmwareId);
  955. }
  956. return;
  957. }
  958. #####################################
  959. # THZ_Write -- simple write
  960. # Parameter: hash and message HEX
  961. #
  962. ########################################################################################
  963. sub THZ_Write($$) {
  964. my ($hash,$bstring) = @_;
  965. my $name = $hash->{NAME};
  966. Log3 $hash->{NAME}, 5, "$hash->{NAME} sending $bstring";
  967. DevIo_SimpleWrite($hash, $bstring, 1);
  968. }
  969. #####################################
  970. # sub THZ_Read($)
  971. # called from the global loop, when the select for hash reports data
  972. # used just for testing the interface
  973. ########################################################################################
  974. sub THZ_Read($) {
  975. my ($hash) = @_;
  976. my $buf = DevIo_SimpleRead($hash);
  977. return "" if(!defined($buf));
  978. my $name = $hash->{NAME};
  979. $hash->{helper}{PARTIAL} .= uc(unpack('H*', $buf));
  980. my $msg=$hash->{helper}{PARTIAL};
  981. my $err;
  982. if ( !defined($hash->{helper}{step}) or (length($msg) == 1) or (($msg =~ m/^01/) and ($msg !~ m/1003$/m ))) {}
  983. else {
  984. if ($hash->{helper}{step} eq "step0") { #Expectedanswer0 is "10" DLE data link escape
  985. if ($msg ne "10") {$err .= " THZ_Get_Com: error found at step0 $msg"; $err .=" NAK!!" if ($msg eq "15"); THZ_Resethelper($hash);}
  986. else { THZ_Write($hash, $hash->{helper}{cmdHex}); $hash->{helper}{step}="step1"; $hash->{helper}{PARTIAL}=""; }
  987. }
  988. elsif ($hash->{helper}{step} eq "step1") { #Expectedanswer1 is "1002", DLE data link escape -- STX start of text
  989. if ($msg eq "10") { }
  990. elsif ($msg eq "15") { $err .= " THZ_Get_Com: error found at step1 NAK!! "; THZ_Resethelper($hash); }
  991. elsif ($msg eq "1002" || $msg eq "02") {THZ_Write($hash, "10"); $hash->{helper}{step}="step2"; $hash->{helper}{PARTIAL}=""; }
  992. }
  993. elsif ($hash->{helper}{step} eq "step2") { #Expectedanswer2 is message from the heatpump
  994. ($err, $msg) = THZ_decode($msg);
  995. $msg.=THZ_Parse1($hash,$msg);
  996. THZ_Write($hash, "10");
  997. #THZ_Resethelper($hash);
  998. }
  999. }
  1000. Log3 $name, 3, "$name/RAW: $msg - $err - $hash->{helper}{step}";
  1001. }
  1002. #####################################
  1003. #
  1004. # THZ_Resethelper()
  1005. #
  1006. # Parameter hash
  1007. #
  1008. ########################################################################################
  1009. sub THZ_Resethelper($) {
  1010. my ($hash) = @_;
  1011. $hash->{helper}{step}="";
  1012. $hash->{helper}{cmdHex}="";
  1013. $hash->{helper}{PARTIAL}="";
  1014. }
  1015. sub THZ_Testloopapproach($) {
  1016. my ($hash) = @_;
  1017. my $cmd="sGlobal";
  1018. #my $cmd="sHC1";
  1019. my $cmdhash = $gets{$cmd};
  1020. THZ_Write($hash, "02");
  1021. $hash->{helper}{step}="step0";
  1022. $hash->{helper}{cmdHex}=THZ_encodecommand($cmdhash->{cmd2},"get");
  1023. $hash->{helper}{PARTIAL}="";
  1024. }
  1025. sub THZ_testtimer($) {
  1026. my ($hash) = @_;
  1027. my $counter=1;
  1028. my $stringa = ("starttest \n");
  1029. foreach my $a (keys %intAt)
  1030. {
  1031. if ($intAt{$a}{FN} eq "THZ_GetRefresh")
  1032. {
  1033. $stringa = $stringa . ("timer ". $counter ." ARG". $intAt{$a}{ARG} ."fn " . $intAt{$a}{FN} ."\n") ;
  1034. $counter+=1;
  1035. }
  1036. }
  1037. Log3 $hash->{NAME}, 5, $stringa;
  1038. }
  1039. #####################################
  1040. #
  1041. # THZ_Ready($) - Cchecks the status
  1042. #
  1043. # Parameter hash
  1044. #
  1045. ########################################################################################
  1046. sub THZ_Ready($) {
  1047. my ($hash) = @_;
  1048. if($hash->{STATE} eq "disconnected")
  1049. { RemoveInternalTimer(0, "THZ_GetRefresh");
  1050. #THZ_testtimer($hash);
  1051. #THZ_RemoveInternalTimer("THZ_GetRefresh");
  1052. select(undef, undef, undef, 0.25); #equivalent to sleep 250ms
  1053. return DevIo_OpenDev($hash, 1, "THZ_Refresh_all_gets")
  1054. }
  1055. # This is relevant for windows/USB only
  1056. my $po = $hash->{USBDev};
  1057. if($po) {
  1058. my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
  1059. return ($InBytes>0);
  1060. }
  1061. }
  1062. #####################################
  1063. #
  1064. # THZ_Set - provides a method for setting the heatpump
  1065. #
  1066. # Parameters: hash and command to be sent to the interface
  1067. #
  1068. ########################################################################################
  1069. sub THZ_Set($@){
  1070. my ($hash, @a) = @_;
  1071. my $dev = $hash->{DeviceName};
  1072. my $name = $hash->{NAME};
  1073. return "\"set $name\" needs at least two parameters: <device-parameter> and <value-to-be-modified>" if(@a < 2);
  1074. my $cmd = $a[1];
  1075. my $arg = $a[2];
  1076. my $arg1 = "00:00";
  1077. my ($err, $msg) =("", " ");
  1078. my $cmdhash = $sets{$cmd};
  1079. #return "Unknown argument $cmd, choose one of " . join(" ", sort keys %sets) if(!defined($cmdhash));
  1080. if(!defined($cmdhash)) {
  1081. my $setList;
  1082. foreach my $key (sort keys %sets) {
  1083. my $value = $sets{$key};
  1084. $setList .= $key;
  1085. #if (($value->{type} eq "0clean" or $value->{type} eq "1clean") and $value->{unit} eq "") {
  1086. if ($value->{type} =~ /clean/ ) {
  1087. #if (($value->{argMax} - $value->{argMin})<2 ) {$setList .= ":uzsuToggle," . join (",", ($value->{argMin} .. $value->{argMax})) . " ";}
  1088. if (($value->{argMax} - $value->{argMin})<13 ) {$setList .= ":uzsuSelectRadio," . join (",", ($value->{argMin} .. $value->{argMax})) . " ";}
  1089. else {$setList .= ":textField ";}
  1090. #else {$setList .= ":slider,$value->{argMin},1,$value->{argMax} ";}
  1091. #else {$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:1 " ;}
  1092. }
  1093. elsif ($value->{type} eq "2opmode"){
  1094. $setList .= ":" . join (",", (sort {lc $a cmp lc $b} values %OpMode)) . " ";
  1095. #$setList .= ":uzsuSelectRadio," . join (",", (sort {lc $a cmp lc $b} values %OpMode)) . " ";
  1096. #attr Mythz widgetOverride pOpMode:uzsuDropDown,automatic,standby
  1097. }
  1098. #elsif ($value->{type} eq "9holy"){
  1099. #$setList .= ":time ";
  1100. # $setList .= ":textField ";
  1101. # }
  1102. #elsif ($value->{type} eq "5temp") {
  1103. # $setList .= ":slider,$value->{argMin},0.1,$value->{argMax},1 " ;
  1104. #$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:0.1 " ;
  1105. #$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:0.1,angleOffset:-125,angleArc:250 "
  1106. #attr Mythz widgetOverride p01RoomTempDayHC1:knob,min:22,max:26,step:0.1,angleOffset:-125,angleArc:250
  1107. #attr Mythz widgetOverride p01RoomTempDayHC1:slider,$value->{argMin},0.1,$value->{argMax}
  1108. #attr Mythz widgetOverride p01RoomTempDayHC1:uzsuDropDown,21,29
  1109. #attr Mythz widgetOverride p01RoomTempDayHC1:uzsuSelectRadio,44,234,21
  1110. # }
  1111. #elsif ($value->{type} eq "6gradient") {
  1112. # $setList .= ":slider,$value->{argMin},0.01,$value->{argMax},1 " ;
  1113. #$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:0.01 " ;
  1114. # }
  1115. else {
  1116. #$setList .= ":textField ";
  1117. $setList .= " ";
  1118. }
  1119. }
  1120. return "Unknown argument $cmd, choose one of $setList";
  1121. }
  1122. return "\"set $name $cmd\" needs at least one further argument: <value-to-be-modified>" if(!defined($arg));
  1123. my $cmdHex2 = $cmdhash->{cmd2};
  1124. my $argMax = $cmdhash->{argMax};
  1125. my $argMin = $cmdhash->{argMin};
  1126. #-- check the parameter range
  1127. if ($cmdhash->{type} =~ /ptime/) {
  1128. $arg1=undef;
  1129. return "Argument does not match the allowed inerval Min $argMin ...... Max $argMax " if (($arg ne "n.a.") and ($arg !~ /^(?:\d|[01]\d|2[0-3]):[0-5]\d$/ )) ;
  1130. }
  1131. elsif ($cmdhash->{type} =~ /7prog|8party/) {
  1132. ($arg, $arg1)=split('--', $arg);
  1133. return "Argument does not match the allowed inerval Min $argMin ...... Max $argMax " if (($arg ne "n.a.") and ($arg1 ne "n.a.") and (($arg !~ /^(?:\d|[01]\d|2[0-3]):[0-5]\d$/ ) or ($arg1 !~ /^(?:\d|[01]\d|2[0-3]):[0-5]\d$/ )) ) ;
  1134. }
  1135. elsif ($cmdhash->{type} eq "2opmode") {
  1136. $arg1=undef;
  1137. $arg=$Rev_OpMode{$arg};
  1138. return "Unknown argument $arg1: $cmd supports " . join(" ", sort values %OpMode) if(!defined($arg));
  1139. }
  1140. else {
  1141. $arg1=undef;
  1142. return "Argument does not match the allowed inerval Min $argMin ...... Max $argMax " if(($arg > $argMax) or ($arg < $argMin));
  1143. }
  1144. #--
  1145. my $i=0; my $parsingrule;
  1146. THZ_AvoidCollisions($hash);
  1147. my $parent = $cmdhash->{parent};
  1148. #if I have a father read from it: important for older firmwares
  1149. if(defined($parent) ) {
  1150. my $parenthash=$gets{$parent};
  1151. $cmdHex2 = $parenthash->{cmd2}; #overwrite $cmdHex2 with the parent
  1152. Log3 $hash->{NAME}, 5, "searching for parent; parenthash= $parenthash, parent = $parent, cmdHex2 = $cmdHex2 ";
  1153. $cmdHex2=THZ_encodecommand($cmdHex2, "get"); #read before write the register
  1154. ($err, $msg) = THZ_Get_Comunication($hash, $cmdHex2);
  1155. if (defined($err)) {
  1156. Log3 $hash->{NAME}, 3, "THZ_Set: error reading register: '$err'";
  1157. return ($msg ."\n msg " . $err);
  1158. }
  1159. substr($msg, 0, 2, ""); #remove the checksum from the head of the payload
  1160. Log3 $hash->{NAME}, 5, "read before write from THZ: $msg";
  1161. #--
  1162. $parsingrule = $parsinghash{$parenthash->{type}};
  1163. for (@$parsingrule) {
  1164. last if ((@$parsingrule[$i]->[0]) =~ m/$cmd/);
  1165. $i++;
  1166. }
  1167. select(undef, undef, undef, 0.25);
  1168. }
  1169. else {
  1170. $msg = $cmdHex2 . "0000";
  1171. my $msgtype =$cmdhash->{type};
  1172. $parsingrule = $parsinghash{$msgtype} if(defined($msgtype));
  1173. }
  1174. my $pos = @$parsingrule[$i]->[1] -2; #I removed the checksum
  1175. my $len = @$parsingrule[$i]->[2];
  1176. my $parsingtype = @$parsingrule[$i]->[3];
  1177. my $dec = @$parsingrule[$i]->[4];
  1178. Log3 $hash->{NAME}, 5, "write command (parsed element/pos/len/dec/parsingtype): $i / $pos / $len / $dec / $parsingtype";
  1179. $arg *= $dec if ($dec != 1);
  1180. $arg = time2quaters($arg) if ($parsingtype eq "quater");
  1181. $arg= join('', (split(':', $arg))) if ($parsingtype eq "hex2time"); # only in firmware 2.x
  1182. #$arg= eval(join('*100+', (split(':', $arg)))) if ($parsingtype eq "hex2time"); #just in case the above does not work
  1183. $arg=(hex(substr($msg, $pos, 1)) & (15-2**$1)) | (2**$1*$arg) if ($parsingtype =~ /bit(\d)/);
  1184. $arg = substr((sprintf(("%0".$len."X"), $arg)), (-1*$len)); #04X converts to hex and fills up 0s; for negative, it must be trunckated.
  1185. substr($msg, $pos, $len, $arg);
  1186. if (defined($arg1)) { #only in case of "8party" or "7prog"
  1187. $arg1 = time2quaters($arg1);
  1188. $arg1 = substr((sprintf(("%02X"), $arg1)), -2);
  1189. $pos = @$parsingrule[($i+1)]->[1] -2;
  1190. substr($msg, $pos, $len, $arg1);
  1191. }
  1192. Log3 $hash->{NAME}, 5, "THZ_Set: '$cmd $arg $msg' ... Check if port is open. State = '($hash->{STATE})'";
  1193. $cmdHex2=THZ_encodecommand($msg,"set");
  1194. ($err, $msg) = THZ_Get_Comunication($hash, $cmdHex2);
  1195. #$err=undef;
  1196. if (defined($err)) {
  1197. Log3 $hash->{NAME}, 3, "THZ_Set: Error msg: $err -- $cmdHex2 -> $msg";
  1198. return($cmdHex2 . "-". $msg ."--" . $err);
  1199. }
  1200. else {
  1201. select(undef, undef, undef, 0.25);
  1202. if (defined($gets{$cmd})) {
  1203. $msg=THZ_Get($hash, $name, $cmd);
  1204. }
  1205. else {
  1206. $msg=$cmd.": OK";
  1207. }
  1208. #because of F8 reset introduced by andre topic=33211 msg695420
  1209. #take care of program of the week
  1210. if ($a[1] =~ /Mo-So/){
  1211. select(undef, undef, undef, 0.05);
  1212. $a[1] =~ s/Mo-So/Mo-Fr/; $msg.= "\n" . THZ_Set($hash, @a);
  1213. select(undef, undef, undef, 0.05);
  1214. $a[1] =~ s/Mo-Fr/Sa-So/; $msg.="\n" . THZ_Set($hash, @a);
  1215. }
  1216. elsif ($a[1] =~ /Mo-Fr/) {
  1217. select(undef, undef, undef, 0.05);
  1218. $a[1] =~ s/_Mo-Fr_/_Mo_/; $msg.="\n" . THZ_Set($hash, @a);
  1219. select(undef, undef, undef, 0.05);
  1220. $a[1] =~ s/_Mo_/_Tu_/ ; $msg.="\n" . THZ_Set($hash, @a);
  1221. select(undef, undef, undef, 0.05);
  1222. $a[1] =~ s/_Tu_/_We_/ ; $msg.="\n" . THZ_Set($hash, @a);
  1223. select(undef, undef, undef, 0.05);
  1224. $a[1] =~ s/_We_/_Th_/ ; $msg.="\n" . THZ_Set($hash, @a);
  1225. select(undef, undef, undef, 0.05);
  1226. $a[1] =~ s/_Th_/_Fr_/ ; $msg.="\n" . THZ_Set($hash, @a);
  1227. }
  1228. elsif ($a[1] =~ /Sa-So/){
  1229. select(undef, undef, undef, 0.05);
  1230. $a[1] =~ s/_Sa-So_/_Sa_/; $msg.="\n" . THZ_Set($hash, @a);
  1231. select(undef, undef, undef, 0.05);
  1232. $a[1] =~ s/_Sa_/_So_/ ; $msg.="\n" . THZ_Set($hash, @a);
  1233. }
  1234. #split _ mo-fr when [3] undefined do nothing, when mo-fr chiama gli altri
  1235. return ($msg);
  1236. }
  1237. }
  1238. ########################################################################################
  1239. #
  1240. # THZ_GetNB - NonBlocking Get parameter from heatpump
  1241. #
  1242. # Parameters: "name | command" (single string)
  1243. #
  1244. ########################################################################################
  1245. sub THZ_GetNB($){
  1246. my ($string) = @_;
  1247. my ($name, $cmd) = split("\\|", $string);
  1248. my $hash = $defs{$name};
  1249. my $dev = $hash->{DeviceName};
  1250. my $ret = DevIo_OpenDev($hash, 0, undef); #open device in child process
  1251. #($hash->{STATE}, $hash->{USBDev} , $hash->{TCPDev} , $hash->{conn} , $hash->{FD} , $selectlist{"$name.$dev"}) = split("\\|", $hash->{connection});
  1252. #($hash->{STATE}, $hash->{TCPDev} , $hash->{FD} , $selectlist{"$name.$dev"}) = split("\\|", $hash->{connection});
  1253. #$selectlist{"$name.$dev"} = $hash;
  1254. #open (MYFILE, '>>data.txt');
  1255. #print MYFILE ($hash->{connection} . "\n");
  1256. #close (MYFILE);
  1257. if (defined($ret)) {
  1258. Log3 $hash, 3, "[$name] THZ_GetNB: open device $hash->{DeviceName} error:$ret";
  1259. return ("$name|$cmd|$ret");
  1260. }
  1261. my $msg = THZ_Get($hash, $name, $cmd);
  1262. DevIo_CloseDev($hash); #close device in child process
  1263. if ($msg =~ m/\n/m) { #error message from get contains \n
  1264. return ("$name|$cmd|[ERROR]");
  1265. }
  1266. else {
  1267. return ("$name|$cmd|$msg");
  1268. }
  1269. }
  1270. ########################################################################################
  1271. #
  1272. # THZ_GetNBDone - Finish Function
  1273. #
  1274. # Parameters: "name | command | message" (single string)
  1275. #
  1276. ########################################################################################
  1277. sub THZ_GetNBDone($){
  1278. my ($string) = @_;
  1279. my ($name, $cmd, $msg) = split("\\|", $string);
  1280. my $hash = $defs{$name};
  1281. Log3 $hash, 4, "[$name] THZ_GetNBDone: $cmd - $msg";
  1282. readingsSingleUpdate($hash, $cmd, $msg, 1) if ($msg ne "[ERROR]");
  1283. delete($hash->{helper}{RUNNING_PID}) if (defined($hash->{helper}{RUNNING_PID}));
  1284. DevIo_OpenDev($hash, 1, undef); # if($hash->{STATE} ne "opened"); #reopen device for parent process
  1285. return;
  1286. }
  1287. ########################################################################################
  1288. #
  1289. # THZ_GetNBAbort - Abort Function
  1290. #
  1291. # Parameter: hash
  1292. #
  1293. ########################################################################################
  1294. sub THZ_GetNBAbort($){
  1295. my ($hash) = @_;
  1296. delete($hash->{helper}{RUNNING_PID}) if (defined($hash->{helper}{RUNNING_PID}));
  1297. DevIo_OpenDev($hash, 1, undef);# if($hash->{STATE} ne "opened"); #reopen device for parent process
  1298. Log3 $hash->{NAME}, 3, "BlockingCall for ".$hash->{NAME}." was aborted";
  1299. return;
  1300. }
  1301. ########################################################################################
  1302. #
  1303. # THZ_AvoidCollisions - prevents collisions between parent and child process is used at the beginning of THZ_Get and THZ_Set
  1304. #
  1305. # Parameter: hash
  1306. #
  1307. ########################################################################################
  1308. sub THZ_AvoidCollisions($) {
  1309. my ($hash) = @_;
  1310. # if child found, wait 0,25 second, and kill it
  1311. # maybe after 1 second child would have finished, but its THZ_GetNBDone is blocked
  1312. if (defined($hash->{helper}{RUNNING_PID})){
  1313. select(undef, undef, undef, 0.25);
  1314. BlockingKill($hash->{helper}{RUNNING_PID});
  1315. delete($hash->{helper}{RUNNING_PID});
  1316. DevIo_OpenDev($hash, 1, undef); #if($hash->{STATE} ne "opened");
  1317. #reset heatpump
  1318. THZ_Write($hash, "10");
  1319. select(undef, undef, undef, 0.1);
  1320. THZ_ReadAnswer($hash);
  1321. THZ_Write($hash, "10");
  1322. select(undef, undef, undef, 0.1);
  1323. Log3 $hash->{NAME}, 3, "Possible collision in ".$hash->{NAME}." was aborted";
  1324. }
  1325. return;
  1326. }
  1327. #####################################
  1328. #
  1329. # THZ_Get - provides a method for polling the heatpump
  1330. #
  1331. # Parameters: hash and command to be sent to the interface
  1332. #
  1333. ########################################################################################
  1334. sub THZ_Get($@) {
  1335. my ($hash, @a) = @_;
  1336. my $dev = $hash->{DeviceName};
  1337. my $name = $hash->{NAME};
  1338. return "\"get $name\" needs one parameter" if(@a != 2);
  1339. my $cmd = $a[1];
  1340. my ($err, $msg2) =("", " ");
  1341. if ($cmd eq "debug_read_raw_register_slow") {
  1342. THZ_debugread($hash);
  1343. return ("all raw registers read and saved");
  1344. }
  1345. if ($cmd eq "zBackupParameters") {
  1346. $err=THZ_backup_readings($hash);
  1347. return $err;
  1348. }
  1349. my $cmdhash = $gets{$cmd};
  1350. #return "Unknown argument $cmd, choose one of " . join(" ", sort keys %gets) if(!defined($cmdhash));
  1351. if(!defined($cmdhash)) {
  1352. my $getList;
  1353. foreach my $key (sort keys %gets) {$getList .= "$key:noArg ";}
  1354. $getList .= "zBackupParameters:noArg";
  1355. return "Unknown argument $cmd, choose one of $getList";
  1356. }
  1357. Log3 $hash->{NAME}, 5, "THZ_Get: Try to get '$cmd'";
  1358. THZ_AvoidCollisions($hash);
  1359. my $parent = $cmdhash->{parent}; #if I have a father read from it
  1360. if(defined($parent) ) {
  1361. my ($seconds, $microseconds) = gettimeofday();
  1362. $seconds= abs($seconds - time_str2num(ReadingsTimestamp($name, $parent, "1970-01-01 01:00:00")));
  1363. my $risultato=ReadingsVal($name, $parent, 0);
  1364. $risultato=THZ_Get($hash, $name, $parent) if ($seconds > 20 ); #update of the parent: if under 20sec use the current value
  1365. #$risultato=THZ_Parse1($hash,"B81700C800BE00A001C20190006402010000E601D602");
  1366. my $parenthash=$gets{$parent}; my $parsingrule = $parsinghash{$parenthash->{type}};
  1367. my $i=0;
  1368. for (@$parsingrule) {
  1369. last if ((@$parsingrule[$i]->[0]) =~ m/$cmd/);
  1370. $i++;}
  1371. $msg2=(split ' ', $risultato)[$i*2+1];
  1372. Log3 $hash->{NAME}, 5, "THZ_split: $msg2 --- $risultato";
  1373. }
  1374. else {
  1375. my $cmdHex2 = $cmdhash->{cmd2};
  1376. if(defined($cmdHex2) ) {
  1377. #empty
  1378. ($err, $msg2) = THZ_Get_Comunication($hash, THZ_encodecommand($cmdHex2,"get") );
  1379. if (defined($err)) {
  1380. Log3 $hash->{NAME}, 3, "THZ_Get: Error msg2: $err -- $cmdHex2 -> $msg2";
  1381. return ($msg2 ."\n msg2 " . $err);
  1382. }
  1383. $msg2 = THZ_Parse1($hash,$msg2);
  1384. }
  1385. my $cmdHex3 = $cmdhash->{cmd3};
  1386. if(defined($cmdHex3)) {
  1387. my $msg3= " ";
  1388. #empty
  1389. ($err, $msg3) = THZ_Get_Comunication($hash, THZ_encodecommand($cmdHex3,"get"));
  1390. if (defined($err)) {
  1391. Log3 $hash->{NAME}, 3, "THZ_Get: Error msg3: $err -- $cmdHex3 -> $msg3";
  1392. return ($msg3 ."\n msg3 " . $err);
  1393. }
  1394. $msg2 = THZ_Parse1($hash,$msg3) * 1000 + $msg2 ;
  1395. }
  1396. }
  1397. my $unit = $cmdhash->{unit};
  1398. $msg2 = $msg2 . $unit if(defined($unit)) ;
  1399. my $activatetrigger =1;
  1400. readingsSingleUpdate($hash, $cmd, $msg2, $activatetrigger);
  1401. return ($msg2);
  1402. }
  1403. #####################################
  1404. #
  1405. # THZ_Get_Comunication- provides a method for comunication called from THZ_Get or THZ_Set
  1406. #
  1407. # Parameter hash and CMD2 or 3
  1408. #
  1409. ########################################################################################
  1410. sub THZ_Get_Comunication($$) {
  1411. my ($hash, $cmdHex) = @_;
  1412. my ($err, $msg) =("", " ");
  1413. Log3 $hash->{NAME}, 5, "THZ_Get_Comunication: Check if port is open. State = '($hash->{STATE})'";
  1414. if (!(($hash->{STATE}) eq "opened")) { return("closed connection", "");}
  1415. select(undef, undef, undef, 0.001);
  1416. THZ_Write($hash, "02"); # step0 --> STX start of text
  1417. ($err, $msg) = THZ_ReadAnswer($hash);
  1418. #Expectedanswer0 is "10" DLE data link escape
  1419. if ($msg ne "10") {$err .= " THZ_Get_Com: error found at step0 $msg"; $err .=" NAK!!" if ($msg eq "15"); select(undef, undef, undef, 0.1); return($err, $msg) ;}
  1420. else {
  1421. THZ_Write($hash, $cmdHex); # step1 --> send request SOH start of heading -- Null -- ?? -- DLE data link escape -- EOT End of Text
  1422. ($err, $msg) = THZ_ReadAnswer($hash);
  1423. }
  1424. if ((defined($err))) { $err .= " THZ_Get_Com: error found at step1 "; select(undef, undef, undef, 0.1); return($err, $msg) ;}
  1425. # Expectedanswer1 is "1002", DLE data link escape -- STX start of text
  1426. if ($msg eq "10") { ($err, $msg) = THZ_ReadAnswer($hash);}
  1427. elsif ($msg eq "15") { $err .= " THZ_Get_Com: error found at step1 NAK!! "; select(undef, undef, undef, 0.1); return($err, $msg) ;}
  1428. if ($msg eq "1002" || $msg eq "02") {
  1429. THZ_Write($hash, "10"); # step2 send DLE data link escape
  1430. ($err, $msg) = THZ_ReadAnswer($hash); # Expectedanswer2 // read from the heatpump
  1431. THZ_Write($hash, "10");
  1432. }
  1433. if ((defined($err))) { $err .= " THZ_Get_Com: error found at step2"; select(undef, undef, undef, 0.1);}
  1434. else {($err, $msg) = THZ_decode($msg);} #clean up and remove footer and header
  1435. return($err, $msg) ;
  1436. }
  1437. #####################################
  1438. #
  1439. # THZ_ReadAnswer- provides a method for simple read
  1440. #
  1441. # Parameter hash and command to be sent to the interface
  1442. #
  1443. ########################################################################################
  1444. sub THZ_ReadAnswer($) {
  1445. my ($hash) = @_;
  1446. my $name = $hash->{NAME};
  1447. Log3 $hash->{NAME}, 5, "$name start Function THZ_ReadAnswer";
  1448. select(undef, undef, undef, 0.025) if( $^O =~ /Win/ ); ###delay of 25 ms for windows-OS, because SimpleReadWithTimeout does not wait
  1449. my $rtimeout = (AttrVal($name, "simpleReadTimeout", "0.5")) / 2; #added for Andre he would like to have 8/2 second.
  1450. $rtimeout = 0.5 if (AttrVal($name, "nonblocking", "0") eq 0); # set to 0.5s is nonblocking disabled
  1451. my $buf = DevIo_SimpleReadWithTimeout($hash, $rtimeout);
  1452. $buf = DevIo_SimpleReadWithTimeout($hash, $rtimeout) if(!defined($buf)) ; #added for karl msg468515
  1453. return ("THZ_ReadAnswer: InterfaceNotRespondig. Maybe too slow", "") if(!defined($buf)) ;
  1454. my $data = uc(unpack('H*', $buf));
  1455. my $count =1;
  1456. my $countmax = 60;
  1457. while (( (length($data) == 1) or (($data =~ m/^01/) and ($data !~ m/1003$/m ))) and ($count <= $countmax)){
  1458. select(undef, undef, undef, 0.005) if( $^O =~ /Win/ ); ###delay of 5 ms for windows-OS, because SimpleReadWithTimeout does not wait
  1459. my $buf1 = DevIo_SimpleReadWithTimeout($hash, 0.02);
  1460. Log3($hash->{NAME}, 5, "double read $count activated $data");
  1461. if(defined($buf1)) {
  1462. $buf .= $buf1 ;
  1463. $data = uc(unpack('H*', $buf));
  1464. Log3($hash->{NAME}, 5, "double read $count result with buf1 $data");
  1465. $count ++;
  1466. }
  1467. else{ $count += 5; }
  1468. }
  1469. return ("THZ_ReadAnswer: Interface max repeat limited to $countmax ", $data) if ($count == ($countmax +1));
  1470. Log3 $hash->{NAME}, 5, "THZ_ReadAnswer: uc unpack: '$data'";
  1471. return (undef, $data);
  1472. }
  1473. #####################################
  1474. #
  1475. # THZ_checksum - takes a string, removes the footer (4bytes) and computes checksum (without checksum of course)
  1476. #
  1477. # Parameter string
  1478. # returns the checksum 2bytes
  1479. #
  1480. ########################################################################################
  1481. sub THZ_checksum($) {
  1482. my ($stringa) = @_;
  1483. my $ml = length($stringa) - 4;
  1484. my $checksum = 0;
  1485. for(my $i = 0; $i < $ml; $i += 2) {
  1486. ($checksum= $checksum + hex(substr($stringa, $i, 2))) if ($i != 4);
  1487. }
  1488. return (sprintf("%02X", ($checksum %256)));
  1489. }
  1490. #####################################
  1491. #
  1492. # hex2int - convert from hex to int with sign 16bit
  1493. #
  1494. ########################################################################################
  1495. sub hex2int($) {
  1496. my ($num) = @_;
  1497. $num = unpack('s', pack('S', hex($num)));
  1498. return $num;
  1499. }
  1500. ####################################
  1501. #
  1502. # quaters2time - convert from hex to time; specific to the week programm registers
  1503. #
  1504. # parameter 1 byte representing number of quarter from midnight
  1505. # returns string representing time
  1506. #
  1507. # example: value 1E is converted to decimal 30 and then to a time 7:30
  1508. ########################################################################################
  1509. sub quaters2time($) {
  1510. my ($num) = @_;
  1511. return("n.a.") if($num eq "80");
  1512. my $quarters= hex($num) %4;
  1513. my $hour= (hex($num) - $quarters)/4 ;
  1514. my $time = sprintf("%02u", ($hour)) . ":" . sprintf("%02u", ($quarters*15));
  1515. return $time;
  1516. }
  1517. ####################################
  1518. #
  1519. # time2quarters - convert from time to quarters in hex; specific to the week programm registers
  1520. #
  1521. # parameter: string representing time
  1522. # returns: 1 byte representing number of quarter from midnight
  1523. #
  1524. # example: a time 7:30 is converted to decimal 30
  1525. ########################################################################################
  1526. sub time2quaters($) {
  1527. my ($stringa) = @_;
  1528. return("128") if($stringa eq "n.a.");
  1529. my ($h,$m) = split(":", $stringa);
  1530. $m = 0 if(!$m);
  1531. $h = 0 if(!$h);
  1532. my $num = $h*4 + int($m/15);
  1533. return ($num);
  1534. }
  1535. ####################################
  1536. #
  1537. # bitmap2string - convert from bitmap to concatenated string
  1538. #
  1539. # parameter: bitmap representing yes/no, hashref to stringmapping
  1540. # returns: concatenated string
  1541. #
  1542. ########################################################################################
  1543. sub bitmap2string($$) {
  1544. my($bitmap, $href) = @_;
  1545. my $idx = 1;
  1546. my $res = "";
  1547. foreach my $bit (split //, $bitmap) {
  1548. $res .= $href->{$idx} if ($bit);
  1549. $idx++;
  1550. }
  1551. return $res;
  1552. }
  1553. ####################################
  1554. #
  1555. # THZ_replacebytes - replaces bytes in string
  1556. #
  1557. # parameters: string, bytes to be searched, replacing bytes
  1558. # retunrns changed string
  1559. #
  1560. ########################################################################################
  1561. sub THZ_replacebytes($$$) {
  1562. my ($stringa, $find, $replace) = @_;
  1563. my $leng_str = length($stringa);
  1564. my $leng_find = length($find);
  1565. my $new_stringa ="";
  1566. for(my $i = 0; $i < $leng_str; $i += 2) {
  1567. if (substr($stringa, $i, $leng_find) eq $find){
  1568. $new_stringa=$new_stringa . $replace;
  1569. if ($leng_find == 4) {$i += 2;}
  1570. }
  1571. else {$new_stringa=$new_stringa . substr($stringa, $i, 2);};
  1572. }
  1573. return ($new_stringa);
  1574. }
  1575. ## usage THZ_overwritechecksum("0100XX". $cmd."1003"); not needed anymore
  1576. sub THZ_overwritechecksum($) {
  1577. my ($stringa) = @_;
  1578. my $checksumadded=substr($stringa,0,4) . THZ_checksum($stringa) . substr($stringa,6);
  1579. return($checksumadded);
  1580. }
  1581. ####################################
  1582. #
  1583. # THZ_encodecommand - creates a telegram for the heatpump with a given command
  1584. #
  1585. # usage THZ_encodecommand($cmd,"get") or THZ_encodecommand($cmd,"set");
  1586. # parameter string,
  1587. # retunrns encoded string
  1588. #
  1589. ########################################################################################
  1590. sub THZ_encodecommand($$) {
  1591. my ($cmd,$getorset) = @_;
  1592. my $header = "0100";
  1593. $header = "0180" if ($getorset eq "set"); # "set" and "get" have differnt header
  1594. my $footer ="1003";
  1595. my $checksumadded=THZ_checksum($header . "XX" . $cmd . $footer) . $cmd;
  1596. # each 2B byte must be completed by byte 18
  1597. # each 10 byte must be repeated (duplicated)
  1598. my $find = "10";
  1599. my $replace = "1010";
  1600. #$checksumadded =~ s/$find/$replace/g; #problems in 1% of the cases, in middle of a byte
  1601. $checksumadded=THZ_replacebytes($checksumadded, $find, $replace);
  1602. $find = "2B";
  1603. $replace = "2B18";
  1604. #$checksumadded =~ s/$find/$replace/g;
  1605. $checksumadded=THZ_replacebytes($checksumadded, $find, $replace);
  1606. return($header. $checksumadded .$footer);
  1607. }
  1608. ####################################
  1609. #
  1610. # THZ_decode - decodes a telegram from the heatpump -- no parsing here
  1611. #
  1612. # Each response has the same structure as request - header (four bytes), optional data and footer:
  1613. # Header: 01
  1614. # Read/Write: 00 for Read (get) response, 80 for Write (set) response; when some error occured, then device stores error code here; actually, I know only meaning of error 03 = unknown command
  1615. # Checksum: ? 1 byte - the same algorithm as for request
  1616. # Command: ? 1 byte - should match Request.Command
  1617. # Data: ? only when Read, length depends on data type
  1618. # Footer: 10 03
  1619. #
  1620. ########################################################################################
  1621. sub THZ_decode($) {
  1622. my ($message_orig) = @_;
  1623. # raw data received from device have to be de-escaped before header evaluation and data use:
  1624. my $find = "1010"; # - each sequece 10 10 must be replaced with single byte 10
  1625. my $replace = "10";
  1626. $message_orig=THZ_replacebytes($message_orig, $find, $replace);
  1627. $find = "2B18"; # - each sequece 2B 18 must be replaced with single byte 2B
  1628. $replace = "2B";
  1629. $message_orig=THZ_replacebytes($message_orig, $find, $replace);
  1630. #Check if answer is NAK
  1631. if (length($message_orig) == 2 && $message_orig eq "15") {
  1632. return("decode: NAK received from device",$message_orig);
  1633. }
  1634. #check header and if ok 0100, check checksum and return the decoded msg
  1635. my $header = substr($message_orig,0,4);
  1636. if ($header eq "0100") {
  1637. if (THZ_checksum($message_orig) eq substr($message_orig,4,2)) {
  1638. $message_orig =~ /0100(.*)1003/;
  1639. my $message = $1;
  1640. return (undef, $message);
  1641. }
  1642. else {return(THZ_checksum($message_orig) . "decode: crc_error in answer", $message_orig)};
  1643. }
  1644. if ($header eq "0101") { return ("decode: timing issue", $message_orig);}
  1645. if ($header eq "0103") { return ("decode: command not known", $message_orig);}
  1646. if ($header eq "0102") { return("decode: CRC error in request", $message_orig);}
  1647. if ($header eq "0104") { return("decode: UNKNOWN Register REQUEST", $message_orig);}
  1648. if ($header eq "0180") { return(undef, $message_orig);}
  1649. return("decode: new unknown answer " , $message_orig);
  1650. }
  1651. ###############################
  1652. #added by jakob do not know if needed
  1653. #
  1654. ###############################
  1655. local $SIG{__WARN__} = sub {
  1656. my $message = shift;
  1657. if (!defined($internalHash)) {
  1658. Log3 "Mythz", 3, "EXCEPTION in THZ: '$message'";
  1659. }
  1660. else
  1661. {
  1662. Log3 $internalHash->{NAME},3, "EXCEPTION in THZ: '$message'";
  1663. }
  1664. };
  1665. #######################################
  1666. #THZ_Parse1($) could be used in order to test an external config file; I do not know if I want it
  1667. #e.g. {THZ_Parse1(undef,"F70B000500E6")}
  1668. #######################################
  1669. sub THZ_Parse1($$) {
  1670. my ($hash,$message) = @_;
  1671. Log3 $hash->{NAME}, 5, "Parse message: $message";
  1672. my $length = length($message);
  1673. Log3 $hash->{NAME}, 5, "Message length: $length";
  1674. my $parsingcmd = substr($message,2,2);
  1675. $parsingcmd = substr($message,2,6) if (($parsingcmd =~ m/(0A|0B|0C)/) and (AttrVal($hash->{NAME}, "firmware" , "4.39") !~ /^2/) );
  1676. my $msgtype;
  1677. my $parsingrule;
  1678. my $parsingelement;
  1679. # search for the type in %gets
  1680. foreach my $cmdhash (values %gets) {
  1681. if (defined ($cmdhash->{cmd2}) and ($cmdhash->{cmd2} eq $parsingcmd))
  1682. {$msgtype = $cmdhash->{type} ;
  1683. last
  1684. }
  1685. elsif (defined ($cmdhash->{cmd3}))
  1686. { if ($cmdhash->{cmd3} eq $parsingcmd)
  1687. {$msgtype = $cmdhash->{type} ;
  1688. last
  1689. }
  1690. }
  1691. }
  1692. $parsingrule = $parsinghash{$msgtype} if(defined($msgtype));
  1693. my $ParsedMsg = $message;
  1694. if(defined($parsingrule)) {
  1695. $ParsedMsg = "";
  1696. for $parsingelement (@$parsingrule) {
  1697. my $parsingtitle = $parsingelement->[0];
  1698. my $positionInMsg = $parsingelement->[1];
  1699. my $lengthInMsg = $parsingelement->[2];
  1700. my $Type = $parsingelement->[3];
  1701. my $divisor = $parsingelement->[4];
  1702. #check if parsing out of message, and fill with zeros; the other possibility is to skip the step.
  1703. if (length($message) < ($positionInMsg + $lengthInMsg)) {
  1704. Log3 $hash->{NAME}, 3, "THZ_Parsing: offset($positionInMsg) + length($lengthInMsg) is longer then message : '$message'";
  1705. $message.= '0' x ($positionInMsg + $lengthInMsg - length($message)); # fill up with 0s to the end if needed
  1706. #Log3 $hash->{NAME},3, "after: '$message'";
  1707. }
  1708. my $value = substr($message, $positionInMsg, $lengthInMsg);
  1709. if ($Type eq "hex") {$value= hex($value);}
  1710. elsif ($Type eq "year") {$value= hex($value)+2000;}
  1711. elsif ($Type eq "hex2int") {$value= hex2int($value);}
  1712. elsif ($Type eq "turnhexdate") {$value= substr($value, 2,2) . substr($value, 0,2); $value= sprintf("%02u.%02u", hex($value)/100, hex($value)%100); }
  1713. elsif ($Type eq "hexdate") {$value= sprintf("%02u.%02u", hex($value)/100, hex($value)%100) ;}
  1714. #elsif ($Type eq "turnhex2time") {$value= sprintf(join(':', split("\\.", hex(substr($value, 2,2) . substr($value, 0,2))/100))) ;}
  1715. #elsif ($Type eq "hex2time") {$value= sprintf(join(':', split("\\.", hex(substr($value, 0,2) . substr($value, 2,2))/100))) ;}
  1716. elsif ($Type eq "turnhex2time") {$value= substr($value, 2,2) . substr($value, 0,2); $value= sprintf("%02u:%02u", hex($value)/100, hex($value)%100); }
  1717. elsif ($Type eq "hex2time") {$value= sprintf("%02u:%02u", hex($value)/100, hex($value)%100) ;}
  1718. elsif ($Type eq "swver") {$value= sprintf("%01u.%02u", hex(substr($value, 0,2)), hex(substr($value, 2,2)));}
  1719. elsif ($Type eq "hex2ascii") {$value= uc(pack('H*', $value));}
  1720. elsif ($Type eq "opmode") {$value= $OpMode{hex($value)};}
  1721. elsif ($Type eq "opmode2") {$value= $opMode2{hex($value)};}
  1722. elsif ($Type eq "opmodehc") {$value= $OpModeHC{hex($value)};}
  1723. elsif ($Type eq "esp_mant") {$value= sprintf("%.3f", unpack('f', pack( 'L', reverse(hex($value)))));}
  1724. elsif ($Type eq "somwinmode") {$value= $SomWinMode{($value)};}
  1725. #elsif ($Type eq "hex2wday") {$value= bitmap2string(unpack('b7', pack('H*',$value)), \%weekdaymap);}
  1726. elsif ($Type eq "hex2error") {$value= bitmap2string(unpack('b32', pack('H*',$value)), \%faultmap);}
  1727. elsif ($Type eq "weekday") {$value= $weekday{($value)};}
  1728. elsif ($Type eq "faultmap") {$value= $faultmap{(hex($value))};}
  1729. elsif ($Type eq "quater") {$value= quaters2time($value);}
  1730. elsif ($Type eq "bit0") {$value= (hex($value) & 0b0001) / 0b0001;}
  1731. elsif ($Type eq "bit1") {$value= (hex($value) & 0b0010) / 0b0010;}
  1732. elsif ($Type eq "bit2") {$value= (hex($value) & 0b0100) / 0b0100;}
  1733. elsif ($Type eq "bit3") {$value= (hex($value) & 0b1000) / 0b1000;}
  1734. elsif ($Type eq "nbit0") {$value= 1-((hex($value) & 0b0001) / 0b0001);}
  1735. elsif ($Type eq "nbit1") {$value= 1-((hex($value) & 0b0010) / 0b0010);}
  1736. elsif ($Type eq "raw") {;}
  1737. elsif ($Type eq "n.a.") {$value= "n.a.";}
  1738. $value = $value/$divisor if ($divisor != 1);
  1739. $ParsedMsg .= $parsingtitle . $value;
  1740. }
  1741. }
  1742. return (undef, $ParsedMsg);
  1743. }
  1744. ########################################################################################
  1745. # only for debug
  1746. #
  1747. ########################################################################################
  1748. sub THZ_debugread($){
  1749. my ($hash) = @_;
  1750. my ($err, $msg) =("", " ");
  1751. my @numbers=('01', '09', '16', 'D1', 'D2', 'E8', 'E9', 'F2', 'F3', 'F4', 'F5', 'F6', 'F8', 'FB', 'FC', 'FD', 'FE', 'FF');
  1752. #my @numbers=('FB', 'FB', 'FB', 'FB', 'FB', 'FB', 'FB', '0A05B3', '0A05B4', '0B0264', '0B0287', '0B0582', '0B0583', '0B0584', '0A0126','0A0265', '0A0597', '0A0598', '0A0599', '0A059C','0A05AD', '0A05B0', '0A05DD', '0A05DE', '0A0BA3');
  1753. #my @numbers=(1, 3, 4, 5, 8, 12, 13, 14, 15, 17, 18, 19, 20, 22, 26, 39, 40, 82, 83, 86, 87, 96, 117, 128, 239, 265, 268, 269, 270, 271, 274, 275, 278, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 297, 299, 317, 320, 354, 384, 410, 428, 440, 442, 443, 444, 445, 446, 603, 607, 612, 613, 634, 647, 650, 961, 1385, 1386, 1387, 1388, 1389, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 830, 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, 2970, 2971, 2974, 2975, 2976, 2977, 2978, 2979, 1413, 1426, 1427, 474, 1499, 757, 758, 952, 955, 1501, 1502, 374, 1553, 1554, 1555, 272, 1489, 1490, 1491, 1492, 1631, 933, 934, 1634, 928, 718, 64990, 64991, 64992, 64993, 2372, 2016, 936, 937, 938, 939, 1632, 2350, 2351, 2352, 2353, 2346, 2347, 2348, 2349, 2334, 2335, 2336, 2337, 2330, 2331, 2332, 2333, 2344, 2345, 2340, 2341, 942, 943, 944, 945, 328, 2029, 2030, 2031, 2032, 2033);
  1754. #my @numbers=(1, 3, 12, 13, 14, 15, 19, 20, 22, 26, 39, 82, 83, 86, 87, 96, 239, 265, 268, 274, 278, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 320, 354, 384, 410, 428, 440, 442, 443, 444, 445, 446, 613, 634, 961, 1388, 1389, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 2970, 2971, 2975, 2976, 2977, 2978, 2979, 474, 1499, 757, 758, 952, 955, 1501, 1502, 374, 1553, 1554, 272, 1489, 1491, 1492, 1631, 718, 64990, 64991, 64992, 64993, 2372, 2016, 936, 937, 938, 939, 1632, 2350, 2351, 2352, 2353, 2346, 2347, 2348, 2349, 2334, 2335, 2336, 2337, 2330, 2331, 2332, 2333, 2344, 2345, 2340, 2341, 942, 943, 944, 945, 328, );
  1755. # my @numbers=(239, 410, 603, 607, 634, 830, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1467, 1468, 1469, 1478, 1479, 1480, 1481, 2970, 2971, 2974, 2975, 2976, 2977, 2978, 2979, 1413, 1426, 1427, 474, 1501, 1502, 374, 1631, 718, 2372, 328);
  1756. #my @numbers = (1..256);
  1757. #my @numbers = (1..65535);
  1758. # my @numbers = (1..3179);
  1759. my $indice= "FF";
  1760. unlink("data.txt"); #delete debuglog
  1761. #my $i=0;
  1762. foreach $indice(@numbers) {
  1763. # $i=$i+1;
  1764. #my $cmd = sprintf("%02X", $indice);
  1765. # my $cmd = sprintf("%04X", $indice);
  1766. #my $cmd = "0A" . sprintf("%04X", $indice);
  1767. my $cmd = $indice;
  1768. my $cmdHex2 = THZ_encodecommand($cmd,"get");
  1769. #($err, $msg) = THZ_Get_Comunication($hash, $cmdHex2);
  1770. #STX start of text
  1771. THZ_Write($hash, "02");
  1772. ($err, $msg) = THZ_ReadAnswer($hash);
  1773. #select(undef, undef, undef, (0.05*$i));
  1774. #if you wait here more than 600ms connection dropped
  1775. # send request
  1776. THZ_Write($hash, $cmdHex2);
  1777. #select(undef, undef, undef, (0.05*$i));
  1778. ($err, $msg) = THZ_ReadAnswer($hash);
  1779. #expected 1002; if not following if takes care
  1780. if ($msg eq "10") {
  1781. select(undef, undef, undef, 0.01);
  1782. ($err, $msg) = THZ_ReadAnswer($hash);
  1783. }
  1784. # ack datatranfer and read from the heatpump
  1785. select(undef, undef, undef, 0.015);
  1786. THZ_Write($hash, "10");
  1787. select(undef, undef, undef, 0.001);
  1788. ($err, $msg) = THZ_ReadAnswer($hash);
  1789. THZ_Write($hash, "10");
  1790. if (defined($err)) {return ($msg ."\n" . $err);}
  1791. else { #clean up and remove footer and header
  1792. ($err, $msg) = THZ_decode($msg);
  1793. if (defined($err)) {
  1794. $msg = THZ_Parse1($hash,$msg);
  1795. $msg=$cmdHex2 ."-". $msg ."-". $err;}
  1796. my $activatetrigger =1;
  1797. # readingsSingleUpdate($hash, $cmd, $msg, $activatetrigger);
  1798. open (MYFILE, '>>data.txt');
  1799. print MYFILE ($cmdHex2 ."-". $cmd . "-" . $msg . "\n");
  1800. close (MYFILE);
  1801. #Log3 $hash->{NAME}, 3, "$cmd - $msg";
  1802. }
  1803. select(undef, undef, undef, 0.2);
  1804. }
  1805. }
  1806. #######################################
  1807. #THZ_Attr($)
  1808. #in case of change of attribute starting with interval_ refresh all
  1809. ########################################################################################
  1810. sub THZ_Attr(@) {
  1811. my ($cmd, $name, $attrName, $attrVal) = @_;
  1812. my $hash = $defs{$name};
  1813. $attrVal = "4.39" if (($cmd eq "del") and ($attrName eq "firmware"));
  1814. if ( $attrName eq "firmware" ) {
  1815. if ($attrVal eq "2.06") {
  1816. %sets = %sets206;
  1817. %gets = (%getsonly2xx, %getsonly206, %sets);
  1818. THZ_Refresh_all_gets($hash);
  1819. }
  1820. elsif ($attrVal eq "2.14") {
  1821. %sets = (%sets206, %setsonly214);
  1822. %gets = (%getsonly2xx, %getsonly214, %sets206);
  1823. THZ_Refresh_all_gets($hash);
  1824. }
  1825. elsif ($attrVal eq "5.39") {
  1826. %sets=(%sets439539common, %sets539only);
  1827. %gets=(%getsonly539, %sets);
  1828. THZ_Refresh_all_gets($hash);
  1829. }
  1830. elsif ($attrVal eq "4.39technician") {
  1831. %sets=(%sets439539common, %sets439only, %sets439technician);
  1832. %gets=(%getsonly439, %sets);
  1833. THZ_Refresh_all_gets($hash);
  1834. }
  1835. else { #in all other cases I assume $attrVal eq "4.39" cambiato nella v0140
  1836. %sets=(%sets439539common, %sets439only);
  1837. %gets=(%getsonly439, %sets);
  1838. THZ_Refresh_all_gets($hash);
  1839. }
  1840. }
  1841. if( $attrName =~ /^interval_/ ) {
  1842. #DevIo_CloseDev($hash);
  1843. #sleep 1;
  1844. #DevIo_OpenDev($hash, 1, "THZ_Refresh_all_gets");
  1845. THZ_Refresh_all_gets($hash);
  1846. }
  1847. return undef;
  1848. }
  1849. #####################################
  1850. sub THZ_Undef($$) {
  1851. my ($hash, $arg) = @_;
  1852. my $name = $hash->{NAME};
  1853. RemoveInternalTimer(0, "THZ_GetRefresh");
  1854. #THZ_RemoveInternalTimer("THZ_GetRefresh");
  1855. foreach my $d (sort keys %defs) {
  1856. if(defined($defs{$d}) &&
  1857. defined($defs{$d}{IODev}) &&
  1858. $defs{$d}{IODev} == $hash)
  1859. {
  1860. my $lev = ($reread_active ? 4 : 2);
  1861. Log3 $hash->{NAME}, $lev, "deleting port for $d";
  1862. delete $defs{$d}{IODev};
  1863. }
  1864. }
  1865. BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));
  1866. DevIo_CloseDev($hash);
  1867. return undef;
  1868. }
  1869. ##########################################
  1870. # nearest rounds to the nearrest value multiple of the first argumen
  1871. # nearest_ceil(10, 45); --> 50
  1872. # nearest_floor(10, 45); --> 40
  1873. # for all other values outside the middlevalues they take he nearest
  1874. # modified takes as an argument the function to be called, not the argument
  1875. ########################################################################################
  1876. sub nearest_ceil($$) {
  1877. my $targ = abs(shift);
  1878. my $Math1 = 0.5000000000003;
  1879. my @res = map { $targ * POSIX::floor(($_ + $Math1 * $targ) / $targ) } @_;
  1880. return wantarray ? @res : $res[0];
  1881. }
  1882. sub nearest_floor($$) {
  1883. my $targ = abs(shift);
  1884. my $Math1 = 0.5000000000003;
  1885. my @res = map { $targ * POSIX::ceil(($_ - $Math1 * $targ) / $targ) } @_;
  1886. return wantarray ? @res : $res[0];
  1887. }
  1888. ##########################################
  1889. # THZ_RemoveInternalTimer($)
  1890. # modified takes as an argument the function to be called, not the argument
  1891. ########################################################################################
  1892. #sub THZ_RemoveInternalTimer($){
  1893. # my ($callingfun) = @_;
  1894. # foreach my $a (keys %intAt) {
  1895. # delete($intAt{$a}) if($intAt{$a}{FN} eq $callingfun);
  1896. # }
  1897. #}
  1898. ################################
  1899. #
  1900. sub function_heatSetTemp($$) {
  1901. my ($start, $stop) = @_;
  1902. my ($p13GradientHC1, $p14LowEndHC1, $p15RoomInfluenceHC1);
  1903. my $pOpMode = " ";
  1904. my $devname; #normally Mythz but could be defined differently
  1905. foreach (keys %defs) {
  1906. $devname=$_;
  1907. last if(($defs{$_}{TYPE}) =~ "THZ");
  1908. }
  1909. if (AttrVal($devname, "firmware" , "4.39") =~ /^2/ ) {
  1910. ($p13GradientHC1, $p14LowEndHC1, $p15RoomInfluenceHC1) = (split ' ',ReadingsVal($devname,"pHeat1",0))[1,3,5];
  1911. }
  1912. else {
  1913. $pOpMode = ReadingsVal($devname,"pOpMode"," ");
  1914. $p13GradientHC1 = ReadingsVal($devname,"p13GradientHC1",0.4);
  1915. $p15RoomInfluenceHC1 = (split ' ',ReadingsVal($devname,"p15RoomInfluenceHC1",0))[0];
  1916. $p14LowEndHC1 = (split ' ',ReadingsVal($devname,"p14LowEndHC1",0))[0];
  1917. }
  1918. my ($heatSetTemp, $roomSetTemp, $insideTemp) = (split ' ',ReadingsVal($devname,"sHC1",0))[11,21,27];
  1919. my $outside_tempFiltered =(split ' ',ReadingsVal($devname,"sGlobal",0))[65];
  1920. if (!$roomSetTemp) {
  1921. $insideTemp=23.8 ; $roomSetTemp = 19.5; $p13GradientHC1 = 0.31; $heatSetTemp = 15; $p15RoomInfluenceHC1 = 80;
  1922. $pOpMode ="DEMO: no data";
  1923. $outside_tempFiltered = 0; $p14LowEndHC1 =0.5;
  1924. }
  1925. my $a= 0.7 + ($roomSetTemp * (1 + $p13GradientHC1 * 0.87)) + $p14LowEndHC1 + ($p15RoomInfluenceHC1 * $p13GradientHC1 * ($roomSetTemp - $insideTemp) /10);
  1926. my $a1= 0.7 + ($roomSetTemp * (1 + $p13GradientHC1 * 0.87)) + $p14LowEndHC1;
  1927. my $b= -14 * $p13GradientHC1 / $roomSetTemp;
  1928. my $c= -1 * $p13GradientHC1 /75;
  1929. my $Simul_heatSetTemp; my $Simul_heatSetTemp_simplified; my @ret;
  1930. foreach ($start..$stop) {
  1931. my $tmp =$_ * $_ * $c + $_ * $b;
  1932. $Simul_heatSetTemp = sprintf("%.1f", maxNum(5,( $tmp + $a)));
  1933. #$Simul_heatSetTemp = 8 if ($pOpMode eq "DHWmode"); # DHWmode is always at 8 grad C
  1934. $Simul_heatSetTemp_simplified = sprintf("%.1f", maxNum(5,($tmp + $a1)));
  1935. push(@ret, [$_, $Simul_heatSetTemp, $Simul_heatSetTemp_simplified]);
  1936. }
  1937. my $titlestring = 'roomSetTemp=' . $roomSetTemp . '°C p13GradientHC1=' . $p13GradientHC1 . ' p14LowEndHC1=' . $p14LowEndHC1 . 'K p15RoomInfluenceHC1=' . $p15RoomInfluenceHC1 . "% insideTemp=" . $insideTemp .'°C';
  1938. return (\@ret, $titlestring, $heatSetTemp, $outside_tempFiltered, $pOpMode);
  1939. }
  1940. #####################################
  1941. # sub THZ_PrintcurveSVG
  1942. # plots heat curve
  1943. #define wl_hr weblink htmlCode {THZ_PrintcurveSVG}
  1944. # da mettere dentro lo style per funzionare sopra svg { height:200px; width:800px;}
  1945. #define wl_hr2 weblink htmlCode <div class="SVGplot"><embed src="/fhem/THZ_PrintcurveSVG/" type="image/svg+xml" width="800" height="160" name="wl_7"/></div> <a href="/fhem?detail=wl_hr2">wl_hr2</a><br>
  1946. #####################################
  1947. sub THZ_PrintcurveSVG {
  1948. my ($ycurvevalues, $titlestring, $heatSetTemp, $outside_tempFiltered, $pOpMode) = function_heatSetTemp(-15,20);
  1949. my $v0min = minNum(15, ($ycurvevalues->[33][1]), ($ycurvevalues->[33][2]), $heatSetTemp); #lower offset than 15, if out of scale
  1950. $v0min = maxNum(5, nearest_ceil(5, $v0min)); #start only from a multiple of 5, but do not go below 5
  1951. my $vstep= 5;
  1952. $vstep= 10 if ((($ycurvevalues->[0][1])>($v0min+4*$vstep)) or (($ycurvevalues->[0][2])>($v0min+4*$vstep))); #increase step, if out of scale
  1953. my $v1=$v0min+$vstep; my $v2=$v1+$vstep; my $v3=$v2+$vstep; my $v4=$v3+$vstep;
  1954. my $ret = <<'END';
  1955. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg> <svg width="800" height="164" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
  1956. <style type="text/css"><![CDATA[
  1957. text { font-family:Times; font-size:12px; }
  1958. text.title { font-size:14px; }
  1959. text.copy { text-decoration:underline; stroke:none; fill:blue; }
  1960. text.paste { text-decoration:underline; stroke:none; fill:blue; }
  1961. polyline { stroke:black; fill:none; }
  1962. .border { stroke:black; fill:url(#gr_bg); }
  1963. .vgrid { stroke:gray; stroke-dasharray:2,6; }
  1964. .hgrid { stroke:gray; stroke-dasharray:2,6; }
  1965. .pasted { stroke:black; stroke-dasharray:1,1; }
  1966. .l0 { stroke:red; } text.l0 { stroke:none; fill:red; }
  1967. .l1 { stroke:green; } text.l1 { stroke:none; fill:green; }
  1968. .l3 { stroke:blue; } text.l3 { stroke:none; fill:blue; }
  1969. .l0dot { stroke:red; stroke-dasharray:2,4; } text.ldot { stroke:none; fill:red; }
  1970. ]]></style>
  1971. <defs>
  1972. <linearGradient id="gr_bg" x1="0%" y1="0%" x2="0%" y2="100%">
  1973. <stop offset="0%" style="stop-color:#FFFFF7; stop-opacity:1"/>
  1974. <stop offset="100%" style="stop-color:#FFFFC7; stop-opacity:1"/>
  1975. </linearGradient>
  1976. <linearGradient id="gr_0" x1="0%" y1="0%" x2="0%" y2="100%">
  1977. <stop offset="0%" style="stop-color:#f00; stop-opacity:.6"/>
  1978. <stop offset="100%" style="stop-color:#f88; stop-opacity:.4"/>
  1979. </linearGradient>
  1980. <linearGradient id="gr_1" x1="0%" y1="0%" x2="0%" y2="100%">
  1981. <stop offset="0%" style="stop-color:#291; stop-opacity:.6"/>
  1982. <stop offset="100%" style="stop-color:#8f7; stop-opacity:.4"/>
  1983. </linearGradient>
  1984. <pattern id="gr0_stripe" width="4" height="4" patternUnits="userSpaceOnUse" patternTransform="rotate(-45 2 2)">
  1985. <path d="M -1,2 l 6,0" stroke="#f00" stroke-width="0.5"/>
  1986. </pattern>
  1987. <pattern id="gr1_stripe" width="4" height="4" patternUnits="userSpaceOnUse" patternTransform="rotate(45 2 2)">
  1988. <path d="M -1,2 l 6,0" stroke="green" stroke-width="0.5"/>
  1989. </pattern>
  1990. <linearGradient id="gr0_gyr" x1="0%" y1="0%" x2="0%" y2="100%">
  1991. <stop offset="0%" style="stop-color:#f00; stop-opacity:.6"/>
  1992. <stop offset="50%" style="stop-color:#ff0; stop-opacity:.6"/>
  1993. <stop offset="100%" style="stop-color:#0f0; stop-opacity:.6"/>
  1994. </linearGradient>
  1995. </defs>
  1996. <rect x="48" y="19.2" width="704" height="121.6" rx="8" ry="8" fill="none" class="border"/>
  1997. <text x="12" y="80" text-anchor="middle" class="ylabel" transform="rotate(270,12,80)">HC1 heat SetTemp °C</text>
  1998. <text x="399" y="163.5" class="xlabel" text-anchor="middle">outside temperature filtered °C</text>
  1999. <text x="44" y="155" class="ylabel" text-anchor="middle">-15</text>
  2000. <text x="145" y="155" class="ylabel" text-anchor="middle">-10</text> <polyline points="145,19 145,140" class="hgrid"/>
  2001. <text x="246" y="155" class="ylabel" text-anchor="middle">-5</text> <polyline points="246,19 246,140" class="hgrid"/>
  2002. <text x="347" y="155" class="ylabel" text-anchor="middle">0</text> <polyline points="347,19 347,140" class="hgrid"/>
  2003. <text x="448" y="155" class="ylabel" text-anchor="middle">5</text> <polyline points="448,19 448,140" class="hgrid"/>
  2004. <text x="549" y="155" class="ylabel" text-anchor="middle">10</text> <polyline points="549,19 549,140" class="hgrid"/>
  2005. <text x="650" y="155" class="ylabel" text-anchor="middle">15</text> <polyline points="650,19 650,140" class="hgrid"/>
  2006. <text x="751" y="155" class="ylabel" text-anchor="middle">20</text> <polyline points="751,19 751,140" class="hgrid"/>
  2007. <g>
  2008. END
  2009. $ret .= '<polyline points="44,140 49,140"/> <text x="39" y="144" class="ylabel" text-anchor="end">' . $v0min . '</text>';
  2010. $ret .= '<polyline points="44,110 49,110"/> <text x="39" y="114" class="ylabel" text-anchor="end">' . $v1 . '</text>';
  2011. $ret .= '<polyline points="44,80 49,80"/> <text x="39" y="84" class="ylabel" text-anchor="end">' . $v2 . '</text>';
  2012. $ret .= '<polyline points="44,49 49,49"/> <text x="39" y="53" class="ylabel" text-anchor="end">' . $v3 . '</text>';
  2013. $ret .= '<polyline points="44,19 49,19"/> <text x="39" y="23" class="ylabel" text-anchor="end">' . $v4 . '</text>';
  2014. $ret .= '</g> <g>';
  2015. $ret .= '<polyline points="751,140 756,140"/> <text x="760" y="144" class="ylabel">'. $v0min .'</text>';
  2016. $ret .= '<polyline points="751,110 756,110"/> <text x="760" y="114" class="ylabel">'. $v1 .'</text>';
  2017. $ret .= '<polyline points="751,80 756,80"/> <text x="760" y="84" class="ylabel">' . $v2 .'</text>';
  2018. $ret .= '<polyline points="751,49 756,49"/> <text x="760" y="53" class="ylabel">' . $v3 .'</text>';
  2019. $ret .= '<polyline points="751,19 756,19"/> <text x="760" y="23" class="ylabel">' . $v4 .'</text>';
  2020. $ret .= '</g>' ."\n";
  2021. #labels ######################
  2022. $ret .= '<text line_id="line_1" x="70" y="100" class="l1"> --- heat curve with insideTemp correction</text>' ;
  2023. $ret .= '<text line_id="line_3" x="70" y="115" class="l3"> --- heat curve simplified</text>' ;
  2024. $ret .= '<text line_id="line_0" x="70" y="130" class="l0"> --- working point: ';
  2025. $ret .= 'outside_tempFiltered=' . $outside_tempFiltered . '°C heatSetTemp=' . $heatSetTemp . '°C </text>';
  2026. $ret .= '<text line_id="line_3" x="650" y="50" class="title"> -'. $pOpMode . '- </text>' ." \n" ;
  2027. #title ######################
  2028. $ret .= '<text id="svg_title" x="400" y="14.4" class="title" text-anchor="middle">';
  2029. $ret .= $titlestring .' </text>' . "\n";
  2030. #point ######################
  2031. $ret .='<polyline id="line_0" style="stroke-width:2" class="l0" points="';
  2032. my ($px,$py) = (sprintf("%.1f", (($outside_tempFiltered+15)*(750-49)/(15+20)+49)),sprintf("%.1f", (($heatSetTemp-$v4)*(140-19)/($v0min-$v4)+19)));
  2033. $ret.= ($px-3) . "," . ($py) ." " . ($px) . "," . ($py-3) ." " . ($px+3) . "," . ($py) ." " . ($px) . "," . ($py+3) ." " . ($px-3) . "," . ($py) ." " . '"/>' . "\n";
  2034. #curve with inside temperature correction ######################
  2035. $ret .='<polyline id="line_1" title="Heat Curve with insideTemp correction" style="stroke-width:1" class="l1" points="';
  2036. foreach (@{$ycurvevalues}) {
  2037. $ret.= (sprintf("%.1f", ($_->[0]+15)*(750-49)/(15+20)+49) ). "," . sprintf("%.1f", (($_->[1]-$v4)*(140-19)/($v0min-$v4)+19)) ." ";
  2038. }
  2039. $ret .= '"/> ' . "\n";
  2040. #curve without inside temperature correction ######################
  2041. $ret .='<polyline id="line_3" title="Heat Curve simplified" style="stroke-width:1" class="l3" points="';
  2042. foreach (@{$ycurvevalues}) {
  2043. $ret.= (sprintf("%.1f", ($_->[0]+15)*(750-49)/(15+20)+49) ). "," . sprintf("%.1f", (($_->[2]-$v4)*(140-19)/($v0min-$v4)+19)) ." ";
  2044. }
  2045. $ret .= '"/> ' . "\n";
  2046. $ret .= '</svg>';
  2047. my $FW_RETTYPE = "image/svg+xml";
  2048. return ($FW_RETTYPE, $ret);
  2049. }
  2050. sub THZ_detailFn(@){
  2051. my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn.
  2052. my $hash = $defs{$d}; #$d is the name of the defined device
  2053. return '<div class="SVGplot"><embed src="/fhem/THZ_PrintcurveSVG/" type="image/svg+xml" name="wl_hr22"/></div> <br>';
  2054. }
  2055. #####################################
  2056. sub THZ_backup_readings($){
  2057. my ($hash) = @_;
  2058. return "No statefile specified" if(!$attr{global}{statefile});
  2059. my $backupfile=$attr{global}{statefile};
  2060. my $t = localtime;
  2061. my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime;
  2062. $month++;
  2063. $year+=1900;
  2064. #$year+=1900 - 2000;
  2065. my $replacestr= "$hash->{NAME}-$year-$month-$mday.backup";
  2066. $backupfile=~ s/fhem.save/$replacestr/g; #saving to statefile path
  2067. if(!open(BAFH, ">$backupfile")) {
  2068. my $msg = "WriteStateFile: Cannot open $backupfile: $!";
  2069. Log3 $hash->{NAME},3, $msg;
  2070. return $msg;
  2071. }
  2072. print BAFH "#$t\n";
  2073. my $r = $hash->{READINGS};
  2074. foreach my $c (sort keys %{$r}) {
  2075. my $rd = $r->{$c};
  2076. if(($c =~ /^p[HOr0-9]/) and (defined($rd->{VAL}))) {
  2077. my $val = $rd->{VAL};
  2078. $val =~ s/;/;;/g;
  2079. $val =~ s/\n/\\\n/g;
  2080. print BAFH "set $hash->{NAME} $c $val\n";
  2081. }
  2082. }
  2083. return "$backupfile: $!" if(!close(BAFH));
  2084. return "saved Readings in $backupfile";
  2085. }
  2086. 1;
  2087. =pod
  2088. =item device
  2089. =item summary Monitors and controls Tecalor/StiebelEltron heatpumps via serial interface
  2090. =begin html
  2091. <a name="THZ"></a>
  2092. <h3>THZ</h3>
  2093. <ul>
  2094. THZ module: comunicate through serial interface RS232/USB (eg /dev/ttyxx) or through ser2net (e.g 10.0.x.x:5555) with a Tecalor/Stiebel Eltron heatpump. <br>
  2095. Tested on a THZ303/Sol (with serial speed 57600/115200@USB) and a THZ403 (with serial speed 115200) with the same Firmware 4.39. <br>
  2096. Tested on a LWZ404 (with serial speed 115200) with Firmware 5.39. <br>
  2097. Tested on fritzbox, nas-qnap, raspi and macos.<br>
  2098. Implemented: read of status parameters and read/write of configuration parameters.
  2099. A complete description can be found in the 00_THZ wiki http://www.fhemwiki.de/wiki/Tecalor_THZ_Heatpump
  2100. <br><br>
  2101. <a name="THZdefine"></a>
  2102. <b>Define</b>
  2103. <ul>
  2104. <code>define &lt;name&gt; THZ &lt;device&gt;</code> <br>
  2105. <br>
  2106. <code>device</code> can take the same parameters (@baudrate, @directio,
  2107. TCP/IP, none) like the <a href="#CULdefine">CUL</a>, e.g 57600 baud or 115200.<br>
  2108. Example:
  2109. direct connection
  2110. <ul><code>
  2111. define Mytecalor THZ /dev/ttyUSB0@115200<br>
  2112. </code></ul>
  2113. or network connection (like via ser2net)<br>
  2114. <ul><code>
  2115. define Myremotetecalor THZ 192.168.0.244:2323
  2116. </code></ul>
  2117. <br>
  2118. <ul><code>
  2119. define Mythz THZ /dev/ttyUSB0@115200 <br>
  2120. define FileLog_Mythz FileLog ./log/Mythz-%Y.log Mythz <br>
  2121. attr Mythz event-min-interval s.*:4800 <br>
  2122. attr Mythz event-on-change-reading .* <br>
  2123. attr Mythz interval_sDHW 400 <br>
  2124. attr Mythz interval_sElectrDHWDay 2400 <br>
  2125. attr Mythz interval_sElectrDHWTotal 43200 <br>
  2126. attr Mythz interval_sGlobal 400 <br>
  2127. attr Mythz interval_sHC1 400 <br>
  2128. attr Mythz interval_sHeatDHWDay 2400 <br>
  2129. attr Mythz interval_sHeatDHWTotal 43200 <br>
  2130. attr Mythz interval_sHeatRecoveredDay 2400 <br>
  2131. attr Mythz interval_sHeatRecoveredTotal 43200 <br>
  2132. attr Mythz interval_sHistory 86400 <br>
  2133. attr Mythz interval_sLast10errors 86400 <br>
  2134. attr Mythz room pompa <br>
  2135. attr FileLog_Mythz room pompa <br>
  2136. </code></ul>
  2137. <br>
  2138. If the attributes interval_XXXX are not defined (or 0 seconds), their internal polling is disabled.
  2139. <br>
  2140. This module is starting to support older firmware 2.06 or newer firmware 5.39; the following attribute adapts decoding <br>
  2141. <br>
  2142. <ul><code>
  2143. attr Mythz firmware 2.06 <br>
  2144. </code></ul>
  2145. <br>
  2146. <br>
  2147. <ul><code>
  2148. attr Mythz firmware 5.39 <br>
  2149. </code></ul>
  2150. <br>
  2151. If no attribute firmware is set, it is assumed your firmware is compatible with 4.39.
  2152. <br>
  2153. A backup function has been implemented
  2154. <ul><code>
  2155. get Mythz zBackupParameters implemented
  2156. </code></ul>
  2157. The command saves all pXXX in a backupfile with a special text format.
  2158. All (or some) parameters can be easily restored with one copy&paste from the backupfile in a telnet fhem session.
  2159. </ul>
  2160. <br>
  2161. </ul>
  2162. =end html
  2163. =begin html_DE
  2164. <a name="THZ"></a>
  2165. <h3>THZ</h3>
  2166. <ul>
  2167. THZ Modul: Kommuniziert mittels einem seriellen Interface RS232/USB (z.B. /dev/ttyxx), oder mittels ser2net (z.B. 10.0.x.x:5555) mit einer Tecalor / Stiebel
  2168. Eltron W&auml;rmepumpe. <br>
  2169. Getestet mit einer Tecalor THZ303/Sol (Serielle Geschwindigkeit 57600/115200@USB) und einer THZ403 (Serielle Geschwindigkeit 115200) mit identischer
  2170. Firmware 4.39. <br>
  2171. Getestet mit einer Stiebel LWZ404 (Serielle Geschwindigkeit 115200@USB) mit Firmware 5.39. <br>
  2172. Getestet auf FritzBox, nas-qnap, Raspberry Pi and MacOS.<br>
  2173. Dieses Modul funktioniert nicht mit &aumlterer Firmware; Gleichwohl, das "parsing" k&ouml;nnte leicht angepasst werden da die Register gut
  2174. beschrieben wurden.
  2175. https://answers.launchpad.net/heatpumpmonitor/+question/100347 <br>
  2176. Implementiert: Lesen der Statusinformation sowie Lesen und Schreiben einzelner Einstellungen.
  2177. Genauere Beschreinung des Modules --> 00_THZ wiki http://www.fhemwiki.de/wiki/Tecalor_THZ_W%C3%A4rmepumpe
  2178. <br><br>
  2179. <a name="THZdefine"></a>
  2180. <b>Define</b>
  2181. <ul>
  2182. <code>define &lt;name&gt; THZ &lt;device&gt;</code> <br>
  2183. <br>
  2184. <code>device</code> kann einige Parameter beinhalten (z.B. @baudrate, @direction,
  2185. TCP/IP, none) wie das <a href="#CULdefine">CUL</a>, z.B. 57600 baud oder 115200.<br>
  2186. Beispiel:<br>
  2187. Direkte Verbindung
  2188. <ul><code>
  2189. define Mytecalor THZ /dev/ttyUSB0@115200<br>
  2190. </code></ul>
  2191. oder vir Netzwerk (via ser2net)<br>
  2192. <ul><code>
  2193. define Myremotetecalor THZ 192.168.0.244:2323
  2194. </code></ul>
  2195. <br>
  2196. <ul><code>
  2197. define Mythz THZ /dev/ttyUSB0@115200 <br>
  2198. define FileLog_Mythz FileLog ./log/Mythz-%Y.log Mythz <br>
  2199. attr Mythz event-min-interval s.*:4800 <br>
  2200. attr Mythz event-on-change-reading .* <br>
  2201. attr Mythz interval_sDHW 400 <br>
  2202. attr Mythz interval_sElectrDHWDay 2400 <br>
  2203. attr Mythz interval_sElectrDHWTotal 43200 <br>
  2204. attr Mythz interval_sGlobal 400 <br>
  2205. attr Mythz interval_sHC1 400 <br>
  2206. attr Mythz interval_sHeatDHWDay 2400 <br>
  2207. attr Mythz interval_sHeatDHWTotal 43200 <br>
  2208. attr Mythz interval_sHeatRecoveredDay 2400 <br>
  2209. attr Mythz interval_sHeatRecoveredTotal 43200 <br>
  2210. attr Mythz interval_sHistory 86400 <br>
  2211. attr Mythz interval_sLast10errors 86400 <br>
  2212. attr Mythz room pompa <br>
  2213. attr FileLog_Mythz room pompa <br>
  2214. </code></ul>
  2215. <br>
  2216. Wenn die Attribute interval_XXXXXXX nicht definiert sind (oder 0), ist das interne Polling deaktiviert.
  2217. </ul>
  2218. <br>
  2219. </ul>
  2220. =end html_DE
  2221. =cut