00_THZ.pm 106 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029
  1. ##############################################
  2. # 00_THZ
  3. # $Id: 00_THZ.pm 13417 2017-02-15 19:44:51Z immi $
  4. # by immi 01/2017
  5. my $thzversion = "0.156";
  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. sub THZ_Read($);
  33. sub THZ_ReadAnswer($);
  34. sub THZ_Ready($);
  35. sub THZ_Write($$);
  36. sub THZ_Parse1($$);
  37. sub THZ_checksum($);
  38. sub THZ_replacebytes($$$);
  39. sub THZ_decode($);
  40. sub THZ_overwritechecksum($);
  41. sub THZ_encodecommand($$);
  42. sub hex2int($);
  43. sub quaters2time($);
  44. sub time2quaters($);
  45. sub THZ_debugread($);
  46. sub THZ_GetRefresh($);
  47. sub THZ_Refresh_all_gets($);
  48. sub THZ_Get_Comunication($$);
  49. sub THZ_PrintcurveSVG;
  50. sub THZ_RemoveInternalTimer($);
  51. sub THZ_Set($@);
  52. sub function_heatSetTemp($$);
  53. sub THZ_Get($@);
  54. ########################################################################################
  55. #
  56. # %parsinghash - known type of message structure
  57. #
  58. ########################################################################################
  59. my %parsinghash = (
  60. #msgtype => parsingrule
  61. "01pxx206" => [["p37Fanstage1AirflowInlet: ", 4, 4, "hex", 1],[" p38Fanstage2AirflowInlet: ", 8, 4, "hex", 1], [" p39Fanstage3AirflowInlet: ", 12, 4, "hex", 1],
  62. [" p40Fanstage1AirflowOutlet: ", 16, 4, "hex", 1],[" p41Fanstage2AirflowOutlet: ", 20, 4, "hex", 1], [" p42Fanstage3AirflowOutlet: ", 24, 4, "hex", 1],
  63. [" p43UnschedVent3: ", 28, 4, "hex", 1], [" p44UnschedVent2: ", 32, 4, "hex", 1], [" p45UnschedVent1: ", 36, 4, "hex", 1],
  64. [" p46UnschedVent0: ", 40, 4, "hex", 1], [" p75PassiveCooling: ", 44, 4, "hex", 1]
  65. ],
  66. "01pxx214" => [["p37Fanstage1AirflowInlet: ", 4, 2, "hex", 1],[" p38Fanstage2AirflowInlet: ", 6, 2, "hex", 1], [" p39Fanstage3AirflowInlet: ", 8, 2, "hex", 1],
  67. [" p40Fanstage1AirflowOutlet: ", 10, 2, "hex", 1],[" p41Fanstage2AirflowOutlet: ", 12, 2, "hex", 1], [" p42Fanstage3AirflowOutlet: ", 14, 2, "hex", 1],
  68. [" p43UnschedVent3: ", 16, 4, "hex", 1], [" p44UnschedVent2: ", 20, 4, "hex", 1], [" p45UnschedVent1: ", 24, 4, "hex", 1],
  69. [" p46UnschedVent0: ", 28, 4, "hex", 1], [" p75PassiveCooling: ", 32, 2, "hex", 1]
  70. ],
  71. "03pxx206" => [["UpTempLimitDefrostEvaporatorEnd: ", 4, 4, "hex", 10], [" MaxTimeDefrostEvaporator: ", 8, 4, "hex", 1], [" LimitTempCondenserElectBoost: ", 12, 4, "hex", 10],
  72. [" LimitTempCondenserDefrostTerm: ", 16, 4, "hex", 10], [" CompressorRestartDelay: ", 20, 2, "hex", 1], [" MainFanSpeed: ", 22, 2, "hex", 1]
  73. ],
  74. "04pxx206" => [["MaxDefrostDurationAAExchenger: ", 4, 2, "hex", 1], [" DefrostStartThreshold: ", 6, 4, "hex", 10], [" VolumeFlowFilterReplacement: ", 10, 4, "hex", 1]
  75. ],
  76. "05pxx206" => [["p13GradientHC1: ", 4, 4, "hex", 10], [" p14LowEndHC1: ", 8, 4, "hex", 10], [" p15RoomInfluenceHC1: ", 12, 2, "hex", 10],
  77. [" p16GradientHC2: ", 14, 4, "hex", 10], [" p17LowEndHC2: ", 18, 4, "hex", 10], [" p18RoomInfluenceHC2: ", 22, 2, "hex", 10],
  78. [" p19FlowProportionHC1: ", 24, 4, "hex", 1], [" p20FlowProportionHC2: ", 28, 4, "hex", 1], [" MaxSetHeatFlowTempHC1: ", 32, 4, "hex", 10],
  79. [" MinSetHeatFlowTempHC1: ", 36, 4, "hex", 10], [" MaxSetHeatFlowTempHC2: ", 40, 4, "hex", 10], [" MinSetHeatFlowTempHC2: ", 44, 4, "hex", 10],
  80. ],
  81. "06pxx206" => [["p21Hyst1: ", 4, 2, "hex", 10], [" p22Hyst2: ", 6, 2, "hex", 10], [" p23Hyst3: ", 8, 2, "hex", 10],
  82. [" p24Hyst4: ", 10, 2, "hex", 10], [" p25Hyst5: ", 12, 2, "hex", 10], [" p26Hyst6: ", 14, 2, "hex", 10],
  83. [" p27Hyst7: ", 16, 2, "hex", 10], [" p28Hyst8: ", 18, 2, "hex", 10], [" p29HystAsymmetry: ", 20, 2, "hex", 1],
  84. [" p30integralComponent: ", 22, 4, "hex", 1], [" p31MaxBoostStages: ", 26, 2, "hex", 1], [" MaxHeatFlowTemp: ", 28, 4, "hex", 10],
  85. [" p49SummerModeTemp: ", 32, 4, "hex", 10], [" p50SummerModeHysteresis: ", 36, 4, "hex", 10], [" p77OutTempAdjust: ", 40, 4, "hex", 1],
  86. [" p78DualModePoint: ", 44, 4, "hex2int", 10], [" p79ReHeatingDelay: ", 48, 2, "hex", 1]
  87. ],
  88. "07pxx206" => [["p32HystDHW: ", 4, 2, "hex", 10], [" p33BoosterTimeoutDHW: ", 6, 2, "hex", 1], [" p34TempLimitBoostDHW: ", 8, 4, "hex2int", 10], [" p35PasteurisationInterval: ", 12, 2, "hex", 1],
  89. [" p36MaxDurationDHWLoad: ", 14, 2, "hex", 1], [" PasteurisationTemp: ", 16, 4, "hex", 10], [" MaxBoostStagesDHW: ", 20, 2, "hex", 1],
  90. [" p84EnableDHWBuffer: ", 22, 2, "hex", 1]
  91. ],
  92. "08pxx206" => [["p80EnableSolar: ", 4, 2, "hex", 1], [" p81DiffTempSolarLoading: ", 6, 4, "hex", 10], [" p82DelayCompStartSolar: ", 10, 2, "hex", 1],
  93. [" p84DHWTempSolarMode: ", 12, 4, "hex", 10], [" HystDiffTempSolar: ", 16, 4, "hex", 10], [" CollectLimitTempSolar: ", 20, 4, "hex", 10]
  94. ],
  95. "09his" => [["compressorHeating: ", 4, 4, "hex", 1], [" compressorCooling: ", 8, 4, "hex", 1],
  96. [" compressorDHW: ", 12, 4, "hex", 1], [" boosterDHW: ", 16, 4, "hex", 1],
  97. [" boosterHeating: ", 20, 4, "hex", 1]
  98. ],
  99. "09his206" => [["operatingHours1: ", 4, 4, "hex", 1], [" operatingHours2: ", 8, 4, "hex", 1],
  100. [" heatingHours: ", 12, 4, "hex", 1], [" DHWhours: ", 16, 4, "hex", 1],
  101. [" coolingHours: ", 20, 4, "hex", 1]
  102. ],
  103. "0Apxx206" => [["p54MinPumpCycles: ", 4, 2, "hex", 1], [" p55MaxPumpCycles: ", 6, 4, "hex", 1], [" p56OutTempMaxPumpCycles: ", 10, 4, "hex", 10],
  104. [" p57OutTempMinPumpCycles: ", 14, 4, "hex", 10], [" p58SuppressTempCaptPumpStart: ", 18, 4, "hex", 1]
  105. ],
  106. "0Bpxx206" => [["pHTG1StartTime: ", 4, 4, "hex2time", 1], [" pHTG1EndTime: ", 8, 4, "hex2time", 1], [" pHTG1Weekdays: ", 12, 2, "hex2wday", 1],
  107. [" pHTG1Enable: ", 14, 2, "hex", 1], [" pHTG2StartTime: ", 16, 4, "hex2time", 1], [" pHTG2EndTime: ", 20, 4, "hex2time", 1],
  108. [" pHTG2Weekdays: ", 24, 2, "hex2wday", 1], [" pHTG2Enable: ", 26, 2, "hex", 1]
  109. ],
  110. "0Cpxx206" => [["pDHWStartTime: ", 4, 4, "hex2time", 1], [" pDHWEndTime: ", 8, 4, "hex2time", 1], [" pDHWWeekdays: ", 12, 2, "hex2wday", 1],
  111. [" pDHWEnable: ", 14, 2, "hex", 1],
  112. ],
  113. "0Dpxx206" => [["pFAN1StartTime: ", 4, 4, "hex2time", 1], [" pFAN1EndTime: ", 8, 4, "hex2time", 1], [" pFAN1Weekdays: ", 12, 2, "hex2wday", 1],
  114. [" pFAN1Enable: ", 14, 2, "hex", 1], [" pFAN2StartTime: ", 16, 4, "hex2time", 1], [" pFAN2EndTime: ", 20, 4, "hex2time", 1],
  115. [" pFAN2Weekdays: ", 24, 2, "hex2wday", 1], [" pFAN2Enable: ", 26, 2, "hex", 1]
  116. ],
  117. "0Epxx206" => [["p59RestartBeforeSetbackEnd: ", 4, 4, "hex", 1]
  118. ],
  119. "0Fpxx206" => [["pA0DurationUntilAbsenceStart: ", 4, 4, "hex", 10], [" pA0AbsenceDuration: ", 8, 4, "hex", 10], [" pA0EnableAbsenceProg: ", 12, 2, "hex", 1]
  120. ],
  121. "10pxx206" => [["p70StartDryHeat: ", 4, 2, "hex", 1], [" p71BaseTemp: ", 6, 4, "hex", 10], [" p72PeakTemp: ", 10, 4, "hex", 10],
  122. [" p73TempDuration: ", 14, 4, "hex", 1], [" p74TempIncrease: ", 18, 4, "hex", 10]
  123. ],
  124. "16sol" => [["collector_temp: ", 4, 4, "hex2int", 10], [" dhw_temp: ", 8, 4, "hex2int", 10],
  125. [" flow_temp: ", 12, 4, "hex2int", 10], [" ed_sol_pump_temp: ", 16, 4, "hex2int", 10],
  126. [" x20: ", 20, 4, "hex2int", 1], [" x24: ", 24, 4, "hex2int", 1],
  127. [" x28: ", 28, 4, "hex2int", 1], [" x32: ", 32, 2, "hex2int", 1]
  128. ],
  129. "17pxx206" => [["p01RoomTempDay: ", 4, 4, "hex", 10], [" p02RoomTempNight: ", 8, 4, "hex", 10],
  130. [" p03RoomTempStandby: ", 12, 4, "hex", 10], [" p04DHWsetTempDay: ", 16, 4, "hex", 10],
  131. [" p05DHWsetTempNight: ", 20, 4, "hex", 10], [" p06DHWsetTempStandby: ", 24, 4, "hex", 10],
  132. [" p07FanStageDay: ", 28, 2, "hex", 1], [" p08FanStageNight: ", 30, 2, "hex", 1],
  133. [" p09FanStageStandby: ", 32, 2, "hex", 1], [" p10RoomTempManual: ", 34, 4, "hex", 10],
  134. [" p11DHWsetTempManual: ", 38, 4, "hex", 10], [" p12FanStageManual: ", 42, 2, "hex", 1],
  135. ],
  136. "D1last" => [["number_of_faults: ", 4, 2, "hex", 1],
  137. [" fault0CODE: ", 8, 2, "faultmap", 1], [" fault0TIME: ", 12, 4, "turnhex2time", 1], [" fault0DATE: ", 16, 4, "turnhexdate", 1],
  138. [" fault1CODE: ", 20, 2, "faultmap", 1], [" fault1TIME: ", 24, 4, "turnhex2time", 1], [" fault1DATE: ", 28, 4, "turnhexdate", 1],
  139. [" fault2CODE: ", 32, 2, "faultmap", 1], [" fault2TIME: ", 36, 4, "turnhex2time", 1], [" fault2DATE: ", 40, 4, "turnhexdate", 1],
  140. [" fault3CODE: ", 44, 2, "faultmap", 1], [" fault3TIME: ", 48, 4, "turnhex2time", 1], [" fault3DATE: ", 52, 4, "turnhexdate", 1]
  141. ],
  142. "D1last206" => [["number_of_faults: ", 4, 2, "hex", 1],
  143. [" fault0CODE: ", 8, 4, "faultmap", 1], [" fault0TIME: ", 12, 4, "hex2time", 1], [" fault0DATE: ", 16, 4, "hexdate", 1],
  144. [" fault1CODE: ", 20, 4, "faultmap", 1], [" fault1TIME: ", 24, 4, "hex2time", 1], [" fault1DATE: ", 28, 4, "hexdate", 1],
  145. [" fault2CODE: ", 32, 4, "faultmap", 1], [" fault2TIME: ", 36, 4, "hex2time", 1], [" fault2DATE: ", 40, 4, "hexdate", 1],
  146. [" fault3CODE: ", 44, 4, "faultmap", 1], [" fault3TIME: ", 48, 4, "hex2time", 1], [" fault3DATE: ", 52, 4, "hexdate", 1]
  147. ],
  148. "EEprg206" => [["OpMode: ", 4, 2, "hex", 1], [" ProgStateHC: ", 10, 2, "opmodehc", 1], [" ProgStateDHW: ", 12, 2, "opmodehc", 1],
  149. [" ProgStateFAN: ", 14, 2, "opmodehc", 1], [" BaseTimeAP0: ", 16, 8, "hex", 1], [" StatusAP0: ", 24, 2, "hex", 1],
  150. [" StartTimeAP0: ", 26, 8, "hex", 1], [" EndTimeAP0: ", 34, 8, "hex", 1]
  151. ],
  152. "F3dhw" => [["dhw_temp: ", 4, 4, "hex2int", 10], [" outside_temp: ", 8, 4, "hex2int", 10],
  153. [" dhw_set_temp: ", 12, 4, "hex2int", 10], [" comp_block_time: ", 16, 4, "hex2int", 1],
  154. [" x20: ", 20, 4, "hex2int", 1], [" heat_block_time: ", 24, 4, "hex2int", 1],
  155. [" BoosterStage: ", 28, 2, "hex", 1], [" x30: ", 30, 4, "hex", 1],
  156. [" opMode: ", 34, 2, "opmodehc", 1], [" x36: ", 36, 4, "hex", 1]
  157. ],
  158. "F4hc1" => [["outsideTemp: ", 4, 4, "hex2int", 10], [" x08: ", 8, 4, "hex2int", 10],
  159. [" returnTemp: ", 12, 4, "hex2int", 10], [" integralHeat: ", 16, 4, "hex2int", 1],
  160. [" flowTemp: ", 20, 4, "hex2int", 10], [" heatSetTemp: ", 24, 4, "hex2int", 10],
  161. [" heatTemp: ", 28, 4, "hex2int", 10],
  162. [" seasonMode: ", 38, 2, "somwinmode", 1], #[" x40: ", 40, 4, "hex2int", 1],
  163. [" integralSwitch: ", 44, 4, "hex2int", 1], [" opMode: ", 48, 2, "opmodehc", 1],
  164. #[" x52: ", 52, 4, "hex2int", 1],
  165. [" roomSetTemp: ", 56, 4, "hex2int", 10], [" x60: ", 60, 4, "hex2int", 10],
  166. [" x64: ", 64, 4, "hex2int", 10], [" insideTempRC: ", 68, 4, "hex2int", 10],
  167. [" x72: ", 72, 4, "hex2int", 10], [" x76: ", 76, 4, "hex2int", 10],
  168. [" onHysteresisNo: ", 32, 2, "hex", 1], [" offHysteresisNo: ", 34, 2, "hex", 1],
  169. [" HCBoosterStage: ", 36, 2, "hex", 1]
  170. ],
  171. "F4hc1214" => [["outsideTemp: ", 4, 4, "hex2int", 10], [" x08: ", 8, 4, "hex2int", 10],
  172. [" returnTemp: ", 12, 4, "hex2int", 10], [" integralHeat: ", 16, 4, "hex2int", 1],
  173. [" flowTemp: ", 20, 4, "hex2int", 10], [" heatSetTemp: ", 24, 4, "hex2int", 10],
  174. [" heatTemp: ", 28, 4, "hex2int", 10],
  175. [" seasonMode: ", 38, 2, "somwinmode", 1], #[" x40: ", 40, 4, "hex2int", 1],
  176. [" integralSwitch: ", 44, 4, "hex2int", 1], [" opMode: ", 48, 2, "opmodehc", 1],
  177. #[" x52: ", 52, 4, "hex2int", 1],
  178. [" roomSetTemp: ", 62, 4, "hex2int", 10], [" x60: ", 60, 4, "hex2int", 10],
  179. [" x64: ", 64, 4, "hex2int", 10], [" insideTempRC: ", 68, 4, "hex2int", 10],
  180. [" x72: ", 72, 4, "hex2int", 10], [" x76: ", 76, 4, "hex2int", 10],
  181. [" onHysteresisNo: ", 32, 2, "hex", 1], [" offHysteresisNo: ", 34, 2, "hex", 1],
  182. [" HCBoosterStage: ", 36, 2, "hex", 1]
  183. ],
  184. "F5hc2" => [["outsideTemp: ", 4, 4, "hex2int", 10], [" returnTemp: ", 8, 4, "hex2int", 10],
  185. [" vorlaufTemp: ", 12, 4, "hex2int", 10], [" heatSetTemp: ", 16, 4, "hex2int", 10],
  186. [" heatTemp: ", 20, 4, "hex2int", 10], [" stellgroesse: ", 24, 4, "hex2int", 10],
  187. [" seasonMode: ", 30, 2, "somwinmode",1], [" opMode: ", 36, 2, "opmodehc", 1]
  188. ],
  189. "F6sys206" => [["LüfterstufeManuell: ", 30, 2, "hex", 1], [" RestlaufzeitLüfter: ", 36, 4, "hex", 1]
  190. ],
  191. "FBglob" => [["outsideTemp: ", 8, 4, "hex2int", 10], [" flowTemp: ", 12, 4, "hex2int", 10],
  192. [" returnTemp: ", 16, 4, "hex2int", 10], [" hotGasTemp: ", 20, 4, "hex2int", 10],
  193. [" dhwTemp: ", 24, 4, "hex2int", 10], [" flowTempHC2: ", 28, 4, "hex2int", 10],
  194. [" evaporatorTemp: ", 36, 4, "hex2int", 10], [" condenserTemp: ", 40, 4, "hex2int", 10],
  195. [" mixerOpen: ", 45, 1, "bit0", 1], [" mixerClosed: ", 45, 1, "bit1", 1],
  196. [" heatPipeValve: ", 45, 1, "bit2", 1], [" diverterValve: ", 45, 1, "bit3", 1],
  197. [" dhwPump: ", 44, 1, "bit0", 1], [" heatingCircuitPump: ", 44, 1, "bit1", 1],
  198. [" solarPump: ", 44, 1, "bit3", 1], [" compressor: ", 47, 1, "bit3", 1],
  199. [" boosterStage3: ", 46, 1, "bit0", 1], [" boosterStage2: ", 46, 1, "bit1", 1],
  200. [" boosterStage1: ", 46, 1, "bit2", 1], [" highPressureSensor: ", 49, 1, "nbit0", 1],
  201. [" lowPressureSensor: ", 49, 1, "nbit1", 1], [" evaporatorIceMonitor: ", 49, 1, "bit2", 1],
  202. [" signalAnode: ", 49, 1, "bit3", 1], [" evuRelease: ", 48, 1, "bit0", 1],
  203. [" ovenFireplace: ", 48, 1, "bit1", 1], [" STB: ", 48, 1, "bit2", 1],
  204. [" outputVentilatorPower: ",50, 4, "hex", 10], [" inputVentilatorPower: ", 54, 4, "hex", 10], [" mainVentilatorPower: ", 58, 4, "hex", 10],
  205. [" outputVentilatorSpeed: ",62, 4, "hex", 1], [" inputVentilatorSpeed: ", 66, 4, "hex", 1], [" mainVentilatorSpeed: ", 70, 4, "hex", 1],
  206. [" outside_tempFiltered: ",74, 4, "hex2int", 10], [" relHumidity: ", 78, 4, "hex2int", 10],
  207. [" dewPoint: ", 82, 4, "hex2int", 10],
  208. [" P_Nd: ", 86, 4, "hex2int", 100], [" P_Hd: ", 90, 4, "hex2int", 100],
  209. [" actualPower_Qc: ", 94, 8, "esp_mant", 1], [" actualPower_Pel: ", 102, 8, "esp_mant", 1],
  210. [" collectorTemp: ", 4, 4, "hex2int", 10], [" insideTemp: ", 32, 4, "hex2int", 10] #, [" x84: ", 84, 4, "donottouch", 1]
  211. ],
  212. "FBglob206" => [["outsideTemp: ", 8, 4, "hex2int", 10], [" flowTemp: ", 12, 4, "hex2int", 10],
  213. [" returnTemp: ", 16, 4, "hex2int", 10], [" hotGasTemp: ", 20, 4, "hex2int", 10],
  214. [" dhwTemp: ", 24, 4, "hex2int", 10], [" flowTempHC2: ", 28, 4, "hex2int", 10],
  215. [" evaporatorTemp: ", 36, 4, "hex2int", 10], [" condenserTemp: ", 40, 4, "hex2int", 10],
  216. [" mixerOpen: ", 47, 1, "bit1", 1], [" mixerClosed: ", 47, 1, "bit0", 1],
  217. [" heatPipeValve: ", 45, 1, "bit3", 1], [" diverterValve: ", 45, 1, "bit2", 1],
  218. [" dhwPump: ", 45, 1, "bit1", 1], [" heatingCircuitPump: ", 45, 1, "bit0", 1],
  219. [" solarPump: ", 44, 1, "bit2", 1], [" compressor: ", 44, 1, "bit0", 1],
  220. [" boosterStage3: ", 44, 1, "bit3", 1], [" boosterStage2: ", 44, 1, "n.a.", 1],
  221. [" boosterStage1: ", 44, 1, "bit1", 1], [" highPressureSensor: ", 49, 1, "n.a.", 1],
  222. [" lowPressureSensor: ", 49, 1, "n.a.", 1], [" evaporatorIceMonitor: ", 49, 1, "n.a.", 1],
  223. [" signalAnode: ", 49, 1, "n.a.", 1], [" evuRelease: ", 48, 1, "n.a.", 1],
  224. [" ovenFireplace: ", 48, 1, "n.a.", 1], [" STB: ", 48, 1, "n.a.", 1],
  225. [" outputVentilatorPower: ",48, 2, "hex", 1], [" inputVentilatorPower: ", 50, 2, "hex", 1], [" mainVentilatorPower: ", 52, 2, "hex", 1],
  226. [" outputVentilatorSpeed: ",56, 2, "hex", 1], [" inputVentilatorSpeed: ", 58, 2, "hex", 1], [" mainVentilatorSpeed: ", 60, 2, "hex", 1],
  227. [" outside_tempFiltered: ",64, 4, "hex2int", 10], [" relHumidity: ", 70, 4, "n.a.", 1],
  228. [" dewPoint: ", 5, 4, "n.a.", 1],
  229. [" P_Nd: ", 5, 4, "n.a.", 1], [" P_Hd: ", 5, 4, "n.a.", 1],
  230. [" actualPower_Qc: ", 5, 8, "n.a.", 1], [" actualPower_Pel: ", 5, 8, "n.a.", 1],
  231. [" collectorTemp: ", 4, 4, "hex2int", 10], [" insideTemp: ", 32, 4, "hex2int", 10] #, [" x84: ", 84, 4, "donottouch", 1]
  232. ],
  233. "FCtime" => [["Weekday: ", 5, 1, "weekday", 1], [" Hour: ", 6, 2, "hex", 1],
  234. [" Min: ", 8, 2, "hex", 1], [" Sec: ", 10, 2, "hex", 1],
  235. [" Date: ", 12, 2, "year", 1], ["/", 14, 2, "hex", 1],
  236. ["/", 16, 2, "hex", 1]
  237. ],
  238. "FCtime206" => [["Weekday: ", 7, 1, "weekday", 1], [" pClockHour: ", 8, 2, "hex", 1],
  239. [" pClockMinutes: ", 10, 2, "hex", 1], [" Sec: ", 12, 2, "hex", 1],
  240. [" pClockYear: ", 14, 2, "hex", 1], [" pClockMonth: ", 18, 2, "hex", 1],
  241. [" pClockDay: ", 20, 2, "hex", 1]
  242. ],
  243. "FDfirm" => [["version: ", 4, 4, "hexdate", 1]
  244. ],
  245. "FEfirmId" => [[" HW: ", 30, 2, "hex", 1], [" SW: ", 32, 4, "swver", 1],
  246. [" Date: ", 36, 22, "hex2ascii", 1]
  247. ],
  248. "0A0176Dis" => [[" switchingProg: ", 11, 1, "bit0", 1], [" compressor: ", 11, 1, "bit1", 1],
  249. [" heatingHC: ", 11, 1, "bit2", 1], [" heatingDHW: ", 10, 1, "bit0", 1],
  250. [" boosterHC: ", 10, 1, "bit1", 1], [" filterBoth: ", 9, 1, "bit0", 1],
  251. [" ventStage: ", 9, 1, "bit1", 1], [" pumpHC: ", 9, 1, "bit2", 1],
  252. [" defrost: ", 9, 1, "bit3", 1], [" filterUp: ", 8, 1, "bit0", 1],
  253. [" filterDown: ", 8, 1, "bit1", 1]
  254. ],
  255. "0clean" => [["", 8, 2, "hex", 1]
  256. ],
  257. "1clean" => [["", 8, 4, "hex", 1]
  258. ],
  259. "2opmode" => [["", 8, 2, "opmode", 1]
  260. ],
  261. "4temp" => [["", 8, 4, "hex2int",2560]
  262. ],
  263. "5temp" => [["", 8, 4, "hex2int",10]
  264. ],
  265. "6gradient" => [["", 8, 4, "hex", 100]
  266. ],
  267. "7prog" => [["", 8, 2, "quater", 1], ["--", 10, 2, "quater", 1]
  268. ],
  269. "8party" => [["", 10, 2, "quater", 1], ["--", 8, 2, "quater", 1]
  270. ],
  271. "9holy" => [["", 10, 2, "quater", 1]
  272. ]
  273. );
  274. ########################################################################################
  275. #
  276. # %sets - all supported protocols are listed 59E
  277. #
  278. ########################################################################################
  279. my %sets439technician =(
  280. # "zResetLast10errors" => {cmd2=>"D1", argMin => "0", argMax => "0", type =>"0clean", unit =>""},
  281. "zPumpHC" => {cmd2=>"0A0052", argMin => "0", argMax => "1", type =>"0clean", unit =>""},
  282. "zPumpDHW" => {cmd2=>"0A0056", argMin => "0", argMax => "1", type =>"0clean", unit =>""}
  283. );
  284. my %sets439 = (
  285. "pOpMode" => {cmd2=>"0A0112", type => "2opmode"}, # 1 Standby bereitschaft; 11 in Automatic; 3 DAYmode; SetbackMode; DHWmode; Manual; Emergency
  286. "p01RoomTempDayHC1" => {cmd2=>"0B0005", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  287. "p02RoomTempNightHC1" => {cmd2=>"0B0008", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  288. "p03RoomTempStandbyHC1" => {cmd2=>"0B013D", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  289. "p01RoomTempDayHC1SummerMode" => {cmd2=>"0B0569", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  290. "p02RoomTempNightHC1SummerMode" => {cmd2=>"0B056B", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  291. "p03RoomTempStandbyHC1SummerMode" => {cmd2=>"0B056A", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  292. "p13GradientHC1" => {cmd2=>"0B010E", argMin => "0.1", argMax => "5", type =>"6gradient", unit =>""}, # 0..5 rappresentato/100
  293. "p14LowEndHC1" => {cmd2=>"0B059E", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"}, #in °K 0..20°K rappresentato/10
  294. "p15RoomInfluenceHC1" => {cmd2=>"0B010F", argMin => "0", argMax => "100", type =>"0clean", unit =>" %"},
  295. "p19FlowProportionHC1" => {cmd2=>"0B059D", argMin => "0", argMax => "100", type =>"1clean", unit =>" %"}, #in % 0..100%
  296. "p01RoomTempDayHC2" => {cmd2=>"0C0005", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  297. "p02RoomTempNightHC2" => {cmd2=>"0C0008", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  298. "p03RoomTempStandbyHC2" => {cmd2=>"0C013D", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  299. "p01RoomTempDayHC2SummerMode" => {cmd2=>"0C0569", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  300. "p02RoomTempNightHC2SummerMode" => {cmd2=>"0C056B", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  301. "p03RoomTempStandbyHC2SummerMode" => {cmd2=>"0C056A", argMin => "12", argMax => "27", type =>"5temp", unit =>" °C"},
  302. "p16GradientHC2" => {cmd2=>"0C010E", argMin => "0.1", argMax => "5", type =>"6gradient", unit =>""}, # /100
  303. "p17LowEndHC2" => {cmd2=>"0C059E", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"},
  304. "p18RoomInfluenceHC2" => {cmd2=>"0C010F", argMin => "0", argMax => "100", type =>"0clean", unit =>" %"},
  305. "p04DHWsetDayTemp" => {cmd2=>"0A0013", argMin => "14", argMax => "50", type =>"5temp", unit =>" °C"},
  306. "p05DHWsetNightTemp" => {cmd2=>"0A05BF", argMin => "14", argMax => "50", type =>"5temp", unit =>" °C"},
  307. "p83DHWsetSolarTemp" => {cmd2=>"0A05BE", argMin => "14", argMax => "75", type =>"5temp", unit =>" °C"},
  308. "p06DHWsetStandbyTemp" => {cmd2=>"0A0581", argMin => "14", argMax => "49", type =>"5temp", unit =>" °C"},
  309. "p11DHWsetManualTemp" => {cmd2=>"0A0580", argMin => "14", argMax => "54", type =>"5temp", unit =>" °C"},
  310. "p36DHWMaxTime" => {cmd2=>"0A0180", argMin => "6", argMax => "12", type =>"1clean", unit =>""},
  311. "p07FanStageDay" => {cmd2=>"0A056C", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
  312. "p08FanStageNight" => {cmd2=>"0A056D", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
  313. "p09FanStageStandby" => {cmd2=>"0A056F", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
  314. "p99FanStageParty" => {cmd2=>"0A0570", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
  315. "p75passiveCooling" => {cmd2=>"0A0575", argMin => "0", argMax => "2", type =>"1clean", unit =>""},
  316. "p21Hyst1" => {cmd2=>"0A05C0", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"},
  317. "p22Hyst2" => {cmd2=>"0A05C1", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"},
  318. "p23Hyst3" => {cmd2=>"0A05C2", argMin => "0", argMax => "5", type =>"5temp", unit =>" K"},
  319. "p24Hyst4" => {cmd2=>"0A05C3", argMin => "0", argMax => "5", type =>"5temp", unit =>" K"},
  320. "p25Hyst5" => {cmd2=>"0A05C4", argMin => "0", argMax => "5", type =>"5temp", unit =>" K"},
  321. "p29HystAsymmetry" => {cmd2=>"0A05C5", argMin => "1", argMax => "5", type =>"1clean", unit =>""},
  322. "p30integralComponent" => {cmd2=>"0A0162", argMin => "10", argMax => "999", type =>"1clean", unit =>" Kmin"},
  323. "p32HystDHW" => {cmd2=>"0A0140", argMin => "0", argMax => "10", type =>"5temp", unit =>" K"},
  324. "p33BoosterTimeoutDHW" => {cmd2=>"0A0588", argMin => "0", argMax => "200", type =>"1clean", unit =>" min"}, #during DHW heating
  325. "p79BoosterTimeoutHC" => {cmd2=>"0A05A0", argMin => "0", argMax => "60", type =>"1clean", unit =>" min"}, #delayed enabling of booster heater
  326. "p46UnschedVent0" => {cmd2=>"0A0571", argMin => "0", argMax => "1000", type =>"1clean", unit =>" min"}, #in min
  327. "p45UnschedVent1" => {cmd2=>"0A0572", argMin => "0", argMax => "1000", type =>"1clean", unit =>" min"}, #in min
  328. "p44UnschedVent2" => {cmd2=>"0A0573", argMin => "0", argMax => "1000", type =>"1clean", unit =>" min"}, #in min
  329. "p43UnschedVent3" => {cmd2=>"0A0574", argMin => "0", argMax => "1000", type =>"1clean", unit =>" min"}, #in min
  330. "p37Fanstage1AirflowInlet" => {cmd2=>"0A0576", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #zuluft
  331. "p38Fanstage2AirflowInlet" => {cmd2=>"0A0577", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #zuluft
  332. "p39Fanstage3AirflowInlet" => {cmd2=>"0A0578", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #zuluft
  333. "p40Fanstage1AirflowOutlet" => {cmd2=>"0A0579", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #abluft extrated
  334. "p41Fanstage2AirflowOutlet" => {cmd2=>"0A057A", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #abluft extrated
  335. "p42Fanstage3AirflowOutlet" => {cmd2=>"0A057B", argMin => "50", argMax => "300", type =>"1clean", unit =>" m3/h"}, #abluft extrated
  336. "p49SummerModeTemp" => {cmd2=>"0A0116", argMin => "11", argMax => "24", type =>"5temp", unit =>" °C"}, #threshold for summer mode !!
  337. "p50SummerModeHysteresis" => {cmd2=>"0A05A2", argMin => "0.5", argMax => "5", type =>"5temp", unit =>" K"}, #Hysteresis for summer mode !!
  338. "p78DualModePoint" => {cmd2=>"0A01AC", argMin => "-10", argMax => "20", type =>"5temp", unit =>" °C"},
  339. "p54MinPumpCycles" => {cmd2=>"0A05B8", argMin => "1", argMax => "24", type =>"1clean", unit =>""},
  340. "p55MaxPumpCycles" => {cmd2=>"0A05B7", argMin => "25", argMax => "200", type =>"1clean", unit =>""},
  341. "p56OutTempMaxPumpCycles" => {cmd2=>"0A05B9", argMin => "0", argMax => "20", type =>"5temp", unit =>" °C"},
  342. "p57OutTempMinPumpCycles" => {cmd2=>"0A05BA", argMin => "0", argMax => "25", type =>"5temp", unit =>" °C"},
  343. "p76RoomThermCorrection" => {cmd2=>"0A0109", argMin => "-5", argMax => "5", type =>"4temp", unit =>" K"},
  344. "p77OutThermFilterTime" => {cmd2=>"0A010C", argMin => "1", argMax => "24", type =>"0clean", unit =>" h"},
  345. "p35PasteurisationInterval" => {cmd2=>"0A0586", argMin => "1", argMax => "30", type =>"1clean", unit =>""},
  346. "p35PasteurisationTemp" => {cmd2=>"0A0587", argMin => "10", argMax => "65", type =>"5temp", unit =>" °C"},
  347. "p34BoosterDHWTempAct" => {cmd2=>"0A0589", argMin => "-10", argMax => "10", type =>"5temp", unit =>" °C"},
  348. "p99DHWmaxFlowTemp" => {cmd2=>"0A058C", argMin => "10", argMax => "75", type =>"5temp", unit =>" °C"},
  349. "p99HC1maxFlowTemp" => {cmd2=>"0A0027", argMin => "10", argMax => "75", type =>"5temp", unit =>" °C"},
  350. "p89DHWeco" => {cmd2=>"0A058D", argMin => "0", argMax => "1", type =>"1clean", unit =>""},
  351. "p99startUnschedVent" => {cmd2=>"0A05DD", argMin => "0", argMax => "3", type =>"1clean", unit =>""},
  352. "pClockDay" => {cmd2=>"0A0122", argMin => "1", argMax => "31", type =>"0clean", unit =>""},
  353. "pClockMonth" => {cmd2=>"0A0123", argMin => "1", argMax => "12", type =>"0clean", unit =>""},
  354. "pClockYear" => {cmd2=>"0A0124", argMin => "12", argMax => "20", type =>"0clean", unit =>""},
  355. "pClockHour" => {cmd2=>"0A0125", argMin => "0", argMax => "23", type =>"0clean", unit =>""},
  356. "pClockMinutes" => {cmd2=>"0A0126", argMin => "0", argMax => "59", type =>"0clean", unit =>""},
  357. "pHolidayBeginDay" => {cmd2=>"0A011B", argMin => "1", argMax => "31", type =>"0clean", unit =>""},
  358. "pHolidayBeginMonth" => {cmd2=>"0A011C", argMin => "1", argMax => "12", type =>"0clean", unit =>""},
  359. "pHolidayBeginYear" => {cmd2=>"0A011D", argMin => "12", argMax => "20", type =>"0clean", unit =>""},
  360. "pHolidayBeginTime" => {cmd2=>"0A05D3", argMin => "00:00", argMax => "23:59", type =>"9holy", unit =>""},
  361. "pHolidayEndDay" => {cmd2=>"0A011E", argMin => "1", argMax => "31", type =>"0clean", unit =>""},
  362. "pHolidayEndMonth" => {cmd2=>"0A011F", argMin => "1", argMax => "12", type =>"0clean", unit =>""},
  363. "pHolidayEndYear" => {cmd2=>"0A0120", argMin => "12", argMax => "20", type =>"0clean", unit =>""},
  364. "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
  365. #"party-time" => {cmd2=>"0A05D1", argMin => "00:00", argMax => "23:59", type =>"8party", unit =>""}, # value 1Ch 28dec is 7 ; value 1Eh 30dec is 7:30
  366. "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
  367. "programHC1_Mo_1" => {cmd2=>"0B1411", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  368. "programHC1_Mo_2" => {cmd2=>"0B1412", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  369. "programHC1_Tu_0" => {cmd2=>"0B1420", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  370. "programHC1_Tu_1" => {cmd2=>"0B1421", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  371. "programHC1_Tu_2" => {cmd2=>"0B1422", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  372. "programHC1_We_0" => {cmd2=>"0B1430", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  373. "programHC1_We_1" => {cmd2=>"0B1431", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  374. "programHC1_We_2" => {cmd2=>"0B1432", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  375. "programHC1_Th_0" => {cmd2=>"0B1440", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  376. "programHC1_Th_1" => {cmd2=>"0B1441", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  377. "programHC1_Th_2" => {cmd2=>"0B1442", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  378. "programHC1_Fr_0" => {cmd2=>"0B1450", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  379. "programHC1_Fr_1" => {cmd2=>"0B1451", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  380. "programHC1_Fr_2" => {cmd2=>"0B1452", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  381. "programHC1_Sa_0" => {cmd2=>"0B1460", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  382. "programHC1_Sa_1" => {cmd2=>"0B1461", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  383. "programHC1_Sa_2" => {cmd2=>"0B1462", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  384. "programHC1_So_0" => {cmd2=>"0B1470", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  385. "programHC1_So_1" => {cmd2=>"0B1471", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  386. "programHC1_So_2" => {cmd2=>"0B1472", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  387. "programHC1_Mo-Fr_0" => {cmd2=>"0B1480", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  388. "programHC1_Mo-Fr_1" => {cmd2=>"0B1481", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  389. "programHC1_Mo-Fr_2" => {cmd2=>"0B1482", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  390. "programHC1_Sa-So_0" => {cmd2=>"0B1490", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  391. "programHC1_Sa-So_1" => {cmd2=>"0B1491", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  392. "programHC1_Sa-So_2" => {cmd2=>"0B1492", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  393. "programHC1_Mo-So_0" => {cmd2=>"0B14A0", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  394. "programHC1_Mo-So_1" => {cmd2=>"0B14A1", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  395. "programHC1_Mo-So_2" => {cmd2=>"0B14A2", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  396. "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
  397. "programHC2_Mo_1" => {cmd2=>"0C1511", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  398. "programHC2_Mo_2" => {cmd2=>"0C1512", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  399. "programHC2_Tu_0" => {cmd2=>"0C1520", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  400. "programHC2_Tu_1" => {cmd2=>"0C1521", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  401. "programHC2_Tu_2" => {cmd2=>"0C1522", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  402. "programHC2_We_0" => {cmd2=>"0C1530", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  403. "programHC2_We_1" => {cmd2=>"0C1531", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  404. "programHC2_We_2" => {cmd2=>"0C1532", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  405. "programHC2_Th_0" => {cmd2=>"0C1540", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  406. "programHC2_Th_1" => {cmd2=>"0C1541", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  407. "programHC2_Th_2" => {cmd2=>"0C1542", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  408. "programHC2_Fr_0" => {cmd2=>"0C1550", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  409. "programHC2_Fr_1" => {cmd2=>"0C1551", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  410. "programHC2_Fr_2" => {cmd2=>"0C1552", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  411. "programHC2_Sa_0" => {cmd2=>"0C1560", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  412. "programHC2_Sa_1" => {cmd2=>"0C1561", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  413. "programHC2_Sa_2" => {cmd2=>"0C1562", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  414. "programHC2_So_0" => {cmd2=>"0C1570", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  415. "programHC2_So_1" => {cmd2=>"0C1571", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  416. "programHC2_So_2" => {cmd2=>"0C1572", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  417. "programHC2_Mo-Fr_0" => {cmd2=>"0C1580", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  418. "programHC2_Mo-Fr_1" => {cmd2=>"0C1581", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  419. "programHC2_Mo-Fr_2" => {cmd2=>"0C1582", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  420. "programHC2_Sa-So_0" => {cmd2=>"0C1590", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  421. "programHC2_Sa-So_1" => {cmd2=>"0C1591", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  422. "programHC2_Sa-So_2" => {cmd2=>"0C1592", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  423. "programHC2_Mo-So_0" => {cmd2=>"0C15A0", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  424. "programHC2_Mo-So_1" => {cmd2=>"0C15A1", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  425. "programHC2_Mo-So_2" => {cmd2=>"0C15A2", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  426. "programDHW_Mo_0" => {cmd2=>"0A1710", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  427. "programDHW_Mo_1" => {cmd2=>"0A1711", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  428. "programDHW_Mo_2" => {cmd2=>"0A1712", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  429. "programDHW_Tu_0" => {cmd2=>"0A1720", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  430. "programDHW_Tu_1" => {cmd2=>"0A1721", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  431. "programDHW_Tu_2" => {cmd2=>"0A1722", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  432. "programDHW_We_0" => {cmd2=>"0A1730", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  433. "programDHW_We_1" => {cmd2=>"0A1731", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  434. "programDHW_We_2" => {cmd2=>"0A1732", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  435. "programDHW_Th_0" => {cmd2=>"0A1740", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  436. "programDHW_Th_1" => {cmd2=>"0A1741", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  437. "programDHW_Th_2" => {cmd2=>"0A1742", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  438. "programDHW_Fr_0" => {cmd2=>"0A1750", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  439. "programDHW_Fr_1" => {cmd2=>"0A1751", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  440. "programDHW_Fr_2" => {cmd2=>"0A1752", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  441. "programDHW_Sa_0" => {cmd2=>"0A1760", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  442. "programDHW_Sa_1" => {cmd2=>"0A1761", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  443. "programDHW_Sa_2" => {cmd2=>"0A1762", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  444. "programDHW_So_0" => {cmd2=>"0A1770", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  445. "programDHW_So_1" => {cmd2=>"0A1771", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  446. "programDHW_So_2" => {cmd2=>"0A1772", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  447. "programDHW_Mo-Fr_0" => {cmd2=>"0A1780", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  448. "programDHW_Mo-Fr_1" => {cmd2=>"0A1781", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  449. "programDHW_Mo-Fr_2" => {cmd2=>"0A1782", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  450. "programDHW_Sa-So_0" => {cmd2=>"0A1790", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  451. "programDHW_Sa-So_1" => {cmd2=>"0A1791", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  452. "programDHW_Sa-So_2" => {cmd2=>"0A1792", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  453. "programDHW_Mo-So_0" => {cmd2=>"0A17A0", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  454. "programDHW_Mo-So_1" => {cmd2=>"0A17A1", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  455. "programDHW_Mo-So_2" => {cmd2=>"0A17A2", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  456. "programFan_Mo_0" => {cmd2=>"0A1D10", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  457. "programFan_Mo_1" => {cmd2=>"0A1D11", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  458. "programFan_Mo_2" => {cmd2=>"0A1D12", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  459. "programFan_Tu_0" => {cmd2=>"0A1D20", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  460. "programFan_Tu_1" => {cmd2=>"0A1D21", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  461. "programFan_Tu_2" => {cmd2=>"0A1D22", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  462. "programFan_We_0" => {cmd2=>"0A1D30", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  463. "programFan_We_1" => {cmd2=>"0A1D31", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  464. "programFan_We_2" => {cmd2=>"0A1D32", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  465. "programFan_Th_0" => {cmd2=>"0A1D40", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  466. "programFan_Th_1" => {cmd2=>"0A1D41", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  467. "programFan_Th_2" => {cmd2=>"0A1D42", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  468. "programFan_Fr_0" => {cmd2=>"0A1D50", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  469. "programFan_Fr_1" => {cmd2=>"0A1D51", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  470. "programFan_Fr_2" => {cmd2=>"0A1D52", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  471. "programFan_Sa_0" => {cmd2=>"0A1D60", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  472. "programFan_Sa_1" => {cmd2=>"0A1D61", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  473. "programFan_Sa_2" => {cmd2=>"0A1D62", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  474. "programFan_So_0" => {cmd2=>"0A1D70", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  475. "programFan_So_1" => {cmd2=>"0A1D71", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  476. "programFan_So_2" => {cmd2=>"0A1D72", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  477. "programFan_Mo-Fr_0" => {cmd2=>"0A1D80", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  478. "programFan_Mo-Fr_1" => {cmd2=>"0A1D81", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  479. "programFan_Mo-Fr_2" => {cmd2=>"0A1D82", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  480. "programFan_Sa-So_0" => {cmd2=>"0A1D90", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  481. "programFan_Sa-So_1" => {cmd2=>"0A1D91", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  482. "programFan_Sa-So_2" => {cmd2=>"0A1D92", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  483. "programFan_Mo-So_0" => {cmd2=>"0A1DA0", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  484. "programFan_Mo-So_1" => {cmd2=>"0A1DA1", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""},
  485. "programFan_Mo-So_2" => {cmd2=>"0A1DA2", argMin => "00:00", argMax => "24:00", type =>"7prog", unit =>""}
  486. );
  487. my %sets539only =(
  488. "p99PumpRateHC" => {cmd2=>"0A02CB", argMin => "0", argMax => "100", type =>"5temp", unit =>" %"},
  489. "p99PumpRateDHW" => {cmd2=>"0A02CC", argMin => "0", argMax => "100", type =>"5temp", unit =>" %"}
  490. );
  491. my %sets206 = (
  492. "p01RoomTempDay" => {parent=>"p01-p12", argMin => "10", argMax => "30", unit =>" °C"},
  493. "p02RoomTempNight" => {parent=>"p01-p12", argMin => "10", argMax => "30", unit =>" °C"},
  494. "p03RoomTempStandby" => {parent=>"p01-p12", argMin => "10", argMax => "30", unit =>" °C"},
  495. "p04DHWsetTempDay" => {parent=>"p01-p12", argMin => "10", argMax => "55", unit =>" °C"},
  496. "p05DHWsetTempNight" => {parent=>"p01-p12", argMin => "10", argMax => "55", unit =>" °C"},
  497. "p06DHWsetTempStandby"=> {parent=>"p01-p12", argMin => "10", argMax => "55", unit =>" °C"},
  498. "p07FanStageDay" => {parent=>"p01-p12", argMin => "0", argMax => "3", unit =>""},
  499. "p08FanStageNight" => {parent=>"p01-p12", argMin => "0", argMax => "3", unit =>""},
  500. "p09FanStageStandby" => {parent=>"p01-p12", argMin => "0", argMax => "3", unit =>""},
  501. "p10RoomTempManual" => {parent=>"p01-p12", argMin => "10", argMax => "65", unit =>" °C"},
  502. "p11DHWsetTempManual" => {parent=>"p01-p12", argMin => "10", argMax => "65", unit =>" °C"},
  503. "p12FanStageManual" => {parent=>"p01-p12", argMin => "0", argMax => "3", unit =>""},
  504. "p80EnableSolar" => {parent=>"pSolar", argMin => "0", argMax => "1", unit =>""},
  505. "pClockDay" => {parent=>"sTimedate", argMin => "1", argMax => "31", unit =>""},
  506. "pClockMonth" => {parent=>"sTimedate", argMin => "1", argMax => "12", unit =>""},
  507. "pClockYear" => {parent=>"sTimedate", argMin => "12", argMax => "20", unit =>""},
  508. "pClockHour" => {parent=>"sTimedate", argMin => "0", argMax => "23", unit =>""},
  509. "pClockMinutes" => {parent=>"sTimedate", argMin => "0", argMax => "59", unit =>""}
  510. );
  511. ########################################################################################
  512. #
  513. # %gets - all supported protocols are listed without header and footer
  514. #
  515. ########################################################################################
  516. my %getsonly439 = (
  517. #"debug_read_raw_register_slow" => { },
  518. "sSol" => {cmd2=>"16", type =>"16sol", unit =>""},
  519. "sDHW" => {cmd2=>"F3", type =>"F3dhw", unit =>""},
  520. "sHC1" => {cmd2=>"F4", type =>"F4hc1", unit =>""},
  521. "sHC2" => {cmd2=>"F5", type =>"F5hc2", unit =>""},
  522. "sHistory" => {cmd2=>"09", type =>"09his", unit =>""},
  523. "sLast10errors" => {cmd2=>"D1", type =>"D1last", unit =>""},
  524. "sGlobal" => {cmd2=>"FB", type =>"FBglob", unit =>""}, #allFB
  525. "sTimedate" => {cmd2=>"FC", type =>"FCtime", unit =>""},
  526. "sFirmware" => {cmd2=>"FD", type =>"FDfirm", unit =>""},
  527. "sFirmware-Id" => {cmd2=>"FE", type =>"FEfirmId", unit =>""},
  528. "sDisplay" => {cmd2=>"0A0176", type =>"0A0176Dis", unit =>""},
  529. "sBoostDHWTotal" => {cmd2=>"0A0924", cmd3=>"0A0925", type =>"1clean", unit =>" kWh"},
  530. "sBoostHCTotal" => {cmd2=>"0A0928", cmd3=>"0A0929", type =>"1clean", unit =>" kWh"},
  531. "sHeatRecoveredDay" => {cmd2=>"0A03AE", cmd3=>"0A03AF", type =>"1clean", unit =>" Wh"},
  532. "sHeatRecoveredTotal" => {cmd2=>"0A03B0", cmd3=>"0A03B1", type =>"1clean", unit =>" kWh"},
  533. "sHeatDHWDay" => {cmd2=>"0A092A", cmd3=>"0A092B", type =>"1clean", unit =>" Wh"},
  534. "sHeatDHWTotal" => {cmd2=>"0A092C", cmd3=>"0A092D", type =>"1clean", unit =>" kWh"},
  535. "sHeatHCDay" => {cmd2=>"0A092E", cmd3=>"0A092F", type =>"1clean", unit =>" Wh"},
  536. "sHeatHCTotal" => {cmd2=>"0A0930", cmd3=>"0A0931", type =>"1clean", unit =>" kWh"},
  537. "sElectrDHWDay" => {cmd2=>"0A091A", cmd3=>"0A091B", type =>"1clean", unit =>" Wh"},
  538. "sElectrDHWTotal" => {cmd2=>"0A091C", cmd3=>"0A091D", type =>"1clean", unit =>" kWh"},
  539. "sElectrHCDay" => {cmd2=>"0A091E", cmd3=>"0A091F", type =>"1clean", unit =>" Wh"},
  540. "sElectrHCTotal" => {cmd2=>"0A0920", cmd3=>"0A0921", type =>"1clean", unit =>" kWh"},
  541. "party-time" => {cmd2=>"0A05D1", argMin => "00:00", argMax => "23:59", type =>"8party", unit =>""} # value 1Ch 28dec is 7 ; value 1Eh 30dec is 7:30
  542. );
  543. my %getsonly539 = ( #info from belu and godmorgon
  544. "sFlowRate" => {cmd2=>"0A033B", type =>"1clean", unit =>" cl/min"},
  545. "sHumMaskingTime" => {cmd2=>"0A064F", type =>"1clean", unit =>" min"},
  546. "sHumThreshold" => {cmd2=>"0A0650", type =>"1clean", unit =>" %"},
  547. "sOutputReduction" => {cmd2=>"0A06A4", type =>"1clean", unit =>" %"},
  548. "sOutputIncrease" => {cmd2=>"0A06A5", type =>"1clean", unit =>" %"},
  549. "sHumProtection" => {cmd2=>"0A09D1", type =>"1clean", unit =>""},
  550. "sSetHumidityMin" => {cmd2=>"0A09D2", type =>"1clean", unit =>" %"},
  551. "sSetHumidityMax" => {cmd2=>"0A09D3", type =>"1clean", unit =>" %"}
  552. );
  553. %getsonly539=(%getsonly539, %getsonly439);
  554. my %getsonly2xx = (
  555. "pExpert" => {cmd2=>"02", type =>"02pxx206", unit =>""},
  556. "pDefrostEva" => {cmd2=>"03", type =>"03pxx206", unit =>""},
  557. "pDefrostAA" => {cmd2=>"04", type =>"04pxx206", unit =>""},
  558. "pHeat1" => {cmd2=>"05", type =>"05pxx206", unit =>""},
  559. "pHeat2" => {cmd2=>"06", type =>"06pxx206", unit =>""},
  560. "pDHW" => {cmd2=>"07", type =>"07pxx206", unit =>""},
  561. "pSolar" => {cmd2=>"08", type =>"08pxx206", unit =>""},
  562. "pCircPump" => {cmd2=>"0A", type =>"0Apxx206", unit =>""},
  563. "pHeatProg" => {cmd2=>"0B", type =>"0Bpxx206", unit =>""},
  564. "pDHWProg" => {cmd2=>"0C", type =>"0Cpxx206", unit =>""},
  565. "pFanProg" => {cmd2=>"0D", type =>"0Dpxx206", unit =>""},
  566. "pRestart" => {cmd2=>"0E", type =>"0Epxx206", unit =>""},
  567. "pAbsence" => {cmd2=>"0F", type =>"0Fpxx206", unit =>""},
  568. "pDryHeat" => {cmd2=>"10", type =>"10pxx206", unit =>""},
  569. "sSol" => {cmd2=>"16", type =>"16sol", unit =>""},
  570. "p01-p12" => {cmd2=>"17", type =>"17pxx206", unit =>""},
  571. "sProgram" => {cmd2=>"EE", type =>"EEprg206", unit =>""},
  572. "sDHW" => {cmd2=>"F3", type =>"F3dhw", unit =>""},
  573. "sHC2" => {cmd2=>"F5", type =>"F5hc2", unit =>""},
  574. "sSystem" => {cmd2=>"F6", type =>"F6sys206", unit =>""},
  575. "sHistory" => {cmd2=>"09", type =>"09his206", unit =>""},
  576. "sLast10errors" => {cmd2=>"D1", type =>"D1last206", unit =>""},
  577. "sGlobal" => {cmd2=>"FB", type =>"FBglob206", unit =>""}, #allFB
  578. "sTimedate" => {cmd2=>"FC", type =>"FCtime206", unit =>""},
  579. );
  580. my %getsonly206 = (
  581. "sHC1" => {cmd2=>"F4", type =>"F4hc1", unit =>""},
  582. "pFan" => {cmd2=>"01", type =>"01pxx206", unit =>""},
  583. "sLast10errors" => {cmd2=>"D1", type =>"D1last206", unit =>""},
  584. "sFirmware" => {cmd2=>"FD", type =>"FDfirm", unit =>""},
  585. "sFirmware-Id" => {cmd2=>"FE", type =>"FEfirmId", unit =>""},
  586. );
  587. my %getsonly214 = (
  588. "pFan" => {cmd2=>"01", type =>"01pxx214", unit =>""},
  589. "sHC1" => {cmd2=>"F4", type =>"F4hc1214", unit =>""},
  590. );
  591. my %sets=%sets439;
  592. my %gets=(%getsonly439, %sets);
  593. my %OpMode = ("1" =>"standby", "11" => "automatic", "3" =>"DAYmode", "4" =>"setback", "5" =>"DHWmode", "14" =>"manual", "0" =>"emergency");
  594. my %Rev_OpMode = reverse %OpMode;
  595. my %OpModeHC = ("1" =>"normal", "2" => "setback", "3" =>"standby", "4" =>"restart", "5" =>"restart");
  596. my %SomWinMode = ( "01" =>"winter", "02" => "summer");
  597. my %weekday = ( "0" =>"Monday", "1" => "Tuesday", "2" =>"Wednesday", "3" => "Thursday", "4" => "Friday", "5" =>"Saturday", "6" => "Sunday" );
  598. 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" );
  599. my $firstLoadAll = 0;
  600. my $noanswerreceived = 0;
  601. my $internalHash;
  602. ########################################################################################
  603. #
  604. # THZ_Initialize($)
  605. #
  606. # Parameter hash
  607. #
  608. ########################################################################################
  609. sub THZ_Initialize($)
  610. {
  611. my ($hash) = @_;
  612. require "$attr{global}{modpath}/FHEM/DevIo.pm";
  613. # Provider
  614. $hash->{ReadFn} = "THZ_Read";
  615. $hash->{WriteFn} = "THZ_Write";
  616. $hash->{ReadyFn} = "THZ_Ready";
  617. # Normal devices
  618. $hash->{DefFn} = "THZ_Define";
  619. $hash->{UndefFn} = "THZ_Undef";
  620. $hash->{GetFn} = "THZ_Get";
  621. $hash->{SetFn} = "THZ_Set";
  622. $hash->{AttrFn} = "THZ_Attr";
  623. $hash->{FW_detailFn} ="THZ_detailFn";
  624. $hash->{AttrList}= "IODev do_not_notify:1,0 ignore:0,1 dummy:1,0 showtime:1,0 loglevel:0,1,2,3,4,5,6 "
  625. ."interval_sGlobal:0,60,120,180,300,600,3600,7200,43200,86400 "
  626. ."interval_sSol:0,60,120,180,300,600,3600,7200,43200,86400 "
  627. ."interval_sDHW:0,60,120,180,300,600,3600,7200,43200,86400 "
  628. ."interval_sHC1:0,60,120,180,300,600,3600,7200,43200,86400 "
  629. ."interval_sHC2:0,60,120,180,300,600,3600,7200,43200,86400 "
  630. ."interval_sHistory:0,3600,7200,28800,43200,86400 "
  631. ."interval_sLast10errors:0,3600,7200,28800,43200,86400 "
  632. ."interval_sHeatRecoveredDay:0,1200,3600,7200,28800,43200,86400 "
  633. ."interval_sHeatRecoveredTotal:0,3600,7200,28800,43200,86400 "
  634. ."interval_sHeatDHWDay:0,1200,3600,7200,28800,43200,86400 "
  635. ."interval_sHeatDHWTotal:0,3600,7200,28800,43200,86400 "
  636. ."interval_sHeatHCDay:0,1200,3600,7200,28800,43200,86400 "
  637. ."interval_sHeatHCTotal:0,3600,7200,28800,43200,86400 "
  638. ."interval_sElectrDHWDay:0,1200,3600,7200,28800,43200,86400 "
  639. ."interval_sElectrDHWTotal:0,3600,7200,28800,43200,86400 "
  640. ."interval_sElectrHCDay:0,1200,3600,7200,28800,43200,86400 "
  641. ."interval_sElectrHCTotal:0,3600,7200,28800,43200,86400 "
  642. ."interval_sBoostDHWTotal:0,3600,7200,28800,43200,86400 "
  643. ."interval_sBoostHCTotal:0,3600,7200,28800,43200,86400 "
  644. ."interval_sFlowRate:0,3600,7200,28800,43200,86400 "
  645. ."interval_sDisplay:0,60,120,180,300 "
  646. ."firmware:4.39,2.06,2.14,5.39,4.39technician "
  647. . $readingFnAttributes;
  648. $data{FWEXT}{"/THZ_PrintcurveSVG"}{FUNC} = "THZ_PrintcurveSVG";
  649. }
  650. ########################################################################################
  651. #
  652. # THZ_define
  653. #
  654. # Parameter hash and configuration
  655. #
  656. ########################################################################################
  657. sub THZ_Define($$)
  658. {
  659. my ($hash, $def) = @_;
  660. my @a = split("[ \t][ \t]*", $def);
  661. my $name = $a[0];
  662. $hash->{VERSION} = $thzversion;
  663. return "wrong syntax. Correct is: define <name> THZ ".
  664. "{devicename[\@baudrate]|ip:port}"
  665. if(@a != 3);
  666. DevIo_CloseDev($hash);
  667. my $dev = $a[2];
  668. if($dev eq "none") {
  669. Log 1, "$name device is none, commands will be echoed only";
  670. $attr{$name}{dummy} = 1;
  671. return undef;
  672. }
  673. $hash->{DeviceName} = $dev;
  674. my $ret = DevIo_OpenDev($hash, 0, "THZ_Refresh_all_gets");
  675. return $ret;
  676. }
  677. ########################################################################################
  678. #
  679. # THZ_Refresh_all_gets - Called once refreshes current reading for all gets and initializes the regular interval calls
  680. #
  681. # Parameter $hash
  682. #
  683. ########################################################################################
  684. sub THZ_Refresh_all_gets($) {
  685. my ($hash) = @_;
  686. # unlink("data.txt");
  687. THZ_RemoveInternalTimer("THZ_GetRefresh");
  688. Log3 $hash->{NAME}, 5, "thzversion = $thzversion ";
  689. #readingsSingleUpdate($hash, "state", "opened", 1); # copied from cul 26.11.2014
  690. my $timedelay= 5; #start after 5 seconds
  691. foreach my $cmdhash (keys %gets) {
  692. my %par = ( hash => $hash, command => $cmdhash );
  693. RemoveInternalTimer(\%par);
  694. InternalTimer(gettimeofday() + ($timedelay) , "THZ_GetRefresh", \%par, 0); #increment 0.6 $timedelay++
  695. $timedelay += 0.6;
  696. } #refresh all registers; the register with interval_command ne 0 will keep on refreshing
  697. }
  698. ########################################################################################
  699. #
  700. # THZ_GetRefresh - Called in regular intervals to obtain current reading
  701. #
  702. # Parameter (hash => $hash, command => "allFB" )
  703. # it get the intervall directly from a attribute; the register with interval_command ne 0 will keep on refreshing
  704. ########################################################################################
  705. sub THZ_GetRefresh($) {
  706. my ($par)=@_;
  707. my $hash=$par->{hash};
  708. my $command=$par->{command};
  709. my $interval = AttrVal($hash->{NAME}, ("interval_".$command), 0);
  710. my $replyc = "";
  711. if ($interval) {
  712. $interval = 60 if ($interval < 60); #do not allow intervall <60 sec
  713. InternalTimer(gettimeofday()+ $interval, "THZ_GetRefresh", $par, 1) ;
  714. }
  715. $replyc = THZ_Get($hash, $hash->{NAME}, $command) if ($hash->{STATE} ne "disconnected");
  716. return ($replyc);
  717. }
  718. #####################################
  719. # THZ_Write -- simple write
  720. # Parameter: hash and message HEX
  721. #
  722. ########################################################################################
  723. sub THZ_Write($$) {
  724. my ($hash,$msg) = @_;
  725. my $name = $hash->{NAME};
  726. my $ll5 = GetLogLevel($name,5);
  727. my $bstring;
  728. $bstring = $msg;
  729. Log $ll5, "$hash->{NAME} sending $bstring";
  730. DevIo_SimpleWrite($hash, $bstring, 1);
  731. }
  732. #####################################
  733. # sub THZ_Read($)
  734. # called from the global loop, when the select for hash reports data
  735. # used just for testing the interface
  736. ########################################################################################
  737. sub THZ_Read($)
  738. {
  739. my ($hash) = @_;
  740. my $buf = DevIo_SimpleRead($hash);
  741. return "" if(!defined($buf));
  742. my $name = $hash->{NAME};
  743. my $ll5 = GetLogLevel($name,5);
  744. my $ll2 = GetLogLevel($name,2);
  745. my $data = $hash->{PARTIAL} . uc(unpack('H*', $buf));
  746. Log $ll5, "$name/RAW: $data";
  747. Log $ll2, "$name/RAW: $data";
  748. }
  749. #####################################
  750. #
  751. # THZ_Ready($) - Cchecks the status
  752. #
  753. # Parameter hash
  754. #
  755. ########################################################################################
  756. sub THZ_Ready($)
  757. {
  758. my ($hash) = @_;
  759. if($hash->{STATE} eq "disconnected")
  760. { THZ_RemoveInternalTimer("THZ_GetRefresh");
  761. select(undef, undef, undef, 0.25); #equivalent to sleep 250ms
  762. return DevIo_OpenDev($hash, 1, "THZ_Refresh_all_gets")
  763. }
  764. # This is relevant for windows/USB only
  765. my $po = $hash->{USBDev};
  766. if($po) {
  767. my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
  768. return ($InBytes>0);
  769. }
  770. }
  771. #####################################
  772. #
  773. # THZ_Set - provides a method for setting the heatpump
  774. #
  775. # Parameters: hash and command to be sent to the interface
  776. #
  777. ########################################################################################
  778. sub THZ_Set($@){
  779. my ($hash, @a) = @_;
  780. my $dev = $hash->{DeviceName};
  781. my $name = $hash->{NAME};
  782. return "\"set $name\" needs at least two parameters: <device-parameter> and <value-to-be-modified>" if(@a < 2);
  783. my $cmd = $a[1];
  784. my $arg = $a[2];
  785. my $arg1 = "00:00";
  786. my ($err, $msg) =("", " ");
  787. my $cmdhash = $sets{$cmd};
  788. #return "Unknown argument $cmd, choose one of " . join(" ", sort keys %sets) if(!defined($cmdhash));
  789. if(!defined($cmdhash)) {
  790. my $setList;
  791. foreach my $key (sort keys %sets) {
  792. my $value = $sets{$key};
  793. $setList .= $key;
  794. #if (($value->{type} eq "0clean" or $value->{type} eq "1clean") and $value->{unit} eq "") {
  795. if (($value->{type} eq "0clean" or $value->{type} eq "1clean")) {
  796. #if (($value->{argMax} - $value->{argMin})<2 ) {$setList .= ":uzsuToggle," . join (",", ($value->{argMin} .. $value->{argMax})) . " ";}
  797. if (($value->{argMax} - $value->{argMin})<13 ) {$setList .= ":uzsuSelectRadio," . join (",", ($value->{argMin} .. $value->{argMax})) . " ";}
  798. else {$setList .= ":textField ";}
  799. #else {$setList .= ":slider,$value->{argMin},1,$value->{argMax} ";}
  800. #else {$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:1 " ;}
  801. }
  802. elsif ($value->{type} eq "2opmode"){
  803. $setList .= ":" . join (",", (sort {lc $a cmp lc $b} values %OpMode)) . " ";
  804. #$setList .= ":uzsuSelectRadio," . join (",", (sort {lc $a cmp lc $b} values %OpMode)) . " ";
  805. #attr Mythz widgetOverride pOpMode:uzsuDropDown,automatic,standby
  806. }
  807. #elsif ($value->{type} eq "9holy"){
  808. #$setList .= ":time ";
  809. # $setList .= ":textField ";
  810. # }
  811. # elsif ($value->{type} eq "5temp") {
  812. # $setList .= ":slider,$value->{argMin},0.1,$value->{argMax},1 " ;
  813. #$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:0.1 " ;
  814. #$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:0.1,angleOffset:-125,angleArc:250 "
  815. #attr Mythz widgetOverride p01RoomTempDayHC1:knob,min:22,max:26,step:0.1,angleOffset:-125,angleArc:250
  816. #attr Mythz widgetOverride p01RoomTempDayHC1:slider,$value->{argMin},0.1,$value->{argMax}
  817. #attr Mythz widgetOverride p01RoomTempDayHC1:uzsuDropDown,21,29
  818. #attr Mythz widgetOverride p01RoomTempDayHC1:uzsuSelectRadio,44,234,21
  819. # }
  820. #elsif ($value->{type} eq "6gradient") {
  821. # $setList .= ":slider,$value->{argMin},0.01,$value->{argMax},1 " ;
  822. #$setList .= ":knob,min:$value->{argMin},max:$value->{argMax},step:0.01 " ;
  823. # }
  824. else {
  825. #$setList .= ":textField ";
  826. $setList .= " ";
  827. }
  828. }
  829. return "Unknown argument $cmd, choose one of $setList";
  830. }
  831. return "\"set $name $cmd\" needs at least one further argument: <value-to-be-modified>" if(!defined($arg));
  832. my $cmdHex2 = $cmdhash->{cmd2};
  833. my $argMax = $cmdhash->{argMax};
  834. my $argMin = $cmdhash->{argMin};
  835. #-- check the parameter range
  836. if ($cmdhash->{type} =~ /7prog|8party/) {
  837. ($arg, $arg1)=split('--', $arg);
  838. return "Argument does not match the allowed inerval Min $argMin ...... Max $argMax " if (($arg ne "n.a.") and ($arg1 ne "n.a.") and (($arg1 gt $argMax) or ($arg1 lt $argMin) or ($arg gt $argMax) or ($arg lt $argMin)) ) ;
  839. }
  840. elsif ($cmdhash->{type} eq "2opmode") {
  841. $arg1=undef;
  842. $arg=$Rev_OpMode{$arg};
  843. return "Unknown argument $arg1: $cmd supports " . join(" ", sort values %OpMode) if(!defined($arg));
  844. }
  845. else {
  846. $arg1=undef;
  847. return "Argument does not match the allowed inerval Min $argMin ...... Max $argMax " if(($arg > $argMax) or ($arg < $argMin));
  848. }
  849. #--
  850. my $i=0; my $parsingrule;
  851. my $parent = $cmdhash->{parent};
  852. #if I have a father read from it: important for older firmwares
  853. if(defined($parent) ) {
  854. my $parenthash=$gets{$parent};
  855. $cmdHex2 = $parenthash->{cmd2}; #overwrite $cmdHex2 with the parent
  856. Log3 $hash->{NAME}, 5, "searching for parent; parenthash= $parenthash, parent = $parent, cmdHex2 = $cmdHex2 ";
  857. $cmdHex2=THZ_encodecommand($cmdHex2, "get"); #read before write the register
  858. ($err, $msg) = THZ_Get_Comunication($hash, $cmdHex2);
  859. if (defined($err)) {
  860. Log3 $hash->{NAME}, 3, "THZ_Set: error reading register: '$err'";
  861. return ($msg ."\n msg " . $err);
  862. }
  863. substr($msg, 0, 2, ""); #remove the checksum from the head of the payload
  864. Log3 $hash->{NAME}, 5, "read before write from THZ: $msg";
  865. #--
  866. $parsingrule = $parsinghash{$parenthash->{type}};
  867. for (@$parsingrule) {
  868. last if ((@$parsingrule[$i]->[0]) =~ m/$cmd/);
  869. $i++;
  870. }
  871. select(undef, undef, undef, 0.25);
  872. }
  873. else {
  874. $msg = $cmdHex2 . "0000";
  875. my $msgtype =$cmdhash->{type};
  876. $parsingrule = $parsinghash{$msgtype} if(defined($msgtype));
  877. }
  878. my $pos = @$parsingrule[$i]->[1] -2; #I removed the checksum
  879. my $len = @$parsingrule[$i]->[2];
  880. my $parsingtype = @$parsingrule[$i]->[3];
  881. my $dec = @$parsingrule[$i]->[4];
  882. Log3 $hash->{NAME}, 5, "write command (parsed element/pos/len/dec/parsingtype): $i / $pos / $len / $dec / $parsingtype";
  883. $arg *= $dec if ($dec != 1);
  884. $arg = time2quaters($arg) if ($parsingtype eq "quater");
  885. $arg = substr((sprintf(("%0".$len."X"), $arg)), (-1*$len)); #04X converts to hex and fills up 0s; for negative, it must be trunckated.
  886. substr($msg, $pos, $len, $arg);
  887. if (defined($arg1)) { #only in case of "8party" or "7prog"
  888. $arg1 = time2quaters($arg1);
  889. $arg1 = substr((sprintf(("%02X"), $arg1)), -2);
  890. $pos = @$parsingrule[($i+1)]->[1] -2;
  891. substr($msg, $pos, $len, $arg1);
  892. }
  893. Log3 $hash->{NAME}, 5, "THZ_Set: '$cmd $arg $msg' ... Check if port is open. State = '($hash->{STATE})'";
  894. $cmdHex2=THZ_encodecommand($msg,"set");
  895. ($err, $msg) = THZ_Get_Comunication($hash, $cmdHex2);
  896. #$err=undef;
  897. if (defined($err)) { return ($cmdHex2 . "-". $msg ."--" . $err);}
  898. else {
  899. select(undef, undef, undef, 0.25);
  900. $msg=THZ_Get($hash, $name, $cmd);
  901. #take care of program of the week
  902. if ($a[1] =~ /Mo-So/){
  903. select(undef, undef, undef, 0.05);
  904. $a[1] =~ s/Mo-So/Mo-Fr/; $msg.= "\n" . THZ_Set($hash, @a);
  905. select(undef, undef, undef, 0.05);
  906. $a[1] =~ s/Mo-Fr/Sa-So/; $msg.="\n" . THZ_Set($hash, @a);
  907. }
  908. elsif ($a[1] =~ /Mo-Fr/) {
  909. select(undef, undef, undef, 0.05);
  910. $a[1] =~ s/_Mo-Fr_/_Mo_/; $msg.="\n" . THZ_Set($hash, @a);
  911. select(undef, undef, undef, 0.05);
  912. $a[1] =~ s/_Mo_/_Tu_/ ; $msg.="\n" . THZ_Set($hash, @a);
  913. select(undef, undef, undef, 0.05);
  914. $a[1] =~ s/_Tu_/_We_/ ; $msg.="\n" . THZ_Set($hash, @a);
  915. select(undef, undef, undef, 0.05);
  916. $a[1] =~ s/_We_/_Th_/ ; $msg.="\n" . THZ_Set($hash, @a);
  917. select(undef, undef, undef, 0.05);
  918. $a[1] =~ s/_Th_/_Fr_/ ; $msg.="\n" . THZ_Set($hash, @a);
  919. }
  920. elsif ($a[1] =~ /Sa-So/){
  921. select(undef, undef, undef, 0.05);
  922. $a[1] =~ s/_Sa-So_/_Sa_/; $msg.="\n" . THZ_Set($hash, @a);
  923. select(undef, undef, undef, 0.05);
  924. $a[1] =~ s/_Sa_/_So_/ ; $msg.="\n" . THZ_Set($hash, @a);
  925. }
  926. #split _ mo-fr when [3] undefined do nothing, when mo-fr chiama gli altri
  927. return ($msg);
  928. }
  929. }
  930. #####################################
  931. #
  932. # THZ_Get - provides a method for polling the heatpump
  933. #
  934. # Parameters: hash and command to be sent to the interface
  935. #
  936. ########################################################################################
  937. sub THZ_Get($@){
  938. my ($hash, @a) = @_;
  939. my $dev = $hash->{DeviceName};
  940. my $name = $hash->{NAME};
  941. my $ll5 = GetLogLevel($name,5);
  942. my $ll2 = GetLogLevel($name,2);
  943. return "\"get $name\" needs one parameter" if(@a != 2);
  944. my $cmd = $a[1];
  945. my ($err, $msg2) =("", " ");
  946. if ($cmd eq "debug_read_raw_register_slow") {
  947. THZ_debugread($hash);
  948. return ("all raw registers read and saved");
  949. }
  950. if ($cmd eq "zBackupParameters") {
  951. $err=THZ_backup_readings($hash);
  952. return $err;
  953. }
  954. my $cmdhash = $gets{$cmd};
  955. #return "Unknown argument $cmd, choose one of " . join(" ", sort keys %gets) if(!defined($cmdhash));
  956. if(!defined($cmdhash)) {
  957. my $getList;
  958. foreach my $key (sort keys %gets) {$getList .= "$key:noArg ";}
  959. $getList .= "zBackupParameters:noArg";
  960. return "Unknown argument $cmd, choose one of $getList";
  961. }
  962. Log3 $hash->{NAME}, 5, "THZ_Get: Try to get '$cmd'";
  963. my $parent = $cmdhash->{parent}; #if I have a father read from it
  964. if(defined($parent) ) {
  965. my ($seconds, $microseconds) = gettimeofday();
  966. $seconds= abs($seconds - time_str2num(ReadingsTimestamp($name, $parent, "1970-01-01 01:00:00")));
  967. my $risultato=ReadingsVal($name, $parent, 0);
  968. $risultato=THZ_Get($hash, $name, $parent) if ($seconds > 20 ); #update of the parent: if under 20sec use the current value
  969. #$risultato=THZ_Parse1($hash,"B81700C800BE00A001C20190006402010000E601D602");
  970. my $parenthash=$gets{$parent}; my $parsingrule = $parsinghash{$parenthash->{type}};
  971. my $i=0;
  972. for (@$parsingrule) {
  973. last if ((@$parsingrule[$i]->[0]) =~ m/$cmd/);
  974. $i++;}
  975. $msg2=(split ' ', $risultato)[$i*2+1];
  976. Log3 $hash->{NAME}, 5, "THZ_split: $msg2 --- $risultato";
  977. }
  978. else {
  979. my $cmdHex2 = $cmdhash->{cmd2};
  980. if(defined($cmdHex2) ) {
  981. $cmdHex2=THZ_encodecommand($cmdHex2,"get");
  982. ($err, $msg2) = THZ_Get_Comunication($hash, $cmdHex2);
  983. if (defined($err)) {
  984. Log3 $hash->{NAME}, 5, "THZ_Get: Error msg2: '$err'";
  985. return ($msg2 ."\n msg2 " . $err);
  986. }
  987. $msg2 = THZ_Parse1($hash,$msg2);
  988. }
  989. my $cmdHex3 = $cmdhash->{cmd3};
  990. if(defined($cmdHex3)) {
  991. my $msg3= " ";
  992. $cmdHex3=THZ_encodecommand($cmdHex3,"get");
  993. ($err, $msg3) = THZ_Get_Comunication($hash, $cmdHex3);
  994. if (defined($err)) {
  995. Log3 $hash->{NAME}, 5, "THZ_Get: Error msg3: '$err'";
  996. return ($msg3 ."\n msg3 " . $err);
  997. }
  998. $msg2 = THZ_Parse1($hash,$msg3) * 1000 + $msg2 ;
  999. }
  1000. }
  1001. my $unit = $cmdhash->{unit};
  1002. $msg2 = $msg2 . $unit if(defined($unit)) ;
  1003. my $activatetrigger =1;
  1004. readingsSingleUpdate($hash, $cmd, $msg2, $activatetrigger);
  1005. #open (MYFILE, '>>data.txt');
  1006. #print MYFILE ($cmd . "-" . $msg2 . "\n");
  1007. #close (MYFILE);
  1008. return ($msg2);
  1009. }
  1010. #####################################
  1011. #
  1012. # THZ_Get_Comunication- provides a method for comunication called from THZ_Get or THZ_Set
  1013. #
  1014. # Parameter hash and CMD2 or 3
  1015. #
  1016. ########################################################################################
  1017. sub THZ_Get_Comunication($$) {
  1018. my ($hash, $cmdHex) = @_;
  1019. my ($err, $msg) =("", " ");
  1020. Log3 $hash->{NAME}, 5, "THZ_Get_Comunication: Check if port is open. State = '($hash->{STATE})'";
  1021. if (!(($hash->{STATE}) eq "opened")) { return("closed connection", "");}
  1022. #slow down for old firmwares
  1023. select(undef, undef, undef, 0.25) if (AttrVal($hash->{NAME}, "firmware" , "4.39") =~ /^2/ );
  1024. select(undef, undef, undef, 0.001);
  1025. THZ_Write($hash, "02"); # step1 --> STX start of text
  1026. ($err, $msg) = THZ_ReadAnswer($hash);
  1027. #Expectedanswer1 is "10" DLE data link escape
  1028. if ($msg eq "10") {
  1029. THZ_Write($hash, $cmdHex); # step2 --> send request SOH start of heading -- Null -- ?? -- DLE data link escape -- EOT End of Text
  1030. ($err, $msg) = THZ_ReadAnswer($hash);
  1031. }
  1032. elsif ($msg eq "15") {Log3 $hash->{NAME}, 3, "$hash->{NAME} NAK!!"; select(undef, undef, undef, 0.5);}
  1033. if ((defined($err))) { $err .= " error found at step1"; select(undef, undef, undef, 0.1); return($err, $msg) ;}
  1034. # Expectedanswer2 is "1002", DLE data link escape -- STX start of text
  1035. if ($msg eq "10") { ($err, $msg) = THZ_ReadAnswer($hash);}
  1036. elsif ($msg eq "15") {Log3 $hash->{NAME}, 3, "$hash->{NAME} NAK!!"; select(undef, undef, undef, 0.5); return($err, $msg) ;}
  1037. if ($msg eq "1002" || $msg eq "02") {
  1038. THZ_Write($hash, "10"); # step3 --> DLE data link escape // ack datatranfer
  1039. ($err, $msg) = THZ_ReadAnswer($hash); # Expectedanswer3 // read from the heatpump
  1040. THZ_Write($hash, "10");
  1041. }
  1042. if ((defined($err))) { $err .= " error found at step2";}
  1043. else {($err, $msg) = THZ_decode($msg);} #clean up and remove footer and header
  1044. return($err, $msg) ;
  1045. }
  1046. #####################################
  1047. #
  1048. # THZ_ReadAnswer- provides a method for simple read
  1049. #
  1050. # Parameter hash and command to be sent to the interface
  1051. #
  1052. ########################################################################################
  1053. sub THZ_ReadAnswer($)
  1054. {
  1055. my ($hash) = @_;
  1056. my $name = $hash->{NAME};
  1057. Log3 $hash->{NAME}, 5, "$hash->{NAME} start Funktion THZ_ReadAnswer";
  1058. ###------Windows support
  1059. select(undef, undef, undef, 0.025) if( $^O =~ /Win/ ); ###delay of 25 ms for windows-OS, because SimpleReadWithTimeout does not wait
  1060. my $buf = DevIo_SimpleReadWithTimeout($hash, 0.5);
  1061. $buf = DevIo_SimpleReadWithTimeout($hash, 0.1) if(!defined($buf)) ; #added for Karl Antwort msg468515
  1062. if(!defined($buf)) {
  1063. Log3 $hash->{NAME}, 3, "$hash->{NAME} THZ_ReadAnswer got no answer from DevIo_SimpleRead. Maybe too slow?";
  1064. return ("InterfaceNotRespondig", "");
  1065. }
  1066. my $data = uc(unpack('H*', $buf));
  1067. my $count =1;
  1068. my $countmax = 80;
  1069. while (( (length($data) == 1) or (($data =~ m/^01/) and ($data !~ m/1003$/m ))) and ($count <= $countmax))
  1070. { ###------Windows support
  1071. select(undef, undef, undef, 0.005) if( $^O =~ /Win/ ); ###delay of 5 ms for windows-OS, because SimpleReadWithTimeout does not wait
  1072. my $buf1 = DevIo_SimpleReadWithTimeout($hash, 0.02);
  1073. Log3($hash->{NAME}, 5, "double read $count activated $data");
  1074. if(defined($buf1)) {
  1075. $buf .= $buf1 ;
  1076. $data = uc(unpack('H*', $buf));
  1077. Log3($hash->{NAME}, 5, "double read $count result with buf1 $data");
  1078. $count ++;
  1079. }
  1080. else{ $count += 5; }
  1081. }
  1082. return ("WInterface max repeat limited to $countmax ", $data) if ($count == ($countmax +1));
  1083. Log3 $hash->{NAME}, 5, "THZ_ReadAnswer: uc unpack: '$data'";
  1084. return (undef, $data);
  1085. }
  1086. #####################################
  1087. #
  1088. # THZ_checksum - takes a string, removes the footer (4bytes) and computes checksum (without checksum of course)
  1089. #
  1090. # Parameter string
  1091. # returns the checksum 2bytes
  1092. #
  1093. ########################################################################################
  1094. sub THZ_checksum($) {
  1095. my ($stringa) = @_;
  1096. my $ml = length($stringa) - 4;
  1097. my $checksum = 0;
  1098. for(my $i = 0; $i < $ml; $i += 2) {
  1099. ($checksum= $checksum + hex(substr($stringa, $i, 2))) if ($i != 4);
  1100. }
  1101. return (sprintf("%02X", ($checksum %256)));
  1102. }
  1103. #####################################
  1104. #
  1105. # hex2int - convert from hex to int with sign 16bit
  1106. #
  1107. ########################################################################################
  1108. sub hex2int($) {
  1109. my ($num) = @_;
  1110. $num = unpack('s', pack('S', hex($num)));
  1111. return $num;
  1112. }
  1113. ####################################
  1114. #
  1115. # quaters2time - convert from hex to time; specific to the week programm registers
  1116. #
  1117. # parameter 1 byte representing number of quarter from midnight
  1118. # returns string representing time
  1119. #
  1120. # example: value 1E is converted to decimal 30 and then to a time 7:30
  1121. ########################################################################################
  1122. sub quaters2time($) {
  1123. my ($num) = @_;
  1124. return("n.a.") if($num eq "80");
  1125. my $quarters= hex($num) %4;
  1126. my $hour= (hex($num) - $quarters)/4 ;
  1127. my $time = sprintf("%02u", ($hour)) . ":" . sprintf("%02u", ($quarters*15));
  1128. return $time;
  1129. }
  1130. ####################################
  1131. #
  1132. # time2quarters - convert from time to quarters in hex; specific to the week programm registers
  1133. #
  1134. # parameter: string representing time
  1135. # returns: 1 byte representing number of quarter from midnight
  1136. #
  1137. # example: a time 7:30 is converted to decimal 30
  1138. ########################################################################################
  1139. sub time2quaters($) {
  1140. my ($stringa) = @_;
  1141. return("128") if($stringa eq "n.a.");
  1142. my ($h,$m) = split(":", $stringa);
  1143. $m = 0 if(!$m);
  1144. $h = 0 if(!$h);
  1145. my $num = $h*4 + int($m/15);
  1146. return ($num);
  1147. }
  1148. ####################################
  1149. #
  1150. # THZ_replacebytes - replaces bytes in string
  1151. #
  1152. # parameters: string, bytes to be searched, replacing bytes
  1153. # retunrns changed string
  1154. #
  1155. ########################################################################################
  1156. sub THZ_replacebytes($$$) {
  1157. my ($stringa, $find, $replace) = @_;
  1158. my $leng_str = length($stringa);
  1159. my $leng_find = length($find);
  1160. my $new_stringa ="";
  1161. for(my $i = 0; $i < $leng_str; $i += 2) {
  1162. if (substr($stringa, $i, $leng_find) eq $find){
  1163. $new_stringa=$new_stringa . $replace;
  1164. if ($leng_find == 4) {$i += 2;}
  1165. }
  1166. else {$new_stringa=$new_stringa . substr($stringa, $i, 2);};
  1167. }
  1168. return ($new_stringa);
  1169. }
  1170. ## usage THZ_overwritechecksum("0100XX". $cmd."1003"); not needed anymore
  1171. sub THZ_overwritechecksum($) {
  1172. my ($stringa) = @_;
  1173. my $checksumadded=substr($stringa,0,4) . THZ_checksum($stringa) . substr($stringa,6);
  1174. return($checksumadded);
  1175. }
  1176. ####################################
  1177. #
  1178. # THZ_encodecommand - creates a telegram for the heatpump with a given command
  1179. #
  1180. # usage THZ_encodecommand($cmd,"get") or THZ_encodecommand($cmd,"set");
  1181. # parameter string,
  1182. # retunrns encoded string
  1183. #
  1184. ########################################################################################
  1185. sub THZ_encodecommand($$) {
  1186. my ($cmd,$getorset) = @_;
  1187. my $header = "0100";
  1188. $header = "0180" if ($getorset eq "set"); # "set" and "get" have differnt header
  1189. my $footer ="1003";
  1190. my $checksumadded=THZ_checksum($header . "XX" . $cmd . $footer) . $cmd;
  1191. # each 2B byte must be completed by byte 18
  1192. # each 10 byte must be repeated (duplicated)
  1193. my $find = "10";
  1194. my $replace = "1010";
  1195. #$checksumadded =~ s/$find/$replace/g; #problems in 1% of the cases, in middle of a byte
  1196. $checksumadded=THZ_replacebytes($checksumadded, $find, $replace);
  1197. $find = "2B";
  1198. $replace = "2B18";
  1199. #$checksumadded =~ s/$find/$replace/g;
  1200. $checksumadded=THZ_replacebytes($checksumadded, $find, $replace);
  1201. return($header. $checksumadded .$footer);
  1202. }
  1203. ####################################
  1204. #
  1205. # THZ_decode - decodes a telegram from the heatpump -- no parsing here
  1206. #
  1207. # Each response has the same structure as request - header (four bytes), optional data and footer:
  1208. # Header: 01
  1209. # 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
  1210. # Checksum: ? 1 byte - the same algorithm as for request
  1211. # Command: ? 1 byte - should match Request.Command
  1212. # Data: ? only when Read, length depends on data type
  1213. # Footer: 10 03
  1214. #
  1215. ########################################################################################
  1216. sub THZ_decode($) {
  1217. my ($message_orig) = @_;
  1218. # raw data received from device have to be de-escaped before header evaluation and data use:
  1219. # - each sequece 2B 18 must be replaced with single byte 2B
  1220. # - each sequece 10 10 must be replaced with single byte 10
  1221. my $find = "1010";
  1222. my $replace = "10";
  1223. $message_orig=THZ_replacebytes($message_orig, $find, $replace);
  1224. $find = "2B18";
  1225. $replace = "2B";
  1226. $message_orig=THZ_replacebytes($message_orig, $find, $replace);
  1227. #Check if answer is NAK
  1228. if (length($message_orig) == 2 && $message_orig eq "15") {
  1229. return("NAK received from device",$message_orig);
  1230. }
  1231. #check header and if ok 0100, check checksum and return the decoded msg
  1232. my $header = substr($message_orig,0,4);
  1233. if ($header eq "0100")
  1234. {
  1235. if (THZ_checksum($message_orig) eq substr($message_orig,4,2)) {
  1236. $message_orig =~ /0100(.*)1003/;
  1237. my $message = $1;
  1238. return (undef, $message);
  1239. }
  1240. else {return (THZ_checksum($message_orig) . "crc_error in answer", $message_orig)};
  1241. }
  1242. if ($header eq "0103")
  1243. {
  1244. return ("command not known", $message_orig);
  1245. }
  1246. if ($header eq "0102")
  1247. {
  1248. return ("CRC error in request", $message_orig);
  1249. }
  1250. if ($header eq "0104")
  1251. {
  1252. return ("UNKNOWN REQUEST", $message_orig);
  1253. }
  1254. if ($header eq "0180")
  1255. {
  1256. return (undef, $message_orig);
  1257. }
  1258. return ("new unknown answer " , $message_orig);
  1259. }
  1260. ###############################
  1261. #added by jakob do not know if needed
  1262. #
  1263. ###############################
  1264. local $SIG{__WARN__} = sub
  1265. {
  1266. my $message = shift;
  1267. if (!defined($internalHash)) {
  1268. Log 3, "EXCEPTION in THZ: '$message'";
  1269. }
  1270. else
  1271. {
  1272. Log3 $internalHash->{NAME},3, "EXCEPTION in THZ: '$message'";
  1273. }
  1274. };
  1275. #######################################
  1276. #THZ_Parse1($) could be used in order to test an external config file; I do not know if I want it
  1277. #e.g. {THZ_Parse1(undef,"F70B000500E6")}
  1278. #######################################
  1279. sub THZ_Parse1($$) {
  1280. my ($hash,$message) = @_;
  1281. Log3 $hash->{NAME}, 5, "Parse message: $message";
  1282. my $length = length($message);
  1283. Log3 $hash->{NAME}, 5, "Message length: $length";
  1284. my $parsingcmd = substr($message,2,2);
  1285. $parsingcmd = substr($message,2,6) if (($parsingcmd =~ m/(0A|0B|0C)/) and (AttrVal($hash->{NAME}, "firmware" , "4.39") !~ /^2/) );
  1286. my $msgtype;
  1287. my $parsingrule;
  1288. my $parsingelement;
  1289. # search for the type in %gets
  1290. foreach my $cmdhash (values %gets) {
  1291. if ($cmdhash->{cmd2} eq $parsingcmd)
  1292. {$msgtype = $cmdhash->{type} ;
  1293. last
  1294. }
  1295. elsif (defined ($cmdhash->{cmd3}))
  1296. { if ($cmdhash->{cmd3} eq $parsingcmd)
  1297. {$msgtype = $cmdhash->{type} ;
  1298. last
  1299. }
  1300. }
  1301. }
  1302. $parsingrule = $parsinghash{$msgtype} if(defined($msgtype));
  1303. my $ParsedMsg = $message;
  1304. if(defined($parsingrule)) {
  1305. $ParsedMsg = "";
  1306. for $parsingelement (@$parsingrule) {
  1307. my $parsingtitle = $parsingelement->[0];
  1308. my $positionInMsg = $parsingelement->[1];
  1309. my $lengthInMsg = $parsingelement->[2];
  1310. my $Type = $parsingelement->[3];
  1311. my $divisor = $parsingelement->[4];
  1312. #check if parsing out of message, and fill with zeros; the other possibility is to skip the step.
  1313. if (length($message) < ($positionInMsg + $lengthInMsg)) {
  1314. Log3 $hash->{NAME}, 3, "THZ_Parsing: offset($positionInMsg) + length($lengthInMsg) is longer then message : '$message'";
  1315. $message.= '0' x ($positionInMsg + $lengthInMsg - length($message)); # fill up with 0s to the end if needed
  1316. #Log3 $hash->{NAME},3, "after: '$message'";
  1317. }
  1318. my $value = substr($message, $positionInMsg, $lengthInMsg);
  1319. if ($Type eq "hex") {$value= hex($value);}
  1320. elsif ($Type eq "year") {$value= hex($value)+2000;}
  1321. elsif ($Type eq "hex2int") {$value= hex2int($value);}
  1322. elsif ($Type eq "turnhexdate") {$value= substr($value, 2,2) . substr($value, 0,2); $value= sprintf("%02u.%02u", hex($value)/100, hex($value)%100); }
  1323. elsif ($Type eq "hexdate") {$value= sprintf("%02u.%02u", hex($value)/100, hex($value)%100) ;}
  1324. #elsif ($Type eq "turnhex2time") {$value= sprintf(join(':', split("\\.", hex(substr($value, 2,2) . substr($value, 0,2))/100))) ;}
  1325. #elsif ($Type eq "hex2time") {$value= sprintf(join(':', split("\\.", hex(substr($value, 0,2) . substr($value, 2,2))/100))) ;}
  1326. elsif ($Type eq "turnhex2time") {$value= substr($value, 2,2) . substr($value, 0,2); $value= sprintf("%02u:%02u", hex($value)/100, hex($value)%100); }
  1327. elsif ($Type eq "hex2time") {$value= sprintf("%02u:%02u", hex($value)/100, hex($value)%100) ;}
  1328. elsif ($Type eq "swver") {$value= sprintf("%01u.%02u", hex(substr($value, 0,2)), hex(substr($value, 2,2)));}
  1329. elsif ($Type eq "hex2ascii") {$value= uc(pack('H*', $value));}
  1330. elsif ($Type eq "opmode") {$value= $OpMode{hex($value)};}
  1331. elsif ($Type eq "opmodehc") {$value= $OpModeHC{hex($value)};}
  1332. elsif ($Type eq "esp_mant") {$value= sprintf("%.3f", unpack('f', pack( 'L', reverse(hex($value)))));}
  1333. elsif ($Type eq "somwinmode") {$value= $SomWinMode{($value)};}
  1334. elsif ($Type eq "hex2wday") {$value= unpack('b7', pack('H*',$value));}
  1335. elsif ($Type eq "weekday") {$value= $weekday{($value)};}
  1336. elsif ($Type eq "faultmap") {$value= $faultmap{(hex($value))};}
  1337. elsif ($Type eq "quater") {$value= quaters2time($value);}
  1338. elsif ($Type eq "bit0") {$value= (hex($value) & 0b0001) / 0b0001;}
  1339. elsif ($Type eq "bit1") {$value= (hex($value) & 0b0010) / 0b0010;}
  1340. elsif ($Type eq "bit2") {$value= (hex($value) & 0b0100) / 0b0100;}
  1341. elsif ($Type eq "bit3") {$value= (hex($value) & 0b1000) / 0b1000;}
  1342. elsif ($Type eq "nbit0") {$value= 1-((hex($value) & 0b0001) / 0b0001);}
  1343. elsif ($Type eq "nbit1") {$value= 1-((hex($value) & 0b0010) / 0b0010);}
  1344. elsif ($Type eq "n.a.") {$value= "n.a.";}
  1345. $value = $value/$divisor if ($divisor != 1);
  1346. $ParsedMsg .= $parsingtitle . $value;
  1347. }
  1348. }
  1349. return (undef, $ParsedMsg);
  1350. }
  1351. ########################################################################################
  1352. # only for debug
  1353. #
  1354. ########################################################################################
  1355. sub THZ_debugread($){
  1356. my ($hash) = @_;
  1357. my ($err, $msg) =("", " ");
  1358. # my @numbers=('01', '09', '16', 'D1', 'D2', 'E8', 'E9', 'F2', 'F3', 'F4', 'F5', 'F6', 'FB', 'FC', 'FD', 'FE');
  1359. my @numbers=('0A0027', '0B011B', '0C011B', '0A02CB', '0A02CC');
  1360. #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);
  1361. #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, );
  1362. # 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);
  1363. #my @numbers = (1..256);
  1364. #my @numbers = (1..65535);
  1365. #my @numbers = (1..3179);
  1366. my $indice= "FF";
  1367. unlink("data.txt"); #delete debuglog
  1368. foreach $indice(@numbers) {
  1369. #my $cmd = sprintf("%02X", $indice);
  1370. # my $cmd = sprintf("%04X", $indice);
  1371. #my $cmd = "0A" . sprintf("%04X", $indice);
  1372. my $cmd = $indice;
  1373. my $cmdHex2 = THZ_encodecommand($cmd,"get");
  1374. #($err, $msg) = THZ_Get_Comunication($hash, $cmdHex2);
  1375. #STX start of text
  1376. THZ_Write($hash, "02");
  1377. ($err, $msg) = THZ_ReadAnswer($hash);
  1378. # send request
  1379. THZ_Write($hash, $cmdHex2);
  1380. ($err, $msg) = THZ_ReadAnswer($hash);
  1381. #expected 1002; if not following if takes care
  1382. if ($msg eq "10") {
  1383. select(undef, undef, undef, 0.01);
  1384. ($err, $msg) = THZ_ReadAnswer($hash);
  1385. }
  1386. # ack datatranfer and read from the heatpump
  1387. select(undef, undef, undef, 0.015);
  1388. THZ_Write($hash, "10");
  1389. select(undef, undef, undef, 0.001);
  1390. ($err, $msg) = THZ_ReadAnswer($hash);
  1391. THZ_Write($hash, "10");
  1392. if (defined($err)) {return ($msg ."\n" . $err);}
  1393. else { #clean up and remove footer and header
  1394. ($err, $msg) = THZ_decode($msg);
  1395. if (defined($err)) {
  1396. $msg = THZ_Parse1($hash,$msg);
  1397. $msg=$cmdHex2 ."-". $msg ."-". $err;}
  1398. my $activatetrigger =1;
  1399. # readingsSingleUpdate($hash, $cmd, $msg, $activatetrigger);
  1400. open (MYFILE, '>>data.txt');
  1401. print MYFILE ($cmd . "-" . $msg . "\n");
  1402. close (MYFILE);
  1403. #Log3 $hash->{NAME}, 3, "$cmd - $msg";
  1404. }
  1405. select(undef, undef, undef, 0.2);
  1406. }
  1407. }
  1408. #######################################
  1409. #THZ_Attr($)
  1410. #in case of change of attribute starting with interval_ refresh all
  1411. ########################################################################################
  1412. sub THZ_Attr(@) {
  1413. my ($cmd, $name, $attrName, $attrVal) = @_;
  1414. my $hash = $defs{$name};
  1415. $attrVal = "4.39" if ($cmd eq "del");
  1416. if ( $attrName eq "firmware" ) {
  1417. if ($attrVal eq "2.06") {
  1418. THZ_RemoveInternalTimer("THZ_GetRefresh");
  1419. %sets = %sets206;
  1420. %gets = (%getsonly2xx, %getsonly206, %sets);
  1421. THZ_Refresh_all_gets($hash);
  1422. }
  1423. elsif ($attrVal eq "2.14") {
  1424. THZ_RemoveInternalTimer("THZ_GetRefresh");
  1425. %sets = %sets206;
  1426. %gets = (%getsonly2xx, %getsonly214, %sets);
  1427. THZ_Refresh_all_gets($hash);
  1428. }
  1429. elsif ($attrVal eq "5.39") {
  1430. THZ_RemoveInternalTimer("THZ_GetRefresh");
  1431. %sets=(%sets439, %sets539only);
  1432. %gets=(%getsonly539, %sets);
  1433. THZ_Refresh_all_gets($hash);
  1434. }
  1435. elsif ($attrVal eq "4.39technician") {
  1436. THZ_RemoveInternalTimer("THZ_GetRefresh");
  1437. %sets=(%sets439, %sets439technician);
  1438. %gets=(%getsonly439, %sets);
  1439. THZ_Refresh_all_gets($hash);
  1440. }
  1441. else { #in all other cases I assume $attrVal eq "4.39" cambiato nella v0140
  1442. THZ_RemoveInternalTimer("THZ_GetRefresh");
  1443. %sets=%sets439;
  1444. %gets=(%getsonly439, %sets);
  1445. THZ_Refresh_all_gets($hash);
  1446. }
  1447. }
  1448. if( $attrName =~ /^interval_/ ) {
  1449. #DevIo_CloseDev($hash);
  1450. THZ_RemoveInternalTimer("THZ_GetRefresh");
  1451. #sleep 1;
  1452. #DevIo_OpenDev($hash, 1, "THZ_Refresh_all_gets");
  1453. THZ_Refresh_all_gets($hash);
  1454. }
  1455. return undef;
  1456. }
  1457. #####################################
  1458. sub THZ_Undef($$) {
  1459. my ($hash, $arg) = @_;
  1460. my $name = $hash->{NAME};
  1461. THZ_RemoveInternalTimer("THZ_GetRefresh");
  1462. foreach my $d (sort keys %defs) {
  1463. if(defined($defs{$d}) &&
  1464. defined($defs{$d}{IODev}) &&
  1465. $defs{$d}{IODev} == $hash)
  1466. {
  1467. my $lev = ($reread_active ? 4 : 2);
  1468. Log3 $hash->{NAME}, $lev, "deleting port for $d";
  1469. delete $defs{$d}{IODev};
  1470. }
  1471. }
  1472. DevIo_CloseDev($hash);
  1473. return undef;
  1474. }
  1475. ##########################################
  1476. # nearest rounds to the nearrest value multiple of the first argumen
  1477. # nearest_ceil(10, 45); --> 50
  1478. # nearest_floor(10, 45); --> 40
  1479. # for all other values outside the middlevalues they take he nearest
  1480. # modified takes as an argument the function to be called, not the argument
  1481. ########################################################################################
  1482. sub nearest_ceil($$) {
  1483. my $targ = abs(shift);
  1484. my $Math1 = 0.5000000000003;
  1485. my @res = map { $targ * POSIX::floor(($_ + $Math1 * $targ) / $targ) } @_;
  1486. return wantarray ? @res : $res[0];
  1487. }
  1488. sub nearest_floor($$) {
  1489. my $targ = abs(shift);
  1490. my $Math1 = 0.5000000000003;
  1491. my @res = map { $targ * POSIX::ceil(($_ - $Math1 * $targ) / $targ) } @_;
  1492. return wantarray ? @res : $res[0];
  1493. }
  1494. ##########################################
  1495. # THZ_RemoveInternalTimer($)
  1496. # modified takes as an argument the function to be called, not the argument
  1497. ########################################################################################
  1498. sub THZ_RemoveInternalTimer($){
  1499. my ($callingfun) = @_;
  1500. foreach my $a (keys %intAt) {
  1501. delete($intAt{$a}) if($intAt{$a}{FN} eq $callingfun);
  1502. }
  1503. }
  1504. ################################
  1505. #
  1506. sub function_heatSetTemp($$) {
  1507. my ($start, $stop) = @_;
  1508. my ($p13GradientHC1, $p14LowEndHC1, $p15RoomInfluenceHC1);
  1509. my $pOpMode = " ";
  1510. my $devname; #normally Mythz but could be defined differently
  1511. foreach (keys %defs) {
  1512. $devname=$_;
  1513. last if(($defs{$_}{TYPE}) =~ "THZ");
  1514. }
  1515. if (AttrVal($devname, "firmware" , "4.39") =~ /^2/ ) {
  1516. ($p13GradientHC1, $p14LowEndHC1, $p15RoomInfluenceHC1) = (split ' ',ReadingsVal($devname,"pHeat1",0))[1,3,5];
  1517. }
  1518. else {
  1519. $pOpMode = ReadingsVal($devname,"pOpMode"," ");
  1520. $p13GradientHC1 = ReadingsVal($devname,"p13GradientHC1",0.4);
  1521. $p15RoomInfluenceHC1 = (split ' ',ReadingsVal($devname,"p15RoomInfluenceHC1",0))[0];
  1522. $p14LowEndHC1 = (split ' ',ReadingsVal($devname,"p14LowEndHC1",0))[0];
  1523. }
  1524. my ($heatSetTemp, $roomSetTemp, $insideTemp) = (split ' ',ReadingsVal($devname,"sHC1",0))[11,21,27];
  1525. my $outside_tempFiltered =(split ' ',ReadingsVal($devname,"sGlobal",0))[65];
  1526. if (!defined($roomSetTemp)) {
  1527. $insideTemp=23.8 ; $roomSetTemp = 19.5; $p13GradientHC1 = 0.31; $heatSetTemp = 15; $p15RoomInfluenceHC1 = 80;
  1528. $pOpMode ="DEMO: no data";
  1529. $outside_tempFiltered = 0; $p14LowEndHC1 =0.5;
  1530. }
  1531. my $a= 0.7 + ($roomSetTemp * (1 + $p13GradientHC1 * 0.87)) + $p14LowEndHC1 + ($p15RoomInfluenceHC1 * $p13GradientHC1 * ($roomSetTemp - $insideTemp) /10);
  1532. my $a1= 0.7 + ($roomSetTemp * (1 + $p13GradientHC1 * 0.87)) + $p14LowEndHC1;
  1533. my $b= -14 * $p13GradientHC1 / $roomSetTemp;
  1534. my $c= -1 * $p13GradientHC1 /75;
  1535. my $Simul_heatSetTemp; my $Simul_heatSetTemp_simplified; my @ret;
  1536. foreach ($start..$stop) {
  1537. my $tmp =$_ * $_ * $c + $_ * $b;
  1538. $Simul_heatSetTemp = sprintf("%.1f", maxNum(5,( $tmp + $a)));
  1539. #$Simul_heatSetTemp = 8 if ($pOpMode eq "DHWmode"); # DHWmode is always at 8 grad C
  1540. $Simul_heatSetTemp_simplified = sprintf("%.1f", maxNum(5,($tmp + $a1)));
  1541. push(@ret, [$_, $Simul_heatSetTemp, $Simul_heatSetTemp_simplified]);
  1542. }
  1543. my $titlestring = 'roomSetTemp=' . $roomSetTemp . '°C p13GradientHC1=' . $p13GradientHC1 . ' p14LowEndHC1=' . $p14LowEndHC1 . 'K p15RoomInfluenceHC1=' . $p15RoomInfluenceHC1 . "% insideTemp=" . $insideTemp .'°C';
  1544. return (\@ret, $titlestring, $heatSetTemp, $outside_tempFiltered, $pOpMode);
  1545. }
  1546. #####################################
  1547. # sub THZ_PrintcurveSVG
  1548. # plots heat curve
  1549. #define wl_hr weblink htmlCode {THZ_PrintcurveSVG}
  1550. # da mettere dentro lo style per funzionare sopra svg { height:200px; width:800px;}
  1551. #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>
  1552. #####################################
  1553. sub THZ_PrintcurveSVG {
  1554. my ($ycurvevalues, $titlestring, $heatSetTemp, $outside_tempFiltered, $pOpMode) = function_heatSetTemp(-15,20);
  1555. my $v0min = minNum(15, ($ycurvevalues->[33][1]), ($ycurvevalues->[33][2]), $heatSetTemp); #lower offset than 15, if out of scale
  1556. $v0min = maxNum(5, nearest_ceil(5, $v0min)); #start only from a multiple of 5, but do not go below 5
  1557. my $vstep= 5;
  1558. $vstep= 10 if ((($ycurvevalues->[0][1])>($v0min+4*$vstep)) or (($ycurvevalues->[0][2])>($v0min+4*$vstep))); #increase step, if out of scale
  1559. my $v1=$v0min+$vstep; my $v2=$v1+$vstep; my $v3=$v2+$vstep; my $v4=$v3+$vstep;
  1560. my $ret = <<'END';
  1561. <?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" >
  1562. <style type="text/css"><![CDATA[
  1563. text { font-family:Times; font-size:12px; }
  1564. text.title { font-size:14px; }
  1565. text.copy { text-decoration:underline; stroke:none; fill:blue; }
  1566. text.paste { text-decoration:underline; stroke:none; fill:blue; }
  1567. polyline { stroke:black; fill:none; }
  1568. .border { stroke:black; fill:url(#gr_bg); }
  1569. .vgrid { stroke:gray; stroke-dasharray:2,6; }
  1570. .hgrid { stroke:gray; stroke-dasharray:2,6; }
  1571. .pasted { stroke:black; stroke-dasharray:1,1; }
  1572. .l0 { stroke:red; } text.l0 { stroke:none; fill:red; }
  1573. .l1 { stroke:green; } text.l1 { stroke:none; fill:green; }
  1574. .l3 { stroke:blue; } text.l3 { stroke:none; fill:blue; }
  1575. .l0dot { stroke:red; stroke-dasharray:2,4; } text.ldot { stroke:none; fill:red; }
  1576. ]]></style>
  1577. <defs>
  1578. <linearGradient id="gr_bg" x1="0%" y1="0%" x2="0%" y2="100%">
  1579. <stop offset="0%" style="stop-color:#FFFFF7; stop-opacity:1"/>
  1580. <stop offset="100%" style="stop-color:#FFFFC7; stop-opacity:1"/>
  1581. </linearGradient>
  1582. <linearGradient id="gr_0" x1="0%" y1="0%" x2="0%" y2="100%">
  1583. <stop offset="0%" style="stop-color:#f00; stop-opacity:.6"/>
  1584. <stop offset="100%" style="stop-color:#f88; stop-opacity:.4"/>
  1585. </linearGradient>
  1586. <linearGradient id="gr_1" x1="0%" y1="0%" x2="0%" y2="100%">
  1587. <stop offset="0%" style="stop-color:#291; stop-opacity:.6"/>
  1588. <stop offset="100%" style="stop-color:#8f7; stop-opacity:.4"/>
  1589. </linearGradient>
  1590. <pattern id="gr0_stripe" width="4" height="4" patternUnits="userSpaceOnUse" patternTransform="rotate(-45 2 2)">
  1591. <path d="M -1,2 l 6,0" stroke="#f00" stroke-width="0.5"/>
  1592. </pattern>
  1593. <pattern id="gr1_stripe" width="4" height="4" patternUnits="userSpaceOnUse" patternTransform="rotate(45 2 2)">
  1594. <path d="M -1,2 l 6,0" stroke="green" stroke-width="0.5"/>
  1595. </pattern>
  1596. <linearGradient id="gr0_gyr" x1="0%" y1="0%" x2="0%" y2="100%">
  1597. <stop offset="0%" style="stop-color:#f00; stop-opacity:.6"/>
  1598. <stop offset="50%" style="stop-color:#ff0; stop-opacity:.6"/>
  1599. <stop offset="100%" style="stop-color:#0f0; stop-opacity:.6"/>
  1600. </linearGradient>
  1601. </defs>
  1602. <rect x="48" y="19.2" width="704" height="121.6" rx="8" ry="8" fill="none" class="border"/>
  1603. <text x="12" y="80" text-anchor="middle" class="ylabel" transform="rotate(270,12,80)">HC1 heat SetTemp °C</text>
  1604. <text x="399" y="163.5" class="xlabel" text-anchor="middle">outside temperature filtered °C</text>
  1605. <text x="44" y="155" class="ylabel" text-anchor="middle">-15</text>
  1606. <text x="145" y="155" class="ylabel" text-anchor="middle">-10</text> <polyline points="145,19 145,140" class="hgrid"/>
  1607. <text x="246" y="155" class="ylabel" text-anchor="middle">-5</text> <polyline points="246,19 246,140" class="hgrid"/>
  1608. <text x="347" y="155" class="ylabel" text-anchor="middle">0</text> <polyline points="347,19 347,140" class="hgrid"/>
  1609. <text x="448" y="155" class="ylabel" text-anchor="middle">5</text> <polyline points="448,19 448,140" class="hgrid"/>
  1610. <text x="549" y="155" class="ylabel" text-anchor="middle">10</text> <polyline points="549,19 549,140" class="hgrid"/>
  1611. <text x="650" y="155" class="ylabel" text-anchor="middle">15</text> <polyline points="650,19 650,140" class="hgrid"/>
  1612. <text x="751" y="155" class="ylabel" text-anchor="middle">20</text> <polyline points="751,19 751,140" class="hgrid"/>
  1613. <g>
  1614. END
  1615. $ret .= '<polyline points="44,140 49,140"/> <text x="39" y="144" class="ylabel" text-anchor="end">' . $v0min . '</text>';
  1616. $ret .= '<polyline points="44,110 49,110"/> <text x="39" y="114" class="ylabel" text-anchor="end">' . $v1 . '</text>';
  1617. $ret .= '<polyline points="44,80 49,80"/> <text x="39" y="84" class="ylabel" text-anchor="end">' . $v2 . '</text>';
  1618. $ret .= '<polyline points="44,49 49,49"/> <text x="39" y="53" class="ylabel" text-anchor="end">' . $v3 . '</text>';
  1619. $ret .= '<polyline points="44,19 49,19"/> <text x="39" y="23" class="ylabel" text-anchor="end">' . $v4 . '</text>';
  1620. $ret .= '</g> <g>';
  1621. $ret .= '<polyline points="751,140 756,140"/> <text x="760" y="144" class="ylabel">'. $v0min .'</text>';
  1622. $ret .= '<polyline points="751,110 756,110"/> <text x="760" y="114" class="ylabel">'. $v1 .'</text>';
  1623. $ret .= '<polyline points="751,80 756,80"/> <text x="760" y="84" class="ylabel">' . $v2 .'</text>';
  1624. $ret .= '<polyline points="751,49 756,49"/> <text x="760" y="53" class="ylabel">' . $v3 .'</text>';
  1625. $ret .= '<polyline points="751,19 756,19"/> <text x="760" y="23" class="ylabel">' . $v4 .'</text>';
  1626. $ret .= '</g>' ."\n";
  1627. #labels ######################
  1628. $ret .= '<text line_id="line_1" x="70" y="100" class="l1"> --- heat curve with insideTemp correction</text>' ;
  1629. $ret .= '<text line_id="line_3" x="70" y="115" class="l3"> --- heat curve simplified</text>' ;
  1630. $ret .= '<text line_id="line_0" x="70" y="130" class="l0"> --- working point: ';
  1631. $ret .= 'outside_tempFiltered=' . $outside_tempFiltered . '°C heatSetTemp=' . $heatSetTemp . '°C </text>';
  1632. $ret .= '<text line_id="line_3" x="650" y="50" class="title"> -'. $pOpMode . '- </text>' ." \n" ;
  1633. #title ######################
  1634. $ret .= '<text id="svg_title" x="400" y="14.4" class="title" text-anchor="middle">';
  1635. $ret .= $titlestring .' </text>' . "\n";
  1636. #point ######################
  1637. $ret .='<polyline id="line_0" style="stroke-width:2" class="l0" points="';
  1638. my ($px,$py) = (sprintf("%.1f", (($outside_tempFiltered+15)*(750-49)/(15+20)+49)),sprintf("%.1f", (($heatSetTemp-$v4)*(140-19)/($v0min-$v4)+19)));
  1639. $ret.= ($px-3) . "," . ($py) ." " . ($px) . "," . ($py-3) ." " . ($px+3) . "," . ($py) ." " . ($px) . "," . ($py+3) ." " . ($px-3) . "," . ($py) ." " . '"/>' . "\n";
  1640. #curve with inside temperature correction ######################
  1641. $ret .='<polyline id="line_1" title="Heat Curve with insideTemp correction" style="stroke-width:1" class="l1" points="';
  1642. foreach (@{$ycurvevalues}) {
  1643. $ret.= (sprintf("%.1f", ($_->[0]+15)*(750-49)/(15+20)+49) ). "," . sprintf("%.1f", (($_->[1]-$v4)*(140-19)/($v0min-$v4)+19)) ." ";
  1644. }
  1645. $ret .= '"/> ' . "\n";
  1646. #curve without inside temperature correction ######################
  1647. $ret .='<polyline id="line_3" title="Heat Curve simplified" style="stroke-width:1" class="l3" points="';
  1648. foreach (@{$ycurvevalues}) {
  1649. $ret.= (sprintf("%.1f", ($_->[0]+15)*(750-49)/(15+20)+49) ). "," . sprintf("%.1f", (($_->[2]-$v4)*(140-19)/($v0min-$v4)+19)) ." ";
  1650. }
  1651. $ret .= '"/> ' . "\n";
  1652. $ret .= '</svg>';
  1653. my $FW_RETTYPE = "image/svg+xml";
  1654. return ($FW_RETTYPE, $ret);
  1655. }
  1656. sub THZ_detailFn(@)
  1657. {
  1658. my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn.
  1659. my $hash = $defs{$d}; #$d is the name of the defined device
  1660. return '<div class="SVGplot"><embed src="/fhem/THZ_PrintcurveSVG/" type="image/svg+xml" name="wl_hr22"/></div> <br>';
  1661. }
  1662. #####################################
  1663. sub THZ_backup_readings($){
  1664. my ($hash) = @_;
  1665. return "No statefile specified" if(!$attr{global}{statefile});
  1666. my $backupfile=$attr{global}{statefile};
  1667. my $t = localtime;
  1668. my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime;
  1669. $month++;
  1670. $year+=1900;
  1671. #$year+=1900 - 2000;
  1672. my $replacestr= "$hash->{NAME}-$year-$month-$mday.backup";
  1673. $backupfile=~ s/fhem.save/$replacestr/g; #saving to statefile path
  1674. if(!open(BAFH, ">$backupfile")) {
  1675. my $msg = "WriteStateFile: Cannot open $backupfile: $!";
  1676. Log 1, $msg;
  1677. return $msg;
  1678. }
  1679. print BAFH "#$t\n";
  1680. my $r = $hash->{READINGS};
  1681. foreach my $c (sort keys %{$r}) {
  1682. my $rd = $r->{$c};
  1683. if(($c =~ /^p[HOr0-9]/) and (defined($rd->{VAL}))) {
  1684. my $val = $rd->{VAL};
  1685. $val =~ s/;/;;/g;
  1686. $val =~ s/\n/\\\n/g;
  1687. print BAFH "set $hash->{NAME} $c $val\n";
  1688. }
  1689. }
  1690. return "$backupfile: $!" if(!close(BAFH));
  1691. return "saved Readings in $backupfile";
  1692. }
  1693. 1;
  1694. =pod
  1695. =item device
  1696. =item summary Monitors and controls Tecalor/StiebelEltron heatpumps via serial interface
  1697. =begin html
  1698. <a name="THZ"></a>
  1699. <h3>THZ</h3>
  1700. <ul>
  1701. 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>
  1702. 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>
  1703. Tested on a LWZ404 (with serial speed 115200) with Firmware 5.39. <br>
  1704. Tested on fritzbox, nas-qnap, raspi and macos.<br>
  1705. Implemented: read of status parameters and read/write of configuration parameters.
  1706. A complete description can be found in the 00_THZ wiki http://www.fhemwiki.de/wiki/Tecalor_THZ_Heatpump
  1707. <br><br>
  1708. <a name="THZdefine"></a>
  1709. <b>Define</b>
  1710. <ul>
  1711. <code>define &lt;name&gt; THZ &lt;device&gt;</code> <br>
  1712. <br>
  1713. <code>device</code> can take the same parameters (@baudrate, @directio,
  1714. TCP/IP, none) like the <a href="#CULdefine">CUL</a>, e.g 57600 baud or 115200.<br>
  1715. Example:
  1716. direct connection
  1717. <ul><code>
  1718. define Mytecalor THZ /dev/ttyUSB0@115200<br>
  1719. </code></ul>
  1720. or network connection (like via ser2net)<br>
  1721. <ul><code>
  1722. define Myremotetecalor THZ 192.168.0.244:2323
  1723. </code></ul>
  1724. <br>
  1725. <ul><code>
  1726. define Mythz THZ /dev/ttyUSB0@115200 <br>
  1727. define FileLog_Mythz FileLog ./log/Mythz-%Y.log Mythz <br>
  1728. attr Mythz event-min-interval s.*:4800 <br>
  1729. attr Mythz event-on-change-reading .* <br>
  1730. attr Mythz interval_sDHW 400 <br>
  1731. attr Mythz interval_sElectrDHWDay 2400 <br>
  1732. attr Mythz interval_sElectrDHWTotal 43200 <br>
  1733. attr Mythz interval_sGlobal 400 <br>
  1734. attr Mythz interval_sHC1 400 <br>
  1735. attr Mythz interval_sHeatDHWDay 2400 <br>
  1736. attr Mythz interval_sHeatDHWTotal 43200 <br>
  1737. attr Mythz interval_sHeatRecoveredDay 2400 <br>
  1738. attr Mythz interval_sHeatRecoveredTotal 43200 <br>
  1739. attr Mythz interval_sHistory 86400 <br>
  1740. attr Mythz interval_sLast10errors 86400 <br>
  1741. attr Mythz room pompa <br>
  1742. attr FileLog_Mythz room pompa <br>
  1743. </code></ul>
  1744. <br>
  1745. If the attributes interval_XXXX are not defined (or 0 seconds), their internal polling is disabled.
  1746. <br>
  1747. This module is starting to support older firmware 2.06 or newer firmware 5.39; the following attribute adapts decoding <br>
  1748. <br>
  1749. <ul><code>
  1750. attr Mythz firmware 2.06 <br>
  1751. </code></ul>
  1752. <br>
  1753. <br>
  1754. <ul><code>
  1755. attr Mythz firmware 5.39 <br>
  1756. </code></ul>
  1757. <br>
  1758. If no attribute firmware is set, it is assumed your firmware is compatible with 4.39.
  1759. <br>
  1760. A backup function has been implemented
  1761. <ul><code>
  1762. get Mythz zBackupParameters implemented
  1763. </code></ul>
  1764. The command saves all pXXX in a backupfile with a special text format.
  1765. All (or some) parameters can be easily restored with one copy&paste from the backupfile in a telnet fhem session.
  1766. </ul>
  1767. <br>
  1768. </ul>
  1769. =end html
  1770. =begin html_DE
  1771. <a name="THZ"></a>
  1772. <h3>THZ</h3>
  1773. <ul>
  1774. 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
  1775. Eltron W&auml;rmepumpe. <br>
  1776. Getestet mit einer Tecalor THZ303/Sol (Serielle Geschwindigkeit 57600/115200@USB) und einer THZ403 (Serielle Geschwindigkeit 115200) mit identischer
  1777. Firmware 4.39. <br>
  1778. Getestet mit einer Stiebel LWZ404 (Serielle Geschwindigkeit 115200@USB) mit Firmware 5.39. <br>
  1779. Getestet auf FritzBox, nas-qnap, Raspberry Pi and MacOS.<br>
  1780. Dieses Modul funktioniert nicht mit &aumlterer Firmware; Gleichwohl, das "parsing" k&ouml;nnte leicht angepasst werden da die Register gut
  1781. beschrieben wurden.
  1782. https://answers.launchpad.net/heatpumpmonitor/+question/100347 <br>
  1783. Implementiert: Lesen der Statusinformation sowie Lesen und Schreiben einzelner Einstellungen.
  1784. Genauere Beschreinung des Modules --> 00_THZ wiki http://www.fhemwiki.de/wiki/Tecalor_THZ_W%C3%A4rmepumpe
  1785. <br><br>
  1786. <a name="THZdefine"></a>
  1787. <b>Define</b>
  1788. <ul>
  1789. <code>define &lt;name&gt; THZ &lt;device&gt;</code> <br>
  1790. <br>
  1791. <code>device</code> kann einige Parameter beinhalten (z.B. @baudrate, @direction,
  1792. TCP/IP, none) wie das <a href="#CULdefine">CUL</a>, z.B. 57600 baud oder 115200.<br>
  1793. Beispiel:<br>
  1794. Direkte Verbindung
  1795. <ul><code>
  1796. define Mytecalor THZ /dev/ttyUSB0@115200<br>
  1797. </code></ul>
  1798. oder vir Netzwerk (via ser2net)<br>
  1799. <ul><code>
  1800. define Myremotetecalor THZ 192.168.0.244:2323
  1801. </code></ul>
  1802. <br>
  1803. <ul><code>
  1804. define Mythz THZ /dev/ttyUSB0@115200 <br>
  1805. define FileLog_Mythz FileLog ./log/Mythz-%Y.log Mythz <br>
  1806. attr Mythz event-min-interval s.*:4800 <br>
  1807. attr Mythz event-on-change-reading .* <br>
  1808. attr Mythz interval_sDHW 400 <br>
  1809. attr Mythz interval_sElectrDHWDay 2400 <br>
  1810. attr Mythz interval_sElectrDHWTotal 43200 <br>
  1811. attr Mythz interval_sGlobal 400 <br>
  1812. attr Mythz interval_sHC1 400 <br>
  1813. attr Mythz interval_sHeatDHWDay 2400 <br>
  1814. attr Mythz interval_sHeatDHWTotal 43200 <br>
  1815. attr Mythz interval_sHeatRecoveredDay 2400 <br>
  1816. attr Mythz interval_sHeatRecoveredTotal 43200 <br>
  1817. attr Mythz interval_sHistory 86400 <br>
  1818. attr Mythz interval_sLast10errors 86400 <br>
  1819. attr Mythz room pompa <br>
  1820. attr FileLog_Mythz room pompa <br>
  1821. </code></ul>
  1822. <br>
  1823. Wenn die Attribute interval_XXXXXXX nicht definiert sind (oder 0), ist das interne Polling deaktiviert.
  1824. </ul>
  1825. <br>
  1826. </ul>
  1827. =end html_DE
  1828. =cut