Hi,
ich habe ebenfalls eine tfa 47.3003. Die Signale werden durch einen SIGNALduino empfangen.
Bei mir laufen die Signale in ein Device "Unknown" vom Typ CUL_TCM97001.
Ich erhalte einen State der z.B. so aussieht: "Code: 700B30EAC0" - diesen habe ich (mit etwas Aufwand) enkodiert.
Vorgehensweise:
- Hex Code (z.B. 700B30EAC0) in Binär wandeln
- Binären Code umdrehen (reverse). Also 1. Zeichen ist danach das letzte Zeichen etc.
Die Temperatur steckt dann in Stelle 17-28 (Hex zu Dezimal). Die Dezimalstelle muss noch um 1 verschoben werden (=> /10). Negative Temperatur Werte werden allerdings als Differenz zum maximal ausdrückbaren Wert übermittelt (siehe Beispiele in angehängter Text Datei).
Die Regenwerte sind in Stelle 8-16 (Hex zu Dezimal). Es handelt sich um eine hochzählende Zahl, die je Einheit 0,45 mm Regen entspricht. Ich vermute, dass es nach 255 wieder bei 0 weitergeht.
Sicherlich stecken irgendwo auch noch Batteriestand Informationen und evtl. gibts auch noch eine Checksumme.
Ich habe mir folgende Routine geschrieben (eher zum Debuggen), die mittels Notify auf das Unkown Device angetriggert werden kann.
sub tfa473003_decode {
sub tfa473003_decode {
my $device = shift; #device that should store the readings
my $code = shift; #the current code
my $only_id = ReadingsVal($device,"id",undef);
my $debug = ReadingsVal($device,"debug",0);
if($debug)
{
Log 3, "tfa473003, device: $device, code: $code";
}
#extract code
$code = substr($code,6);
#continue only if code has 10 digits
if(length($code) != 10) { return; }
#convert hex to bin
# sprintf has issues with large numbers, split into 2 parts
my $code_bin_0 = sprintf( "%b", hex( substr($code,0,5) ) );
my $code_bin_1 = sprintf( "%b", hex( substr($code,5) ) );
my $code_bin = substr("00000000000000000000$code_bin_0",-20); #add leading zeros
$code_bin .= substr("00000000000000000000$code_bin_1",-20); #add leading zeros
#reverse bin code
my $code_bin_rev = reverse($code_bin);
#crc check
my $crc = 0;
my $crc_signal = substr($code_bin_rev,4,4);
foreach my $i (2 .. 9) {
my $part = oct("0b".substr($code_bin_rev,$i*4,4)); #extract binary block
$crc += $part;
}
$crc = sprintf ("%b", $crc); #bin to dec
$crc = substr($crc,-4); #only the last 4 digits matters
if($crc != $crc_signal) {
Log 3, "tfa473003, device: $device, ERROR: CRC is wrong! crc_signal: $crc_signal, crc: $crc";
return;
}
#id
my $id_bin = substr($code_bin_rev,36,4); #32,8 28,12
my $id_dec = oct("0b$id_bin");
if(!defined($only_id) && $debug)
{
Log 3, "tfa473003, device: $device, device_id: $id_dec, ('setreading $device id $id_dec' if you want to ignore all other devices) ";
}
#continue only if only_id is equal to current id (if set)
if (defined($only_id) && $only_id ne $id_dec) {
if ($debug) { Log 3, "tfa473003, id wrong, is $id_dec ($id_bin), should be $only_id"; }
return;
}
#temp (17-28)
my $temp_bin = substr($code_bin_rev,17,11);
my $temp_dec = oct("0b$temp_bin");
if (substr($code_bin_rev,16,1) eq "1" ) #negativ values
{
$temp_dec = (2048-$temp_dec)*-1;
}
$temp_dec /= 10; #decimal point
#rain (8-16)
my $rain_bin = substr($code_bin_rev,8,8);
my $rain_dec = oct("0b$rain_bin");
#calc difference to last value
my $rain_dec_old = ReadingsVal($device,"rain_count",$rain_dec);
my $rain_diff = $rain_dec - $rain_dec_old;
if ($rain_diff < 0) { $rain_diff += 255 + 1 ; } #handle overflow
#convert to mm
my $rain_mm = $rain_diff * 0.45;
my $rain_mm_old = ReadingsVal($device,"rain_mm",0);
my $rain_mm_sum = $rain_mm+$rain_mm_old;
#store results
my $cmd = 'sleep 0.01;'; #without "sleep 0.01" readings wont be logged
if($debug)
{
$cmd .= "setreading $device code_bin $code_bin;";
$cmd .= "setreading $device code_bin_rev $code_bin_rev;";
$cmd .= "setreading $device id_bin $id_bin;";
$cmd .= "setreading $device temp_bin $temp_bin;";
$cmd .= "setreading $device rain_bin $rain_bin;";
$cmd .= "setreading $device rain_diff $rain_diff;";
}
$cmd .= "setreading $device id_dec $id_dec;";
if (!$rain_diff) { $cmd .= "setreading $device temp $temp_dec;"; } #avoid wrong temps, same behavior like display
$cmd .= "setreading $device rain_count $rain_dec;";
$cmd .= "setreading $device rain_mm $rain_mm_sum;";
fhem($cmd);
}
Ich habe mir ein Dummy angelegt, in dem die Werte gespeichert werden sollen. Das Reading "debug" kann 1 oder 0 sein und schaltet das ausführliche logging ein. Das reading "id" enthält die zu berücksichtigende ID (des regenmessers). Am besten am Anfang nicht setzen, debug einschalten und dann die richtige id aus dem reading "id_dec" entnehmen (und mittels "setreading Regenmesser_tfa id xxx" setzen)
define Regenmesser_tfa dummy
attr Regenmesser_tfa event-on-change-reading .*
attr Regenmesser_tfa group Regenmesser
attr Regenmesser_tfa icon weather_rain_gauge
attr Regenmesser_tfa room Außen
attr Regenmesser_tfa stateFormat rain_mm_quarterhour mm, temp°
setstate Regenmesser_tfa 2018-06-17 16:40:15 debug 0
setstate Regenmesser_tfa 2018-06-17 12:20:22 id 14
Notify, das bei einer Änderung in Unknown die Decodierung und Speicherung im zuvor angelegten Dummy anstößt
define Notify_Regenmesser notify (Unknown:Code.*) { tfa473003_decode("Regenmesser_tfa",$EVENT) }
EDIT: 25.08.2018:
Zeile:
my $id_bin = substr($code_bin_rev,28,12);
geändert zu:
my $id_bin = substr($code_bin_rev,32,8); #28,12
EDIT: 07.05.2019:
Zeile:
my $id_bin = substr($code_bin_rev,32,8); #28,12
geändert zu:
my $id_bin = substr($code_bin_rev,36,4); #32,8 28,12
Umwandlung zu binär nun 1 Schritten (da manchmal Überlauf)
EDIT: 12.10.2019:
Hinzu: Debug Ausgabe der ID des Signals im FHEM Log
Hinzu: CRC Check