From 1a5b5ab5b0f87afa8c397cfa58a828e26cd983de Mon Sep 17 00:00:00 2001 From: sidey79 Date: Wed, 20 Feb 2019 20:52:45 +0000 Subject: [PATCH] 14_SD_WS07.pm: Attributes to correction-xxx to offset-xxx renamed! - new negation-batt attribute - Temp only sensors supported - support for max deviation attribute git-svn-id: https://svn.fhem.de/fhem/trunk@18673 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 4 + fhem/FHEM/14_SD_WS07.pm | 251 +++++++++++++++++++++++++++++----------- 2 files changed, 185 insertions(+), 70 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index c03a9732f..23ded3663 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. + - changed: 14_SD_WS07: attr correction-xxx to offset-xxx renamed! + - feature: 14_SD_WS07: new negation-batt attribute + Temp only sensors supported + support for max deviation attribute - changed: 14_SD_WS09: reading batteryState added, commandref extended - changed: 14_Hideki: reading batteryState added - bugfix: 73_AutoShuttersControl: fix typo in shuttersMode diff --git a/fhem/FHEM/14_SD_WS07.pm b/fhem/FHEM/14_SD_WS07.pm index 4fa60ae80..e713c61fd 100644 --- a/fhem/FHEM/14_SD_WS07.pm +++ b/fhem/FHEM/14_SD_WS07.pm @@ -43,7 +43,7 @@ SD_WS07_Initialize($) $hash->{ParseFn} = "SD_WS07_Parse"; $hash->{AttrFn} = "SD_WS07_Attr"; $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 showtime:1,0 " . - "correction-hum correction-temp ". + "negation-batt:no,yes ". "$readingFnAttributes "; $hash->{AutoCreate} = { @@ -91,7 +91,6 @@ SD_WS07_Parse($$) { my ($iohash, $msg) = @_; #my $rawData = substr($msg, 2); - my $name = $iohash->{NAME}; my (undef ,$rawData, $rssi) = split("#",$msg); if (defined($rssi)) { $rssi = hex(substr($rssi,1)); @@ -100,124 +99,189 @@ SD_WS07_Parse($$) #$protocol=~ s/^P(\d+)/$1/; # extract protocol my $model = "SD_WS07"; + my $typ = $model; my $hlen = length($rawData); my $blen = $hlen * 4; my $bitData = unpack("B$blen", pack("H$hlen", $rawData)); - Log3 $name, 4, "$name SD_WS07: $msg, length=$hlen"; + if (defined($rssi)) { + Log3 $iohash, 4, "$iohash->{NAME}: SD_WS07_Parse $model ($msg) length: $hlen RSSI = $rssi"; + } else { + Log3 $iohash, 4, "$iohash->{NAME}: SD_WS07_Parse $model ($msg) length: $hlen"; + } # 4 8 9 12 24 28 36 # 0011 0110 1 010 000100000010 1111 00111000 0000 eas8007 # 0111 0010 1 010 000010111100 1111 00000000 0000 other device from anfichtn + # 1101 0010 0 000 000000010001 1111 00101000 other device from elektron-bbs + # 0110 0011 1 000 000011101010 1111 00001010 other device from HomeAuto_User SD_WS07_TH_631 + # 1110 1011 1 000 000010111000 1111 00000000 other device from HomeAuto_User SD_WS07_T_EB1 + # 1100 0100 1 000 000100100010 1111 00000000 other device from HomeAuto_User SD_WS07_T_C41 + # 0110 0100 0 000 000100001110 1111 00101010 hama TS36E from HomeAuto_User - Bat bit identified # ID Bat CHN TMP ?? HUM - #my $hashumidity = FALSE; - - ## Todo: Change decoding per model into a foreach - #foreach $key (keys %models) { - # .... - #} - my $bitData2 = substr($bitData,0,8) . ' ' . substr($bitData,8,1) . ' ' . substr($bitData,9,3); - $bitData2 = $bitData2 . ' ' . substr($bitData,12,12) . ' ' . substr($bitData,24,4) . ' ' . substr($bitData,28,8); - Log3 $iohash, 5, "$name SD_WS07: converted to bits: $bitData2"; + # Modelliste + my %models = ( + "0" => "T", + "1" => "TH", + ); + + my $bitData2 = substr($bitData,0,8) . ' ' . substr($bitData,8,4) . ' ' . substr($bitData,12,12) . ' ' . substr($bitData,24,4) . ' ' . substr($bitData,28,8); + Log3 $iohash, 4, "$iohash->{NAME}: SD_WS07_Parse $model converted to bits " . $bitData2; my $id = substr($rawData,0,2); - my $bat = int(substr($bitData,8,1)) eq "1" ? "ok" : "low"; + my $bat = substr($bitData,8,1) eq "1" ? "ok" : "low"; # 1 = ok | 0 = low --> identified on hama TS36E my $channel = oct("0b" . substr($bitData,9,3)) + 1; my $temp = oct("0b" . substr($bitData,12,12)); my $bit24bis27 = oct("0b".substr($bitData,24,4)); my $hum = oct("0b" . substr($bitData,28,8)); + my $modelkey; - if ($hum==0) - { - $model=$model."_T"; - } else { - $model=$model."_TH"; - if ($hum < 10 || $hum > 99) { - Log3 $iohash, 4, "$name: SD_WS07: err HUM: hum=$hum, msg=$msg" ; - return ''; - } - } - - if ($temp > 700 && $temp < 3840) { - Log3 $iohash, 4, "$name: SD_WS07: err TEMP: temp=$temp, msg=$msg" ; - return ''; - } elsif ($temp >= 3840) { # negative Temperaturen, muss noch ueberprueft und optimiert werden - $temp -= 4096; - } - $temp /= 10; - - Log3 $iohash, 4, "$name SD_WS07: model=$model, id=$id, channel=$channel, temp=$temp, hum=$hum, bat=$bat"; - - my $deviceCode; - - my $longids = AttrVal($iohash->{NAME},'longids',0); - if ( ($longids ne "0") && ($longids eq "1" || $longids eq "ALL" || (",$longids," =~ m/,$model,/))) - { - $deviceCode=$model.'_'.$id.$channel; - Log3 $iohash,4, "$name SD_WS07: using longid=$longids model=$model"; - } else { - $deviceCode = $model . "_" . $channel; + if ($hum == 0) { + $modelkey = $hum; + } elsif ($hum != 0) { + $modelkey = 1; } + $model = $model."_".$models{$modelkey}; + my $deviceCode; + my $longids = AttrVal($iohash->{NAME},'longids',0); + if ( ($longids ne "0") && ($longids eq "1" || $longids eq "ALL" || (",$longids," =~ m/,$model,/))) { + $deviceCode = $id.$channel; + Log3 $iohash,4, "$iohash->{NAME}: using longid $longids model $model"; + } else { + $deviceCode = $channel; + } + + ### Model specific attributes + if ($models{$modelkey} eq "T") { + addToDevAttrList($model."_".$deviceCode,"max-deviation-temp:1,2,3,4,5,6,7,8,9,10,15,20,25,30,35,40,45,50 "); + addToDevAttrList($model."_".$deviceCode,"offset-temp:slider,-25,1.0,25"); + } elsif ($models{$modelkey} eq "TH") { + addToDevAttrList($model."_".$deviceCode,"max-deviation-temp:1,2,3,4,5,6,7,8,9,10,15,20,25,30,35,40,45,50 "); + addToDevAttrList($model."_".$deviceCode,"max-deviation-hum:1,2,3,4,5,6,7,8,9,10,15,20,25,30,35,40,45,50 "); + addToDevAttrList($model."_".$deviceCode,"offset-temp:slider,-25,1.0,25"); + addToDevAttrList($model."_".$deviceCode,"offset-hum:slider,-50,1.0,50"); + } #print Dumper($modules{SD_WS07}{defptr}); my $def = $modules{SD_WS07}{defptr}{$iohash->{NAME} . "." . $deviceCode}; $def = $modules{SD_WS07}{defptr}{$deviceCode} if(!$def); + my $device = $model."_".$deviceCode; if(!$def) { - Log3 $iohash, 1, "$name SD_WS07: UNDEFINED sensor $deviceCode detected, code $msg"; - return "UNDEFINED $deviceCode SD_WS07 $deviceCode"; + Log3 $iohash, 1, "$iohash->{NAME}: UNDEFINED Sensor $model detected, code $deviceCode"; + return "UNDEFINED $device SD_WS07 $deviceCode"; } #Log3 $iohash, 3, 'SD_WS07: ' . $def->{NAME} . ' ' . $id; my $hash = $def; - $name = $hash->{NAME}; + my $name = $hash->{NAME}; return "" if(IsIgnored($name)); #Log3 $name, 4, "$iohash->{NAME} SD_WS07: $name ($rawData)"; - if (!defined(AttrVal($hash->{NAME},"event-min-interval",undef))) - { + 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, "$iohash->{NAME} SD_WS07: $name $deviceCode dropped due to short time. minsecs=$minsecs"; + Log3 $hash, 4, "$iohash->{NAME}: $deviceCode Dropped due to short time. minsecs=$minsecs"; return ""; } } - $hum += AttrVal($name, "correction-hum", 0); # correction value for humidity (default 0 %) - if ($hum > 99) { - Log3 $name, 4, "$iohash->{NAME} SD_WS07: $name ERROR - Humidity unknown ($hum)"; + $hum += AttrVal($name, "offset-hum", 0); # correction value for humidity (default 0 %) + if ($model ne "SD_WS07_T" && $hum > 100 || $model ne "SD_WS07_T" && $hum < 0) { + Log3 $name, 3, "$iohash->{NAME}: $name ERROR - Humidity unknown ($hum)"; return ""; } - $temp += AttrVal($name, "correction-temp", 0); # correction value for temperature (default 0 K) - Log3 $name, 4, "$iohash->{NAME} SD_WS07: $name id=$id, channel=$channel, temp=$temp, hum=$hum, bat=$bat"; + if ($temp > 700 && $temp < 3840) { # -25,6 .. 70,0 °C + Log3 $name, 3, "$iohash->{NAME}: $name ERROR - Temperature unknown ($temp)"; + return ""; + } elsif ($temp >= 3840) { # negative Temperaturen, ist ueberprueft worden + $temp -= 4096; + } + $temp /= 10; + $temp += AttrVal($name, "offset-temp", 0); # correction value for temperature (default 0 K) + Log3 $iohash, 4, "$iohash->{NAME}: $name id=$id, channel=$channel, temp=$temp, hum=$hum, bat=$bat"; + # Sanity check temperature and humidity + if($def) { + my $timeSinceLastUpdate = ReadingsAge($hash->{NAME}, "state", 0); + if ($timeSinceLastUpdate < 0) { + $timeSinceLastUpdate = -$timeSinceLastUpdate; + } + if (ReadingsVal($name, "temperature", undef) && (defined(AttrVal($hash->{NAME},"max-deviation-temp",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, "$iohash->{NAME}: $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, "$iohash->{NAME}: $name max difference temperature $maxDiffTemp K"; + if ($diffTemp > $maxDiffTemp) { + Log3 $name, 3, "$iohash->{NAME}: $name ERROR - Temp diff too large (old $oldTemp, new $temp, diff $diffTemp)"; + return ""; + } + } + if (defined($hash->{READINGS}{humidity}{VAL}) && defined(AttrVal($hash->{NAME},"max-deviation-hum",undef)) && $models{$modelkey} eq "TH") { + 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); + } + Log3 $name, 4, "$iohash->{NAME}: $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, "$iohash->{NAME}: $name max difference humidity $maxDiffHum %"; + if ($diffHum > $maxDiffHum) { + Log3 $name, 3, "$iohash->{NAME}: $name ERROR - Hum diff too large (old $oldHum, new $hum, diff $diffHum)"; + return ""; + } + } + } $hash->{lastReceive} = time(); $hash->{lastMSG} = $rawData; $hash->{bitMSG} = $bitData2; + if (AttrVal($name, "negation-batt", "no") eq "yes") { # default undef negation batt bit + $bat = "0" eq "0" ? "ok" : "low"; # 0 = ok + } + my $state = "T: $temp". ($hum>0 ? " H: $hum":""); readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "model", $models{$modelkey}); readingsBulkUpdate($hash, "state", $state); readingsBulkUpdate($hash, "temperature", $temp) if ($temp ne""); - readingsBulkUpdate($hash, "humidity", $hum) if ($hum ne "" && $hum != 0 ); - if ($bat ne "") { + readingsBulkUpdate($hash, "humidity", $hum) if ($models{$modelkey} eq "TH"); #my $battery = ReadingsVal($name, "battery", "unknown"); #if ($bat ne $battery) { + readingsBulkUpdate($hash, "battery", $bat); readingsBulkUpdate($hash, "batteryState", $bat); #} - } readingsBulkUpdate($hash, "channel", $channel) if ($channel ne ""); - readingsEndUpdate($hash, 1); # Notify is done by Dispatch + ### ZusatzCheck | Beauty - humidity wird einmal definiert obwohl Typ T ### + #delete $hash->{READINGS}{"humidity"} if($hash->{READINGS} && $models{$modelkey} eq "T"); + delete $hash->{READINGS}{humidity} if($hash->{READINGS}{humidity} && $models{$modelkey} eq "T"); + + if(defined($rssi)) { + $hash->{RSSI} = $rssi; + } return $name; } @@ -272,24 +336,47 @@ sub SD_WS07_Attr(@)
Attributes +
+ +
Set
@@ -306,7 +393,7 @@ sub SD_WS07_Attr(@)

SD_WS07