46_TRX_WEATHER.pm 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042
  1. # $Id: 46_TRX_WEATHER.pm 16542 2018-04-02 22:10:20Z KernSani $
  2. ##############################################################################
  3. #
  4. # 46_TRX_WEATHER.pm
  5. # FHEM module to decode weather sensor messages for RFXtrx
  6. #
  7. # Copyright (C) 2012-2016 by Willi Herzig (Willi.Herzig@gmail.com)
  8. # Maintenance since 2018 by KernSani
  9. #
  10. # The following devices are implemented to be received:
  11. #
  12. # temperature sensors (TEMP):
  13. # * "THR128" is THR128/138, THC138
  14. # * "THGR132N" is THC238/268,THN132,THWR288,THRN122,THN122,AW129/131
  15. # * "THWR800" is THWR800
  16. # * "RTHN318" is RTHN318
  17. # * "TX3_T" is LaCrosse TX3, TX4, TX17
  18. # * "TS15C" is TS15C
  19. # * "VIKING_02811" is Viking 02811
  20. # * "WS2300" is La Crosse WS2300
  21. # * "RUBICSON" is RUBiCSON
  22. # * "TFA_303133" is TFA 30.3133
  23. # * "WT0122" is WT0122 pool sensor
  24. #
  25. # humidity sensors (HYDRO):
  26. # * "TX3" is LaCrosse TX3
  27. # * "WS2300" is LaCrosse WS2300
  28. # * "S80" is Inovalley S80 plant humidity sensor
  29. #
  30. # temperature/humidity sensors (TEMPHYDRO):
  31. # * "THGR228N" is THGN122/123, THGN132, THGR122/228/238/268
  32. # * "THGR810" is THGR810
  33. # * "RTGR328" is RTGR328
  34. # * "THGR328" is THGR328
  35. # * "WTGR800_T" is WTGR800
  36. # * "THGR918" is THGR918, THGRN228, THGN500
  37. # * "TFATS34C" is TFA TS34C, Cresta
  38. # * "WT450H" is WT260,WT260H,WT440H,WT450,WT450H
  39. # * "VIKING_02038" is Viking 02035,02038 (02035 has no humidity)
  40. # * "RUBICSON" is Rubicson
  41. # * "EW109" is EW109
  42. # * "XT300" is Imagintronix/Opus XT300 Soil sensor
  43. # * "WS1700" is Alecto WS1700 and compatibles
  44. # * "WS3500" is Alecto WS3500, WS4500, Auriol H13726, Hama EWS1500, Meteoscan W155/W160, Ventus WS155
  45. #
  46. # temperature/humidity/pressure sensors (TEMPHYDROBARO):
  47. # * "BTHR918" is BTHR918
  48. # * "BTHR918N" is BTHR918N, BTHR968
  49. #
  50. # rain gauge sensors (RAIN):
  51. # * "RGR918" is RGR126/682/918
  52. # * "PCR800" is PCR800
  53. # * "TFA_RAIN" is TFA
  54. # * "RG700" is UPM RG700
  55. # * "WS2300_RAIN" is WS2300
  56. # * "TX5_RAIN" is La Crosse TX5
  57. # * "WS4500_RAIN" is Alecto WS4500, Auriol H13726, Hama EWS1500, Meteoscan W155/W160,
  58. #
  59. # wind sensors (WIND):
  60. # * "WTGR800_A" is WTGR800
  61. # * "WGR800_A" is WGR800
  62. # * "WGR918" is STR918, WGR918
  63. # * "TFA_WIND" is TFA
  64. # * "WDS500" is UPM WDS500u
  65. # * "WS2300_WIND" is WS2300
  66. # * "WS4500_WIND" is Alecto WS4500, Auriol H13726, Hama EWS1500, Meteoscan W155/W160, Ventus WS155
  67. #
  68. # UV Sensors:
  69. # * "UVN128" is Oregon UVN128, UV138
  70. # * "UVN800" is Oregon UVN800
  71. # * "TFA_UV" is TFA_UV-Sensor
  72. #
  73. # Date/Time Sensors:
  74. # * "RTGR328_DATE" is RTGR328N
  75. #
  76. # Energy Sensors:
  77. # * "CM160" is OWL CM119, CM160
  78. # * "CM180" is OWL CM180
  79. # * "REVOLT" is Revolt
  80. #
  81. # Weighing scales (WEIGHT):
  82. # * "BWR101" is Oregon Scientific BWR101
  83. # * "GR101" is Oregon Scientific GR101
  84. #
  85. # BBQ-Sensors (two temperature values):
  86. # * "ET732" is Maverick ET-732
  87. #
  88. # thermostats (THERMOSTAT):
  89. # * "TH10" is XDOM TH10
  90. # * "TLX7506" is Digimax TLX7506
  91. #
  92. # Copyright (C) 2012-2016 Willi Herzig
  93. #
  94. # This script is distributed in the hope that it will be useful,
  95. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  96. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  97. #
  98. # Due to RFXCOM SDK requirements this code may only be used with a RFXCOM device.
  99. #
  100. # Some code was derived and modified from xpl-perl
  101. # from the following two files:
  102. # xpl-perl/lib/xPL/Utils.pm:
  103. # xpl-perl/lib/xPL/RF/Oregon.pm:
  104. #
  105. #SEE ALSO
  106. # Project website: http://www.xpl-perl.org.uk/
  107. # AUTHOR: Mark Hindess, soft-xpl-perl@temporalanomaly.com
  108. #
  109. # Copyright (C) 2007, 2009 by Mark Hindess
  110. #
  111. # This library is free software; you can redistribute it and/or modify
  112. # it under the same terms as Perl itself, either Perl version 5.8.7 or,
  113. # at your option, any later version of Perl 5 you may have available.
  114. ##################################
  115. #
  116. # values for "set global verbose"
  117. # 4: log unknown prologtocols
  118. # 5: log decoding hexlines for debugging
  119. #
  120. ##############################################################################
  121. #
  122. # CHANGELOG
  123. #
  124. # 02.04.2018 support for vair CO2 sensors (forum #67734) -Thanks to vbs
  125. # 29.03.2018 Summary for Commandref
  126. #
  127. #
  128. ##############################################################################
  129. package main;
  130. use strict;
  131. use warnings;
  132. # Hex-Debugging into READING hexline? YES = 1, NO = 0
  133. my $TRX_HEX_debug = 0;
  134. # Max temperatute für Maverick BBQ
  135. my $TRX_MAX_TEMP_BBQ = 1000;
  136. my $time_old = 0;
  137. my $trx_rssi;
  138. sub
  139. TRX_WEATHER_Initialize($)
  140. {
  141. my ($hash) = @_;
  142. $hash->{Match} = "^..(40|4e|50|51|52|54|55|56|57|58|5a|5c|5d|71).*";
  143. $hash->{DefFn} = "TRX_WEATHER_Define";
  144. $hash->{UndefFn} = "TRX_WEATHER_Undef";
  145. $hash->{ParseFn} = "TRX_WEATHER_Parse";
  146. $hash->{AttrList} = "IODev ignore:1,0 do_not_notify:1,0 ".
  147. $readingFnAttributes;
  148. }
  149. #####################################
  150. sub
  151. TRX_WEATHER_Define($$)
  152. {
  153. my ($hash, $def) = @_;
  154. my @a = split("[ \t][ \t]*", $def);
  155. #my $a = int(@a);
  156. #print "a0 = $a[0]";
  157. return "wrong syntax: define <name> TRX_WEATHER code" if (int(@a) < 3);
  158. my $name = $a[0];
  159. my $code = $a[2];
  160. if (($code =~ /^CM160/) || ($code =~ /^CM180/) || ($code =~ /^REVOLT/)) {
  161. return "wrong syntax: define <name> TRX_WEATHER code [scale_current scale_total add_total]" if (int(@a) != 3 && int(@a) != 6);
  162. $hash->{scale_current} = ((int(@a) == 6) ? $a[3] : 1);
  163. $hash->{scale_total} = ((int(@a) == 6) ? $a[4] : 1.0);
  164. $hash->{add_total} = ((int(@a) == 6) ? $a[5] : 0.0);
  165. } elsif ($code =~ /^RFXMETER/) {
  166. return "wrong syntax: define <name> TRX_WEATHER RFXMETER [scale_current]" if (int(@a) != 3 && int(@a) != 5);
  167. $hash->{scale_current} = ((int(@a) == 5) ? $a[3] : 1);
  168. $hash->{value_label} = $a[4] if (int(@a) == 5);
  169. } else {
  170. return "wrong syntax: define <name> TRX_WEATHER code" if(int(@a) > 3);
  171. }
  172. $hash->{CODE} = $code;
  173. $modules{TRX_WEATHER}{defptr}{$code} = $hash;
  174. AssignIoPort($hash);
  175. return undef;
  176. }
  177. #####################################
  178. sub
  179. TRX_WEATHER_Undef($$)
  180. {
  181. my ($hash, $name) = @_;
  182. delete($modules{TRX_WEATHER}{defptr}{$name});
  183. return undef;
  184. }
  185. # --------------------------------------------
  186. # sensor types
  187. my %types =
  188. (
  189. # THERMOSTAT
  190. 0x4009 => { part => 'THERMOSTAT', method => \&TRX_WEATHER_common_therm, },
  191. # BBQ
  192. 0x4e0a => { part => 'BBQ', method => \&TRX_WEATHER_common_bbq, },
  193. # TEMP
  194. 0x5008 => { part => 'TEMP', method => \&TRX_WEATHER_common_temp, },
  195. # HYDRO
  196. 0x5108 => { part => 'HYDRO', method => \&TRX_WEATHER_common_hydro, },
  197. # TEMP HYDRO
  198. 0x520a => { part => 'TEMPHYDRO', method => \&TRX_WEATHER_common_temphydro, },
  199. # TEMP HYDRO BARO
  200. 0x540d => { part => 'TEMPHYDROBARO', method => \&TRX_WEATHER_common_temphydrobaro, },
  201. # RAIN
  202. 0x550b => { part => 'RAIN', method => \&TRX_WEATHER_common_rain, },
  203. # WIND
  204. 0x5610 => { part => 'WIND', method => \&TRX_WEATHER_common_anemometer, },
  205. # UV
  206. 0x5709 => { part => 'UV', method => \&TRX_WEATHER_common_uv, },
  207. # Date/Time sensors
  208. 0x580D => { part => 'DATE', method => \&TRX_WEATHER_common_datetime, },
  209. # Energy usage sensors
  210. 0x5A11 => { part => 'ENERGY', method => \&TRX_WEATHER_common_energy, },
  211. 0x5B13 => { part => 'ENERGY2', method => \&TRX_WEATHER_common_energy2, },
  212. 0x5c0f => { part => 'ENERGY3', method => \&TRX_WEATHER_common_energy3, },
  213. # WEIGHT
  214. 0x5D08 => { part => 'WEIGHT', method => \&TRX_WEATHER_common_weight, },
  215. # RFXMETER
  216. 0x710a => { part => 'RFXMETER', method => \&TRX_WEATHER_common_rfxmeter, },
  217. );
  218. # --------------------------------------------
  219. #my $DOT = q{.};
  220. # Important: change it to _, because FHEM uses regexp
  221. my $DOT = q{_};
  222. my @TRX_WEATHER_winddir_name=("N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW");
  223. # --------------------------------------------
  224. # The following functions are changed:
  225. # - some parameter like "parent" and others are removed
  226. # - @res array return the values directly (no usage of xPL::Message)
  227. sub TRX_WEATHER_temperature {
  228. my ($bytes, $dev, $res, $off) = @_;
  229. my $temp =
  230. (
  231. (($bytes->[$off] & 0x80) ? -1 : 1) *
  232. (($bytes->[$off] & 0x7f)*256 + $bytes->[$off+1])
  233. )/10;
  234. push @$res, {
  235. device => $dev,
  236. type => 'temp',
  237. current => $temp,
  238. units => 'Grad Celsius'
  239. }
  240. }
  241. sub TRX_WEATHER_temperature_food {
  242. my ($bytes, $dev, $res, $off) = @_;
  243. my $temp = $bytes->[$off]*256 + $bytes->[$off+1];
  244. return if ($temp > $TRX_MAX_TEMP_BBQ);
  245. push @$res, {
  246. device => $dev,
  247. type => 'temp-food',
  248. current => $temp,
  249. units => 'Grad Celsius'
  250. }
  251. }
  252. # -----------------------------
  253. sub TRX_WEATHER_common_therm {
  254. my $type = shift;
  255. my $longids = shift;
  256. my $bytes = shift;
  257. my $subtype = sprintf "%02x", $bytes->[1];
  258. my $dev_type;
  259. my %devname =
  260. ( # HEXSTRING => "NAME"
  261. 0x00 => "TLX7506",
  262. 0x01 => "TH10",
  263. );
  264. if (exists $devname{$bytes->[1]}) {
  265. $dev_type = $devname{$bytes->[1]};
  266. } else {
  267. Log3 undef, 3, "TRX_WEATHER: common_therm error undefined subtype=$subtype";
  268. my @res = ();
  269. return @res;
  270. }
  271. #my $seqnbr = sprintf "%02x", $bytes->[2];
  272. my $dev_str = $dev_type;
  273. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  274. $dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
  275. }
  276. if ($bytes->[4] > 0) {
  277. $dev_str .= $DOT.sprintf("%d", $bytes->[4]);
  278. }
  279. my @res = ();
  280. # hexline debugging
  281. if ($TRX_HEX_debug) {
  282. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  283. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  284. }
  285. my $temp = ($bytes->[5]);
  286. if ($temp) {
  287. push @res, {
  288. device => $dev_str,
  289. type => 'temp',
  290. current => $temp,
  291. units => 'Grad Celsius'
  292. }
  293. }
  294. my $setpoint =($bytes->[6]);
  295. if ($setpoint) {
  296. push @res, {
  297. device => $dev_str,
  298. type => 'setpoint',
  299. current => $setpoint,
  300. units => 'Grad Celsius'
  301. }
  302. }
  303. my $demand;
  304. my $t_status = ($bytes->[7] & 0x03);
  305. if ($t_status == 0) { $demand = 'n/a'}
  306. elsif ($t_status == 1) { $demand = 'on'}
  307. elsif ($t_status == 2) { $demand = 'off'}
  308. elsif ($t_status == 3) { $demand = 'initializing'}
  309. else {
  310. $demand = sprintf("unknown-%02x",$t_status);
  311. }
  312. Log3 undef, 5, "TRX_WEATHER: demand = $bytes->[7] $t_status $demand";
  313. push @res, {
  314. device => $dev_str,
  315. type => 'demand',
  316. current => sprintf("%s",$demand),
  317. };
  318. my $rssi = ($bytes->[8] & 0xf0) >> 4;
  319. if ($trx_rssi == 1) {
  320. push @res, {
  321. device => $dev_str,
  322. type => 'rssi',
  323. current => sprintf("%d",$rssi),
  324. };
  325. }
  326. return @res;
  327. }
  328. sub TRX_WEATHER_temperature_bbq {
  329. my ($bytes, $dev, $res, $off) = @_;
  330. my $temp = $bytes->[$off]*256 + $bytes->[$off+1];
  331. return if ($temp > $TRX_MAX_TEMP_BBQ);
  332. push @$res, {
  333. device => $dev,
  334. type => 'temp-bbq',
  335. current => $temp,
  336. units => 'Grad Celsius'
  337. }
  338. }
  339. sub TRX_WEATHER_chill_temperature {
  340. my ($bytes, $dev, $res, $off) = @_;
  341. my $temp =
  342. (
  343. (($bytes->[$off] & 0x80) ? -1 : 1) *
  344. (($bytes->[$off] & 0x7f)*256 + $bytes->[$off+1])
  345. )/10;
  346. push @$res, {
  347. device => $dev,
  348. type => 'chilltemp',
  349. current => $temp,
  350. units => 'Grad Celsius'
  351. }
  352. }
  353. sub TRX_WEATHER_humidity {
  354. my ($bytes, $dev, $res, $off) = @_;
  355. my $hum = $bytes->[$off];
  356. my $hum_str = ['dry', 'comfortable', 'normal', 'wet']->[$bytes->[$off+1]];
  357. push @$res, {
  358. device => $dev,
  359. type => 'humidity',
  360. current => $hum,
  361. string => $hum_str,
  362. units => '%'
  363. }
  364. }
  365. sub TRX_WEATHER_pressure {
  366. my ($bytes, $dev, $res, $off) = @_;
  367. #my $offset = 795 unless ($offset);
  368. my $hpa = ($bytes->[$off])*256 + $bytes->[$off+1];
  369. my $forecast = { 0x00 => 'noforecast',
  370. 0x01 => 'sunny',
  371. 0x02 => 'partly',
  372. 0x03 => 'cloudy',
  373. 0x04 => 'rain',
  374. }->{$bytes->[$off+2]} || 'unknown';
  375. push @$res, {
  376. device => $dev,
  377. type => 'pressure',
  378. current => $hpa,
  379. units => 'hPa',
  380. forecast => $forecast,
  381. };
  382. }
  383. sub TRX_WEATHER_simple_battery {
  384. my ($bytes, $dev, $res, $off) = @_;
  385. my $battery;
  386. my $battery_level = $bytes->[$off] & 0x0f;
  387. if ($battery_level == 0x9) { $battery = 'ok'}
  388. elsif ($battery_level == 0x0) { $battery = 'low'}
  389. else {
  390. $battery = sprintf("unknown-%02x",$battery_level);
  391. }
  392. push @$res, {
  393. device => $dev,
  394. type => 'battery',
  395. current => $battery,
  396. };
  397. my $rssi = ($bytes->[$off] & 0xf0) >> 4;
  398. if ($trx_rssi == 1) {
  399. push @$res, {
  400. device => $dev,
  401. type => 'rssi',
  402. current => sprintf("%d",$rssi),
  403. };
  404. }
  405. }
  406. sub TRX_WEATHER_battery {
  407. my ($bytes, $dev, $res, $off) = @_;
  408. my $battery;
  409. my $battery_level = ($bytes->[$off] & 0x0f) + 1;
  410. if ($battery_level > 5) {
  411. $battery = sprintf("ok %d0%%",$battery_level);
  412. } else {
  413. $battery = sprintf("low %d0%%",$battery_level);
  414. }
  415. push @$res, {
  416. device => $dev,
  417. type => 'battery',
  418. current => $battery,
  419. };
  420. my $rssi = ($bytes->[$off] & 0xf0) >> 4;
  421. if ($trx_rssi == 1) {
  422. push @$res, {
  423. device => $dev,
  424. type => 'rssi',
  425. current => sprintf("%d",$rssi),
  426. };
  427. }
  428. }
  429. # Test if to use longid for device type
  430. sub TRX_WEATHER_use_longid {
  431. my ($longids,$dev_type) = @_;
  432. return 0 if ($longids eq "");
  433. return 0 if ($longids eq "0");
  434. return 1 if ($longids eq "1");
  435. return 1 if ($longids eq "ALL");
  436. return 1 if(",$longids," =~ m/,$dev_type,/);
  437. return 0;
  438. }
  439. # ------------------------------------------------------------
  440. # T R X _ W E A T H E R _ c o m m o n _ a n e m o m e t e r
  441. # 0x5610 => { part => 'WIND'
  442. sub TRX_WEATHER_common_anemometer {
  443. my $type = shift;
  444. my $longids = shift;
  445. my $bytes = shift;
  446. my $subtype = sprintf "%02x", $bytes->[1];
  447. my $dev_type;
  448. my %devname =
  449. ( # HEXSTRING => "NAME"
  450. 0x01 => "WTGR800_A",
  451. 0x02 => "WGR800",
  452. 0x03 => "WGR918",
  453. 0x04 => "TFA_WIND",
  454. 0x05 => "WDS500", # UPM WDS500
  455. 0x06 => "WS2300_WIND", # WS2300
  456. 0x07 => "WS4500_WIND", # Alecto WS4500, Auriol H13726, Hama EWS1500, Meteoscan W155/W160, Ventus WS155
  457. );
  458. if (exists $devname{$bytes->[1]}) {
  459. $dev_type = $devname{$bytes->[1]};
  460. } else {
  461. Log3 undef, 3, "TRX_WEATHER: common_anemometer error undefined subtype=$subtype";
  462. my @res = ();
  463. return @res;
  464. }
  465. my $dev_str = $dev_type;
  466. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  467. $dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
  468. }
  469. if ($bytes->[4] > 0) {
  470. $dev_str .= $DOT.sprintf("%d", $bytes->[4]);
  471. }
  472. my @res = ();
  473. # hexline debugging
  474. if ($TRX_HEX_debug) {
  475. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  476. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  477. }
  478. my $dir = $bytes->[5]*256 + $bytes->[6];
  479. my $dirname = $TRX_WEATHER_winddir_name[int((($dir + 11.25) % 360) / 22.5)];
  480. my $avspeed = ($bytes->[7]*256 + $bytes->[8]) / 10;
  481. my $speed = ($bytes->[9]*256 + $bytes->[10]) / 10;
  482. if ($dev_type eq "TFA_WIND") {
  483. TRX_WEATHER_temperature($bytes, $dev_str, \@res, 11);
  484. TRX_WEATHER_chill_temperature($bytes, $dev_str, \@res, 13);
  485. }
  486. push @res, {
  487. device => $dev_str,
  488. type => 'speed',
  489. current => $speed,
  490. average => $avspeed,
  491. units => 'mps',
  492. } , {
  493. device => $dev_str,
  494. type => 'direction',
  495. current => $dir,
  496. string => $dirname,
  497. units => 'degrees',
  498. };
  499. TRX_WEATHER_battery($bytes, $dev_str, \@res, 15);
  500. return @res;
  501. }
  502. # --------------------------------------------------------------------
  503. # T R X _ W E A T H E R _ c o m m o n _ b b q
  504. # 0x4e0a => { part => 'BBQ'
  505. #
  506. sub TRX_WEATHER_common_bbq {
  507. my $type = shift;
  508. my $longids = shift;
  509. my $bytes = shift;
  510. my $subtype = sprintf "%02x", $bytes->[1];
  511. my $dev_type;
  512. my %devname =
  513. ( # HEXSTRING => "NAME"
  514. 0x01 => "ET732",
  515. );
  516. if (exists $devname{$bytes->[1]}) {
  517. $dev_type = $devname{$bytes->[1]};
  518. } else {
  519. Log3 undef, 3, "TRX_WEATHER: common_bbq error undefined subtype=$subtype";
  520. my @res = ();
  521. return @res;
  522. }
  523. #my $seqnbr = sprintf "%02x", $bytes->[2];
  524. my $dev_str = $dev_type;
  525. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  526. $dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
  527. $dev_str .= $DOT.sprintf("%02x", $bytes->[4]);
  528. }
  529. my @res = ();
  530. # hexline debugging
  531. if ($TRX_HEX_debug) {
  532. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  533. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  534. }
  535. TRX_WEATHER_temperature_food($bytes, $dev_str, \@res, 5);
  536. TRX_WEATHER_temperature_bbq($bytes, $dev_str, \@res, 7);
  537. TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 9);
  538. return @res;
  539. }
  540. #########################################
  541. # From xpl-perl/lib/xPL/Util.pm:
  542. sub RFXMETER_hi_nibble {
  543. ($_[0]&0xf0)>>4;
  544. }
  545. sub RFXMETER_lo_nibble {
  546. $_[0]&0xf;
  547. }
  548. sub RFXMETER_nibble_sum {
  549. my $c = $_[0];
  550. my $s = 0;
  551. foreach (0..$_[0]-1) {
  552. $s += RFXMETER_hi_nibble($_[1]->[$_]);
  553. $s += RFXMETER_lo_nibble($_[1]->[$_]);
  554. }
  555. $s += RFXMETER_hi_nibble($_[1]->[$_[0]]) if (int($_[0]) != $_[0]);
  556. return $s;
  557. }
  558. #####################################
  559. sub TRX_WEATHER_common_rfxmeter {
  560. my $typeDev = shift;
  561. my $longids = shift;
  562. my $bytes = shift;
  563. my $dev_type;
  564. my %devname =
  565. ( # HEXSTRING => "NAME"
  566. 0x00 => "RFXMETER",
  567. );
  568. if (exists $devname{$bytes->[1]}) {
  569. $dev_type = $devname{$bytes->[1]};
  570. } else {
  571. my $subtype = sprintf "%02x", $bytes->[1];
  572. Log3 undef, 3, "TRX_WEATHER: common_rfxmeter error undefined subtype=$subtype";
  573. my @res = ();
  574. return @res;
  575. }
  576. my $dev_str = $dev_type;
  577. $dev_str .= $DOT.sprintf("%d", $bytes->[3]);
  578. my @res = ();
  579. # hexline debugging
  580. if ($TRX_HEX_debug) {
  581. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  582. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  583. }
  584. if ( ($bytes->[3] + ($bytes->[4]^0xf)) != 0xff) {
  585. Log 4, "RFXMETER: check1 failed";
  586. return @res;
  587. }
  588. my $type = RFXMETER_hi_nibble($bytes->[5]);
  589. Log 4, "RFXMETER: type=$type";
  590. my $check = RFXMETER_lo_nibble($bytes->[5]);
  591. Log 4, "RFXMETER: check=$check";
  592. # we would do the parity check here but I wasn't able to find the parity bits in the msg
  593. # I will just assume the parity check was done inside the RfxTrx already
  594. # my $nibble_sum = RFXMETER_nibble_sum(5.5, $bytes);
  595. # my $parity = 0xf^($nibble_sum&0xf);
  596. # unless ($parity == $check) {
  597. # warn "RFXMeter parity error $parity != $check\n";
  598. # return @res;
  599. # }
  600. my $type_str =
  601. [
  602. 'normal data packet',
  603. 'new interval time set',
  604. 'calibrate value',
  605. 'new address set',
  606. 'counter value reset to zero',
  607. 'set 1st digit of counter value integer part',
  608. 'set 2nd digit of counter value integer part',
  609. 'set 3rd digit of counter value integer part',
  610. 'set 4th digit of counter value integer part',
  611. 'set 5th digit of counter value integer part',
  612. 'set 6th digit of counter value integer part',
  613. 'counter value set',
  614. 'set interval mode within 5 seconds',
  615. 'calibration mode within 5 seconds',
  616. 'set address mode within 5 seconds',
  617. 'identification packet',
  618. ]->[$type];
  619. unless ($type == 0) {
  620. warn "Unsupported rfxmeter message $type_str\n";
  621. return @res;
  622. }
  623. # the byte order of the actual value is different from the original RfxMeter protocol
  624. # again I assume this was done by RfxTrx
  625. my $current = ($bytes->[6] << 16) + ($bytes->[7] << 8) + ($bytes->[8]);
  626. Log 4, "TRX_WEATHER: current=$current";
  627. # I could not make sense of all bytes of the message. Example message:
  628. # 7100 29 8676 00 016cd8 69
  629. # adr ?? ID ?? data ??
  630. push @res, {
  631. device => $dev_str,
  632. type => 'rfxmeter',
  633. current => $current,
  634. units => ''
  635. };
  636. return @res;
  637. }
  638. # --------------------------------------------------------------------
  639. # T R X _ W E A T H E R _ c o m m o n _ t e m p
  640. # 0x5008 => { part => 'TEMP'
  641. sub TRX_WEATHER_common_temp {
  642. my $type = shift;
  643. my $longids = shift;
  644. my $bytes = shift;
  645. my $subtype = sprintf "%02x", $bytes->[1];
  646. my $dev_type;
  647. my %devname =
  648. ( # HEXSTRING => "NAME"
  649. 0x01 => "THR128",
  650. 0x02 => "THGR132N", # was THGR228N,
  651. 0x03 => "THWR800",
  652. 0x04 => "RTHN318",
  653. 0x05 => "TX3", # LaCrosse TX3
  654. 0x06 => "TS15C",
  655. 0x07 => "VIKING_02811", # Viking 02811
  656. 0x08 => "WS2300", # La Crosse WS2300
  657. 0x09 => "RUBICSON", # RUBiCSON
  658. 0x0a => "TFA_303133", # TFA 30.3133
  659. 0x0b => "WT0122", # WT0122
  660. );
  661. if (exists $devname{$bytes->[1]}) {
  662. $dev_type = $devname{$bytes->[1]};
  663. } else {
  664. Log3 undef, 3, "TRX_WEATHER: common_temp error undefined subtype=$subtype";
  665. my @res = ();
  666. return @res;
  667. }
  668. #my $seqnbr = sprintf "%02x", $bytes->[2];
  669. my $dev_str = $dev_type;
  670. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  671. $dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
  672. }
  673. if ($bytes->[4] > 0) {
  674. $dev_str .= $DOT.sprintf("%d", $bytes->[4]);
  675. }
  676. my @res = ();
  677. # hexline debugging
  678. if ($TRX_HEX_debug) {
  679. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  680. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  681. }
  682. TRX_WEATHER_temperature($bytes, $dev_str, \@res, 5);
  683. TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 7);
  684. return @res;
  685. }
  686. # --------------------------------------------------------------------
  687. # T R X _ W E A T H E R _ c o m m o n _ h y d r o
  688. # 0x5108 => { part => 'HYDRO'
  689. sub TRX_WEATHER_common_hydro {
  690. my $type = shift;
  691. my $longids = shift;
  692. my $bytes = shift;
  693. my $subtype = sprintf "%02x", $bytes->[1];
  694. my $dev_type;
  695. my %devname =
  696. ( # HEXSTRING => "NAME"
  697. 0x01 => "TX3", # LaCrosse TX3
  698. 0x02 => "WS2300", # LaCrosse WS2300 Humidity
  699. 0x03 => "S80", # Inovalley S80 plant humidity sensor
  700. );
  701. if (exists $devname{$bytes->[1]}) {
  702. $dev_type = $devname{$bytes->[1]};
  703. } else {
  704. Log3 undef, 3, "TRX_WEATHER: common_hydro error undefined subtype=$subtype";
  705. my @res = ();
  706. return @res;
  707. }
  708. my $dev_str = $dev_type;
  709. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  710. $dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
  711. }
  712. if ($bytes->[4] > 0) {
  713. $dev_str .= $DOT.sprintf("%d", $bytes->[4]);
  714. }
  715. my @res = ();
  716. # hexline debugging
  717. if ($TRX_HEX_debug) {
  718. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  719. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  720. }
  721. TRX_WEATHER_humidity($bytes, $dev_str, \@res, 5);
  722. TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 7);
  723. return @res;
  724. }
  725. # --------------------------------------------------------------------
  726. # T R X _ W E A T H E R _ c o m m o n _ t e m p h y d r o
  727. # 0x520a => { part => 'TEMPHYDRO'
  728. sub TRX_WEATHER_common_temphydro {
  729. my $type = shift;
  730. my $longids = shift;
  731. my $bytes = shift;
  732. my $subtype = sprintf "%02x", $bytes->[1];
  733. my $dev_type;
  734. my %devname =
  735. ( # HEXSTRING => "NAME"
  736. 0x01 => "THGR228N", # THGN122/123, THGN132, THGR122/228/238/268
  737. 0x02 => "THGR810",
  738. 0x03 => "RTGR328",
  739. 0x04 => "THGR328",
  740. 0x05 => "WTGR800_T",
  741. 0x06 => "THGR918",
  742. 0x07 => "TFATS34C",
  743. 0x08 => "WT450H", # WT260,WT260H,WT440H,WT450,WT450H
  744. 0x09 => "VIKING_02038", # Viking 02035,02038 (02035 has no humidity)
  745. 0x0a => "RUBICSON", # Rubicson
  746. 0x0b => "EW109", # EW109
  747. 0x0c => "XT300", # Imagintronix/Opus XT300 Soil sensor
  748. 0x0d => "WS1700", # Alecto WS1700 and compatibles
  749. 0x0e => "WS3500", # Alecto WS3500, WS4500, Auriol H13726, Hama EWS1500, Meteoscan W155/W160, Ventus WS155
  750. );
  751. if (exists $devname{$bytes->[1]}) {
  752. $dev_type = $devname{$bytes->[1]};
  753. } else {
  754. Log3 undef, 3, "TRX_WEATHER: common_temphydro error undefined subtype=$subtype";
  755. my @res = ();
  756. return @res;
  757. }
  758. my $dev_str = $dev_type;
  759. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  760. $dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
  761. } elsif ($dev_type eq "TFATS34C") {
  762. #Log3 undef, 1,"TRX_WEATHER: TFA";
  763. if ($bytes->[3] > 0x20 && $bytes->[3] <= 0x3F) {
  764. #Log3 undef, 1,"TRX_WEATHER: TFA 1";
  765. $dev_str .= $DOT."1";
  766. } elsif ($bytes->[3] >= 0x40 && $bytes->[3] <= 0x5F) {
  767. #Log3 undef, 1,"TRX_WEATHER: TFA 2";
  768. $dev_str .= $DOT."2";
  769. } elsif ($bytes->[3] >= 0x60 && $bytes->[3] <= 0x7F) {
  770. #Log3 undef, 1,"TRX_WEATHER: TFA 3";
  771. $dev_str .= $DOT."3";
  772. } elsif ($bytes->[3] >= 0xA0 && $bytes->[3] <= 0xBF) {
  773. #Log3 undef, 1,"TRX_WEATHER: TFA 4";
  774. $dev_str .= $DOT."4";
  775. } elsif ($bytes->[3] >= 0xC0 && $bytes->[3] <= 0xDF) {
  776. #Log3 undef, 1,"TRX_WEATHER: TFA 5";
  777. $dev_str .= $DOT."5";
  778. } else {
  779. #Log3 undef, 1,"TRX_WEATHER: TFA 9";
  780. $dev_str .= $DOT."9";
  781. }
  782. }
  783. if ($dev_type ne "TFATS34C" && $bytes->[4] > 0) {
  784. $dev_str .= $DOT.sprintf("%d", $bytes->[4]);
  785. }
  786. my @res = ();
  787. # hexline debugging
  788. if ($TRX_HEX_debug) {
  789. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  790. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  791. }
  792. TRX_WEATHER_temperature($bytes, $dev_str, \@res, 5);
  793. TRX_WEATHER_humidity($bytes, $dev_str, \@res, 7);
  794. if ($dev_type eq "THGR918") {
  795. TRX_WEATHER_battery($bytes, $dev_str, \@res, 9);
  796. } else {
  797. TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 9);
  798. }
  799. return @res;
  800. }
  801. # --------------------------------------------------------------------
  802. # T R X _ W E A T H E R _ c o m m o n _ t e m p h y d r o b a r o
  803. # 0x540d => { part => 'TEMPHYDROBARO'
  804. sub TRX_WEATHER_common_temphydrobaro {
  805. my $type = shift;
  806. my $longids = shift;
  807. my $bytes = shift;
  808. my $subtype = sprintf "%02x", $bytes->[1];
  809. my $dev_type;
  810. my %devname =
  811. ( # HEXSTRING => "NAME"
  812. 0x01 => "BTHR918",
  813. 0x02 => "BTHR918N",
  814. );
  815. if (exists $devname{$bytes->[1]}) {
  816. $dev_type = $devname{$bytes->[1]};
  817. } else {
  818. Log3 undef, 3, "TRX_WEATHER: common_temphydrobaro error undefined subtype=$subtype";
  819. my @res = ();
  820. return @res;
  821. }
  822. my $dev_str = $dev_type;
  823. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  824. $dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
  825. }
  826. if ($bytes->[4] > 0) {
  827. $dev_str .= $DOT.sprintf("%d", $bytes->[4]);
  828. }
  829. my @res = ();
  830. # hexline debugging
  831. if ($TRX_HEX_debug) {
  832. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  833. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  834. }
  835. TRX_WEATHER_temperature($bytes, $dev_str, \@res, 5);
  836. TRX_WEATHER_humidity($bytes, $dev_str, \@res, 7);
  837. TRX_WEATHER_pressure($bytes, $dev_str, \@res, 9);
  838. TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 12);
  839. return @res;
  840. }
  841. # --------------------------------------------------------------------
  842. # T R X _ W E A T H E R _ c o m m o n _ r a i n
  843. # 0x550b => { part => 'RAIN'
  844. sub TRX_WEATHER_common_rain {
  845. my $type = shift;
  846. my $longids = shift;
  847. my $bytes = shift;
  848. my $subtype = sprintf "%02x", $bytes->[1];
  849. my $dev_type;
  850. my %devname =
  851. ( # HEXSTRING => "NAME"
  852. 0x01 => "RGR918",
  853. 0x02 => "PCR800",
  854. 0x03 => "TFA_RAIN",
  855. 0x04 => "RG700",
  856. 0x05 => "WS2300_RAIN", # WS2300
  857. 0x06 => "TX5_RAIN", # La Crosse TX5
  858. 0x07 => "WS4500_RAIN", # Alecto WS4500, Auriol H13726, Hama EWS1500, Meteoscan W155/W160,
  859. );
  860. if (exists $devname{$bytes->[1]}) {
  861. $dev_type = $devname{$bytes->[1]};
  862. } else {
  863. Log3 undef, 3, "TRX_WEATHER: common_rain error undefined subtype=$subtype";
  864. my @res = ();
  865. return @res;
  866. }
  867. my $dev_str = $dev_type;
  868. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  869. $dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
  870. }
  871. if ($bytes->[4] > 0) {
  872. $dev_str .= $DOT.sprintf("%d", $bytes->[4]);
  873. }
  874. my @res = ();
  875. # hexline debugging
  876. if ($TRX_HEX_debug) {
  877. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  878. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  879. }
  880. my $rain = $bytes->[5]*256 + $bytes->[6];
  881. if ($dev_type eq "RGR918") {
  882. push @res, {
  883. device => $dev_str,
  884. type => 'rain',
  885. current => $rain,
  886. units => 'mm/h',
  887. };
  888. } elsif ($dev_type eq "PCR800") {
  889. $rain = $rain / 100;
  890. push @res, {
  891. device => $dev_str,
  892. type => 'rain',
  893. current => $rain,
  894. units => 'mm/h',
  895. };
  896. }
  897. if ($dev_type ne "TX5_RAIN") {
  898. my $train = ($bytes->[7]*256*256 + $bytes->[8]*256 + $bytes->[9])/10; # total rain
  899. push @res, {
  900. device => $dev_str,
  901. type => 'train',
  902. current => $train,
  903. units => 'mm',
  904. };
  905. }
  906. TRX_WEATHER_battery($bytes, $dev_str, \@res, 10);
  907. return @res;
  908. }
  909. my @uv_str =
  910. (
  911. qw/low low low/, # 0 - 2
  912. qw/medium medium medium/, # 3 - 5
  913. qw/high high/, # 6 - 7
  914. 'very high', 'very high', 'very high', # 8 - 10
  915. );
  916. sub TRX_WEATHER_uv_string {
  917. $uv_str[$_[0]] || 'dangerous';
  918. }
  919. # ------------------------------------------------------------
  920. # T R X _ W E A T H E R _ c o m m o n _ u v
  921. # * 0x5709 => { part => 'UV'
  922. sub TRX_WEATHER_common_uv {
  923. my $type = shift;
  924. my $longids = shift;
  925. my $bytes = shift;
  926. my $subtype = sprintf "%02x", $bytes->[1];
  927. my $dev_type;
  928. my %devname =
  929. ( # HEXSTRING => "NAME"
  930. 0x01 => "UVN128", # Oregon UVN128, UV138
  931. 0x02 => "UVN800", # Oregon UVN800
  932. 0x03 => "TFA_UV", # TFA_UV-Sensor
  933. );
  934. if (exists $devname{$bytes->[1]}) {
  935. $dev_type = $devname{$bytes->[1]};
  936. } else {
  937. Log3 undef, 3, "TRX_WEATHER: common_uv error undefined subtype=$subtype";
  938. my @res = ();
  939. return @res;
  940. }
  941. #my $seqnbr = sprintf "%02x", $bytes->[2];
  942. my $dev_str = $dev_type;
  943. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  944. $dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
  945. }
  946. if ($bytes->[4] > 0) {
  947. $dev_str .= $DOT.sprintf("%d", $bytes->[4]);
  948. }
  949. my @res = ();
  950. # hexline debugging
  951. if ($TRX_HEX_debug) {
  952. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  953. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  954. }
  955. my $uv = $bytes->[5]/10; # UV
  956. my $risk = TRX_WEATHER_uv_string(int($uv));
  957. push @res, {
  958. device => $dev_str,
  959. type => 'uv',
  960. current => $uv,
  961. risk => $risk,
  962. units => '',
  963. };
  964. if ($dev_type eq "TFA_UV") {
  965. TRX_WEATHER_temperature($bytes, $dev_str, \@res, 6);
  966. }
  967. TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 8);
  968. return @res;
  969. }
  970. # ------------------------------------------------------------
  971. # T R X _ W E A T H E R _ c o m m o n _ d a t e t i m e
  972. # 0x580D => { part => 'DATE', method => \&TRX_WEATHER_common_datetime, },
  973. sub TRX_WEATHER_common_datetime {
  974. my $type = shift;
  975. my $longids = shift;
  976. my $bytes = shift;
  977. my $subtype = sprintf "%02x", $bytes->[1];
  978. my $dev_type;
  979. my %devname =
  980. ( # HEXSTRING => "NAME"
  981. 0x01 => "RTGR328_DATE", # RTGR328N datetime datagram
  982. );
  983. if (exists $devname{$bytes->[1]}) {
  984. $dev_type = $devname{$bytes->[1]};
  985. } else {
  986. Log3 undef, 3, "TRX_WEATHER: common_datetime error undefined subtype=$subtype";
  987. my @res = ();
  988. return @res;
  989. }
  990. my $dev_str = $dev_type;
  991. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  992. $dev_str .= $DOT.sprintf("%02x%02x", $bytes->[3],$bytes->[4]);
  993. }
  994. my @res = ();
  995. # hexline debugging
  996. if ($TRX_HEX_debug) {
  997. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  998. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  999. }
  1000. push @res, {
  1001. device => $dev_str,
  1002. type => 'date',
  1003. current => sprintf("%02d-%02d-%02d", $bytes->[5],$bytes->[6],$bytes->[7]),
  1004. units => 'yymmdd',
  1005. };
  1006. push @res, {
  1007. device => $dev_str,
  1008. type => 'time',
  1009. current => sprintf("%02d:%02d:%02d", $bytes->[9],$bytes->[10],$bytes->[11]),
  1010. units => 'hhmmss',
  1011. };
  1012. TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 12);
  1013. return @res;
  1014. }
  1015. # ------------------------------------------------------------
  1016. # T R X _ W E A T H E R _ c o m m o n _ e n e r g y ( )
  1017. #
  1018. # devices: CM119, CM160, CM180
  1019. sub TRX_WEATHER_common_energy {
  1020. my $type = shift;
  1021. my $longids = shift;
  1022. my $bytes = shift;
  1023. my $subtype = sprintf "%02x", $bytes->[1];
  1024. my $dev_type;
  1025. my %devname =
  1026. ( # HEXSTRING => "NAME"
  1027. 0x01 => "CM160", # CM119, CM160
  1028. 0x02 => "CM180", # CM180
  1029. );
  1030. if (exists $devname{$bytes->[1]}) {
  1031. $dev_type = $devname{$bytes->[1]};
  1032. } else {
  1033. Log3 undef, 3, "TRX_WEATHER: common_energy error undefined subtype=$subtype";
  1034. my @res = ();
  1035. return @res;
  1036. }
  1037. #my $seqnbr = sprintf "%02x", $bytes->[2];
  1038. my $dev_str = $dev_type;
  1039. $dev_str .= $DOT.sprintf("%02x%02x", $bytes->[3],$bytes->[4]);
  1040. my @res = ();
  1041. # hexline debugging
  1042. if ($TRX_HEX_debug) {
  1043. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  1044. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  1045. }
  1046. my $energy_current = (
  1047. $bytes->[6] * 256*256*256 +
  1048. $bytes->[7] * 256*256 +
  1049. $bytes->[8] * 256 +
  1050. $bytes->[9]
  1051. );
  1052. push @res, {
  1053. device => $dev_str,
  1054. type => 'energy_current',
  1055. current => $energy_current,
  1056. units => 'W',
  1057. };
  1058. my $energy_total = (
  1059. $bytes->[10] * 256*256*256*256*256 +
  1060. $bytes->[11] * 256*256*256*256 +
  1061. $bytes->[12] * 256*256*256 +
  1062. $bytes->[13] * 256*256 +
  1063. $bytes->[14] * 256 +
  1064. $bytes->[15]
  1065. ) / 223.666;
  1066. $energy_total = $energy_total / 1000;
  1067. push @res, {
  1068. device => $dev_str,
  1069. type => 'energy_total',
  1070. current => $energy_total,
  1071. units => 'kWh',
  1072. };
  1073. my $count = $bytes->[5];
  1074. # TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 16) if ($count==0 || $count==1 || $count==2 || $count==3 || $count==8 || $count==9);
  1075. TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 16);
  1076. return @res;
  1077. }
  1078. # ------------------------------------------------------------
  1079. # T R X _ W E A T H E R _ c o m m o n _ e n e r g y 2
  1080. #
  1081. # devices: CM180i
  1082. sub TRX_WEATHER_common_energy2 {
  1083. my $type = shift;
  1084. my $longids = shift;
  1085. my $bytes = shift;
  1086. my $subtype = sprintf "%02x", $bytes->[1];
  1087. my $dev_type;
  1088. my %devname =
  1089. ( # HEXSTRING => "NAME"
  1090. 0x01 => "CM180I", # CM180i
  1091. );
  1092. if (exists $devname{$bytes->[1]}) {
  1093. $dev_type = $devname{$bytes->[1]};
  1094. } else {
  1095. Log3 undef, 3, "TRX_WEATHER: common_energy2 error undefined subtype=$subtype";
  1096. my @res = ();
  1097. return @res;
  1098. }
  1099. #my $seqnbr = sprintf "%02x", $bytes->[2];
  1100. my $dev_str = $dev_type;
  1101. $dev_str .= $DOT.sprintf("%02x%02x", $bytes->[3],$bytes->[4]);
  1102. my @res = ();
  1103. # hexline debugging
  1104. if ($TRX_HEX_debug) {
  1105. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  1106. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  1107. }
  1108. my $energy_count = $bytes->[5];
  1109. if (1) {
  1110. my $energy_current_ch1 = ($bytes->[6] * 256 + $bytes->[7])/10;
  1111. my $energy_current_ch2 = ($bytes->[8] * 256 + $bytes->[9])/10;
  1112. my $energy_current_ch3 = ($bytes->[10] * 256 + $bytes->[11]/10);
  1113. push @res, {
  1114. device => $dev_str,
  1115. type => 'energy_ch1',
  1116. current => $energy_current_ch1,
  1117. units => 'A',
  1118. };
  1119. push @res, {
  1120. device => $dev_str,
  1121. type => 'energy_ch2',
  1122. current => $energy_current_ch2,
  1123. units => 'A',
  1124. };
  1125. push @res, {
  1126. device => $dev_str,
  1127. type => 'energy_ch3',
  1128. current => $energy_current_ch3,
  1129. units => 'A',
  1130. };
  1131. }
  1132. if ($energy_count == 0) {
  1133. my $energy_total = (
  1134. $bytes->[12] * 256*256*256*256*256 +
  1135. $bytes->[13] * 256*256*256*256 +
  1136. $bytes->[14] * 256*256*256 +
  1137. $bytes->[15] * 256*256 +
  1138. $bytes->[16] * 256 +
  1139. $bytes->[17]
  1140. ) / 223.666;
  1141. $energy_total = $energy_total / 1000;
  1142. push @res, {
  1143. device => $dev_str,
  1144. type => 'energy_total',
  1145. current => $energy_total,
  1146. units => 'kWh',
  1147. };
  1148. }
  1149. # TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 16) if ($count==0 || $count==1 || $count==2 || $count==3 || $count==8 || $count==9);
  1150. TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 18);
  1151. return @res;
  1152. }
  1153. # ------------------------------------------------------------
  1154. # T R X _ W E A T H E R _ c o m m o n _ e n e r g y 3
  1155. #
  1156. # devices: REVOLT
  1157. sub TRX_WEATHER_common_energy3 {
  1158. my $type = shift;
  1159. my $longids = shift;
  1160. my $bytes = shift;
  1161. my $subtype = sprintf "%02x", $bytes->[1];
  1162. my $dev_type;
  1163. my %devname =
  1164. ( # HEXSTRING => "NAME"
  1165. 0x01 => "REVOLT", # Revolt
  1166. );
  1167. if (exists $devname{$bytes->[1]}) {
  1168. $dev_type = $devname{$bytes->[1]};
  1169. } else {
  1170. Log3 undef, 3, "TRX_WEATHER: common_energy3 error undefined subtype=$subtype";
  1171. my @res = ();
  1172. return @res;
  1173. }
  1174. #my $seqnbr = sprintf "%02x", $bytes->[2];
  1175. my $dev_str = $dev_type;
  1176. $dev_str .= $DOT.sprintf("%02x%02x", $bytes->[3],$bytes->[4]);
  1177. my @res = ();
  1178. # hexline debugging
  1179. if ($TRX_HEX_debug) {
  1180. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  1181. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  1182. }
  1183. my $energy_voltage = $bytes->[5];
  1184. push @res, {
  1185. device => $dev_str,
  1186. type => 'energy_voltage',
  1187. current => $energy_voltage,
  1188. units => 'V',
  1189. };
  1190. my $energy_current = ($bytes->[6] * 256 + $bytes->[7]) / 100;
  1191. push @res, {
  1192. device => $dev_str,
  1193. type => 'energy_current_revolt',
  1194. current => $energy_current,
  1195. units => 'A',
  1196. };
  1197. my $energy_power = ($bytes->[8] * 256 + $bytes->[9]) / 10;
  1198. push @res, {
  1199. device => $dev_str,
  1200. type => 'energy_power',
  1201. current => $energy_power,
  1202. units => 'W',
  1203. };
  1204. my $energy_total = ($bytes->[10] * 256 + $bytes->[11]) / 100;
  1205. push @res, {
  1206. device => $dev_str,
  1207. type => 'energy_total',
  1208. current => $energy_total,
  1209. units => 'kWh',
  1210. };
  1211. my $energy_pf = $bytes->[12] / 100;
  1212. push @res, {
  1213. device => $dev_str,
  1214. type => 'energy_pf',
  1215. current => $energy_pf,
  1216. units => '',
  1217. };
  1218. my $energy_freq = $bytes->[13];
  1219. push @res, {
  1220. device => $dev_str,
  1221. type => 'energy_freq',
  1222. current => $energy_freq,
  1223. units => 'Hz',
  1224. };
  1225. my $rssi = ($bytes->[14] & 0xf0) >> 4;
  1226. if ($trx_rssi == 1) {
  1227. push @res, {
  1228. device => $dev_str,
  1229. type => 'rssi',
  1230. current => sprintf("%d",$rssi),
  1231. };
  1232. }
  1233. return @res;
  1234. }
  1235. # ------------------------------------------------------------
  1236. #
  1237. sub TRX_WEATHER_common_weight {
  1238. my $type = shift;
  1239. my $longids = shift;
  1240. my $bytes = shift;
  1241. my $subtype = sprintf "%02x", $bytes->[1];
  1242. my $dev_type;
  1243. my %devname =
  1244. ( # HEXSTRING => "NAME"
  1245. 0x01 => "BWR101",
  1246. 0x02 => "GR101",
  1247. );
  1248. if (exists $devname{$bytes->[1]}) {
  1249. $dev_type = $devname{$bytes->[1]};
  1250. } else {
  1251. Log3 undef, 3, "TRX_WEATHER: common_weight error undefined subtype=$subtype";
  1252. my @res = ();
  1253. return @res;
  1254. }
  1255. #my $seqnbr = sprintf "%02x", $bytes->[2];
  1256. my $dev_str = $dev_type;
  1257. if (TRX_WEATHER_use_longid($longids,$dev_type)) {
  1258. $dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
  1259. }
  1260. if ($bytes->[4] > 0) {
  1261. $dev_str .= $DOT.sprintf("%d", $bytes->[4]);
  1262. }
  1263. my @res = ();
  1264. # hexline debugging
  1265. if ($TRX_HEX_debug) {
  1266. my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
  1267. push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
  1268. }
  1269. my $weight = ($bytes->[5]*256 + $bytes->[6])/10;
  1270. push @res, {
  1271. device => $dev_str,
  1272. type => 'weight',
  1273. current => $weight,
  1274. units => 'kg',
  1275. };
  1276. #TRX_WEATHER_simple_battery($bytes, $dev_str, \@res, 7);
  1277. return @res;
  1278. }
  1279. # -----------------------------
  1280. sub
  1281. TRX_WEATHER_Parse($$)
  1282. {
  1283. my ($iohash, $hexline) = @_;
  1284. #my $hashname = $iohash->{NAME};
  1285. #my $longid = AttrVal($hashname,"longids","");
  1286. #Log3 $iohash, $iohash, 5 ,"2: name=$hashname, attr longids = $longid";
  1287. my $longids = 0;
  1288. if (defined($attr{$iohash->{NAME}}{longids})) {
  1289. $longids = $attr{$iohash->{NAME}}{longids};
  1290. #Log3 $iohash, 5,"0: attr longids = $longids";
  1291. }
  1292. $trx_rssi = 0;
  1293. if (defined($attr{$iohash->{NAME}}{rssi})) {
  1294. $trx_rssi = $attr{$iohash->{NAME}}{rssi};
  1295. #Log3 $iohash, 5, "0: attr rssi = $trx_rssi";
  1296. }
  1297. my $time = time();
  1298. # convert to binary
  1299. my $msg = pack('H*', $hexline);
  1300. if ($time_old ==0) {
  1301. Log3 $iohash, 5, "TRX_WEATHER: decoding delay=0 hex=$hexline";
  1302. } else {
  1303. my $time_diff = $time - $time_old ;
  1304. Log3 $iohash, 5, "TRX_WEATHER: decoding delay=$time_diff hex=$hexline";
  1305. }
  1306. $time_old = $time;
  1307. # convert string to array of bytes. Skip length byte
  1308. my @rfxcom_data_array = ();
  1309. foreach (split(//, substr($msg,1))) {
  1310. push (@rfxcom_data_array, ord($_) );
  1311. }
  1312. my $num_bytes = ord($msg);
  1313. if ($num_bytes < 3) {
  1314. return;
  1315. }
  1316. my $type = $rfxcom_data_array[0];
  1317. my $sensor_id = unpack('H*', chr $type);
  1318. my $key = ($type << 8) + $num_bytes;
  1319. my $rec = $types{$key};
  1320. unless ($rec) {
  1321. Log3 $iohash, 1, "TRX_WEATHER: ERROR: Unknown sensor_id=$sensor_id message='$hexline'";
  1322. return "";
  1323. }
  1324. my $method = $rec->{method};
  1325. unless ($method) {
  1326. Log3 $iohash, 4, "TRX_WEATHER: Possible message from Oregon part '$rec->{part}'";
  1327. Log3 $iohash, 4, "TRX_WEATHER: sensor_id=$sensor_id";
  1328. return;
  1329. }
  1330. my @res;
  1331. if (! defined(&$method)) {
  1332. Log3 $iohash, 4, "TRX_WEATHER: Error: Unknown function=$method. Please define it in file $0";
  1333. Log3 $iohash, 4, "TRX_WEATHER: sensor_id=$sensor_id\n";
  1334. return "";
  1335. } else {
  1336. Log3 $iohash, 5, "TRX_WEATHER: parsing sensor_id=$sensor_id message='$hexline'";
  1337. @res = $method->($rec->{part}, $longids, \@rfxcom_data_array);
  1338. }
  1339. # get device name from first entry
  1340. my $device_name = $res[0]->{device};
  1341. #Log3 $iohash, 5, "device_name=$device_name";
  1342. if (! defined($device_name)) {
  1343. Log3 $iohash, 4, "TRX_WEATHER: error device_name undefined\n";
  1344. return "";
  1345. }
  1346. my $def = $modules{TRX_WEATHER}{defptr}{"$device_name"};
  1347. if(!$def) {
  1348. Log3 $iohash, 3, "TRX_WEATHER: Unknown device $device_name, please define it";
  1349. return "UNDEFINED $device_name TRX_WEATHER $device_name";
  1350. }
  1351. # Use $def->{NAME}, because the device may be renamed:
  1352. my $name = $def->{NAME};
  1353. return "" if(IsIgnored($name));
  1354. my $n = 0;
  1355. my $tm = TimeNow();
  1356. my $i;
  1357. my $val = "";
  1358. my $sensor = "";
  1359. readingsBeginUpdate($def);
  1360. foreach $i (@res){
  1361. #print "!> i=".$i."\n";
  1362. #printf "%s\t",$i->{device};
  1363. if ($i->{type} eq "temp") {
  1364. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name Temperatur ".$i->{current}." ".$i->{units};
  1365. $val .= "T: ".$i->{current}." ";
  1366. $sensor = "temperature";
  1367. readingsBulkUpdate($def, $sensor, $i->{current});
  1368. }
  1369. elsif ($i->{type} eq "temp-bbq") {
  1370. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name Temperature-bbq ".$i->{current}." ".$i->{units};
  1371. $val .= "TB: ".$i->{current}." ";
  1372. $sensor = "temp-bbq";
  1373. readingsBulkUpdate($def, $sensor, $i->{current});
  1374. }
  1375. elsif ($i->{type} eq "temp-food") {
  1376. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name Temperatur-food ".$i->{current}." ".$i->{units};
  1377. $val .= "TF: ".$i->{current}." ";
  1378. $sensor = "temp-food";
  1379. readingsBulkUpdate($def, $sensor, $i->{current});
  1380. }
  1381. elsif ($i->{type} eq "chilltemp") {
  1382. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name windchill ".$i->{current}." ".$i->{units};
  1383. $val .= "CT: ".$i->{current}." ";
  1384. $sensor = "windchill";
  1385. readingsBulkUpdate($def, $sensor, $i->{current});
  1386. }
  1387. elsif ($i->{type} eq "humidity") {
  1388. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name Luftfeuchtigkeit ".$i->{current}.$i->{units};
  1389. $val .= "H: ".$i->{current}." ";
  1390. $sensor = "humidity";
  1391. readingsBulkUpdate($def, $sensor, $i->{current});
  1392. }
  1393. elsif ($i->{type} eq "battery") {
  1394. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name Batterie ".$i->{current};
  1395. my $tmp_battery = $i->{current};
  1396. my @words = split(/\s+/,$i->{current});
  1397. $val .= "BAT: ".$words[0]." "; #use only first word
  1398. $sensor = "battery";
  1399. readingsBulkUpdate($def, $sensor, $i->{current});
  1400. }
  1401. elsif ($i->{type} eq "pressure") {
  1402. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name Luftdruck ".$i->{current}." ".$i->{units}." Vorhersage=".$i->{forecast};
  1403. # do not add it due to problems with hms.gplot
  1404. $val .= "P: ".$i->{current}." ";
  1405. $sensor = "pressure";
  1406. readingsBulkUpdate($def, $sensor, $i->{current});
  1407. $sensor = "forecast";
  1408. readingsBulkUpdate($def, $sensor, $i->{forecast});
  1409. }
  1410. elsif ($i->{type} eq "speed") {
  1411. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name wind_speed ".$i->{current}." wind_avspeed ".$i->{average};
  1412. $val .= "W: ".$i->{current}." ";
  1413. $val .= "WA: ".$i->{average}." ";
  1414. $sensor = "wind_speed";
  1415. readingsBulkUpdate($def, $sensor, $i->{current});
  1416. $sensor = "wind_avspeed";
  1417. readingsBulkUpdate($def, $sensor, $i->{average});
  1418. }
  1419. elsif ($i->{type} eq "direction") {
  1420. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name wind_dir ".$i->{current}." ".$i->{string};
  1421. $val .= "WD: ".$i->{current}." ";
  1422. $val .= "WDN: ".$i->{string}." ";
  1423. $sensor = "wind_dir";
  1424. readingsBulkUpdate($def, $sensor, $i->{current} . " " . $i->{string});
  1425. }
  1426. elsif ($i->{type} eq "rain") {
  1427. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name rain ".$i->{current};
  1428. $val .= "RR: ".$i->{current}." ";
  1429. $sensor = "rain_rate";
  1430. readingsBulkUpdate($def, $sensor, $i->{current});
  1431. }
  1432. elsif ($i->{type} eq "train") {
  1433. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name train ".$i->{current};
  1434. $val .= "TR: ".$i->{current}." ";
  1435. $sensor = "rain_total";
  1436. readingsBulkUpdate($def, $sensor, $i->{current});
  1437. }
  1438. elsif ($i->{type} eq "flip") {
  1439. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name flip ".$i->{current};
  1440. $val .= "F: ".$i->{current}." ";
  1441. $sensor = "rain_flip";
  1442. readingsBulkUpdate($def, $sensor, $i->{current});
  1443. }
  1444. elsif ($i->{type} eq "uv") {
  1445. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name uv_val ".$i->{current}." uv_risk ".$i->{risk};
  1446. $val .= "UV: ".$i->{current}." ";
  1447. $val .= "UVR: ".$i->{risk}." ";
  1448. $sensor = "uv_val";
  1449. readingsBulkUpdate($def, $sensor, $i->{current});
  1450. $sensor = "uv_risk";
  1451. readingsBulkUpdate($def, $sensor, $i->{risk});
  1452. }
  1453. elsif ($i->{type} eq "energy_current") {
  1454. my $energy_current = $i->{current};
  1455. if (defined($def->{scale_current})) {
  1456. $energy_current = $energy_current * $def->{scale_current};
  1457. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name scale_current=".$def->{scale_current};
  1458. }
  1459. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_current=".$energy_current;
  1460. $val .= "ECUR: ".$energy_current." ";
  1461. $sensor = "energy_current";
  1462. #readingsBulkUpdate($def, $sensor, $energy_current." ".$i->{units});
  1463. readingsBulkUpdate($def, $sensor, $energy_current);
  1464. }
  1465. elsif ($i->{type} eq "energy_ch1") {
  1466. my $energy_current = $i->{current};
  1467. if (defined($def->{scale_current})) {
  1468. $energy_current = $energy_current * $def->{scale_current};
  1469. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_ch1 scale_current=".$def->{scale_current};
  1470. }
  1471. Log3 $name, 5, "TRX_WEATHER: device=$device_name CH1 energy_current=$energy_current";
  1472. $val .= "CH1: ".$energy_current." ";
  1473. $sensor = "energy_ch1";
  1474. readingsBulkUpdate($def, $sensor, $energy_current);
  1475. }
  1476. elsif ($i->{type} eq "energy_ch2") {
  1477. my $energy_current = $i->{current};
  1478. if (defined($def->{scale_current})) {
  1479. $energy_current = $energy_current * $def->{scale_current};
  1480. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_ch2 scale_current=".$def->{scale_current};
  1481. }
  1482. Log3 $device_name, 5, "TRX_WEATHER: name=$name device=$device_name CH2 energy_current=$energy_current";
  1483. $val .= "CH2: ".$energy_current." ";
  1484. $sensor = "energy_ch2";
  1485. readingsBulkUpdate($def, $sensor, $energy_current);
  1486. }
  1487. elsif ($i->{type} eq "energy_ch3") {
  1488. my $energy_current = $i->{current};
  1489. if (defined($def->{scale_current})) {
  1490. $energy_current = $energy_current * $def->{scale_current};
  1491. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_ch3 scale_current=".$def->{scale_current};
  1492. }
  1493. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name CH3 energy_current=".$energy_current;
  1494. $val .= "CH3: ".$energy_current." ";
  1495. $sensor = "energy_ch3";
  1496. readingsBulkUpdate($def, $sensor, $energy_current);
  1497. }
  1498. elsif ($i->{type} eq "energy_current_revolt") {
  1499. my $energy_current = $i->{current};
  1500. if (defined($def->{scale_current})) {
  1501. $energy_current = $energy_current * $def->{scale_current};
  1502. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name scale_current=".$def->{scale_current};
  1503. }
  1504. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_current=".$energy_current;
  1505. #$val .= "ECUR: ".$energy_current." ";
  1506. $sensor = "energy_current";
  1507. readingsBulkUpdate($def, $sensor, $energy_current." ".$i->{units});
  1508. }
  1509. elsif ($i->{type} eq "energy_total") {
  1510. my $energy_total = $i->{current};
  1511. if (defined($def->{scale_total}) && defined($def->{add_total})) {
  1512. $energy_total = sprintf("%.4f",$energy_total * $def->{scale_total} + $def->{add_total});
  1513. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_total scale_total=".$def->{scale_total};
  1514. }
  1515. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_total=$energy_total";
  1516. $val .= "ESUM: ".$energy_total." ";
  1517. $sensor = "energy_total";
  1518. #readingsBulkUpdate($def, $sensor, $energy_total." ".$i->{units});
  1519. readingsBulkUpdate($def, $sensor, $energy_total);
  1520. }
  1521. elsif ($i->{type} eq "energy_power") {
  1522. my $energy_power = $i->{current};
  1523. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_power=$energy_power";
  1524. $val .= "EPOW: ".$energy_power." ";
  1525. $sensor = "energy_power";
  1526. readingsBulkUpdate($def, $sensor, $energy_power." ".$i->{units});
  1527. }
  1528. elsif ($i->{type} eq "energy_voltage") {
  1529. my $energy_voltage = $i->{current};
  1530. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_voltage=$energy_voltage";
  1531. #$val .= "V: ".$energy_voltage." ";
  1532. $sensor = "voltage";
  1533. readingsBulkUpdate($def, $sensor, $energy_voltage." ".$i->{units});
  1534. }
  1535. elsif ($i->{type} eq "energy_pf") {
  1536. my $energy_pf = $i->{current};
  1537. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_pf=$energy_pf";
  1538. #$val .= "PF: ".$energy_pf." ";
  1539. $sensor = "energy_pf";
  1540. readingsBulkUpdate($def, $sensor, $energy_pf." ".$i->{units});
  1541. }
  1542. elsif ($i->{type} eq "energy_freq") {
  1543. my $energy_freq = $i->{current};
  1544. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name energy_freq=$energy_freq";
  1545. #$val .= "FREQ: ".$energy_freq." ";
  1546. $sensor = "frequency";
  1547. readingsBulkUpdate($def, $sensor, $energy_freq." ".$i->{units});
  1548. }
  1549. elsif ($i->{type} eq "weight") {
  1550. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name weight ".$i->{current};
  1551. $val .= "W: ".$i->{current}." ";
  1552. $sensor = "weight";
  1553. readingsBulkUpdate($def, $sensor, $i->{current});
  1554. }
  1555. elsif ($i->{type} eq "hexline") {
  1556. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name hexline ".$i->{current};
  1557. $sensor = "hexline";
  1558. readingsBulkUpdate($def, $sensor, $i->{current});
  1559. }
  1560. elsif ($i->{type} eq "rssi") {
  1561. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name rssi ".$i->{current};
  1562. $sensor = "rssi";
  1563. readingsBulkUpdate($def, $sensor, $i->{current});
  1564. }
  1565. elsif ($i->{type} eq "date") {
  1566. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name date ".$i->{current};
  1567. $val .= $i->{current}." ";
  1568. $sensor = "date";
  1569. readingsBulkUpdate($def, $sensor, $i->{current});
  1570. }
  1571. elsif ($i->{type} eq "time") {
  1572. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name time ".$i->{current};
  1573. $val .= $i->{current}." ";
  1574. $sensor = "time";
  1575. readingsBulkUpdate($def, $sensor, $i->{current});
  1576. }
  1577. elsif ($i->{type} eq "setpoint") {
  1578. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name setpoint ".$i->{current}." ".$i->{units};
  1579. $val .= "SP: ".$i->{current}." ";
  1580. $sensor = "setpoint";
  1581. readingsBulkUpdate($def, $sensor, $i->{current});
  1582. }
  1583. elsif ($i->{type} eq "demand") {
  1584. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name state ".$i->{current};
  1585. if ($val eq "") {
  1586. $val = "$i->{current}";
  1587. }
  1588. else {
  1589. $val .= "D: ".$i->{current}." ";
  1590. }
  1591. $sensor = "demand";
  1592. readingsBulkUpdate($def, $sensor, $i->{current});
  1593. }
  1594. elsif ($i->{type} eq "rfxmeter") {
  1595. my $current = $i->{current};
  1596. $current = $current * $def->{scale_current} if (defined($def->{scale_current}));
  1597. Log3 $name, 5, "TRX_WEATHER: name=$name device=$device_name co2 ".$i->{current}." ".$i->{units};
  1598. $val .= (defined($def->{value_label}) ? $def->{value_label} : "V") . ": " .$current . " ";
  1599. my $label = defined($def->{value_label}) ? lc $def->{value_label} : "meter";
  1600. readingsBulkUpdate($def, $label, $current);
  1601. }
  1602. else {
  1603. Log3 $name, 1, "TRX_WEATHER: name=$name device=$device_name UNKNOWN Type: ".$i->{type}." Value: ".$i->{current}
  1604. }
  1605. }
  1606. if ("$val" ne "") {
  1607. # remove heading and trailing space chars from $val
  1608. $val =~ s/^\s+|\s+$//g;
  1609. #$def->{STATE} = $val;
  1610. readingsBulkUpdate($def, "state", $val);
  1611. }
  1612. readingsEndUpdate($def, 1);
  1613. return $name;
  1614. }
  1615. 1;
  1616. =pod
  1617. =item device
  1618. =item summary interprets messages of weather sensors received by TRX
  1619. =item summary_DE interpretiert Nachrichten von Wettersensoren des TRX
  1620. =begin html
  1621. <a name="TRX_WEATHER"></a>
  1622. <h3>TRX_WEATHER</h3>
  1623. <ul>
  1624. The TRX_WEATHER module interprets weather sensor messages received by a RTXtrx receiver. See <a href="http://www.rfxcom.com/oregon.htm">http://www.rfxcom.com/oregon.htm</a> for a list of
  1625. Oregon Scientific weather sensors that could be received by the RFXtrx433 tranmitter. You need to define a RFXtrx433 receiver first. See
  1626. See <a href="#TRX">TRX</a>.
  1627. <br><br>
  1628. <a name="TRX_WEATHERdefine"></a>
  1629. <b>Define</b>
  1630. <ul>
  1631. <code>define &lt;name&gt; TRX_WEATHER &lt;deviceid&gt;</code> <br>
  1632. <br>
  1633. <code>&lt;deviceid&gt;</code>
  1634. <ul>
  1635. is the device identifier of the sensor. It consists of the sensors name and (only if the attribute longids is set of the RFXtrx433) an a one byte hex string (00-ff) that identifies the sensor. If an sensor uses an switch to set an additional is then this is also added. The define statement with the deviceid is generated automatically by autocreate. The following sensor names are used: <br>
  1636. "THR128" (for THR128/138, THC138),<br>
  1637. "THGR132N" (for THC238/268,THN132,THWR288,THRN122,THN122,AW129/131),<br>
  1638. "THWR800", <br>
  1639. "RTHN318", <br>
  1640. "TX3_T" (for LaCrosse TX3, TX4, TX17),<br>
  1641. "THGR228N" (for THGN122/123, THGN132, THGR122/228/238/268),<br>
  1642. "THGR810",<br>
  1643. "RTGR328",<br>
  1644. "THGR328",<br>
  1645. "WTGR800_T" (for temperature of WTGR800),<br>
  1646. "THGR918" (for THGR918, THGRN228, THGN500),<br>
  1647. "TFATS34C" (for TFA TS34C),<br>
  1648. "BTHR918",<br>
  1649. "BTHR918N (for BTHR918N, BTHR968),<br>
  1650. "RGR918" (for RGR126/682/918),<br>
  1651. "PCR800",<br>
  1652. "TFA_RAIN" (for TFA rain sensor),<br>
  1653. "WTGR800_A" (for wind sensor of WTGR800),<br>
  1654. "WGR800" (for wind sensor of WGR800),<br>
  1655. "WGR918" (for wind sensor of STR918 and WGR918),<br>
  1656. "TFA_WIND" (for TFA wind sensor),<br>
  1657. "BWR101" (for Oregon Scientific BWR101),<br>
  1658. "GR101" (for Oregon Scientific GR101)
  1659. "TLX7506" (for Digimax TLX7506),<br>
  1660. "TH10" (for Digimax with short format),<br>
  1661. </ul>
  1662. <br>
  1663. Example: <br>
  1664. <ul>
  1665. <code>define Tempsensor TRX_WEATHER TX3_T</code><br>
  1666. <code>define Tempsensor3 TRX_WEATHER THR128_3</code><br>
  1667. <code>define Windsensor TRX_WEATHER WGR918_A</code><br>
  1668. <code>define Regensensor TRX_WEATHER RGR918</code><br>
  1669. </ul>
  1670. </ul>
  1671. <br><br>
  1672. <ul>
  1673. <code>define &lt;name&gt; TRX_WEATHER &lt;deviceid&gt; [&lt;scale_current&gt; &lt;scale_total&gt; &lt;add_total&gt;]</code> <br>
  1674. <br>
  1675. <code>&lt;deviceid&gt;</code>
  1676. <ul>
  1677. is the device identifier of the energy sensor. It consists of the sensors name and (only if the attribute longids is set of the RFXtrx433) an a two byte hex string (0000-ffff) that identifies the sensor. The define statement with the deviceid is generated automatically by autocreate. The following sensor names are used: <br>
  1678. "CM160" (for OWL CM119 or CM160),<br>
  1679. "CM180" (for OWL CM180),<br><br>
  1680. "CM180i"(for OWL CM180i),<br><br>
  1681. </ul>
  1682. The following Readings are generated:<br>
  1683. <ul>
  1684. <code>"energy_current:"</code>:
  1685. <ul>
  1686. Only for CM160 and CM180: current usage in Watt. If &lt;scale_current&gt is defined the result is: <code>energy_current * &lt;scale_current&gt;</code>.
  1687. </ul>
  1688. <code>"energy_chx:"</code>:
  1689. <ul>
  1690. Only for CM180i (where chx is ch1, ch2 or ch3): current usage in Ampere. If &lt;scale_current&gt is defined the result is: <code>energy_chx * &lt;scale_current&gt;</code>.
  1691. </ul>
  1692. <code>"energy_total:"</code>:
  1693. <ul>
  1694. current usage in kWh. If scale_total and add_total is defined the result is: <code>energy_total * &lt;scale_total&gt; + &lt;add_total&gt;</code>.
  1695. </ul>
  1696. <br>
  1697. </ul>
  1698. Example: <br>
  1699. <ul>
  1700. <code>define Tempsensor TRX_WEATHER CM160_1401</code><br>
  1701. <code>define Tempsensor TRX_WEATHER CM180_1401 1 1 0</code><br>
  1702. <code>define Tempsensor TRX_WEATHER CM180_1401 0.9 0.9 -1000</code><br>
  1703. </ul>
  1704. </ul>
  1705. <br>
  1706. <a name="TRX_WEATHERset"></a>
  1707. <b>Set</b> <ul>N/A</ul><br>
  1708. <a name="TRX_WEATHERget"></a>
  1709. <b>Get</b> <ul>N/A</ul><br>
  1710. <a name="TRX_WEATHERattr"></a>
  1711. <b>Attributes</b>
  1712. <ul>
  1713. <li><a href="#ignore">ignore</a></li>
  1714. <li><a href="#do_not_notify">do_not_notify</a></li>
  1715. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  1716. </ul>
  1717. <br>
  1718. </ul>
  1719. =end html
  1720. =cut