2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 12:49:34 +00:00

14_SD_WS.pm: updated to version 3.5.4

added serval new sensors
             easier battery replace via set command

git-svn-id: https://svn.fhem.de/fhem/trunk@26982 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
sidey79 2023-01-06 11:50:39 +00:00
parent aa9e2afc80
commit e2bb20f19b
2 changed files with 542 additions and 76 deletions

View File

@ -1,5 +1,13 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # 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. # Do not insert empty lines here, update check depends on it.
- feature: 14_SD_WS.pm: new sensor Bresser 7-in-1 Comfort Wetter Center
new set command to allow battery replacement
new sensor SM60020 multi purpose environment sensor
new sensor TFA 30.3251.10
new senosr TFA 35.1077.54.S2 with 30.3151
temp/hum, 30.3152 (rain) and 30.3153 (wind)
new sensor TM40, wireless Grill-, Meat-,
Roasting-Thermometer with 4 temp sensors
- feature: 00_SIGNALduino.pm: Updated to vversion 3.5.4 - feature: 00_SIGNALduino.pm: Updated to vversion 3.5.4
update commandref update commandref
make SIGNALduino_IdList more robust make SIGNALduino_IdList more robust

View File

@ -40,14 +40,21 @@
# 05.01.2022 Protokoll 108: neuer Sensor Fody E42 # 05.01.2022 Protokoll 108: neuer Sensor Fody E42
# 08.01.2022 neues Protokoll 107: Soil Moisture Sensor Fine Offset WH51, ECOWITT WH51, MISOL/1, Froggit DP100 # 08.01.2022 neues Protokoll 107: Soil Moisture Sensor Fine Offset WH51, ECOWITT WH51, MISOL/1, Froggit DP100
# 14.01.2022 neues Protokoll 116: Thunder and lightning sensor Fine Offset WH57, aka Froggit DP60, aka Ambient Weather WH31L # 14.01.2022 neues Protokoll 116: Thunder and lightning sensor Fine Offset WH57, aka Froggit DP60, aka Ambient Weather WH31L
# 29.01.2022 neues Protokoll 117: Bresser 7-in-1 Comfort Wetter Center
# 04.02.2022 neu: set replaceBatteryForSec (Ident ersetzen bei Batteriewechsel Sensor)
# 12.03.2022 Protokoll 115: neue Sensoren SM60020 Boden-/Erd-Sensor für Feuchte- und Temperatur, Innensensor für Feuchte- und Temperatur
# 11.04.2022 Protokoll 85: neuer Sensor Windmesser TFA 30.3251.10 mit Windrichtung, Pruefung CRC8 eingearbeitet
# 23.05.2022 neues Protokoll 120: Wetterstation TFA 35.1077.54.S2 mit 30.3151 (Thermo/Hygro-Sender), 30.3152 (Regenmesser), 30.3153 (Windmesser)
# 11.06.2022 neues Protokoll 122: TM40, Wireless Grill-, Meat-, Roasting-Thermometer with 4 Temperature Sensors
package main; package main;
#use version 0.77; our $VERSION = version->declare('v3.4.3'); #use version 0.77; our $VERSION = version->declare('v3.5.4');
use strict; use strict;
use warnings; use warnings;
use Carp qw(carp); use Carp qw(carp);
use FHEM::Meta;
# Forward declarations # Forward declarations
sub SD_WS_LFSR_digest8_reflect; sub SD_WS_LFSR_digest8_reflect;
@ -59,11 +66,11 @@ sub SD_WS_WH2SHIFT;
sub SD_WS_Initialize { sub SD_WS_Initialize {
my $hash = shift // return; my $hash = shift // return;
$hash->{Match} = '^W\d+x{0,1}#.*'; $hash->{Match} = '^W\d+x{0,1}#.*';
$hash->{DefFn} = "SD_WS_Define"; $hash->{DefFn} = \&SD_WS_Define;
$hash->{UndefFn} = "SD_WS_Undef"; $hash->{UndefFn} = \&SD_WS_Undef;$hash->{SetFn} = \&SD_WS_Set;
$hash->{ParseFn} = "SD_WS_Parse"; $hash->{ParseFn} = \&SD_WS_Parse;
$hash->{AttrList} = "do_not_notify:1,0 ignore:0,1 showtime:1,0 " . $hash->{AttrList} = "do_not_notify:1,0 ignore:0,1 showtime:1,0 " .
"model:E0001PA,S522,TX-EZ6,other " . "model:E0001PA,S522,TFA_30.3251.10,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-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 ". "max-deviation-hum:1,2,3,4,5,6,7,8,9,10,15,20,25,30,35,40,45,50 ".
"$readingFnAttributes "; "$readingFnAttributes ";
@ -95,8 +102,11 @@ sub SD_WS_Initialize {
'SD_WS_113_T.*' => { ATTR => 'event-min-interval:.*:60 event-on-change-reading:.*', FILTER => '%NAME', GPLOT => 'temp4:Temp,', autocreateThreshold => '10:180'}, 'SD_WS_113_T.*' => { ATTR => 'event-min-interval:.*:60 event-on-change-reading:.*', FILTER => '%NAME', GPLOT => 'temp4:Temp,', autocreateThreshold => '10:180'},
'SD_WS_115.*' => { ATTR => 'event-min-interval:.*:300 event-on-change-reading:.*', FILTER => '%NAME', GPLOT => 'temp4hum4:Temp/Hum,', autocreateThreshold => '5:120'}, 'SD_WS_115.*' => { ATTR => 'event-min-interval:.*:300 event-on-change-reading:.*', FILTER => '%NAME', GPLOT => 'temp4hum4:Temp/Hum,', autocreateThreshold => '5:120'},
'SD_WS_116.*' => { ATTR => 'event-min-interval:.*:300 event-on-change-reading:.*', FILTER => '%NAME', GPLOT => q{}, autocreateThreshold => '2:180'}, 'SD_WS_116.*' => { ATTR => 'event-min-interval:.*:300 event-on-change-reading:.*', FILTER => '%NAME', GPLOT => q{}, autocreateThreshold => '2:180'},
'SD_WS_117.*' => { ATTR => 'event-min-interval:.*:300 event-on-change-reading:.*', FILTER => '%NAME', GPLOT => 'temp4hum4:Temp/Hum,', autocreateThreshold => '5:120'},
'SD_WS_120.*' => { ATTR => 'event-min-interval:.*:300 event-on-change-reading:.*', FILTER => '%NAME', GPLOT => 'temp4hum4:Temp/Hum,', autocreateThreshold => '2:180'},
'SD_WS_122_T.*' => { ATTR => 'event-min-interval:.*:60 event-on-change-reading:.*', FILTER => '%NAME', GPLOT => 'temp4:Temp,', autocreateThreshold => '10:180'},
}; };
return; return FHEM::Meta::InitMod( __FILE__, $hash );
} }
############################# #############################
@ -123,6 +133,52 @@ sub SD_WS_Undef {
my ($hash, $name) = @_; my ($hash, $name) = @_;
carp "SD_WS_Undef, too few arguments ($hash, $name)" if @_ < 2; carp "SD_WS_Undef, too few arguments ($hash, $name)" if @_ < 2;
delete($modules{SD_WS}{defptr}{$hash->{CODE}}) if(defined($hash->{CODE}) && defined($modules{SD_WS}{defptr}{$hash->{CODE}})); delete($modules{SD_WS}{defptr}{$hash->{CODE}}) if(defined($hash->{CODE}) && defined($modules{SD_WS}{defptr}{$hash->{CODE}}));
RemoveInternalTimer($hash);
return;
}
#############################
sub SD_WS_Set {
my $hash = shift // carp 'device hash needs to be first parameter';
my $name = shift // carp 'name of the device must be second parameter';
my $cmd = shift // carp 'Specify the command as third prarameter';
my @args = @_;
my $ret = undef;
my $LastInputDev = $hash->{LASTInputDev};
return $ret if (!defined $LastInputDev);
my $rhash = $defs{$LastInputDev};
my $rlongids = AttrVal($rhash->{NAME},'longids',0);
my $def = $hash->{DEF};
my @array = split(/_/,$def);
my $model = $array[0] . '_' . $array[1] . '_' . $array[2];
if (($rlongids ne "0") && ($rlongids eq "1" || $rlongids eq "ALL" || ($rlongids =~ m/$model/))) {
if ($cmd eq '?') {
$ret = 'replaceBatteryForSec'; # return setList
} elsif ($cmd eq 'replaceBatteryForSec') {
return "$name: No or too small value specified for the replaceBatteryForSec command" if (scalar(@args) < 1 || $args[0] < 1);
my @found = devspec2array("TYPE=SD_WS:FILTER=i:replaceBattery>0");
return "$name: Only one sensor at a time, replaceBatteryForSec is already activated at @found" if (scalar(@found) > 0);
my $repBatForSec = $args[0];
$hash->{replaceBattery} = $repBatForSec;
InternalTimer(gettimeofday() + $repBatForSec, \&SD_WS_TimerRemoveReplaceBattery, $hash, 0);
Log3 $name, 3, "$name: SD_WS_Set, wait $repBatForSec seconds for a new identity of the sensor";
} else {
$ret = "$name: Unknown argument $cmd, choose replaceBatteryForSec";
}
}
return $ret;
}
#############################
sub SD_WS_TimerRemoveReplaceBattery {
my $hash = shift;
my $name = $hash->{NAME};
delete($hash->{replaceBattery});
RemoveInternalTimer($hash);
Log3 $name, 3, "$name: SD_WS_TimerRemoveReplaceBattery, no sensor with unknown identity received";
return; return;
} }
@ -151,11 +207,13 @@ sub SD_WS_Parse {
my $rawTemp; my $rawTemp;
my $temp; my $temp;
my $temp2; my $temp2;
my $temp3;
my $temp4;
my $hum; my $hum;
my $windspeed; my $windspeed;
my $winddir; my $winddir;
my $winddirtxt; my $winddirtxt;
my @winddirtxtar=('N','NNE','NE','ENE','E','ESE','SE','SSE','S','SSW','SW','WSW','W','WNW','NW','NNW'); my @winddirtxtar=('N','NNE','NE','ENE','E','ESE','SE','SSE','S','SSW','SW','WSW','W','WNW','NW','NNW','N');
my $windgust; my $windgust;
my $trend; my $trend;
my $trendTemp; my $trendTemp;
@ -168,8 +226,12 @@ sub SD_WS_Parse {
my $distance; my $distance;
my $uv; my $uv;
my $adc; my $adc;
my $brightness;
my @moisture_map=(0, 7, 13, 20, 27, 33, 40, 47, 53, 60, 67, 73, 80, 87, 93, 99); # ID 115
my $count; my $count;
my $identified; my $identified;
my $transmitter;
my $dcf;
my %decodingSubs = ( my %decodingSubs = (
50 => # Protocol 50 50 => # Protocol 50
@ -584,12 +646,13 @@ sub SD_WS_Parse {
} , } ,
85 => 85 =>
{ {
# Protokollbeschreibung: Kombisensor TFA 30.3222.02 fuer Wetterstation TFA 35.1140.01 # Protokollbeschreibung: Kombisensor TFA 30.3222.02 fuer Wetterstation TFA 35.1140.01, Windmesser TFA 30.3251.10
# ----------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------------
# 0 4 | 8 12 | 16 20 | 24 28 | 32 36 | 40 44 | 48 52 | 56 60 | 64 # 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 # 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 # 0000 iiii | iiii iiii | iiii iiii | b??? ??yy | tttt tttt | tttt 0000 | hhhh hhhh | CCCC CCCC | ? message 1 TFA 30.3222.02
# ???? iiii | iiii iiii | iiii iiii | b?cc ??yy | wwww wwww | wwww ???? | 0000 0000 | ???? ???? | ? message 2 # 0000 iiii | iiii iiii | iiii iiii | b?cc ??yy | wwww wwww | wwww 0000 | 0000 0000 | CCCC CCCC | ? message 2 TFA 30.3222.02
# 0000 iiii | iiii iiii | iiii iiii | b?cc ??yy | wwww wwww | wwww dddd | dddd dddd | CCCC CCCC | ? message 2 TFA 30.3251.10
# i: 20 bit random id (changes on power-loss) # i: 20 bit random id (changes on power-loss)
# b: 1 bit battery indicator (0=>OK, 1=>LOW) # b: 1 bit battery indicator (0=>OK, 1=>LOW)
# c: 2 bit channel valid channels are (always 00 stands for channel 1) # c: 2 bit channel valid channels are (always 00 stands for channel 1)
@ -597,14 +660,14 @@ sub SD_WS_Parse {
# t: 12 bit unsigned temperature, offset 500, scaled by 10 - if message 1 # t: 12 bit unsigned temperature, offset 500, scaled by 10 - if message 1
# h: 8 bit relative humidity percentage - if message 1 # h: 8 bit relative humidity percentage - if message 1
# w: 12 bit unsigned windspeed, scaled by 10 - if message 2 # w: 12 bit unsigned windspeed, scaled by 10 - if message 2
# d: 12 bit unsigned winddirection - only TFA 30.3251.10
# C: 8 bit CRC of the preceding 7 bytes (Polynomial 0x31, Initial value 0x00, Input not reflected, Result not reflected)
# ?: unknown # ?: unknown
# The sensor sends at intervals of about 30 seconds # The sensor sends at intervals of about 30 seconds
sensortype => 'TFA 30.3222.02, TFA 30.3251.10, LaCrosse TX141W',
sensortype => 'TFA 30.3222.02',
model => 'SD_WS_85_THW', model => 'SD_WS_85_THW',
prematch => sub {my $msg = shift; return 1 if ($msg =~ /^[0-9A-F]{16}/); }, # min 16 nibbles 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 ($rawData,undef) = @_; return substr($rawData,1,5); }, # 0952CF012B1021DF0
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";}, 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 channel => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,26,27) + 1 ); }, # unknown
temp => sub {my (undef,$bitData) = @_; temp => sub {my (undef,$bitData) = @_;
@ -628,6 +691,34 @@ sub SD_WS_Parse {
return; return;
} }
}, },
winddir => sub {my (undef,$bitData) = @_;
if (substr($bitData,30,2) eq "10") { # message 2 winddirection
$winddir = SD_WS_binaryToNumber($bitData,44,55);
return ($winddir * 1, $winddirtxtar[round(($winddir / 22.5),0)]);
} else {
return;
}
},
crcok => sub {my ($rawData,undef) = @_;
my $rc = eval {
require Digest::CRC;
Digest::CRC->import();
1;
};
if ($rc) {
my $datacheck1 = pack( 'H*', substr($rawData,0,14) );
my $crcmein1 = Digest::CRC->new(width => 8, poly => 0x31);
my $rr3 = $crcmein1->add($datacheck1)->hexdigest;
if (hex($rr3) != hex(substr($rawData,14,2))) {
Log3 $name, 3, "$name: SD_WS_85 Parse msg $rawData - ERROR CRC8";
return 0;
}
} else {
Log3 $name, 1, "$name: SD_WS_85 Parse msg $rawData - ERROR CRC not load, please install modul Digest::CRC";
return 0;
}
return 1;
}
} , } ,
89 => 89 =>
{ {
@ -986,64 +1077,92 @@ sub SD_WS_Parse {
# 0123456789012345678901234567890123456789 # 0123456789012345678901234567890123456789
# ---------------------------------------- # ----------------------------------------
# 3DA820B00C1618FFFFFF1808152294FFF01E0000 Msg 1, 40 Nibble from SIGNALduino, T: 15.2 H: 94 G:0 W: 0 D:180 # 3DA820B00C1618FFFFFF1808152294FFF01E0000 Msg 1, 40 Nibble from SIGNALduino, T: 15.2 H: 94 G:0 W: 0 D:180
# CCCCIIIIIIIIFFGGGWWWDDD?TTT?HH????SS Msg 1, 36 Nibble # CCCCIIIIIIIIFFGGGWWWDDD?TTTFHHVVVXSS Msg 1, 36 Nibble, wind, temperature, humidity, uv
# CCCCIIIIIIIIFFGGGWWWDDD?ffRRRRVVV?SS Msg 2, 36 Nibble # CCCCIIIIIIIIFFGGGWWWDDD?RRRRRR???XSS Msg 2, 36 Nibble, wind, rain
# C = CRC16 # C = CRC16
# I = station ID # I = station ID
# F = flags, 4 bit (1: weather station, 2: indoor?, 4: soil probe), 1 bit battery (1=ok, 0=low), 3 bit channel # F = flags, 8 bit (nibble 12 1: weather station, 2: indoor, 4: soil probe, nibble 13 1 bit battery change, 3 bit channel)
# G = wind gust in 1/10 m/s, inverted, BCD coded, GGG = FE6 =~ 019 => 1.9 m/s. # G = wind gust in 1/10 m/s, inverted, BCD coded, GGG = FE6 =~ 019 => 1.9 m/s.
# W = wind speed in 1/10 m/s, inverted, BCD coded, LSB first nibble, MSB last two nibble, WWW = EFE =~ 101 => 1.1 m/s. # W = wind speed in 1/10 m/s, inverted, BCD coded, LSB first nibble, MSB last two nibble, WWW = EFE =~ 101 => 1.1 m/s.
# D = wind direction in grad, BCD coded, DDD = 158 => 158 ° # D = wind direction in grad, BCD coded, DDD = 158 => 158 °
# ? = unknown, always 0x8 # ? = unknown, 0x0, 0x8 or 0xE
# T = temperature in 1/10 °C, only if byte 12 ne 0xFF, BCD coded, TTT = 312 => 31.2 °C # T = temperature in 1/10 °C, TTT = 312 => 31.2 °C
# ? = unknown # F = flags, 4 bit - bit 3 temperature (0=positive, 1=negative), bit 2 ?, bit 1 battery (1=ok, 0=low), bit 0 ?
# H = humidity in percent, only if byte 12 ne 0xFF, BCD coded, HH = 23 => 23 % # H = humidity in percent, BCD coded, HH = 23 => 23 %
# R = rain counter, only if byte 12 eq 0xFF, inverted, BCD coded # R = rain counter, inverted, BCD coded
# V = uv, only if byte 12 eq 0xFF and byte 15/16 not 0xFF01, inverted, BCD coded # V = uv, inverted, BCD coded
# ? = unknown # X = message type, 0 = temp, hum, wind, uv, 1 = wind, rain
# S = checksum (sum over byte 2 - 17 must be 255) # S = checksum (sum over byte 2 - 17 must be 255)
sensortype => 'Bresser_6in1, new Bresser_5in1', sensortype => 'Bresser_6in1, new Bresser_5in1',
model => 'SD_WS_115', model => 'SD_WS_115',
prematch => sub { return 1; }, # no precheck known prematch => sub { return 1; }, # no precheck known
id => sub {my ($rawData,undef) = @_; return substr($rawData,4,8); }, id => sub {my ($rawData,undef) = @_; return substr($rawData,4,8); },
bat => sub {my (undef,$bitData) = @_; return substr($bitData,52,1) eq '1' ? 'ok' : 'low';}, bat => sub {my ($rawData,$bitData) = @_;
channel => sub {my (undef,$bitData) = @_; return (SD_WS_binaryToNumber($bitData,53,55));}, return if (substr($rawData,12,1) eq '1' && substr($rawData,33,1) eq '1'); # not by weather station & rain
return substr($bitData,110,1) eq '1' ? 'ok' : 'low';
},
batChange => sub {my (undef,$bitData) = @_; return substr($bitData,52,1);},
channel => sub {my ($rawData,$bitData) = @_;
$channel = '';
$channel = substr($rawData,12,1) if (substr($rawData,12,1) ne '1'); # not weather station
return ($channel . SD_WS_binaryToNumber($bitData,53,55));
},
windgust => sub {my ($rawData,undef) = @_; windgust => sub {my ($rawData,undef) = @_;
return if (substr($rawData,12,1) ne '1'); # only weather station
$windgust = substr($rawData,14,3); $windgust = substr($rawData,14,3);
$windgust =~ tr/0123456789ABCDEF/FEDCBA9876543210/; $windgust =~ tr/0123456789ABCDEF/FEDCBA9876543210/;
# uncoverable branch true
return if ($windgust !~ m/^\d+$/xms); return if ($windgust !~ m/^\d+$/xms);
return $windgust * 0.1; return $windgust * 0.1;
}, },
windspeed => sub {my ($rawData,undef) = @_; windspeed => sub {my ($rawData,undef) = @_;
return if (substr($rawData,12,1) ne '1'); # only weather station
$windspeed = substr($rawData,18,2) . substr($rawData,17,1); $windspeed = substr($rawData,18,2) . substr($rawData,17,1);
$windspeed =~ tr/0123456789ABCDEF/FEDCBA9876543210/; $windspeed =~ tr/0123456789ABCDEF/FEDCBA9876543210/;
# uncoverable branch true
return if ($windspeed !~ m/^\d+$/xms); return if ($windspeed !~ m/^\d+$/xms);
return $windspeed * 0.1; return $windspeed * 0.1;
}, },
winddir => sub {my ($rawData,undef) = @_; winddir => sub {my ($rawData,undef) = @_;
return if (substr($rawData,12,1) ne '1' || substr($rawData,20,3) !~ m/^\d+$/xms); # only weather station
$winddir = substr($rawData,20,3); $winddir = substr($rawData,20,3);
return if ($winddir !~ m/^\d+$/xms);
return ($winddir * 1, $winddirtxtar[round(($winddir / 22.5),0)]); return ($winddir * 1, $winddirtxtar[round(($winddir / 22.5),0)]);
}, },
temp => sub {my ($rawData,undef) = @_; temp => sub {my ($rawData,$bitData) = @_;
return if (substr($rawData,24,2) eq 'FF'); # uncoverable condition right
$rawTemp = (substr($rawData,24,1) . substr($rawData,25,1) . substr($rawData,26,1)) * 0.1; return if ((substr($rawData,12,1) eq '1' && substr($rawData,33,1) eq '1') || substr($rawData,24,3) !~ m/^\d+$/xms); # not by weather station & rain
if ($rawTemp > 60) {$rawTemp -= 100}; $rawTemp = substr($rawData,24,3) * 0.1;
return $rawTemp; if (substr($bitData,108,1) eq '1') {
if ($rawTemp > 60) {
$rawTemp -= 100; # Bresser 6in1
} else {
$rawTemp *= -1; # Bresser 3in1
}
}
return round($rawTemp,1);
}, },
hum => sub {my ($rawData,undef) = @_; hum => sub {my ($rawData,undef) = @_;
return if (substr($rawData,24,2) eq 'FF'); # uncoverable condition right
return substr($rawData,28,2) + 0; return if ((substr($rawData,12,1) eq '1' && substr($rawData,33,1) eq '1') || substr($rawData,28,2) !~ m/^\d+$/xms); # not by weather station & rain
$hum = substr($rawData,28,2) * 1;
if (substr($rawData,12,1) eq '4' && $hum >= 1 && $hum <= 16) { # Soil Moisture
return $moisture_map[$hum - 1];
}
return $hum;
}, },
rain => sub {my ($rawData,undef) = @_; rain => sub {my ($rawData,undef) = @_;
return if (substr($rawData,24,2) ne 'FF'); return if (substr($rawData,33,1) ne '1' || substr($rawData,12,1) ne '1'); # message type || weather station
$rain = substr($rawData,26,4); $rain = substr($rawData,24,6);
$rain =~ tr/0123456789ABCDEF/FEDCBA9876543210/; $rain =~ tr/0123456789ABCDEF/FEDCBA9876543210/;
# uncoverable branch true
return if ($rain !~ m/^\d+$/xms);
return $rain * 0.1; return $rain * 0.1;
}, },
uv => sub {my ($rawData,undef) = @_; uv => sub {my ($rawData,undef) = @_;
return if (substr($rawData,24,2) ne 'FF' || substr($rawData,30,3) !~ m/^\d+$/xms); return if (substr($rawData,33,1) ne '0' || substr($rawData,12,1) ne '1'); # message type || weather station
$uv = substr($rawData,30,3); $uv = substr($rawData,30,3);
$uv =~ tr/0123456789ABCDEF/FEDCBA9876543210/;
# uncoverable branch true
return if ($uv !~ m/^\d+$/xms); return if ($uv !~ m/^\d+$/xms);
return $uv * 0.1; return $uv * 0.1;
}, },
@ -1116,6 +1235,187 @@ sub SD_WS_Parse {
return 1; return 1;
} }
} , } ,
117 => {
# https://github.com/merbanan/rtl_433/blob/master/src/devices/bresser_7in1.c
# The compact 7-in-1 multifunction outdoor sensor transmits the data on 868.3 MHz.
# The device uses FSK-PCM encoding, the device sends a transmission every 12 seconds.
# A transmission starts with a preamble of 0xAA.
# Preamble: aa aa aa aa aa 2d d4
#
# 1 2 3 4
# 01234567890123456789012345678901234567890123456789
# --------------------------------------------------
# 0CF0A6F5B98A10AAAAAAAAAAAAAABABC3EAABBFCAAAAAAAAAA000000 original message
# A65A0C5F1320BA000000000000001016940011560000000000AAAAAA message after all nibbles xor 0xA
# CCCCIIIIDDD??FGGGWWWRRRRRR??TTTBHHbbbbbbVVVttttttt
# C = LFSR-16 digest, generator 0x8810 key 0xba95 with a final xor 0x6df1, which likely means we got that wrong.
# I = station ID
# D = wind direction in degree, BCD coded, DDD = 158 => 158 °
# F = flags, 4 bit
# Bit: 0123
# 1010
# r???
# r: 1 bit device reset, 1 after inserting battery
# ???: always 010
# G = wind gust in 1/10 m/s, BCD coded, GGG = 123 => 12.3 m/s.
# W = wind speed in 1/10 m/s, BCD coded, WWW = 123 => 12.3 m/s.
# R = rain counter, in 0.1 mm, BCD coded RRRRRR = 000084 => 8.4 mm
# T = temperature in 1/10 °C, BCD coded, TTT = 312 => 31.2 °C
# B = battery. 0=Ok, 6=Low
# H = humidity in percent, BCD coded, HH = 23 => 23 %
# b = brightness, BCD coded, BBBBBB = 005584 => 5.584 klx
# V = uv, BCD coded, VVV = 012 => 1.2
# ? = unknown
# t = trailer
sensortype => 'Bresser_7in1',
model => 'SD_WS_117',
prematch => sub {my $rawData = shift; return 1 if ($rawData =~ /^[0-9A-F]{8}[0-9]{3}[0-9A-F]{3}[0-9]{12}[0-9A-F]{2}[0-9]{15}/); },
id => sub {my ($rawData,undef) = @_; return substr($rawData,4,4); },
winddir => sub {my ($rawData,undef) = @_;
$winddir = substr($rawData,8,3);
return ($winddir * 1, $winddirtxtar[round(($winddir / 22.5),0)]);
},
batChange => sub {my (undef,$bitData) = @_; return substr($bitData,52,1) eq '0' ? '1' : '0';},
windgust => sub {my ($rawData,undef) = @_; return substr($rawData,14,3) * 0.1;},
windspeed => sub {my ($rawData,undef) = @_; return substr($rawData,17,3) * 0.1;},
rain => sub {my ($rawData,undef) = @_; return substr($rawData,20,6) * 0.1;},
temp => sub {my ($rawData,undef) = @_;
$rawTemp = substr($rawData,28,3) * 0.1;
if ($rawTemp > 60) {$rawTemp -= 100};
return $rawTemp;
},
bat => sub {my ($rawData,undef) = @_; return substr($rawData,31,1) eq '0' ? 'ok' : 'low';},
hum => sub {my ($rawData,undef) = @_; return substr($rawData,32,2) * 1;},
brightness => sub {my ($rawData,undef) = @_; return substr($rawData,34,6) * 0.001;},
uv => sub {my ($rawData,undef) = @_; return substr($rawData,40,3) * 0.1;},
crcok => sub {return 1;}, # checks are in SD_Protocols.pm sub ConvBresser_7in1
},
120 => {
# Weather station TFA 35.1077.54.S2 with 30.3151 (T/H-transmitter), 30.3152 (rain gauge), 30.3153 (anemometer)
# ------------------------------------------------------------------------------------------------------------
# https://forum.fhem.de/index.php/topic,119335.msg1221926.html#msg1221926
# 0 4 | 8 12 | 16 20 | 24 28 | 32 36 | 40 44 | 48 52 | 56 60 | 64 68 | 72 76
# 1111 1110 | 1010 1011 | 0000 0100 | 1001 1110 | 1010 1010 | 0000 1000 | 0000 1100 | 0000 1100 | 0101 0011 | 0000 0000 - T: 19.1 H: 85 W: 1.3 R: 473.1
# PPPP PPPW | WWWI IIII | IIIF BTTT | TTTT TTTH | HHHH HHHS | SSSS SSSG | GGGG GGGR | RRRR RRRR | RRRR RRR? | CCCC CCCC
# 1111 1110 | 1100 1011 | 0001 0101 | 0011 0000 | 0000 0110 | 0000 1100 | 0100 0100 | 1000 1100 | 0100 1111 | 1011 1000 - 2022-06-27 18:03:06
# PPPP PPPW | WWWI IIII | IIIF ???? | ?hhh hhh? | mmmm mmm? | ssss sssY | YYYY YYY? | ??MM MMM? | ?DDD DDD? | CCCC CCCC
# P - 7 bit preamble
# W - 4 bit whid, 0101=weather, 0110=time
# I - 8 bit ident
# F - 1 bit flag, 0=weather, 1=time
# B - 1 bit battery
# T - 10 bit temperature in 1/10 °C, offset 40
# H - 8 bit humidity in percent
# S - 8 bit windspeed in 1/10 m/s, resolution 0.33333
# G - 8 bit windgust in 1/10 m/s, resolution 0.33333
# R - 16 bit rain counter, resolution 0.3 mm
# C - 8 bit CRC8 of byte 1-10 bytes, result must be 0 (Polynomial 0x31)
# h - 6 bit hour, BCD coded
# m - 7 bit minute, BCD coded
# s - 7 bit second, BCD coded
# Y - 8 bit year, BCD coded
# M - 5 bit month, BCD coded
# D - 6 bit day, BCD coded
# ? - x bit unknown
sensortype => 'TFA_35.1077',
model => 'SD_WS_120',
prematch => sub {return 1;}, # no precheck known
id => sub {my (undef,$bitData) = @_; return SD_WS_binaryToNumber($bitData,11,18);},
bat => sub {my (undef,$bitData) = @_; return substr($bitData,20,1) eq '0' ? 'ok' : 'low';},
temp => sub {my (undef,$bitData) = @_;
return if (substr($bitData,19,1) eq '1');
return SD_WS_binaryToNumber($bitData,21,30) * 0.1 - 40;
},
hum => sub {my (undef,$bitData) = @_;
return if (substr($bitData,19,1) eq '1');
return SD_WS_binaryToNumber($bitData,31,38);
},
windspeed => sub {my (undef,$bitData) = @_;
return if (substr($bitData,19,1) eq '1');
return round((SD_WS_binaryToNumber($bitData,39,46) / 3.0),1);
},
windgust => sub {my (undef,$bitData) = @_;
return if (substr($bitData,19,1) eq '1');
return round((SD_WS_binaryToNumber($bitData,47,54) / 3.0),1);
},
rawRainCounter => sub {my (undef,$bitData) = @_;
return if (substr($bitData,19,1) eq '1');
return SD_WS_binaryToNumber($bitData,55,70);
},
rain => sub {my (undef,$bitData) = @_;
return if (substr($bitData,19,1) eq '1');
return SD_WS_binaryToNumber($bitData,55,70) * 0.3;
},
dcf => sub {my (undef,$bitData) = @_;
return if (substr($bitData,19,1) eq '0');
return '20' . SD_WS_binaryToNumber($bitData,47,50) . SD_WS_binaryToNumber($bitData,51,54) . '-' # year
. substr($bitData,58,1) . SD_WS_binaryToNumber($bitData,59,62) . '-' # month
. SD_WS_binaryToNumber($bitData,65,66) . SD_WS_binaryToNumber($bitData,67,70) . ' ' # day
. SD_WS_binaryToNumber($bitData,25,26) . SD_WS_binaryToNumber($bitData,27,30) . ':' # hour
. SD_WS_binaryToNumber($bitData,32,34) . SD_WS_binaryToNumber($bitData,35,38) . ':' # minute
. SD_WS_binaryToNumber($bitData,40,42) . SD_WS_binaryToNumber($bitData,43,46) # second
},
crcok => sub {my $rawData = shift;
my $rc = eval {
require Digest::CRC;
Digest::CRC->import();
1;
};
if ($rc) {
my $datacheck1 = pack( 'H*', substr($rawData,2,length($rawData)-2) );
my $crcmein1 = Digest::CRC->new(width => 8, poly => 0x31);
my $rr3 = $crcmein1->add($datacheck1)->hexdigest;
if (hex($rr3) != 0) {
Log3 $name, 3, "$name: SD_WS_120 Parse msg $rawData - ERROR CRC8";
return 0;
}
} else {
Log3 $name, 1, "$name: SD_WS_120 Parse msg $rawData - ERROR CRC not load, please install modul Digest::CRC";
return 0;
}
return 1;
}
},
122 => {
# TM40, Wireless Grill-, Meat-, Roasting-Thermometer with 4 Temperature Sensors
# -----------------------------------------------------------------------------
# 0 4 | 8 12 | 16 20 | 24 28 | 32 36 | 40 44 | 48 52 | 56 60 | 64 68 | 72 76 | 80 84 | 88 92 | 96 100 | 104
# 1001 0010 | 0110 0011 | 0000 0001 | 0011 0110 | 0000 0001 | 0011 0110 | 0000 0001 | 0100 0000 | 0000 0001 | 0110 1000 | 0000 0000 | 0000 0000 | 1011 1000 | 1000
# iiii iiii | iiii iiii | 4444 4444 | 4444 4444 | 3333 3333 | 3333 3333 | 2222 2222 | 2222 2222 | tttt tttt | tttt tttt | ???? ???? | b??? p??? | CCCC CCCC | 1
# i: 16 bit id, changes when the batteries are inserted
# 4: 16 bit unsigned temperature 4, 65235 = sensor not connected
# 3: 16 bit unsigned temperature 3, 65235 = sensor not connected
# 2: 16 bit unsigned temperature 2, 65235 = sensor not connected
# t: 16 bit unsigned temperature 1, 65235 = sensor not connected
# b: 1 bit battery. 0 = Ok, 1 = Low
# p: 1 bit transmitter power. 0 = On, 1 = off
# ?: 16 bit flags, 4 bits per sensor, meaning of the lower 3 bits 101 = not connected, 000 = connected
# C: 8 bit check???, always changes bit 1-7, bit 0 always 0
# Sensor transmits at intervals of about 3 to 4 seconds
sensortype => 'TM40',
model => 'SD_WS_122_T',
prematch => sub { return 1; }, # no precheck known
id => sub { my ($rawData,undef) = @_; return substr($rawData,0,4); },
temp4 => sub { my (undef,$bitData) = @_;
return if (substr($bitData,81,3) ne '000');
return SD_WS_binaryToNumber($bitData,16,31) / 10;
},
temp3 => sub { my (undef,$bitData) = @_;
return if (substr($bitData,85,3) ne '000');
return SD_WS_binaryToNumber($bitData,32,47) / 10;
},
temp2 => sub { my (undef,$bitData) = @_;
return if (substr($bitData,89,3) ne '000');
return SD_WS_binaryToNumber($bitData,48,63) / 10;
},
temp => sub { my (undef,$bitData) = @_;
return if (substr($bitData,93,3) ne '000');
return SD_WS_binaryToNumber($bitData,64,79) / 10;
},
bat => sub { my (undef,$bitData) = @_; return substr($bitData,88,1) eq "0" ? "ok" : "low"; },
transmitter => sub { my (undef,$bitData) = @_; return substr($bitData,92,1) eq "0" ? "on" : "off"; },
crcok => sub {return 1;}, # Check could not be determined yet.
},
); );
Log3 $name, 4, "$name: SD_WS_Parse protocol $protocol, rawData $rawData"; Log3 $name, 4, "$name: SD_WS_Parse protocol $protocol, rawData $rawData";
@ -1430,6 +1730,8 @@ sub SD_WS_Parse {
$id = $decodingSubs{$protocol}{id}->( $rawData,$bitData ); $id = $decodingSubs{$protocol}{id}->( $rawData,$bitData );
$temp = $decodingSubs{$protocol}{temp}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{temp})); $temp = $decodingSubs{$protocol}{temp}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{temp}));
$temp2 = $decodingSubs{$protocol}{temp2}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{temp2})); $temp2 = $decodingSubs{$protocol}{temp2}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{temp2}));
$temp3 = $decodingSubs{$protocol}{temp3}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{temp3}));
$temp4 = $decodingSubs{$protocol}{temp4}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{temp4}));
$hum = $decodingSubs{$protocol}{hum}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{hum})); $hum = $decodingSubs{$protocol}{hum}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{hum}));
$windspeed = $decodingSubs{$protocol}{windspeed}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{windspeed})); $windspeed = $decodingSubs{$protocol}{windspeed}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{windspeed}));
($winddir,$winddirtxt) = $decodingSubs{$protocol}{winddir}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{winddir})); ($winddir,$winddirtxt) = $decodingSubs{$protocol}{winddir}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{winddir}));
@ -1455,6 +1757,9 @@ sub SD_WS_Parse {
$count = $decodingSubs{$protocol}{count}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{count})); $count = $decodingSubs{$protocol}{count}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{count}));
$identified = $decodingSubs{$protocol}{identified}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{identified})); $identified = $decodingSubs{$protocol}{identified}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{identified}));
$uv = $decodingSubs{$protocol}{uv}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{uv})); $uv = $decodingSubs{$protocol}{uv}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{uv}));
$brightness = $decodingSubs{$protocol}{brightness}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{brightness}));
$transmitter = $decodingSubs{$protocol}{transmitter}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{transmitter}));
$dcf = $decodingSubs{$protocol}{dcf}->( $rawData,$bitData ) if (exists($decodingSubs{$protocol}{dcf}));
Log3 $iohash, 4, "$name: SD_WS_Parse decoded protocol-id $protocol ($SensorTyp), sensor-id $id"; Log3 $iohash, 4, "$name: SD_WS_Parse decoded protocol-id $protocol ($SensorTyp), sensor-id $id";
} }
else { else {
@ -1487,6 +1792,22 @@ sub SD_WS_Parse {
$def = $modules{SD_WS}{defptr}{$deviceCode} if(!$def); $def = $modules{SD_WS}{defptr}{$deviceCode} if(!$def);
if(!$def) { if(!$def) {
if (($longids ne "0") && ($longids eq "1" || $longids eq "ALL" || (",$longids," =~ m/,$model,/))) {
my @found = devspec2array(q[TYPE=SD_WS:FILTER=i:replaceBattery>0]);
if (scalar(@found) > 0) {
my $rname = $found[0];
my $rproto = InternalVal($rname, $ioname. q[_Protocol_ID], undef);
if (defined $rproto && $rproto eq $protocol) {
my $rhash = $defs{$rname};
my $rdef = $rhash->{DEF};
Log3 $name, 3, qq[$rname: SD_WS_Parse, change DEF from $rdef in $deviceCode];
CommandModify(undef, qq[$rname $deviceCode]);
delete($rhash->{replaceBattery});
RemoveInternalTimer($rhash);
return $rname;
}
}
}
Log3 $iohash, 1, "$name: SD_WS_Parse 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"; return "UNDEFINED $deviceCode SD_WS $deviceCode";
} }
@ -1496,7 +1817,7 @@ sub SD_WS_Parse {
return "" if(IsIgnored($name)); return "" if(IsIgnored($name));
if (defined $temp) { if (defined $temp) {
if (($temp < -30 || $temp > 70) && $protocol ne '106' && $protocol ne '113') { # not forBBQ temperature sensor GT-TMBBQ-01s and Wireless Grill Thermometer GFGT 433 B1 if (($temp < -30 || $temp > 70) && $protocol ne '106' && $protocol ne '113' && $protocol ne '122') { # not forBBQ temperature sensor GT-TMBBQ-01s, Wireless Grill Thermometer GFGT 433 B1 and TM40
Log3 $name, 3, "$ioname: SD_WS_Parse $deviceCode - ERROR temperature $temp"; Log3 $name, 3, "$ioname: SD_WS_Parse $deviceCode - ERROR temperature $temp";
return ""; return "";
} }
@ -1509,18 +1830,14 @@ sub SD_WS_Parse {
} }
# Sanity checks # Sanity checks
if($def && $protocol ne '106' && $protocol ne '113') { # not forBBQ temperature sensor GT-TMBBQ-01s and Wireless Grill Thermometer GFGT 433 B1 if($def && $protocol ne '106' && $protocol ne '113' && $protocol ne '122') { # not forBBQ temperature sensor GT-TMBBQ-01s, Wireless Grill Thermometer GFGT 433 B1 and TM40
my $timeSinceLastUpdate = abs(ReadingsAge($name, "state", 0)); my $timeSinceLastUpdate = abs(ReadingsAge($name, 'state', 0));
# temperature # temperature
if (defined($temp) && defined(ReadingsVal($name, "temperature", undef))) { my $oldTemp = ReadingsVal($name, 'temperature', undef);
my $diffTemp = 0; if (defined $oldTemp && defined $temp) {
my $oldTemp = ReadingsVal($name, "temperature", undef); #my $oldTemp = ReadingsVal($name, "temperature", undef);
my $maxdeviation = AttrVal($name, "max-deviation-temp", 1); # default 1 K my $maxdeviation = AttrVal($name, "max-deviation-temp", 1); # default 1 K
if ($temp > $oldTemp) { my $diffTemp = abs($temp - $oldTemp);
$diffTemp = ($temp - $oldTemp);
} else {
$diffTemp = ($oldTemp - $temp);
}
$diffTemp = sprintf("%.1f", $diffTemp); $diffTemp = sprintf("%.1f", $diffTemp);
Log3 $name, 4, "$ioname: $name old temp $oldTemp, age $timeSinceLastUpdate, new temp $temp, diff temp $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 my $maxDiffTemp = $timeSinceLastUpdate / 60 + $maxdeviation; # maxdeviation + 1.0 Kelvin/Minute
@ -1532,15 +1849,11 @@ sub SD_WS_Parse {
} }
} }
# humidity # humidity
if (defined($hum) && defined(ReadingsVal($name, "humidity", undef))) { my $oldHum = ReadingsVal($name, 'humidity', undef);
my $diffHum = 0; if (defined $oldHum && defined $hum) {
my $oldHum = ReadingsVal($name, "humidity", undef); #my $oldHum = ReadingsVal($name, "humidity", undef);
my $maxdeviation = AttrVal($name, "max-deviation-hum", 1); # default 1 % my $maxdeviation = AttrVal($name, "max-deviation-hum", 1); # default 1 %
if ($hum > $oldHum) { my $diffHum = abs($hum - $oldHum);
$diffHum = ($hum - $oldHum);
} else {
$diffHum = ($oldHum - $hum);
}
$diffHum = sprintf("%.1f", $diffHum); $diffHum = sprintf("%.1f", $diffHum);
Log3 $name, 4, "$ioname: $name old hum $oldHum, age $timeSinceLastUpdate, new hum $hum, diff hum $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 my $maxDiffHum = $timeSinceLastUpdate / 60 + $maxdeviation; # $maxdeviation + 1.0 %/Minute
@ -1566,12 +1879,20 @@ sub SD_WS_Parse {
#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 = ""; my $state = "";
if (defined($temp)) { if (defined($temp)) {
$state .= "T: $temp" $state .= "T: $temp";
} }
if (defined($temp2)) { if (defined($temp2)) {
$state .= ' ' if (length($state) > 0); $state .= ' ' if (length($state) > 0);
$state .= "T2: $temp2"; $state .= "T2: $temp2";
} }
if (defined($temp3)) {
$state .= ' ' if (length($state) > 0);
$state .= "T3: $temp3";
}
if (defined($temp4)) {
$state .= ' ' if (length($state) > 0);
$state .= "T4: $temp4";
}
if (defined($hum) && ($hum > 0 && $hum < 100)) { if (defined($hum) && ($hum > 0 && $hum < 100)) {
$state .= " H: $hum" $state .= " H: $hum"
} }
@ -1595,6 +1916,11 @@ sub SD_WS_Parse {
$state .= ' ' if (length($state) > 0); $state .= ' ' if (length($state) > 0);
$state .= "D: $distance"; $state .= "D: $distance";
} }
if (defined($brightness)) {
$state .= ' ' if (length($state) > 0);
$state .= "B: $brightness";
}
### protocol 33 has different bits per sensor type ### protocol 33 has different bits per sensor type
if ($protocol eq "33") { if ($protocol eq "33") {
if (AttrVal($name,'model',0) eq "S522") { # Conrad S522 if (AttrVal($name,'model',0) eq "S522") { # Conrad S522
@ -1611,10 +1937,20 @@ sub SD_WS_Parse {
} }
} }
### Protocol 85 without wind direction
if ($protocol eq "85") {
if (AttrVal($name,'model',0) ne "TFA_30.3251.10") {
$winddir = undef;
$winddirtxt = undef;
}
}
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
readingsBulkUpdate($hash, "state", $state); readingsBulkUpdate($hash, "state", $state);
readingsBulkUpdate($hash, "temperature", $temp) if (defined($temp) && (($temp > -60 && $temp < 70 ) || $protocol eq '106' || $protocol eq '113')); readingsBulkUpdate($hash, "temperature", $temp) if (defined($temp) && (($temp > -60 && $temp < 70 ) || $protocol eq '106' || $protocol eq '113' || $protocol eq '122'));
readingsBulkUpdate($hash, "temperature2", $temp2) if (defined($temp2) && (($temp2 > -60 && $temp < 70 ) || $protocol eq '113')); readingsBulkUpdate($hash, "temperature2", $temp2) if (defined($temp2) && (($temp2 > -60 && $temp2 < 70 ) || $protocol eq '113' || $protocol eq '122'));
readingsBulkUpdate($hash, "temperature3", $temp3) if (defined($temp3) && (($temp3 > -60 && $temp3 < 70 ) || $protocol eq '122'));
readingsBulkUpdate($hash, "temperature4", $temp4) if (defined($temp4) && (($temp4 > -60 && $temp4 < 70 ) || $protocol eq '122'));
readingsBulkUpdate($hash, "humidity", $hum) if (defined($hum) && ($hum > 0 && $hum < 100 )) ; readingsBulkUpdate($hash, "humidity", $hum) if (defined($hum) && ($hum > 0 && $hum < 100 )) ;
readingsBulkUpdate($hash, 'windSpeed', $windspeed) if (defined($windspeed)) ; readingsBulkUpdate($hash, 'windSpeed', $windspeed) if (defined($windspeed)) ;
readingsBulkUpdate($hash, 'windDirectionDegree', $winddir) if (defined($winddir)) ; readingsBulkUpdate($hash, 'windDirectionDegree', $winddir) if (defined($winddir)) ;
@ -1640,10 +1976,12 @@ sub SD_WS_Parse {
readingsBulkUpdate($hash, 'count', $count) if (defined($count)); readingsBulkUpdate($hash, 'count', $count) if (defined($count));
readingsBulkUpdate($hash, 'identified', $identified) if (defined($identified)); readingsBulkUpdate($hash, 'identified', $identified) if (defined($identified));
readingsBulkUpdate($hash, "uv", $uv) if (defined($uv)); readingsBulkUpdate($hash, "uv", $uv) if (defined($uv));
readingsBulkUpdate($hash, 'brightness', $brightness) if (defined($brightness));
readingsBulkUpdateIfChanged($hash, 'transmitter', $transmitter) if (defined($transmitter));
readingsBulkUpdate($hash, 'dcf', $dcf) if (defined($dcf));
readingsEndUpdate($hash, 1); # Notify is done by Dispatch readingsEndUpdate($hash, 1); # Notify is done by Dispatch
return $name; return $name;
} }
############################# #############################
@ -1737,7 +2075,7 @@ sub SD_WS_WH2SHIFT {
<li>ADE WS1907 Weather station with rain gauge</li> <li>ADE WS1907 Weather station with rain gauge</li>
<li>Atech wireless weather station</li> <li>Atech wireless weather station</li>
<li>BBQ temperature sensor GT-TMBBQ-01s (transmitter), GT-TMBBQ-01e (receiver)</li> <li>BBQ temperature sensor GT-TMBBQ-01s (transmitter), GT-TMBBQ-01e (receiver)</li>
<li>Bresser 5-in-1 and 6-in-1 Comfort Weather Center, 7009994, Professional rain gauge, Temeo</li> <li>Bresser 5-in-1, 6-in-1 and 7-in-1 Comfort Weather Center, 7009994, Professional rain gauge, Temeo</li>
<li>Conrad S522</li> <li>Conrad S522</li>
<li>EuroChron EFTH-800, EFS-3110A (temperature and humidity sensor)</li> <li>EuroChron EFTH-800, EFS-3110A (temperature and humidity sensor)</li>
<li>Fine Offset WH51, aka ECOWITT WH51, aka Froggit DP100, aka MISOL/1 (soil moisture sensor)</li> <li>Fine Offset WH51, aka ECOWITT WH51, aka Froggit DP100, aka MISOL/1 (soil moisture sensor)</li>
@ -1749,14 +2087,14 @@ sub SD_WS_WH2SHIFT {
<li>Renkforce E0001PA</li> <li>Renkforce E0001PA</li>
<li>Rain gauge DROP TFA 47.3005.01 with rain sensor TFA 30.3233.01</li> <li>Rain gauge DROP TFA 47.3005.01 with rain sensor TFA 30.3233.01</li>
<li>TECVANCE TV-4848</li> <li>TECVANCE TV-4848</li>
<li>Thermometer TFA 30.3228.02, TFA 30.3229.02, FT007T, FT007TP, F007T, F007TP</li> <li>Thermometer FT007T, FT007TP, F007T, F007TP</li>
<li>Thermo-Hygrometer TFA 30.3208.02, FT007TH, F007TH</li> <li>Thermo-Hygrometer FT007TH, F007TH</li>
<li>TS-FT002 Water tank level monitor with temperature</li> <li>TS-FT002 Water tank level monitor with temperature</li>
<li>TX-EZ6 for Weatherstation TZS First Austria</li> <li>TX-EZ6 for Weatherstation TZS First Austria</li>
<li>WH2, WH2A (TFA Dostmann/Wertheim 30.3157 (sold in Germany), Agimex Rosenborg 66796 (sold in Denmark),ClimeMET CM9088 (Sold in UK)</li> <li>WH2, WH2A (TFA Dostmann/Wertheim 30.3157 (sold in Germany), Agimex Rosenborg 66796 (sold in Denmark),ClimeMET CM9088 (Sold in UK)</li>
<li>Weatherstation Auriol IAN 283582 Version 06/2017 (Lidl), Modell-Nr.: HG02832D</li> <li>Weatherstation Auriol IAN 283582 Version 06/2017 (Lidl), Modell-Nr.: HG02832D</li>
<li>Weatherstation Auriol AHFL 433 B2, IAN 314695 (Lidl)</li> <li>Weatherstation Auriol AHFL 433 B2, IAN 314695 (Lidl)</li>
<li>Weatherstation TFA 35.1140.01 with temperature / humidity sensor TFA 30.3221.02 and temperature / humidity / windspeed sensor TFA 30.3222.02</li> <li>Weatherstations and sensors TFA 30.3151, 30.3152, 30.3153, 30.3157, 30.3200, 30.3208.02, 30.3221.02, 30.3222.02, 30.3228.02, 30.3229.02, 30.3233.01, 30.3251.10, 35.1077.54.S2, 35.1140.01</li>
<li>Wireless Grill Thermometer, Model name: GFGT 433 B1</li> <li>Wireless Grill Thermometer, Model name: GFGT 433 B1</li>
</ul><br><br> </ul><br><br>
@ -1787,6 +2125,7 @@ sub SD_WS_WH2SHIFT {
<li>batteryState (low or ok)</li> <li>batteryState (low or ok)</li>
<li>batteryVoltage (battery voltage in volts)</li> <li>batteryVoltage (battery voltage in volts)</li>
<li>batteryPercent (battery level in %)</li> <li>batteryPercent (battery level in %)</li>
<li>brightness (kLux)</li>
<li>channel (number of channel</li> <li>channel (number of channel</li>
<li>distance (distance in cm (protocol 111) or km (protocol 116)</li> <li>distance (distance in cm (protocol 111) or km (protocol 116)</li>
<li>humidity (humidity (1-100 % only if available)</li> <li>humidity (humidity (1-100 % only if available)</li>
@ -1798,6 +2137,7 @@ sub SD_WS_WH2SHIFT {
<li>temperature (&deg;C)</li> <li>temperature (&deg;C)</li>
<li>temperatureTrend (consistent, rising, falling)</li> <li>temperatureTrend (consistent, rising, falling)</li>
<li>type (type of sensor)</li> <li>type (type of sensor)</li>
<li>uv (ultraviolet radiation)</li>
<li>windDirectionDegree (Wind direction, grad)</li> <li>windDirectionDegree (Wind direction, grad)</li>
<li>windDirectionText (Wind direction, N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW)</li> <li>windDirectionText (Wind direction, N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW)</li>
<li>windGust (Gust of wind, m/s)</li> <li>windGust (Gust of wind, m/s)</li>
@ -1833,19 +2173,32 @@ sub SD_WS_WH2SHIFT {
<a name="end_max-deviation-temp"></a> <a name="end_max-deviation-temp"></a>
</li><br> </li><br>
<li>model<br> <li>model<br>
(Default: other, currently supported sensors: E0001PA, S522 and TX-EZ6)<br> (Default: other, currently supported sensors: E0001PA, S522, TFA_30.3251.10 and TX-EZ6)<br>
<a name="model"></a> <a name="model"></a>
The sensors of the "SD_WS_33 series" use different positions for the battery bit and different readings. The sensors of the "SD_WS_33 series" use different positions for the battery bit and different readings.
If the battery bit is detected incorrectly (low instead of ok), then you can possibly adjust with the model selection of the sensor.<br> If the battery bit is detected incorrectly (low instead of ok), then you can possibly adjust with the model selection of the sensor.<br>
So far, 3 variants are known. All sensors are created by Autocreate as model "other". So far, 3 variants are known. All sensors are created by Autocreate as model "other".
If you receive a Conrad S522, Renkforce E0001PA or TX-EZ6, then set the appropriate model for the proper processing of readings. If you receive a Conrad S522, Renkforce E0001PA or TX-EZ6, then set the appropriate model for the proper processing of readings.
<br>
Protocol 85 (SD_WS_85_THW) decodes two different sensor types: TFA 30.3222.02 (thermo-hygro-wind) and 30.3251.10 (wind).
The attribute must be set to this value "TFA_30.3251.10" so that the wind direction is also displayed for the sensor TFA 30.3251.10.
<a name="end_model"></a> <a name="end_model"></a>
</li><br> </li><br>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li><br> <li><a href="#readingFnAttributes">readingFnAttributes</a></li><br>
<li><a href="#showtime">showtime</a></li><br> <li><a href="#showtime">showtime</a></li><br>
</ul><br> </ul><br>
<b>Set</b> <a name="SD_WS Set"></a>
<ul>N/A</ul><br> <b>Set</b><br><br>
<ul>
<li>replaceBatteryForSec<br>
(Only available for devices whose SIGNALduinos have the "longids" attribute activated.)
<br><br>
<code>replaceBatteryForSec &lt;seconds&gt;</code>
<br><br>
Puts the device into battery change mode for <code>&lt;secondes&gt;</code>.
The first unknown address with the same protocol that is received replaces the current device address.
</li>
</ul><br>
</ul> </ul>
=end html =end html
@ -1862,7 +2215,7 @@ sub SD_WS_WH2SHIFT {
<li>ADE WS1907 Wetterstation mit Regenmesser</li> <li>ADE WS1907 Wetterstation mit Regenmesser</li>
<li>Atech Wetterstation</li> <li>Atech Wetterstation</li>
<li>BBQ Temperatur Sensor GT-TMBBQ-01s (Sender), GT-TMBBQ-01e (Empfaenger)</li> <li>BBQ Temperatur Sensor GT-TMBBQ-01s (Sender), GT-TMBBQ-01e (Empfaenger)</li>
<li>Bresser 5-in-1 und 6-in-1 Comfort Wetter Center, 7009994, Profi Regenmesser, Temeo</li> <li>Bresser 5-in-1, 6-in-1 und 7-in-1 Comfort Wetter Center, 7009994, Profi Regenmesser, Temeo</li>
<li>Conrad S522</li> <li>Conrad S522</li>
<li>EuroChron EFTH-800, EFS-3110A (Temperatur- und Feuchtigkeitssensor)</li> <li>EuroChron EFTH-800, EFS-3110A (Temperatur- und Feuchtigkeitssensor)</li>
<li>Fine Offset WH51, aka ECOWITT WH51, aka Froggit DP100, aka MISOL/1 (Bodenfeuchtesensor)</li> <li>Fine Offset WH51, aka ECOWITT WH51, aka Froggit DP100, aka MISOL/1 (Bodenfeuchtesensor)</li>
@ -1875,14 +2228,14 @@ sub SD_WS_WH2SHIFT {
<li>Regenmesser DROP TFA 47.3005.01 mit Regensensor TFA 30.3233.01</li> <li>Regenmesser DROP TFA 47.3005.01 mit Regensensor TFA 30.3233.01</li>
<li>Renkforce E0001PA</li> <li>Renkforce E0001PA</li>
<li>TECVANCE TV-4848</li> <li>TECVANCE TV-4848</li>
<li>Temperatur-Sensor TFA 30.3228.02, TFA 30.3229.02, FT007T, FT007TP, F007T, F007TP</li> <li>Temperatur-Sensor FT007T, FT007TP, F007T, F007TP</li>
<li>Temperatur/Feuchte-Sensor TFA 30.3208.02, FT007TH, F007TH</li> <li>Temperatur/Feuchte-Sensor FT007TH, F007TH</li>
<li>TS-FT002 Wassertank Füllstandswächter mit Temperatur</li> <li>TS-FT002 Wassertank Füllstandswächter mit Temperatur</li>
<li>TX-EZ6 fuer Wetterstation TZS First Austria</li> <li>TX-EZ6 fuer Wetterstation TZS First Austria</li>
<li>WH2, WH2A (TFA Dostmann/Wertheim 30.3157 (Deutschland), Agimex Rosenborg 66796 (Denmark), ClimeMET CM9088 (UK)</li> <li>WH2, WH2A (TFA Dostmann/Wertheim 30.3157 (Deutschland), Agimex Rosenborg 66796 (Denmark), ClimeMET CM9088 (UK)</li>
<li>Wetterstation Auriol IAN 283582 Version 06/2017 (Lidl), Modell-Nr.: HG02832D</li> <li>Wetterstation Auriol IAN 283582 Version 06/2017 (Lidl), Modell-Nr.: HG02832D</li>
<li>Wetterstation Auriol AHFL 433 B2, IAN 314695 (Lidl)</li> <li>Wetterstation Auriol AHFL 433 B2, IAN 314695 (Lidl)</li>
<li>Wetterstation TFA 35.1140.01 mit Temperatur-/Feuchtesensor TFA 30.3221.02 und Temperatur-/Feuchte- und Windsensor TFA 30.3222.02</li> <li>Wetterstationen und Sensoren TFA 30.3151, 30.3152, 30.3153, 30.3157, 30.3200, 30.3208.02, 30.3221.02, 30.3222.02, 30.3228.02, 30.3229.02, 30.3233.01, 30.3251.10, 35.1077.54.S2, 35.1140.01</li>
</ul> </ul>
<br><br> <br><br>
@ -1913,6 +2266,7 @@ sub SD_WS_WH2SHIFT {
<li>batteryState (low oder ok)</li> <li>batteryState (low oder ok)</li>
<li>batteryVoltage (Batteriespannung in Volt)</li> <li>batteryVoltage (Batteriespannung in Volt)</li>
<li>batteryPercent (Batteriestand in %)</li> <li>batteryPercent (Batteriestand in %)</li>
<li>brightness (Helligkeit in kLux)</li>
<li>channel (Sensor-Kanal)</li> <li>channel (Sensor-Kanal)</li>
<li>distance (Entfernung in cm (Protokoll 111) oder km (Protokoll 116)</li> <li>distance (Entfernung in cm (Protokoll 111) oder km (Protokoll 116)</li>
<li>humidity (Luft-/Bodenfeuchte, 1-100 %)</li> <li>humidity (Luft-/Bodenfeuchte, 1-100 %)</li>
@ -1924,6 +2278,7 @@ sub SD_WS_WH2SHIFT {
<li>temperature (Temperatur &deg;C)</li> <li>temperature (Temperatur &deg;C)</li>
<li>temperatureTrend (Trend Temperatur gleichbleibend, steigend, fallend)</li> <li>temperatureTrend (Trend Temperatur gleichbleibend, steigend, fallend)</li>
<li>type (Sensortypen)</li> <li>type (Sensortypen)</li>
<li>uv (Ultraviolettstrahlung)</li>
<li>windDirectionDegree (Windrichtung, Grad)</li> <li>windDirectionDegree (Windrichtung, Grad)</li>
<li>windDirectionText (Windrichtung, N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW)</li> <li>windDirectionText (Windrichtung, N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW)</li>
<li>windGust (Windboe, m/s)</li> <li>windGust (Windboe, m/s)</li>
@ -1961,11 +2316,14 @@ sub SD_WS_WH2SHIFT {
</li><br> </li><br>
<li>model<br> <li>model<br>
<a name="model"></a> <a name="model"></a>
(Standard: other, zur Zeit unterst&uuml;tzte Sensoren: E0001PA, S522, TX-EZ6)<br> (Standard: other, zur Zeit unterst&uuml;tzte Sensoren: E0001PA, S522, TFA_30.3251.10, TX-EZ6)<br>
Die Sensoren der "SD_WS_33 - Reihe" verwenden unterschiedliche Positionen f&uuml;r das Batterie-Bit und unterst&uuml;tzen verschiedene Readings. Die Sensoren der "SD_WS_33 - Reihe" verwenden unterschiedliche Positionen f&uuml;r das Batterie-Bit und unterst&uuml;tzen verschiedene Readings.
Sollte das Batterie-Bit falsch erkannt werden (low statt ok), so kann man mit der Modelauswahl des Sensors das evtl. anpassen.<br> Sollte das Batterie-Bit falsch erkannt werden (low statt ok), so kann man mit der Modelauswahl des Sensors das evtl. anpassen.<br>
Bisher sind 3 Varianten bekannt. Alle Sensoren werden durch Autocreate als Model "other" angelegt. Bisher sind 3 Varianten bekannt. Alle Sensoren werden durch Autocreate als Model "other" angelegt.
Empfangen Sie einen Sensor vom Typ Conrad S522, Renkforce E0001PA oder TX-EZ6, so stellen Sie das jeweilige Modell f&uuml;r die richtige Verarbeitung der Readings ein. Empfangen Sie einen Sensor vom Typ Conrad S522, Renkforce E0001PA oder TX-EZ6, so stellen Sie das jeweilige Modell f&uuml;r die richtige Verarbeitung der Readings ein.
<br>
Protokoll 85 (SD_WS_85_THW) dekodiert zwei verschiedene Sensortypen: TFA 30.3222.02 (Thermo-Hygro-Wind) und 30.3251.10 (Wind).
Damit auch die Windrichtung bei dem Sensor TFA 30.3251.10 angezeigt wird, muss das Attribut auf diesen Wert "TFA_30.3251.10" gesetzt werden.
<a name="end_model"></a> <a name="end_model"></a>
</li><br> </li><br>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li><br> <li><a href="#readingFnAttributes">readingFnAttributes</a></li><br>
@ -1973,8 +2331,108 @@ sub SD_WS_WH2SHIFT {
</ul> </ul>
<br> <br>
<b>Set</b> <ul>N/A</ul><br> <a name="SD_WS Set"></a>
<b>Set</b><br><br>
<ul>
<li>replaceBatteryForSec<br>
(Nur verfügbar bei Geräten, bei deren SIGNALduinos das Attribut "longids" aktiviert ist.)
<br><br>
<code>replaceBatteryForSec &lt;Sekunden&gt;</code>
<br><br>
Versetzt das Gerät für <code>&lt;Sekunden&gt;</code> Sekunden in den Batteriewechselmodus.
Die erste unbekannte Adresse mit gleichem Protokoll, die empfangen wird, ersetzt die aktuelle Geräteadresse.
</li>
</ul><br>
</ul> </ul>
=end html_DE =end html_DE
=for :application/json;q=META.json 14_SD_WS.pm
{
"abstract": "Supports various weather stations",
"author": [
"Sidey <>",
"ralf9 <>"
],
"x_fhem_maintainer": [
"Sidey"
],
"x_fhem_maintainer_github": [
"Sidey79"
],
"description": "The SD_WS module processes the messages from various environmental sensors received from an IO device (CUL, CUN, SIGNALDuino, SignalESP etc.)",
"dynamic_config": 1,
"keywords": [
"fhem-sonstige-systeme",
"fhem-hausautomations-systeme",
"fhem-mod",
"signalduino",
"weather",
"station",
"sensor",
"Hama",
"TFA",
"Bresser"
],
"license": [
"GPL_2"
],
"meta-spec": {
"url": "https://metacpan.org/pod/CPAN::Meta::Spec",
"version": 2
},
"name": "FHEM::SD_WS",
"prereqs": {
"runtime": {
"requires": {
"Carp": "0",
"Digest:CRC": "0"
}
},
"develop": {
"requires": {
"Carp": "0",
"Digest:CRC": "0"
}
}
},
"release_status": "stable",
"resources": {
"bugtracker": {
"web": "https://github.com/RFD-FHEM/RFFHEM/issues/"
},
"x_testData": [
{
"url": "https://raw.githubusercontent.com/RFD-FHEM/RFFHEM/master/t/FHEM/14_SD_WS/testData.json",
"testname": "Testdata with SD_WS sensors"
}
],
"repository": {
"x_master": {
"type": "git",
"url": "https://github.com/RFD-FHEM/RFFHEM.git",
"web": "https://github.com/RFD-FHEM/RFFHEM/tree/master"
},
"type": "svn",
"url": "https://svn.fhem.de/fhem",
"web": "https://svn.fhem.de/trac/browser/trunk/fhem/FHEM/14_Hideki.pm",
"x_branch": "trunk",
"x_filepath": "fhem/FHEM/",
"x_raw": "https://svn.fhem.de/trac/export/latest/trunk/fhem/FHEM/14_SD_WS.pm"
},
"x_support_community": {
"board": "Sonstige Systeme",
"boardId": "29",
"cat": "FHEM - Hausautomations-Systeme",
"description": "Sonstige Hausautomations-Systeme",
"forum": "FHEM Forum",
"rss": "https://forum.fhem.de/index.php?action=.xml;type=rss;board=29",
"title": "FHEM Forum: Sonstige Systeme",
"web": "https://forum.fhem.de/index.php/board,29.0.html"
},
"x_wiki": {
"web": "https://wiki.fhem.de/wiki/SIGNALduino"
}
}
}
=end :application/json;q=META.json
=cut =cut