From 5fa74a5eb2a75f3fa47172cf4c2f0f06d46d7d47 Mon Sep 17 00:00:00 2001 From: sidey79 Date: Wed, 20 Feb 2019 21:25:55 +0000 Subject: [PATCH] 14_SD_WS.pm: new sensors E0001PA,S522,TX-EZ6,other - reading sendmode humidityTrend, temperatureTrend, - windspeed, batteryState added - attr max-deviation-temp and -hum added git-svn-id: https://svn.fhem.de/fhem/trunk@18674 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 4 + fhem/FHEM/14_SD_WS.pm | 578 ++++++++++++++++++++++++++++++++---------- 2 files changed, 445 insertions(+), 137 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 23ded3663..8a869180d 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,9 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: 14_SD_WS: support sensors E0001PA,S522,TX-EZ6,other + reading sendmode humidityTrend, temperatureTrend, + windspeed, batteryState added + attr max-deviation-temp and -hum added - changed: 14_SD_WS07: attr correction-xxx to offset-xxx renamed! - feature: 14_SD_WS07: new negation-batt attribute Temp only sensors supported diff --git a/fhem/FHEM/14_SD_WS.pm b/fhem/FHEM/14_SD_WS.pm index b6242e3c7..90f0c54a5 100644 --- a/fhem/FHEM/14_SD_WS.pm +++ b/fhem/FHEM/14_SD_WS.pm @@ -9,6 +9,14 @@ # 29.05.2017 Test ob Digest::CRC installiert # 22.07.2017 WH2 angepasst # 21.08.2017 WH2 Abbruch wenn kein "FF" am Anfang +# 18.08.2018 Protokoll 51 - prematch auf genau 10 Nibbles angepasst, Protokoll 33 - prematch auf genau 11 Nibbles angepasst +# 21.08.2018 Modelauswahl hinzugefuegt, da 3 versch. Typen SD_WS_33 --> Batterie-Bit Positionen unterschiedlich (34,35,36) +# 11.09.2018 Plotanlegung korrigiert | doc | temp check war falsch positioniert +# 16.09.2018 neues Protokoll 84: Funk Wetterstation Auriol IAN 283582 Version 06/2017 (Lidl), Modell-Nr.: HG02832D +# 31.09.2018 neues Protokoll 85: Kombisensor TFA 30.3222.02 fuer Wetterstation TFA 35.1140.01 +# 09.12.2018 neues Protokoll 89: Temperatur-/Feuchtesensor TFA 30.3221.02 fuer Wetterstation TFA 35.1140.01 +# 06.01.2019 Protokoll 33: Temperatur-/Feuchtesensor TX-EZ6 fuer Wetterstation TZS First Austria hinzugefuegt + package main; @@ -28,23 +36,28 @@ sub SD_WS_Initialize($) $hash->{ParseFn} = "SD_WS_Parse"; $hash->{AttrFn} = "SD_WS_Attr"; $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 showtime:1,0 " . - "$readingFnAttributes "; + "model:E0001PA,S522,TX-EZ6,other " . + "max-deviation-temp:1,2,3,4,5,6,7,8,9,10,15,20,25,30,35,40,45,50 ". + "max-deviation-hum:1,2,3,4,5,6,7,8,9,10,15,20,25,30,35,40,45,50 ". + "$readingFnAttributes "; $hash->{AutoCreate} = { "SD_WS37_TH.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"}, "SD_WS50_SM.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"}, "BresserTemeo.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"}, - "SD_WS51_TH.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"}, - "SD_WS58_TH.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:90"}, - "SD_WH2.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:90"}, - "SD_WS71_T.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"}, + "SD_WS_51_TH.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"}, + "SD_WS_58_TH.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:90"}, + "SD_WH2.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:90"}, + "SD_WS71_T.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4:Temp,", autocreateThreshold => "2:180"}, + "SD_WS_33_T_.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.* model:other", FILTER => "%NAME", GPLOT => "temp4:Temp,", autocreateThreshold => "2:180"}, + "SD_WS_33_TH_.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.* model:other", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"}, + "SD_WS_84_TH_.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:120"}, + "SD_WS_85_THW_.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "4:120"}, + "SD_WS_89_TH.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "3:180"}, }; } - - - ############################# sub SD_WS_Define($$) { @@ -80,25 +93,27 @@ sub SD_WS_Parse($$) my ($iohash, $msg) = @_; #my $rawData = substr($msg, 2); my $name = $iohash->{NAME}; + my $ioname = $iohash->{NAME}; my ($protocol,$rawData) = split("#",$msg); $protocol=~ s/^[WP](\d+)/$1/; # extract protocol - - my $dummyreturnvalue= "Unknown, please report"; my $hlen = length($rawData); my $blen = $hlen * 4; my $bitData = unpack("B$blen", pack("H$hlen", $rawData)); my $bitData2; - my $model; # wenn im elsif Abschnitt definiert, dann wird der Sensor per AutoCreate angelegt my $SensorTyp; my $id; my $bat; + my $sendmode; my $channel; my $rawTemp; my $temp; my $hum; + my $windspeed; my $trend; + my $trendTemp; + my $trendHum; my %decodingSubs = ( 50 => # Protocol 50 @@ -146,23 +161,50 @@ sub SD_WS_Parse($$) }, 33 => { - sensortype => 's014/TFA 30.3200/TCM/Conrad', - model => 'SD_WS_33_TH', - prematch => sub {my $msg = shift; return 1 if ($msg =~ /^[0-9A-F]{10,11}/); }, # prematch - crcok => sub {return SD_WS_binaryToNumber($bitData,36,39)+1; }, # crc currently not calculated + # Protokollbeschreibung: Conrad Temperatursensor S522 fuer Funk-Thermometer S521B + # ------------------------------------------------------------------------ + # 0 4 | 8 12 | 16 20 | 24 28 | 32 36 40 + # 1111 1100 | 0001 0110 | 0001 0000 | 0011 0111 | 0100 1001 01 + # iiii iiii | iixx cctt | tttt tttt | tthh hhhh | hhxx bgxx xx + # i: 10 bit random id (changes on power-loss) - Bit 0 + 1 every 0 ??? + # b: battery indicator (0=>OK, 1=>LOW) + # g: battery changed (1=>changed) - muss noch genauer getestet werden! ???? + # c: Channel (MSB-first, valid channels are 0x00-0x02 -> 1-3) + # t: Temperature (MSB-first, BCD, 12 bit unsigned fahrenheit offset by 90 and scaled by 10) + # h: always 0 + # x: unknown + + # Protokollbeschreibung: renkforce Temperatursensor E0001PA fuer Funk-Wetterstation E0303H2TPR (Conrad) + # ------------------------------------------------------------------------ + # 0 4 | 8 12 | 16 20 | 24 28 | 32 36 40 + # iiii iiii | iixx cctt | tttt tttt | tthh hhhh | hhsb xxxx xx + # h: Humidity (MSB-first, BCD, 8 bit relative humidity percentage) + # s: sendmode (1=>Test push, send manual 0=>automatic send) + # i: | c: | t: | h: | b: | x: same like S522 + + # Protokollbeschreibung: Temperatur-/Fechtesensor TX-EZ6 fuer Wetterstation TZS First Austria + # ------------------------------------------------------------------------ + # 0 4 | 8 12 | 16 20 | 24 28 | 32 36 40 + # iiii iiii | iiHH cctt | tttt tttt | tthh hhhh | hhsb TTxx xx + # H: Humidity trend, 00 = equal, 01 = up, 10 = down + # T: Temperature trend, 00 = equal, 01 = up, 10 = down + # i: | c: | t: | h: | s: | b: | x: same like E0001PA + + sensortype => 's014/TFA 30.3200/TCM/S522/E0001PA/TX-EZ6', + model => 'SD_WS_33_T', + prematch => sub {my $msg = shift; return 1 if ($msg =~ /^[0-9A-F]{11}$/); }, # prematch + crcok => sub {return 1;}, # crc currently not calculated id => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,0,9); }, # id - # sendmode => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,10,11) eq "1" ? "manual" : "auto"; } - temp => sub {my (undef,$bitData) = @_; return (((SD_WS_binaryToNumber($bitData,22,25)*256 + SD_WS_binaryToNumber($bitData,18,21)*16 + SD_WS_binaryToNumber($bitData,14,17)) *10 -12200) /18)/10; }, #temp + temp => sub {my (undef,$bitData) = @_; return round(((SD_WS_binaryToNumber($bitData,22,25)*256 + SD_WS_binaryToNumber($bitData,18,21)*16 + SD_WS_binaryToNumber($bitData,14,17)) - 1220) * 5 / 90.0 , 1); }, #temp hum => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,30,33)*16 + SD_WS_binaryToNumber($bitData,26,29)); }, #hum channel => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,12,13)+1 ); }, #channel - bat => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,34) eq "0" ? "ok" : "low";}, - # sync => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,35,35) eq "1" ? "true" : "false");}, + bat => sub {my (undef,$bitData) = @_; return substr($bitData,34,1) eq "0" ? "ok" : "low";}, # other or modul orginal } , 51 => { - sensortype => 'Lidl Wetterstation 2759001/IAN114324', + sensortype => 'Auriol IAN 275901 / IAN 114324', model => 'SD_WS_51_TH', - prematch => sub {my $msg = shift; return 1 if ($msg =~ /^[0-9A-F]{10}/); }, # prematch + prematch => sub {my $msg = shift; return 1 if ($msg =~ /^[0-9A-F]{10}$/); }, # prematch crcok => sub {return 1; }, # crc is unknown id => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,0,12); }, # random id? # sendmode => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,10,11) eq "1" ? "manual" : "auto"; } @@ -170,12 +212,12 @@ sub SD_WS_Parse($$) hum => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,28,31)*10) + (SD_WS_binaryToNumber($bitData,32,35)); }, #hum channel => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,36,39) ); }, #channel bat => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,13) eq "1" ? "low" : "ok";}, - trend => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,15,16) eq "01" ? "rising" : SD_WS_binaryToNumber($bitData,14,15) eq "00" ? "neutral" : "rising";}, + trend => sub {my (undef,$bitData) = @_; return ('neutral', 'rising', 'falling', 'what?')[SD_WS_binaryToNumber($bitData,14,15)];}, # sync => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,35,35) eq "1" ? "true" : "false");}, } , 58 => { - sensortype => 'TFA 3032080', + sensortype => 'TFA 30.3208.0', model => 'SD_WS_58_TH', prematch => sub {my $msg = shift; return 1 if ($msg =~ /^45[0-9A-F]{11}/); }, # prematch crcok => sub { my $msg = shift; @@ -224,10 +266,113 @@ sub SD_WS_Parse($$) temp => sub {my (undef,$bitData) = @_; return round((SD_WS_binaryToNumber($bitData,20,31)-720)*0.0556,1); }, # temp hum => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,32,39)); }, # hum } , + 84 => + { + # Protokollbeschreibung: Funk Wetterstation Auriol IAN 283582 (Lidl) + # ------------------------------------------------------------------------ + # 0 4 | 8 12 | 16 20 | 24 28 | 32 36 + # 1111 1100 | 0001 0110 | 0001 0000 | 0011 0111 | 0100 1001 + # iiii iiii | hhhh hhhh | bscc tttt | tttt tttt | ???? ???? + # i: 8 bit id (?) - no change after battery change, i have seen two IDs: 0x03 and 0xfe + # h: 8 bit relative humidity percentage + # b: 1 bit battery indicator (0=>OK, 1=>LOW) + # s: 1 bit sendmode 1=manual (button pressed) 0=auto + # c: 2 bit channel valid channels are 0-2 (1-3) + # t: 12 bit signed temperature scaled by 10 + # ?: unknown + # Sensor sends approximately every 30 seconds + sensortype => 'Auriol IAN 283582', + model => 'SD_WS_84_TH', + prematch => sub {my $msg = shift; return 1 if ($msg =~ /^[0-9A-F]{4}[01245689ACDE]{1}[0-9A-F]{5}$/); }, # valid channel only 0-2 + id => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,0,7); }, + hum => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,8,15); }, + bat => sub {my (undef,$bitData) = @_; return substr($bitData,16,1) eq "0" ? "ok" : "low";}, + sendmode => sub {my (undef,$bitData) = @_; return substr($bitData,17,1) eq "1" ? "manual" : "auto"; }, + channel => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,18,19)+1 ); }, + temp => sub { my (undef,$bitData) = @_; + my $tempraw = SD_WS_binaryToNumber($bitData,20,31); + $tempraw -= 4096 if ($tempraw > 1023); # negative + $tempraw /= 10.0; + return $tempraw; + }, + crcok => sub {return 1;}, # crc test method is so far unknown + } , + 85 => + { + # Protokollbeschreibung: Kombisensor TFA 30.3222.02 fuer Wetterstation TFA 35.1140.01 + # ----------------------------------------------------------------------------------- + # 0 4 | 8 12 | 16 20 | 24 28 | 32 36 | 40 44 | 48 52 | 56 60 | 64 + # 0000 1001 | 0001 0110 | 0001 0000 | 0000 0111 | 0100 1001 | 0100 0000 | 0100 1001 | 0100 1001 | 1 + # ???? iiii | iiii iiii | iiii iiii | b??? ??yy | tttt tttt | tttt ???? | hhhh hhhh | ???? ???? | ? message 1 + # ???? iiii | iiii iiii | iiii iiii | b?cc ??yy | wwww wwww | wwww ???? | 0000 0000 | ???? ???? | ? message 2 + # i: 20 bit random id (changes on power-loss) + # b: 1 bit battery indicator (0=>OK, 1=>LOW) + # c: 2 bit channel valid channels are (always 00 stands for channel 1) + # y: 2 bit typ, 01 - thermo/hygro (message 1), 10 - wind (message 2) + # t: 12 bit unsigned temperature, offset 500, scaled by 10 - if message 1 + # h: 8 bit relative humidity percentage - if message 1 + # w: 12 bit unsigned windspeed, scaled by 10 - if message 2 + # ?: unknown + # The sensor sends at intervals of about 30 seconds + sensortype => 'TFA 30.3222.02', + model => 'SD_WS_85_THW', + prematch => sub {my $msg = shift; return 1 if ($msg =~ /^[0-9A-F]{16}/); }, # min 16 nibbles + crcok => sub {return 1;}, # crc test method is so far unknown + id => sub {my (undef,$bitData) = @_; return substr($rawData,1,5); }, # 0952CF012B1021DF0 + bat => sub {my (undef,$bitData) = @_; return substr($bitData,24,1) eq "0" ? "ok" : "low";}, + channel => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,26,27) + 1 ); }, # unknown + temp => sub {my (undef,$bitData) = @_; + if (substr($bitData,30,2) eq "01") { # message 1 thermo/hygro + return ((SD_WS_binaryToNumber($bitData,32,43) - 500) / 10.0); + } else { + return undef; + } + }, + hum => sub {my (undef,$bitData) = @_; + if (substr($bitData,30,2) eq "01") { # message 1 thermo/hygro + return SD_WS_binaryToNumber($bitData,48,55); + } else { + return undef; + } + }, + windspeed => sub {my (undef,$bitData) = @_; + if (substr($bitData,30,2) eq "10") { # message 2 windspeed + return (SD_WS_binaryToNumber($bitData,32,43) / 10.0); + } else { + return undef; + } + }, + } , + 89 => + { + # Protokollbeschreibung: Temperatur-/Feuchtesensor TFA 30.3221.02 fuer Wetterstation TFA 35.1140.01 + # ------------------------------------------------------------------------------------------------- + # 0 4 | 8 12 | 16 20 | 24 28 | 32 36 + # 0000 1001 | 0001 0110 | 0001 0000 | 0000 0111 | 0100 1001 + # iiii iiii | bscc tttt | tttt tttt | hhhh hhhh | ???? ???? + # i: 8 bit random id (changes on power-loss) + # b: 1 bit battery indicator (0=>OK, 1=>LOW) + # s: 1 bit sendmode (0=>auto, 1=>manual) + # c: 2 bit channel valid channels are 0-2 (1-3) + # t: 12 bit unsigned temperature, offset 500, scaled by 10 + # h: 8 bit relative humidity percentage + # ?: 8 bit unknown + # The sensor sends 3 repetitions at intervals of about 60 seconds + sensortype => 'TFA 30.3221.02', + model => 'SD_WS_89_TH', + prematch => sub {my $msg = shift; return 1 if ($msg =~ /^[0-9A-F]{2}[01245689ACDE]{1}[0-9A-F]{7}$/); }, # valid channel only 0-2 + id => sub {my (undef,$bitData) = @_; return substr($rawData,0,2); }, + bat => sub {my (undef,$bitData) = @_; return substr($bitData,8,1) eq "0" ? "ok" : "low";}, + sendmode => sub {my (undef,$bitData) = @_; return substr($bitData,9,1) eq "1" ? "manual" : "auto"; }, + channel => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,10,11) + 1); }, + temp => sub {my (undef,$bitData) = @_; return ((SD_WS_binaryToNumber($bitData,12,23) - 500) / 10.0); }, + hum => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,24,31); }, + crcok => sub {return 1;}, # crc test method is so far unknown + } , ); - Log3 $name, 4, "SD_WS_Parse: Protocol: $protocol, rawData: $rawData"; + Log3 $name, 4, "$name: SD_WS_Parse Protocol: $protocol, rawData: $rawData"; if ($protocol eq "37") { # Bresser 7009994 # Protokollbeschreibung: @@ -250,7 +395,7 @@ sub SD_WS_Parse($$) $SensorTyp = "Bresser 7009994"; my $checksum = (SD_WS_binaryToNumber($bitData,0,7) + SD_WS_binaryToNumber($bitData,8,15) + SD_WS_binaryToNumber($bitData,16,23) + SD_WS_binaryToNumber($bitData,24,31)) & 0xFF; if ($checksum != SD_WS_binaryToNumber($bitData,32,39)) { - Log3 $name, 3, "$name: SD_WS37 ERROR - checksum $checksum != ".SD_WS_binaryToNumber($bitData,32,39); + Log3 $name, 4, "$name: SD_WS37 ERROR - checksum $checksum != ".SD_WS_binaryToNumber($bitData,32,39); return ""; } else { Log3 $name, 4, "$name: SD_WS37 checksum ok $checksum = ".SD_WS_binaryToNumber($bitData,32,39); @@ -288,7 +433,7 @@ sub SD_WS_Parse($$) my $binvalue = $bitData; if (length($binvalue) != 72) { - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: length error (72 bits expected)!!!"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo length error (72 bits expected)!!!"; return ""; } @@ -296,15 +441,15 @@ sub SD_WS_Parse($$) if ($protocol eq "44") { $binvalue = "0".$binvalue; - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: Humidity <= 79 Flag"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo Humidity <= 79 Flag"; } else { $binvalue = "1".$binvalue; - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: Humidity > 79 Flag"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo Humidity > 79 Flag"; } - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: new bin $binvalue"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo new bin $binvalue"; my $checksumOkay = 1; @@ -315,14 +460,14 @@ sub SD_WS_Parse($$) if ($checkHum1 != $hum1Dec || $checkHum2 != $hum2Dec) { - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error in Humidity"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo checksum error in Humidity"; } else { $hum = $hum1Dec.$hum2Dec; if ($hum < 1 || $hum > 100) { - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: Humidity Error. Humidity=$hum"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo Humidity Error. Humidity=$hum"; return ""; } } @@ -334,16 +479,15 @@ sub SD_WS_Parse($$) my $checkTemp2 = SD_WS_binaryToNumber($binvalue, 56, 59) ^ 0b1111; my $checkTemp3 = SD_WS_binaryToNumber($binvalue, 60, 63) ^ 0b1111; $temp = $temp1Dec.$temp2Dec.".".$temp3Dec; - + $temp +=0; # remove leading zeros if ($checkTemp1 != $temp1Dec || $checkTemp2 != $temp2Dec || $checkTemp3 != $temp3Dec) { - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error in Temperature"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo checksum error in Temperature"; $checksumOkay = 0; } - if ($temp > 60) { - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: Temperature Error. temp=$temp"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo Temperature Error. temp=$temp"; return ""; } @@ -352,7 +496,7 @@ sub SD_WS_Parse($$) if ($sign != $checkSign) { - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error in Sign"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo checksum error in Sign"; $checksumOkay = 0; } else @@ -368,7 +512,7 @@ sub SD_WS_Parse($$) if ($bat != $checkBat) { - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error in Bat"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo checksum error in Bat"; $bat = undef; } else @@ -383,18 +527,18 @@ sub SD_WS_Parse($$) if ($channel != $checkChannel || $id != $checkId) { - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error in Channel or Id"; + Log3 $iohash, 4, "$name: SD_WS_Parse BresserTemeo checksum error in Channel or Id"; $checksumOkay = 0; } if ($checksumOkay == 0) { - Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error!!! These Values seem incorrect: temp=$temp, channel=$channel, id=$id"; + Log3 $iohash, 4, "$name:SD_WS_Parse BresserTemeo checksum error!!! These Values seem incorrect: temp=$temp, channel=$channel, id=$id"; return ""; } $id = sprintf('%02X', $id); # wandeln nach hex - Log3 $iohash, 4, "$name SD_WS_Parse: model=$model, temp=$temp, hum=$hum, channel=$channel, id=$id, bat=$bat"; + Log3 $iohash, 4, "$name: SD_WS_Parse model=$model, temp=$temp, hum=$hum, channel=$channel, id=$id, bat=$bat"; } elsif ($protocol eq "64") # WH2 { @@ -499,7 +643,7 @@ sub SD_WS_Parse($$) } $bitData = unpack("B$blen", pack("H$hlen", $rawData)); - Log3 $iohash, 4, "$name converted to bits: WH2 " . $bitData; + Log3 $iohash, 4, "$name: converted to bits WH2 " . $bitData; $model = "SD_WS_WH2"; $SensorTyp = "WH2"; $id = SD_WS_bin2dec(substr($bitData,$vorpre + 4,6)); @@ -516,10 +660,10 @@ sub SD_WS_Parse($$) # Temp negativ $temp = -(SD_WS_bin2dec(substr($bitData,$vorpre + 13,11))) / 10; } - Log3 $iohash, 4, "$name decoded protocolid: $protocol ($SensorTyp) sensor id=$id, Data:".substr($bitData,$vorpre + 12,12)." temp=$temp"; + Log3 $iohash, 4, "$name: decoded protocolid $protocol ($SensorTyp) sensor id=$id, Data:".substr($bitData,$vorpre + 12,12)." temp=$temp"; $hum = SD_WS_bin2dec(substr($bitData,$vorpre + 24,8)); # TFA 30.3157 nur Temp, Hum = 255 - Log3 $iohash, 4, "$name SD_WS_WH2_8: $protocol ($SensorTyp) sensor id=$id, Data:".substr($bitData,$vorpre + 24,8)." hum=$hum"; - Log3 $iohash, 4, "$name SD_WS_WH2_9: $protocol ($SensorTyp) sensor id=$id, channel=$channel, temp=$temp, hum=$hum"; + Log3 $iohash, 4, "$name: SD_WS_WH2_8 $protocol ($SensorTyp) sensor id=$id, Data:".substr($bitData,$vorpre + 24,8)." hum=$hum"; + Log3 $iohash, 4, "$name: SD_WS_WH2_9 $protocol ($SensorTyp) sensor id=$id, channel=$channel, temp=$temp, hum=$hum"; } @@ -528,72 +672,127 @@ sub SD_WS_Parse($$) $SensorTyp=$decodingSubs{$protocol}{sensortype}; if (!$decodingSubs{$protocol}{prematch}->( $rawData )) { - Log3 $iohash, 4, "$name decoded protocolid: $protocol ($SensorTyp) prematch error" ; + Log3 $iohash, 4, "$name: SD_WS_Parse $rawData protocolid $protocol ($SensorTyp) prematch error" ; return ""; } my $retcrc=$decodingSubs{$protocol}{crcok}->( $rawData ); if (!$retcrc) { - Log3 $iohash, 4, "$name decoded protocolid: $protocol ($SensorTyp) crc error: $retcrc"; + Log3 $iohash, 4, "$name: SD_WS_Parse $rawData protocolid $protocol ($SensorTyp) crc error: $retcrc"; return ""; } $id=$decodingSubs{$protocol}{id}->( $rawData,$bitData ); #my $temphex=$decodingSubs{$protocol}{temphex}->( $rawData,$bitData ); - - $temp=$decodingSubs{$protocol}{temp}->( $rawData,$bitData ); - $hum=$decodingSubs{$protocol}{hum}->( $rawData,$bitData ); + $temp=$decodingSubs{$protocol}{temp}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{temp})); + $hum=$decodingSubs{$protocol}{hum}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{hum})); + $windspeed=$decodingSubs{$protocol}{windspeed}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{windspeed})); $channel=$decodingSubs{$protocol}{channel}->( $rawData,$bitData ); $model = $decodingSubs{$protocol}{model}; - $bat = $decodingSubs{$protocol}{bat}->( $rawData,$bitData ); - $trend = $decodingSubs{$protocol}{trend}->( $rawData,$bitData ) if (defined($decodingSubs{$protocol}{trend})); - - Log3 $iohash, 4, "$name decoded protocolid: $protocol ($SensorTyp) sensor id=$id, channel=$channel, temp=$temp, hum=$hum, bat=$bat"; - + $bat = $decodingSubs{$protocol}{bat}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{bat})); + if ($model eq "SD_WS_33_T") { # for SD_WS_33 discrimination T - TH + $model = $decodingSubs{$protocol}{model}."H" if $hum != 0; # for models with Humidity + } + $sendmode = $decodingSubs{$protocol}{sendmode}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{sendmode})); + $trend = $decodingSubs{$protocol}{trend}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{trend})); + #Use of uninitialized value $temp + #Log3 $iohash, 4, "$name: decoded protocolid $protocol ($SensorTyp) sensor id=$id, channel=$channel, temp=$temp, hum=$hum, bat=$bat"; + Log3 $iohash, 4, "$name: decoded protocolid $protocol ($SensorTyp) sensor id=$id"; } else { - Log3 $iohash, 2, "SD_WS_WH2: unknown message, please report. converted to bits: $bitData"; + Log3 $iohash, 2, "$name: SD_WS_Parse unknown message, please report. converted to bits: $bitData"; return undef; } - if (!defined($model)) { return undef; } my $deviceCode; - my $longids = AttrVal($iohash->{NAME},'longids',0); + my $longids = AttrVal($ioname,'longids',0); if (($longids ne "0") && ($longids eq "1" || $longids eq "ALL" || (",$longids," =~ m/,$model,/))) { - $deviceCode = $model . '_' . $id . $channel; - Log3 $iohash,4, "$name using longid: $longids model: $model"; + $deviceCode = $model . '_' . $id . $channel; # old form of longid + if (!defined($modules{SD_WS}{defptr}{$deviceCode})) { + $deviceCode = $model . '_' . $id . '_' . $channel; # new form of longid + } + Log3 $iohash,4, "$name: using longid for $longids device $deviceCode"; } else { $deviceCode = $model . "_" . $channel; } #print Dumper($modules{SD_WS}{defptr}); - my $def = $modules{SD_WS}{defptr}{$iohash->{NAME} . "." . $deviceCode}; + my $def = $modules{SD_WS}{defptr}{$ioname . "." . $deviceCode}; $def = $modules{SD_WS}{defptr}{$deviceCode} if(!$def); if(!$def) { - Log3 $iohash, 1, 'SD_WS: UNDEFINED sensor ' . $model . ' detected, code ' . $deviceCode; + Log3 $iohash, 1, "$name: SD_WS_Parse UNDEFINED sensor $model detected, code $deviceCode"; return "UNDEFINED $deviceCode SD_WS $deviceCode"; } my $hash = $def; $name = $hash->{NAME}; return "" if(IsIgnored($name)); - - Log3 $name, 4, "SD_WS: $name ($rawData)"; - if (!defined(AttrVal($hash->{NAME},"event-min-interval",undef))) - { - my $minsecs = AttrVal($iohash->{NAME},'minsecs',0); - if($hash->{lastReceive} && (time() - $hash->{lastReceive} < $minsecs)) { - Log3 $hash, 4, "$deviceCode Dropped due to short time. minsecs=$minsecs"; - return ""; + if (defined $temp) { + if ($temp < -30 || $temp > 70) { + Log3 $iohash, 3, "$ioname: SD_WS_Parse $deviceCode - ERROR temperature $temp"; + return ""; } } + if (defined $hum) { + if ($hum > 100) { + Log3 $iohash, 3, "$ioname: SD_WS_Parse $deviceCode - ERROR humidity $hum"; + return ""; + } + } + + # Sanity checks + if($def) { + my $timeSinceLastUpdate = abs(ReadingsAge($name, "state", 0)); + # temperature + if (defined($temp) && defined(ReadingsVal($name, "temperature", undef))) { + my $diffTemp = 0; + my $oldTemp = ReadingsVal($name, "temperature", undef); + my $maxdeviation = AttrVal($name, "max-deviation-temp", 1); # default 1 K + if ($temp > $oldTemp) { + $diffTemp = ($temp - $oldTemp); + } else { + $diffTemp = ($oldTemp - $temp); + } + $diffTemp = sprintf("%.1f", $diffTemp); + Log3 $name, 4, "$ioname: $name old temp $oldTemp, age $timeSinceLastUpdate, new temp $temp, diff temp $diffTemp"; + my $maxDiffTemp = $timeSinceLastUpdate / 60 + $maxdeviation; # maxdeviation + 1.0 Kelvin/Minute + $maxDiffTemp = sprintf("%.1f", $maxDiffTemp + 0.05); # round 0.1 + Log3 $name, 4, "$ioname: $name max difference temperature $maxDiffTemp K"; + if ($diffTemp > $maxDiffTemp) { + Log3 $name, 3, "$ioname: $name ERROR - Temp diff too large (old $oldTemp, new $temp, diff $diffTemp)"; + return ""; + } + } + # humidity + if (defined($hum) && defined(ReadingsVal($name, "humidity", undef))) { + my $diffHum = 0; + my $oldHum = ReadingsVal($name, "humidity", undef); + my $maxdeviation = AttrVal($name, "max-deviation-hum", 1); # default 1 % + if ($hum > $oldHum) { + $diffHum = ($hum - $oldHum); + } else { + $diffHum = ($oldHum - $hum); + } + $diffHum = sprintf("%.1f", $diffHum); + Log3 $name, 4, "$ioname: $name old hum $oldHum, age $timeSinceLastUpdate, new hum $hum, diff hum $diffHum"; + my $maxDiffHum = $timeSinceLastUpdate / 60 + $maxdeviation; # $maxdeviation + 1.0 %/Minute + $maxDiffHum = sprintf("%1.f", $maxDiffHum + 0.5); # round 1 + Log3 $name, 4, "$ioname: $name max difference humidity $maxDiffHum %"; + if ($diffHum > $maxDiffHum) { + Log3 $name, 3, "$ioname: $name ERROR - Hum diff too large (old $oldHum, new $hum, diff $diffHum)"; + return ""; + } + } + } + + Log3 $name, 4, "$ioname: SD_WS_Parse $name ($rawData)"; $hash->{lastReceive} = time(); $hash->{lastMSG} = $rawData; @@ -603,17 +802,46 @@ sub SD_WS_Parse($$) $hash->{bitMSG} = $bitData; } - my $state = (($temp > -60 && $temp < 70) ? "T: $temp":"T: xx") . (($hum > 0 && $hum < 100) ? " H: $hum":""); + #my $state = (($temp > -60 && $temp < 70) ? "T: $temp":"T: xx") . (($hum > 0 && $hum < 100) ? " H: $hum":""); + my $state = ""; + if (defined($temp)) { + $state .= "T: $temp" + } + if (defined($hum) && ($hum > 0 && $hum < 100)) { + $state .= " H: $hum" + } + if (defined($windspeed)) { + $state .= " " if (length($state) > 0); + $state .= "W: $windspeed" + } + + ### protocol 33 has different bits per sensor type + if ($protocol eq "33") { + if (AttrVal($name,'model',0) eq "S522") { # Conrad S522 + $bat = substr($bitData,36,1) eq "0" ? "ok" : "low"; + } elsif (AttrVal($name,'model',0) eq "E0001PA") { # renkforce E0001PA + $bat = substr($bitData,35,1) eq "0" ? "ok" : "low"; + $sendmode = substr($bitData,34,1) eq "1" ? "manual" : "auto"; + } elsif (AttrVal($name,'model',0) eq "TX-EZ6") { # TZS First Austria TX-EZ6 + $bat = substr($bitData,35,1) eq "0" ? "ok" : "low"; + $sendmode = substr($bitData,34,1) eq "1" ? "manual" : "auto"; + $trendTemp = ('consistent', 'rising', 'falling', 'unknown')[SD_WS_binaryToNumber($bitData,10,11)]; + $trendHum = ('consistent', 'rising', 'falling', 'unknown')[SD_WS_binaryToNumber($bitData,36,37)]; + } + } readingsBeginUpdate($hash); readingsBulkUpdate($hash, "state", $state); - readingsBulkUpdate($hash, "temperature", $temp) if (defined($temp)&& ($temp > -60 && $temp < 70 )); + readingsBulkUpdate($hash, "temperature", $temp) if (defined($temp) && ($temp > -60 && $temp < 70 )); readingsBulkUpdate($hash, "humidity", $hum) if (defined($hum) && ($hum > 0 && $hum < 100 )) ; - readingsBulkUpdate($hash, "battery", $bat) if (defined($bat) && length($bat) > 0) ; + readingsBulkUpdate($hash, "windspeed", $windspeed) if (defined($windspeed)) ; + readingsBulkUpdate($hash, "batteryState", $bat) if (defined($bat) && length($bat) > 0) ; readingsBulkUpdate($hash, "batteryState", $bat) if (defined($bat) && length($bat) > 0) ; readingsBulkUpdate($hash, "channel", $channel) if (defined($channel)&& length($channel) > 0); readingsBulkUpdate($hash, "trend", $trend) if (defined($trend) && length($trend) > 0); - + readingsBulkUpdate($hash, "temperatureTrend", $trendTemp) if (defined($trendTemp) && length($trendTemp) > 0); + readingsBulkUpdate($hash, "humidityTrend", $trendHum) if (defined($trendHum) && length($trendHum) > 0); + readingsBulkUpdate($hash, "sendmode", $sendmode) if (defined($sendmode) && length($sendmode) > 0); readingsEndUpdate($hash, 1); # Notify is done by Dispatch return $name; @@ -649,7 +877,6 @@ sub SD_WS_binaryToNumber my $fbit=shift; my $lbit=$fbit; $lbit=shift if @_; - return oct("0b".substr($binstr,$fbit,($lbit-$fbit)+1)); } @@ -688,52 +915,88 @@ sub SD_WS_WH2SHIFT($){

Weather Sensors various protocols



- Define - -
+ Define

+

+ - Generated readings: -
Some devices may not support all readings, so they will not be presented
+ Generated readings:

-
- Attributes + Some devices may not support all readings, so they will not be presented
+ - - - Set
- - - Set
+
  • batteryState (low or ok)
  • +
  • channel (number of channel
  • +
  • humidity (humidity (1-100 % only if available)
  • +
  • humidityTrend (consistent, rising, falling)
  • +
  • sendmode (automatic or manual)
  • +
  • state (T: H: W:)
  • +
  • temperature (°C)
  • +
  • temperatureTrend (consistent, rising, falling)
  • +

    + + Attributes

    +
    + Set +
    =end html @@ -743,50 +1006,91 @@ sub SD_WS_WH2SHIFT($){

    SD_WS



    - Define - =end html_DE