diff --git a/fhem/CHANGED b/fhem/CHANGED index 8fa7d79f1..3982bb1ce 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,7 @@ # 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. + - change: 14_SD_WS_Maverick: reworked module, renamed readings + added commandref - bugfix: 14_SD_WS07: Error retrieving rssi value fixed - feature: 14_SD_WS07: added correction-temp and correction-hum added two models temp/temp-hum diff --git a/fhem/FHEM/14_SD_WS_Maverick.pm b/fhem/FHEM/14_SD_WS_Maverick.pm index 2320e8c80..56b967624 100644 --- a/fhem/FHEM/14_SD_WS_Maverick.pm +++ b/fhem/FHEM/14_SD_WS_Maverick.pm @@ -3,7 +3,13 @@ # # The purpose of this module is to support Maverick sensors # Sidey79 & Cruizer 2016 +# Ralf9 2018 # +# CHANGED +############################################################################## +# Version 1.1 +# - changed: 14_SD_WS_Maverick: rename Readings for Temperatures +# - feature: 14_SD_WS_Maverick: added Readings for Sensor-states package main; @@ -12,19 +18,26 @@ use strict; use warnings; #use Data::Dumper; - +sub SD_WS_Maverick_Initialize($); +sub SD_WS_Maverick_Define($$); +sub SD_WS_Maverick_Undef($$); +sub SD_WS_Maverick_Parse($$); +sub SD_WS_Maverick_Attr(@); +sub SD_WS_Maverick_SetSensor1Inaktiv($); +sub SD_WS_Maverick_SetSensor2Inaktiv($); +sub SD_WS_Maverick_updateReadings($); sub SD_WS_Maverick_Initialize($) { my ($hash) = @_; - $hash->{Match} = "^P47#AA9995[A-Fa-f0-9]+"; + $hash->{Match} = "^P47#[A-Fa-f0-9]+"; $hash->{DefFn} = "SD_WS_Maverick_Define"; $hash->{UndefFn} = "SD_WS_Maverick_Undef"; $hash->{ParseFn} = "SD_WS_Maverick_Parse"; - $hash->{AttrFn} = "SD_WS_Maverick_Attr"; - $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 showtime:1,0 " . + $hash->{AttrFn} = "SD_WS_Maverick_Attr"; + $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 showtime:1,0 inactivityinterval " . "$readingFnAttributes "; $hash->{AutoCreate} = { "SD_WS_Maverick.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", autocreateThreshold => "2:180"} }; @@ -50,6 +63,35 @@ SD_WS_Maverick_Define($$) $hash->{STATE} = "Defined"; my $name= $hash->{NAME}; + # prüfen, ob eine neue Definition angelegt wird + if($init_done && !defined($hash->{OLDDEF})) + { + # setzen von stateFormat + $attr{$name}{"stateFormat"} = '{ + my $s1=ReadingsVal($name,"Sensor-1-food_state",-1); + my $s2=ReadingsVal($name,"Sensor-2-bbq_state",-1); + if ($s1 ne "connected" && $s1 eq $s2 ) { + return $s1; + }else{ + my $state="Food: "; + my $temp_food=ReadingsVal($name,"temp-food",""); + my $temp_bbq=ReadingsVal($name,"temp-bbq",""); + if($s1 eq "connected"){ + $state .=$temp_food; + }else{ + $state .=$s1; + } + $state .=" BBQ: "; + if($s2 eq "connected"){ + $state .=$temp_bbq; + }else{ + $state .=$s2; + } + return $state; + } +}'; + + } return undef; } @@ -80,112 +122,211 @@ SD_WS_Maverick_Parse($$) #my $blen = $hlen * 4; #my $bitData = unpack("B$blen", pack("H$hlen", $rawData)); - Log3 $name, 3, "SD_WS_Maverick_Parse $model ($msg) length: $hlen"; + Log3 $name, 4, "$name SD_WS_Maverick_Parse $model ($msg) length: $hlen"; + # https://hackaday.io/project/4690-reverse-engineering-the-maverick-et-732/ + # https://forums.adafruit.com/viewtopic.php?f=8&t=25414&sid=e1775df908194d56692c6ad9650fdfb2&start=15#p322178 + # #1 8 13 18 26 #AA999559 55555 95999 A9A9A669 Sensor 1 =21 2Grad #AA999559 95996 55555 95A65565 Sensor 2 =22 2Grad - # - #Header Sen1 Sens2 - #my $hashumidity = FALSE; - + # ## Todo: Change decoding per model into a foreach - #foreach $key (keys %models) { + #foreach $key (keys %models) { # .... #} - - # - my $startup = substr($rawData,6,2); - my $temp_str1 = substr($rawData,8,5); - my $temp_str2 = substr($rawData,13,5); - my $unknown = substr($rawData,18); - Log3 $iohash, 4, "$model decoded protocolid: 47 sensor startup=$startup, temp1=$temp_str1, temp2=$temp_str2, unknown=$unknown"; - - # Convert + # ohne header: + # MC;LL=-507;LH=490;SL=-258;SH=239;D=AA9995599599A959996699A969;C=248;L=104; + # P47#599599A959996699A969 + # + # 0 2 6 7 12 + # ss 11111 22222 uuuuuuuu + # 59 9599A 95999 6699A969 + # + + my $messageType = substr($rawData,0,2); # 0x6A upon startup, 0x59 otherwise + my $temp_str1 = substr($rawData,2,5); + my $temp_str2 = substr($rawData,7,5); + my $checksum_str = substr($rawData,12); + + Log3 $iohash, 4, "$name $model decoded protocolid: 47 sensor messageType=$messageType, temp-f=$temp_str1, temp-b=$temp_str2, checksum-s=$checksum_str"; + + if ($messageType eq '59'){ + $messageType="normal"; + }elsif ($messageType eq '6A') { + $messageType="sync"; + }else{ + Log3 $iohash, 4, "$name $model ERROR: wrong messageType=$messageType (must be 59 or 6A)"; + return ''; + } + + # Calculate temp from data + my $c; + my $temp_food=-532; + my $temp_bbq=-532; + my $sensor_1_state="unknown"; + my $sensor_2_state="unknown";; + + if ($temp_str1 ne '55555') { $temp_str1 =~ tr/569A/0123/; - $temp_str2 =~ tr/569A/0123/; - - # Calculate temp from data - my $c; - my $temp1=-532; - for ( my $i = 0; $i < length($temp_str1); $i++ ) { - $c = substr( $temp_str1, $i, 1); - $temp1 += $c*4**(4-$i); - } - - my $temp2=-532; - for ( my $i = 0; $i < length($temp_str2); $i++ ) { - $c = substr( $temp_str2, $i, 1); - $temp2 += $c*4**(4-$i); - } - - - Log3 $iohash, 4, "$model decoded protocolid: temp1=$temp1, temp2=$temp2;"; - - + for ( my $i = 0; $i < length($temp_str1); $i++ ) { + $c = substr( $temp_str1, $i, 1); + $temp_food += $c*4**(4-$i); + } + if ($temp_food <= 0 || $temp_food > 300) { + Log3 $iohash, 4, "$name $model ERROR: wrong temp-food=$temp_food"; + $temp_food = ""; + }else{ + $sensor_1_state="connected"; + } + } else { + $sensor_1_state="disconnected" if ($temp_str1 eq '55555'); + $temp_food = ""; + } - - - #print Dumper($modules{SD_WS_Maverick}{defptr}); - - my $def = $modules{SD_WS_Maverick}{defptr}{$iohash->{NAME} }; - $def = $modules{SD_WS_Maverick}{defptr}{$model} if(!$def); - - if(!$def) { - Log3 $iohash, 1, 'SD_WS_Maverick: UNDEFINED sensor ' . $model; - return "UNDEFINED $model SD_WS_Maverick $model"; + if ($temp_str2 ne '55555') { + $temp_str2 =~ tr/569A/0123/; + for ( my $i = 0; $i < length($temp_str2); $i++ ) { + $c = substr( $temp_str2, $i, 1); + $temp_bbq += $c*4**(4-$i); } - #Log3 $iohash, 3, 'SD_WS_Maverick: ' . $def->{NAME} . ' ' . $id; - - my $hash = $def; - $name = $hash->{NAME}; - Log3 $name, 4, "SD_WS_Maverick: $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, "$model Dropped due to short time. minsecs=$minsecs"; - return ""; - } - } - - $hash->{lastReceive} = time(); - $hash->{lastMSG} = $rawData; - #$hash->{bitMSG} = $bitData2; - - my $state = "T: $temp1"." T2: $temp2" ; + if ($temp_bbq <= 0 || $temp_bbq > 300) { + Log3 $iohash, 4, "$name $model ERROR: wrong temp-bbq=$temp_bbq"; + $temp_bbq = ""; + }else{ + $sensor_2_state="connected"; + } + } else { + $sensor_2_state="disconnected" if ($temp_str2 eq '55555'); + $temp_bbq = ""; + } + + #if ($temp_bbq eq "" && $temp_food eq "") { + # return ''; + #} + + Log3 $iohash, 4, "$name $model decoded protocolid: temp-food=$temp_food, temp-bbq=$temp_bbq;"; + + #print Dumper($modules{SD_WS_Maverick}{defptr}); - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "state", $state); - readingsBulkUpdate($hash, "messageType", $startup); - - readingsBulkUpdate($hash, "temp1", $temp1) if ($temp1 ne""); - readingsBulkUpdate($hash, "temp2", $temp2) if ($temp2 ne""); - - readingsEndUpdate($hash, 1); # Notify is done by Dispatch + my $def = $modules{SD_WS_Maverick}{defptr}{$iohash->{NAME} }; + $def = $modules{SD_WS_Maverick}{defptr}{$model} if(!$def); - return $name; + if(!$def) { + Log3 $iohash, 1, "$name SD_WS_Maverick: UNDEFINED sensor $model"; + return "UNDEFINED $model SD_WS_Maverick $model"; + } + #Log3 $iohash, 3, 'SD_WS_Maverick: ' . $def->{NAME} . ' ' . $id; + + my $hash = $def; + $name = $hash->{NAME}; + Log3 $name, 4, "SD_WS_Maverick: $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, "$model Dropped due to short time. minsecs=$minsecs"; + return ""; + } + } + + $hash->{lastReceive} = time(); + $hash->{lastMSG} = $rawData; + #$hash->{bitMSG} = $bitData2; + + # Den SensorState bei Inaktivität zurücksetzen lassen durch Timer + my $inactivityinterval=int(AttrVal($name,"inactivityinterval",360)); + if ($sensor_1_state ne "unknown") { + $hash->{sensor_1_state}=$sensor_1_state; + RemoveInternalTimer($hash, 'SD_WS_Maverick_SetSensor1Inaktiv'); + InternalTimer(time()+($inactivityinterval), 'SD_WS_Maverick_SetSensor1Inaktiv', $hash, 0); + } + if ( $sensor_2_state ne "unknown") { + $hash->{sensor_2_state}=$sensor_2_state; + RemoveInternalTimer($hash, 'SD_WS_Maverick_SetSensor2Inaktiv'); + InternalTimer(time()+($inactivityinterval), 'SD_WS_Maverick_SetSensor2Inaktiv', $hash, 0); + } + + # Checksum auswerten + $checksum_str =~ tr/569A/0123/; + my $checksum=""; + $checksum=$checksum_str; + # TODO: Die eigentliche Checksum errechnen. Diese ändert sich bei jedem Temperaturwechsel + # TODO: Evtl. ist in den checksum-bits auch noch eine Info zur Batterie enthalten + # ggf. ist es möglich die checksum als ID zu verwenden und so mehrere Mavericks in fhem einbinden zu können. + $hash->{checksum}=$checksum; + $hash->{temp_food}=$temp_food if ($temp_food ne""); + $hash->{temp_bbq}=$temp_bbq if ($temp_bbq ne""); + $hash->{messageType}=$messageType; + + # TODO: Logging kann entfernt werden, wenn checksum entschlüsselt ist. Wird zur Analyse verwendet. + Log3 $hash, 4, "$name statistic: checksum=$checksum, t1=$temp_str1, temp-food=$temp_food, t2_$temp_str2, temp-bbq=$temp_bbq;"; + + SD_WS_Maverick_updateReadings($hash); + + return $name; } sub SD_WS_Maverick_Attr(@) { - my @a = @_; - - # Make possible to use the same code for different logical devices when they - # are received through different physical devices. - return if($a[0] ne "set" || $a[2] ne "IODev"); - my $hash = $defs{$a[1]}; - my $iohash = $defs{$a[3]}; - my $cde = $hash->{CODE}; - delete($modules{SD_WS_Maverick}{defptr}{$cde}); - $modules{SD_WS_Maverick}{defptr}{$iohash->{NAME} . "." . $cde} = $hash; + my ($cmd,$name,$attr_name,$attr_value) = @_; + my $hash = $defs{$name}; + if($cmd eq "set") { + if($attr_name eq "IODev") { + # Make possible to use the same code for different logical devices when they + # are received through different physical devices. + my $iohash = $defs{$attr_value}; + my $cde = $hash->{CODE}; + delete($modules{SD_WS_Maverick}{defptr}{$cde}); + $modules{SD_WS_Maverick}{defptr}{$iohash->{NAME} . "." . $cde} = $hash; + } + elsif($attr_name eq "inactivityinterval") { + if (!looks_like_number($attr_value) || int($attr_value) < 60 || int($attr_value) > 3600) { + return "$name: Value \"$attr_value\" is not allowed.\n" + ."inactivityinterval must be a number between 60 and 3600." + } + } + } return undef; } +sub SD_WS_Maverick_SetSensor1Inaktiv($){ + my ($hash) = @_; + my $name = $hash->{NAME}; + Log3 $hash, 5, "$name SD_WS_Maverick_SetSensor1Inaktiv"; + + $hash->{sensor_1_state}="inactiv"; + SD_WS_Maverick_updateReadings($hash); +} + +sub SD_WS_Maverick_SetSensor2Inaktiv($){ + my ($hash) = @_; + my $name = $hash->{NAME}; + Log3 $hash, 5, "$name SD_WS_Maverick_SetSensor2Inaktiv"; + + $hash->{sensor_2_state}="inactiv"; + SD_WS_Maverick_updateReadings($hash); +} + +sub SD_WS_Maverick_updateReadings($){ + my ($hash) = @_; + my $name = $hash->{NAME}; + Log3 $hash, 5, "$name SD_WS_Maverick_updateReadings"; + + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "temp-food", $hash->{temp_food}); + readingsBulkUpdate($hash, "temp-bbq", $hash->{temp_bbq}); + readingsBulkUpdate($hash, "messageType ", $hash->{messageType}); + readingsBulkUpdate($hash, "checksum", $hash->{checksum}); + readingsBulkUpdate($hash, "Sensor-1-food_state", $hash->{sensor_1_state}); + readingsBulkUpdate($hash, "Sensor-2-bbq_state", $hash->{sensor_2_state}); + readingsEndUpdate($hash, 1); # Notify is done by Dispatch + return undef; +} 1; @@ -196,43 +337,45 @@ sub SD_WS_Maverick_Attr(@) =begin html -

Wether Sensors protocol #7

+

BBQ Sensors protocol #47

@@ -249,39 +392,45 @@ sub SD_WS_Maverick_Attr(@) =begin html_DE -

SD_WS_Maverick

+

BBQ Sensors protocol #47