';
return $ret;
}
sub SIGNALduino_FW_saveWhitelist
{
my $name = shift;
my $wl_attr = shift;
if (!IsDevice($name)) {
SIGNALduino_Log3 undef, 3, "SIGNALduino_FW_saveWhitelist: $name is not a valid definition, operation aborted.";
return;
}
if ($wl_attr eq "") { # da ein Attribut nicht leer sein kann, kommt ein Komma rein
$wl_attr = ',';
}
elsif ($wl_attr !~ /\d+(?:,\d.?\d?)*$/ ) {
SIGNALduino_Log3 $name, 3, "$name Whitelist save: attr whitelist_IDs can not be updated";
return;
}
else {
$wl_attr =~ s/,$//; # Komma am Ende entfernen
}
$attr{$name}{whitelist_IDs} = $wl_attr;
SIGNALduino_Log3 $name, 3, "$name Whitelist save: $wl_attr";
SIGNALduino_IdList("x:$name", $wl_attr);
}
sub SIGNALduino_IdList($@)
{
my ($param, $aVal, $blacklist, $develop0) = @_;
my (undef,$name) = split(':', $param);
my $hash = $defs{$name};
my @msIdList = ();
my @muIdList = ();
my @mcIdList = ();
my @skippedDevId = ();
my @skippedBlackId = ();
my @skippedWhiteId = ();
my @devModulId = ();
my %WhitelistIDs;
my %BlacklistIDs;
my $wflag = 0; # whitelist flag, 0=disabled
delete ($hash->{IDsNoDispatch}) if (defined($hash->{IDsNoDispatch}));
if (!defined($aVal)) {
$aVal = AttrVal($name,"whitelist_IDs","");
}
my ($develop,$devFlag) = SIGNALduino_getAttrDevelopment($name, $develop0); # $devFlag = 1 -> alle developIDs y aktivieren
SIGNALduino_Log3 $name, 3, "$name IDlist development version active: development attribute = $develop" if ($devFlag == 1);
if ($aVal eq "" || substr($aVal,0 ,1) eq '#') { # whitelist nicht aktiv
if ($devFlag == 1) {
SIGNALduino_Log3 $name, 3, "$name: IDlist attr whitelist disabled or not defined (all IDs are enabled, except blacklisted): $aVal";
}
else {
SIGNALduino_Log3 $name, 3, "$name: IDlist attr whitelist disabled or not defined (all IDs are enabled, except blacklisted and instable IDs): $aVal";
}
}
else {
%WhitelistIDs = map {$_ => undef} split(",", $aVal); # whitelist in Hash wandeln
#my $w = join ',' => map "$_" => keys %WhitelistIDs;
SIGNALduino_Log3 $name, 3, "$name: IDlist attr whitelist: $aVal";
$wflag = 1;
}
#SIGNALduino_Log3 $name, 3, "$name IdList: attr whitelistIds=$aVal" if ($aVal);
if ($wflag == 0) { # whitelist not aktive
if (!defined($blacklist)) {
$blacklist = AttrVal($name,"blacklist_IDs","");
}
if (length($blacklist) > 0) { # Blacklist in Hash wandeln
SIGNALduino_Log3 $name, 3, "$name: IDlist attr blacklistIds=$blacklist";
%BlacklistIDs = map { $_ => 1 } split(",", $blacklist);
#my $w = join ', ' => map "$_" => keys %BlacklistIDs;
#SIGNALduino_Log3 $name, 3, "$name IdList, Attr blacklist $w";
}
}
my $id;
foreach $id (keys %ProtocolListSIGNALduino)
{
if ($wflag == 1) # whitelist active
{
if (!exists($WhitelistIDs{$id})) # Id wurde in der whitelist nicht gefunden
{
push (@skippedWhiteId, $id);
next;
}
}
else { # whitelist not active
if (exists($BlacklistIDs{$id})) {
#SIGNALduino_Log3 $name, 3, "$name IdList, skip Blacklist ID $id";
push (@skippedBlackId, $id);
next;
}
# wenn es keine developId gibt, dann die folgenden Abfragen ueberspringen
if (exists($ProtocolListSIGNALduino{$id}{developId}))
{
if ($ProtocolListSIGNALduino{$id}{developId} eq "m") {
if ($develop !~ m/m$id/) { # ist nur zur Abwaertskompatibilitaet und kann in einer der naechsten Versionen entfernt werden
push (@devModulId, $id);
if ($devFlag == 0) {
push (@skippedDevId, $id);
next;
}
}
}
elsif ($ProtocolListSIGNALduino{$id}{developId} eq "p") {
SIGNALduino_Log3 $name, 5, "$name: IDlist ID=$id skipped (developId=p), caution, protocol can cause crashes, use only if advised to do";
next;
}
elsif ($devFlag == 0 && $ProtocolListSIGNALduino{$id}{developId} eq "y" && $develop !~ m/y$id/) {
#SIGNALduino_Log3 $name, 3, "$name: IdList ID=$id skipped (developId=y)";
push (@skippedDevId, $id);
next;
}
}
}
if (exists ($ProtocolListSIGNALduino{$id}{format}) && $ProtocolListSIGNALduino{$id}{format} eq "manchester")
{
push (@mcIdList, $id);
}
elsif (exists $ProtocolListSIGNALduino{$id}{sync})
{
push (@msIdList, $id);
}
elsif (exists ($ProtocolListSIGNALduino{$id}{clockabs}))
{
$ProtocolListSIGNALduino{$id}{length_min} = SDUINO_PARSE_DEFAULT_LENGHT_MIN if (!exists($ProtocolListSIGNALduino{$id}{length_min}));
push (@muIdList, $id);
}
}
@msIdList = sort {$a <=> $b} @msIdList;
@muIdList = sort {$a <=> $b} @muIdList;
@mcIdList = sort {$a <=> $b} @mcIdList;
@skippedDevId = sort {$a <=> $b} @skippedDevId;
@skippedBlackId = sort {$a <=> $b} @skippedBlackId;
@skippedWhiteId = sort {$a <=> $b} @skippedWhiteId;
@devModulId = sort {$a <=> $b} @devModulId;
SIGNALduino_Log3 $name, 3, "$name: IDlist MS @msIdList";
SIGNALduino_Log3 $name, 3, "$name: IDlist MU @muIdList";
SIGNALduino_Log3 $name, 3, "$name: IDlist MC @mcIdList";
SIGNALduino_Log3 $name, 5, "$name: IDlist not whitelisted skipped = @skippedWhiteId" if (scalar @skippedWhiteId > 0);
SIGNALduino_Log3 $name, 4, "$name: IDlist blacklistId skipped = @skippedBlackId" if (scalar @skippedBlackId > 0);
SIGNALduino_Log3 $name, 4, "$name: IDlist development skipped = @skippedDevId" if (scalar @skippedDevId > 0);
if (scalar @devModulId > 0)
{
SIGNALduino_Log3 $name, 3, "$name: IDlist development protocol is active (to activate dispatch to not finshed logical module, enable desired protocol via whitelistIDs) = @devModulId";
$hash->{IDsNoDispatch} = join(",", @devModulId);
}
$hash->{msIdList} = \@msIdList;
$hash->{muIdList} = \@muIdList;
$hash->{mcIdList} = \@mcIdList;
}
sub SIGNALduino_getAttrDevelopment
{
my $name = shift;
my $develop = shift;
my $devFlag = 0;
if (index(SDUINO_VERSION, "dev") >= 0) { # development version
$develop = AttrVal($name,"development", 0) if (!defined($develop));
$devFlag = 1 if ($develop eq "1" || (substr($develop,0,1) eq "y" && $develop !~ m/^y\d/)); # Entwicklerversion, y ist nur zur Abwaertskompatibilitaet und kann in einer der naechsten Versionen entfernt werden
}
else {
$develop = "0";
SIGNALduino_Log3 $name, 3, "$name IdList: ### Attribute development is in this version ignored ###";
}
return ($develop,$devFlag);
}
sub SIGNALduino_callsub
{
my $funcname =shift;
my $method = shift;
my $evalFirst = shift;
my $name = shift;
my @args = @_;
if ( defined $method && defined &$method )
{
if (defined($evalFirst) && $evalFirst)
{
eval( $method->($name, @args));
if($@) {
SIGNALduino_Log3 $name, 5, "$name: Error: $funcname, has an error and will not be executed: $@ please report at github.";
return (0,undef);
}
}
#my $subname = @{[eval {&$method}, $@ =~ /.*/]};
SIGNALduino_Log3 $name, 5, "$name: applying $funcname, value before: @args"; # method $subname";
#SIGNALduino_Log3 $name, 5, "$name: value bevore $funcname: @args";
my ($rcode, @returnvalues) = $method->($name, @args) ;
if (@returnvalues && defined($returnvalues[0])) {
SIGNALduino_Log3 $name, 5, "$name: rcode=$rcode, modified value after $funcname: @returnvalues";
} else {
SIGNALduino_Log3 $name, 5, "$name: rcode=$rcode, after calling $funcname";
}
return ($rcode, @returnvalues);
} elsif (defined $method ) {
SIGNALduino_Log3 $name, 5, "$name: Error: Unknown method $funcname pease report at github";
return (0,undef);
}
return (1,@args);
}
# calculates the hex (in bits) and adds it at the beginning of the message
# input = @list
# output = @list
sub SIGNALduino_lengtnPrefix
{
my ($name, @bit_msg) = @_;
my $msg = join("",@bit_msg);
#$msg = unpack("B8", pack("N", length($msg))).$msg;
$msg=sprintf('%08b', length($msg)).$msg;
return (1,split("",$msg));
}
sub SIGNALduino_PreparingSend_FS20_FHT($$$) {
my ($id, $sum, $msg) = @_;
my $temp = 0;
my $newmsg = "P$id#0000000000001"; # 12 Bit Praeambel, 1 bit
for (my $i=0; $i 01 1 -> 10 to be compatible with IT Module
$msg =~ s/0/z/g;
$msg =~ s/1/10/g;
$msg =~ s/z/01/g;
return (1,split("",$msg));
}
sub SIGNALduino_bit2itv1
{
my ($name, @bit_msg) = @_;
my $msg = join("",@bit_msg);
$msg =~ s/0F/01/g; # Convert 0F -> 01 (F) to be compatible with CUL
# $msg =~ s/0F/11/g; # Convert 0F -> 11 (1) float
if (index($msg,'F') == -1) {
return (1,split("",$msg));
} else {
return (0,0);
}
}
sub SIGNALduino_ITV1_tristateToBit($)
{
my ($msg) = @_;
# Convert 0 -> 00 1 -> 11 F => 01 to be compatible with IT Module
$msg =~ s/0/00/g;
$msg =~ s/1/11/g;
$msg =~ s/F/01/g;
$msg =~ s/D/10/g;
return (1,$msg);
}
sub SIGNALduino_HE800($@)
{
my ($name, @bit_msg) = @_;
my $protolength = scalar @bit_msg;
if ($protolength < 40) {
for (my $i=0; $i<(40-$protolength); $i++) {
push(@bit_msg, 0);
}
}
return (1,@bit_msg);
}
sub SIGNALduino_HE_EU($@)
{
my ($name, @bit_msg) = @_;
my $protolength = scalar @bit_msg;
if ($protolength < 72) {
for (my $i=0; $i<(72-$protolength); $i++) {
push(@bit_msg, 0);
}
}
return (1,@bit_msg);
}
sub SIGNALduino_postDemo_EM($@) {
my ($name, @bit_msg) = @_;
my $msg = join("",@bit_msg);
my $msg_start = index($msg, "0000000001"); # find start
my $count;
$msg = substr($msg,$msg_start + 10); # delete preamble + 1 bit
my $new_msg = "";
my $crcbyte;
my $msgcrc = 0;
if ($msg_start > 0 && length $msg == 89) {
for ($count = 0; $count < length ($msg) ; $count +=9) {
$crcbyte = substr($msg,$count,8);
if ($count < (length($msg) - 10)) {
$new_msg.= join "", reverse @bit_msg[$msg_start + 10 + $count.. $msg_start + 17 + $count];
$msgcrc = $msgcrc ^ oct( "0b$crcbyte" );
}
}
if ($msgcrc == oct( "0b$crcbyte" )) {
SIGNALduino_Log3 $name, 4, "$name: EM Protocol - CRC OK";
return (1,split("",$new_msg));
} else {
SIGNALduino_Log3 $name, 3, "$name: EM Protocol - CRC ERROR";
return 0, undef;
}
}
SIGNALduino_Log3 $name, 3, "$name: EM Protocol - Start not found or length msg (".length $msg.") not correct";
return 0, undef;
}
sub SIGNALduino_postDemo_FS20($@) {
my ($name, @bit_msg) = @_;
my $datastart = 0;
my $protolength = scalar @bit_msg;
my $sum = 6;
my $b = 0;
my $i = 0;
for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
last if $bit_msg[$datastart] eq "1";
}
if ($datastart == $protolength) { # all bits are 0
SIGNALduino_Log3 $name, 3, "$name: FS20 - ERROR message all bit are zeros";
return 0, undef;
}
splice(@bit_msg, 0, $datastart + 1); # delete preamble + 1 bit
$protolength = scalar @bit_msg;
SIGNALduino_Log3 $name, 5, "$name: FS20 - pos=$datastart length=$protolength";
if ($protolength == 46 || $protolength == 55) { # If it 1 bit too long, then it will be removed (EOT-Bit)
pop(@bit_msg);
$protolength--;
}
if ($protolength == 45 || $protolength == 54) { ### FS20 length 45 or 54
for(my $b = 0; $b < $protolength - 9; $b += 9) { # build sum over first 4 or 5 bytes
$sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
}
my $checksum = oct( "0b".(join "", @bit_msg[$protolength - 9 .. $protolength - 2])); # Checksum Byte 5 or 6
if ((($sum + 6) & 0xFF) == $checksum) { # Message from FHT80 roothermostat
SIGNALduino_Log3 $name, 5, "$name: FS20 - Detection aborted, checksum matches FHT code";
return 0, undef;
}
if (($sum & 0xFF) == $checksum) { ## FH20 remote control
for(my $b = 0; $b < $protolength; $b += 9) { # check parity over 5 or 6 bytes
my $parity = 0; # Parity even
for(my $i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
$parity += $bit_msg[$i];
}
if ($parity % 2 != 0) {
SIGNALduino_Log3 $name, 3, "$name: FS20 ERROR - Parity not even";
return 0, undef;
}
} # parity ok
for(my $b = $protolength - 1; $b > 0; $b -= 9) { # delete 5 or 6 parity bits
splice(@bit_msg, $b, 1);
}
if ($protolength == 45) { ### FS20 length 45
splice(@bit_msg, 32, 8); # delete checksum
splice(@bit_msg, 24, 0, (0,0,0,0,0,0,0,0)); # insert Byte 3
} else { ### FS20 length 54
splice(@bit_msg, 40, 8); # delete checksum
}
my $dmsg = SIGNALduino_b2h(join "", @bit_msg);
SIGNALduino_Log3 $name, 4, "$name: FS20 - remote control post demodulation $dmsg length $protolength";
return (1, @bit_msg); ## FHT80TF ok
}
else {
SIGNALduino_Log3 $name, 4, "$name: FS20 ERROR - wrong checksum";
}
}
else {
SIGNALduino_Log3 $name, 5, "$name: FS20 ERROR - wrong length=$protolength (must be 45 or 54)";
}
return 0, undef;
}
sub SIGNALduino_postDemo_FHT80($@) {
my ($name, @bit_msg) = @_;
my $datastart = 0;
my $protolength = scalar @bit_msg;
my $sum = 12;
my $b = 0;
my $i = 0;
for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
last if $bit_msg[$datastart] eq "1";
}
if ($datastart == $protolength) { # all bits are 0
SIGNALduino_Log3 $name, 3, "$name: FHT80 - ERROR message all bit are zeros";
return 0, undef;
}
splice(@bit_msg, 0, $datastart + 1); # delete preamble + 1 bit
$protolength = scalar @bit_msg;
SIGNALduino_Log3 $name, 5, "$name: FHT80 - pos=$datastart length=$protolength";
if ($protolength == 55) { # If it 1 bit too long, then it will be removed (EOT-Bit)
pop(@bit_msg);
$protolength--;
}
if ($protolength == 54) { ### FHT80 fixed length
for($b = 0; $b < 45; $b += 9) { # build sum over first 5 bytes
$sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
}
my $checksum = oct( "0b".(join "", @bit_msg[45 .. 52])); # Checksum Byte 6
if ((($sum - 6) & 0xFF) == $checksum) { ## Message from FS20 remote control
SIGNALduino_Log3 $name, 5, "$name: FHT80 - Detection aborted, checksum matches FS20 code";
return 0, undef;
}
if (($sum & 0xFF) == $checksum) { ## FHT80 Raumthermostat
for($b = 0; $b < 54; $b += 9) { # check parity over 6 byte
my $parity = 0; # Parity even
for($i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
$parity += $bit_msg[$i];
}
if ($parity % 2 != 0) {
SIGNALduino_Log3 $name, 3, "$name: FHT80 ERROR - Parity not even";
return 0, undef;
}
} # parity ok
for($b = 53; $b > 0; $b -= 9) { # delete 6 parity bits
splice(@bit_msg, $b, 1);
}
if ($bit_msg[26] != 1) { # Bit 5 Byte 3 must 1
SIGNALduino_Log3 $name, 3, "$name: FHT80 ERROR - byte 3 bit 5 not 1";
return 0, undef;
}
splice(@bit_msg, 40, 8); # delete checksum
splice(@bit_msg, 24, 0, (0,0,0,0,0,0,0,0));# insert Byte 3
my $dmsg = SIGNALduino_b2h(join "", @bit_msg);
SIGNALduino_Log3 $name, 4, "$name: FHT80 - roomthermostat post demodulation $dmsg";
return (1, @bit_msg); ## FHT80 ok
}
else {
SIGNALduino_Log3 $name, 4, "$name: FHT80 ERROR - wrong checksum";
}
}
else {
SIGNALduino_Log3 $name, 5, "$name: FHT80 ERROR - wrong length=$protolength (must be 54)";
}
return 0, undef;
}
sub SIGNALduino_postDemo_FHT80TF($@) {
my ($name, @bit_msg) = @_;
my $datastart = 0;
my $protolength = scalar @bit_msg;
my $sum = 12;
my $b = 0;
if ($protolength < 46) { # min 5 bytes + 6 bits
SIGNALduino_Log3 $name, 4, "$name: FHT80TF - ERROR lenght of message < 46";
return 0, undef;
}
for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
last if $bit_msg[$datastart] eq "1";
}
if ($datastart == $protolength) { # all bits are 0
SIGNALduino_Log3 $name, 3, "$name: FHT80TF - ERROR message all bit are zeros";
return 0, undef;
}
splice(@bit_msg, 0, $datastart + 1); # delete preamble + 1 bit
$protolength = scalar @bit_msg;
if ($protolength == 45) { ### FHT80TF fixed length
for(my $b = 0; $b < 36; $b += 9) { # build sum over first 4 bytes
$sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
}
my $checksum = oct( "0b".(join "", @bit_msg[36 .. 43])); # Checksum Byte 5
if (($sum & 0xFF) == $checksum) { ## FHT80TF Tuer-/Fensterkontakt
for(my $b = 0; $b < 45; $b += 9) { # check parity over 5 byte
my $parity = 0; # Parity even
for(my $i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
$parity += $bit_msg[$i];
}
if ($parity % 2 != 0) {
SIGNALduino_Log3 $name, 4, "$name: FHT80TF ERROR - Parity not even";
return 0, undef;
}
} # parity ok
for(my $b = 44; $b > 0; $b -= 9) { # delete 5 parity bits
splice(@bit_msg, $b, 1);
}
if ($bit_msg[26] != 0) { # Bit 5 Byte 3 must 0
SIGNALduino_Log3 $name, 3, "$name: FHT80TF ERROR - byte 3 bit 5 not 0";
return 0, undef;
}
splice(@bit_msg, 32, 8); # delete checksum
my $dmsg = SIGNALduino_b2h(join "", @bit_msg);
SIGNALduino_Log3 $name, 4, "$name: FHT80TF - door/window switch post demodulation $dmsg";
return (1, @bit_msg); ## FHT80TF ok
}
}
return 0, undef;
}
sub SIGNALduino_postDemo_WS7035($@) {
my ($name, @bit_msg) = @_;
my $msg = join("",@bit_msg);
my $parity = 0; # Parity even
SIGNALduino_Log3 $name, 4, "$name: WS7035 $msg";
if (substr($msg,0,8) ne "10100000") { # check ident
SIGNALduino_Log3 $name, 3, "$name: WS7035 ERROR - Ident not 1010 0000";
return 0, undef;
} else {
for(my $i = 15; $i < 28; $i++) { # Parity over bit 15 and 12 bit temperature
$parity += substr($msg, $i, 1);
}
if ($parity % 2 != 0) {
SIGNALduino_Log3 $name, 3, "$name: WS7035 ERROR - Parity not even";
return 0, undef;
} else {
SIGNALduino_Log3 $name, 4, "$name: WS7035 " . substr($msg,0,4) ." ". substr($msg,4,4) ." ". substr($msg,8,4) ." ". substr($msg,12,4) ." ". substr($msg,16,4) ." ". substr($msg,20,4) ." ". substr($msg,24,4) ." ". substr($msg,28,4) ." ". substr($msg,32,4) ." ". substr($msg,36,4) ." ". substr($msg,40);
substr($msg, 27, 4, ''); # delete nibble 8
return (1,split("",$msg));
}
}
}
sub SIGNALduino_postDemo_WS2000($@) {
my ($name, @bit_msg) = @_;
my $debug = AttrVal($name,"debug",0);
my @new_bit_msg = "";
my $protolength = scalar @bit_msg;
my @datalenghtws = (35,50,35,50,70,40,40,85);
my $datastart = 0;
my $datalength = 0;
my $datalength1 = 0;
my $index = 0;
my $data = 0;
my $dataindex = 0;
my $error = 0;
my $check = 0;
my $sum = 5;
my $typ = 0;
my $adr = 0;
my @sensors = (
"Thermo",
"Thermo/Hygro",
"Rain",
"Wind",
"Thermo/Hygro/Baro",
"Brightness",
"Pyrano",
"Kombi"
);
for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
last if $bit_msg[$datastart] eq "1";
}
if ($datastart == $protolength) { # all bits are 0
SIGNALduino_Log3 $name, 3, "$name: WS2000 - ERROR message all bit are zeros";
return 0, undef;
}
$datalength = $protolength - $datastart;
$datalength1 = $datalength - ($datalength % 5); # modulo 5
SIGNALduino_Log3 $name, 5, "$name: WS2000 protolength: $protolength, datastart: $datastart, datalength $datalength";
$typ = oct( "0b".(join "", reverse @bit_msg[$datastart + 1.. $datastart + 4])); # Sensortyp
if ($typ > 7) {
SIGNALduino_Log3 $name, 4, "$name: WS2000 Sensortyp $typ - ERROR typ to big";
return 0, undef;
}
if ($typ == 1 && ($datalength == 45 || $datalength == 46)) {$datalength1 += 5;} # Typ 1 ohne Summe
if ($datalenghtws[$typ] != $datalength1) { # check lenght of message
SIGNALduino_Log3 $name, 4, "$name: WS2000 Sensortyp $typ - ERROR lenght of message $datalength1 ($datalenghtws[$typ])";
return 0, undef;
} elsif ($datastart > 10) { # max 10 Bit preamble
SIGNALduino_Log3 $name, 4, "$name: WS2000 ERROR preamble > 10 ($datastart)";
return 0, undef;
} else {
do {
$error += !$bit_msg[$index + $datastart]; # jedes 5. Bit muss 1 sein
$dataindex = $index + $datastart + 1;
$data = oct( "0b".(join "", reverse @bit_msg[$dataindex .. $dataindex + 3]));
if ($index == 5) {$adr = ($data & 0x07)} # Sensoradresse
if ($datalength == 45 || $datalength == 46) { # Typ 1 ohne Summe
if ($index <= $datalength - 5) {
$check = $check ^ $data; # Check - Typ XOR Adresse XOR bis XOR Check muss 0 ergeben
}
} else {
if ($index <= $datalength - 10) {
$check = $check ^ $data; # Check - Typ XOR Adresse XOR bis XOR Check muss 0 ergeben
$sum += $data;
}
}
$index += 5;
} until ($index >= $datalength -1 );
}
if ($error != 0) {
SIGNALduino_Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - ERROR examination bit";
return (0, undef);
} elsif ($check != 0) {
SIGNALduino_Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - ERROR check XOR";
return (0, undef);
} else {
if ($datalength < 45 || $datalength > 46) { # Summe pruefen, außer Typ 1 ohne Summe
$data = oct( "0b".(join "", reverse @bit_msg[$dataindex .. $dataindex + 3]));
if ($data != ($sum & 0x0F)) {
SIGNALduino_Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - ERROR sum";
return (0, undef);
}
}
SIGNALduino_Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - $sensors[$typ]";
$datastart += 1; # [x] - 14_CUL_WS
@new_bit_msg[4 .. 7] = reverse @bit_msg[$datastart .. $datastart+3]; # [2] Sensortyp
@new_bit_msg[0 .. 3] = reverse @bit_msg[$datastart+5 .. $datastart+8]; # [1] Sensoradresse
@new_bit_msg[12 .. 15] = reverse @bit_msg[$datastart+10 .. $datastart+13]; # [4] T 0.1, R LSN, Wi 0.1, B 1, Py 1
@new_bit_msg[8 .. 11] = reverse @bit_msg[$datastart+15 .. $datastart+18]; # [3] T 1, R MID, Wi 1, B 10, Py 10
if ($typ == 0 || $typ == 2) { # Thermo (AS3), Rain (S2000R, WS7000-16)
@new_bit_msg[16 .. 19] = reverse @bit_msg[$datastart+20 .. $datastart+23]; # [5] T 10, R MSN
} else {
@new_bit_msg[20 .. 23] = reverse @bit_msg[$datastart+20 .. $datastart+23]; # [6] T 10, Wi 10, B 100, Py 100
@new_bit_msg[16 .. 19] = reverse @bit_msg[$datastart+25 .. $datastart+28]; # [5] H 0.1, Wr 1, B Fak, Py Fak
if ($typ == 1 || $typ == 3 || $typ == 4 || $typ == 7) { # Thermo/Hygro, Wind, Thermo/Hygro/Baro, Kombi
@new_bit_msg[28 .. 31] = reverse @bit_msg[$datastart+30 .. $datastart+33]; # [8] H 1, Wr 10
@new_bit_msg[24 .. 27] = reverse @bit_msg[$datastart+35 .. $datastart+38]; # [7] H 10, Wr 100
if ($typ == 4) { # Thermo/Hygro/Baro (S2001I, S2001ID)
@new_bit_msg[36 .. 39] = reverse @bit_msg[$datastart+40 .. $datastart+43]; # [10] P 1
@new_bit_msg[32 .. 35] = reverse @bit_msg[$datastart+45 .. $datastart+48]; # [9] P 10
@new_bit_msg[44 .. 47] = reverse @bit_msg[$datastart+50 .. $datastart+53]; # [12] P 100
@new_bit_msg[40 .. 43] = reverse @bit_msg[$datastart+55 .. $datastart+58]; # [11] P Null
}
}
}
return (1, @new_bit_msg);
}
}
sub SIGNALduino_postDemo_WS7053($@) {
my ($name, @bit_msg) = @_;
my $msg = join("",@bit_msg);
my $parity = 0; # Parity even
SIGNALduino_Log3 $name, 4, "$name: WS7053 - MSG = $msg";
my $msg_start = index($msg, "10100000");
if ($msg_start > 0) { # start not correct
$msg = substr($msg, $msg_start);
$msg .= "0";
SIGNALduino_Log3 $name, 5, "$name: WS7053 - cut $msg_start char(s) at begin";
}
if ($msg_start < 0) { # start not found
SIGNALduino_Log3 $name, 3, "$name: WS7053 ERROR - Ident 10100000 not found";
return 0, undef;
} else {
if (length($msg) < 32) { # msg too short
SIGNALduino_Log3 $name, 3, "$name: WS7053 ERROR - msg too short, length " . length($msg);
return 0, undef;
} else {
for(my $i = 15; $i < 28; $i++) { # Parity over bit 15 and 12 bit temperature
$parity += substr($msg, $i, 1);
}
if ($parity % 2 != 0) {
SIGNALduino_Log3 $name, 3, "$name: WS7053 ERROR - Parity not even";
return 0, undef;
} else {
SIGNALduino_Log3 $name, 5, "$name: WS7053 before: " . substr($msg,0,4) ." ". substr($msg,4,4) ." ". substr($msg,8,4) ." ". substr($msg,12,4) ." ". substr($msg,16,4) ." ". substr($msg,20,4) ." ". substr($msg,24,4) ." ". substr($msg,28,4);
# Format from 7053: Bit 0-7 Ident, Bit 8-15 Rolling Code/Parity, Bit 16-27 Temperature (12.3), Bit 28-31 Zero
my $new_msg = substr($msg,0,28) . substr($msg,16,8) . substr($msg,28,4);
# Format for CUL_TX: Bit 0-7 Ident, Bit 8-15 Rolling Code/Parity, Bit 16-27 Temperature (12.3), Bit 28 - 35 Temperature (12), Bit 36-39 Zero
SIGNALduino_Log3 $name, 5, "$name: WS7053 after: " . substr($new_msg,0,4) ." ". substr($new_msg,4,4) ." ". substr($new_msg,8,4) ." ". substr($new_msg,12,4) ." ". substr($new_msg,16,4) ." ". substr($new_msg,20,4) ." ". substr($new_msg,24,4) ." ". substr($new_msg,28,4) ." ". substr($new_msg,32,4) ." ". substr($new_msg,36,4);
return (1,split("",$new_msg));
}
}
}
}
# manchester method
sub SIGNALduino_MCTFA
{
my ($name,$bitData,$id,$mcbitnum) = @_;
my $preamble_pos;
my $message_end;
my $message_length;
#if ($bitData =~ m/^.?(1){16,24}0101/) {
if ($bitData =~ m/(1{9}101)/ )
{
$preamble_pos=$+[1];
SIGNALduino_Log3 $name, 4, "$name: TFA 30.3208.0 preamble_pos = $preamble_pos";
return return (-1," sync not found") if ($preamble_pos <=0);
my @messages;
my $i=1;
my $retmsg = "";
do
{
$message_end = index($bitData,"1111111111101",$preamble_pos);
if ($message_end < $preamble_pos)
{
$message_end=$mcbitnum; # length($bitData);
}
$message_length = ($message_end - $preamble_pos);
my $part_str=substr($bitData,$preamble_pos,$message_length);
#$part_str = substr($part_str,0,52) if (length($part_str)) > 52;
SIGNALduino_Log3 $name, 4, "$name: TFA message start($i)=$preamble_pos end=$message_end with length=$message_length";
SIGNALduino_Log3 $name, 5, "$name: TFA message part($i)=$part_str";
my ($rcode, $rtxt) = SIGNALduino_TestLength($name, $id, $message_length, "TFA message part($i)");
if ($rcode) {
my $hex=SIGNALduino_b2h($part_str);
push (@messages,$hex);
SIGNALduino_Log3 $name, 4, "$name: TFA message part($i)=$hex";
}
else {
$retmsg = ", " . $rtxt;
}
$preamble_pos=index($bitData,"1101",$message_end)+4;
$i++;
} while ($message_end < $mcbitnum);
my %seen;
my @dupmessages = map { 1==$seen{$_}++ ? $_ : () } @messages;
return ($i,"loop error, please report this data $bitData") if ($i==10);
if (scalar(@dupmessages) > 0 ) {
SIGNALduino_Log3 $name, 4, "$name: repeated hex ".$dupmessages[0]." found ".$seen{$dupmessages[0]}." times";
return (1,$dupmessages[0]);
} else {
return (-1," no duplicate found$retmsg");
}
}
return (-1,undef);
}
sub SIGNALduino_OSV2
{
my ($name,$bitData,$id,$mcbitnum) = @_;
my $preamble_pos;
my $message_end;
my $message_length;
my $msg_start;
#$bitData =~ tr/10/01/;
if ($bitData =~ m/^.?(01){12,17}.?10011001/)
{ # Valid OSV2 detected!
#$preamble_pos=index($bitData,"10011001",24);
$preamble_pos=$+[1];
SIGNALduino_Log3 $name, 4, "$name: OSV2 protocol detected: preamble_pos = $preamble_pos";
return return (-1," sync not found") if ($preamble_pos <24);
$message_end=$-[1] if ($bitData =~ m/^.{44,}(01){16,17}.?10011001/); #Todo regex .{44,} 44 should be calculated from $preamble_pos+ min message lengh (44)
if (!defined($message_end) || $message_end < $preamble_pos) {
$message_end = length($bitData);
} else {
$message_end += 16;
SIGNALduino_Log3 $name, 4, "$name: OSV2 message end pattern found at pos $message_end lengthBitData=".length($bitData);
}
$message_length = ($message_end - $preamble_pos)/2;
return (-1," message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $message_length < $ProtocolListSIGNALduino{$id}{length_min} );
return (-1," message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $message_length > $ProtocolListSIGNALduino{$id}{length_max} );
my $idx=0;
my $osv2bits="";
my $osv2hex ="";
for ($idx=$preamble_pos;$idx<$message_end;$idx=$idx+16)
{
if ($message_end-$idx < 8 )
{
last;
}
my $osv2byte = "";
$osv2byte=NULL;
$osv2byte=substr($bitData,$idx,16);
my $rvosv2byte="";
for (my $p=0;$p $ProtocolListSIGNALduino{$id}{length_max} );
if (substr($bitData,20,1) != 0) {
$bitData =~ tr/01/10/; # invert message and check if it is possible to deocde now
}
my $calcsum = oct( "0b" . reverse substr($bitData,0,8));
$calcsum += oct( "0b" . reverse substr($bitData,8,8));
$calcsum += oct( "0b" . reverse substr($bitData,16,8));
$calcsum = ($calcsum & 0xFF) + ($calcsum >> 8);
my $checksum = oct( "0b" . reverse substr($bitData,24,8));
if ($calcsum != $checksum) { # Checksum
return (-1,"OSV1 - ERROR checksum not equal: $calcsum != $checksum");
}
SIGNALduino_Log3 $name, 4, "$name: OSV1 input data: $bitData";
my $newBitData = "00001010"; # Byte 0: Id1 = 0x0A
$newBitData .= "01001101"; # Byte 1: Id2 = 0x4D
my $channel = substr($bitData,6,2); # Byte 2 h: Channel
if ($channel == "00") { # in 0 LSB first
$newBitData .= "0001"; # out 1 MSB first
} elsif ($channel == "10") { # in 4 LSB first
$newBitData .= "0010"; # out 2 MSB first
} elsif ($channel == "01") { # in 4 LSB first
$newBitData .= "0011"; # out 3 MSB first
} else { # in 8 LSB first
return (-1,"$name: OSV1 - ERROR channel not valid: $channel");
}
$newBitData .= "0000"; # Byte 2 l: ????
$newBitData .= "0000"; # Byte 3 h: address
$newBitData .= reverse substr($bitData,0,4); # Byte 3 l: address (Rolling Code)
$newBitData .= reverse substr($bitData,8,4); # Byte 4 h: T 0,1
$newBitData .= "0" . substr($bitData,23,1) . "00"; # Byte 4 l: Bit 2 - Batterie 0=ok, 1=low (< 2,5 Volt)
$newBitData .= reverse substr($bitData,16,4); # Byte 5 h: T 10
$newBitData .= reverse substr($bitData,12,4); # Byte 5 l: T 1
$newBitData .= "0000"; # Byte 6 h: immer 0000
$newBitData .= substr($bitData,21,1) . "000"; # Byte 6 l: Bit 3 - Temperatur 0=pos | 1=neg, Rest 0
$newBitData .= "00000000"; # Byte 7: immer 0000 0000
# calculate new checksum over first 16 nibbles
$checksum = 0;
for (my $i = 0; $i < 64; $i = $i + 4) {
$checksum += oct( "0b" . substr($newBitData, $i, 4));
}
$checksum = ($checksum - 0xa) & 0xff;
$newBitData .= sprintf("%08b",$checksum); # Byte 8: new Checksum
$newBitData .= "00000000"; # Byte 9: immer 0000 0000
my $osv1hex = "50" . SIGNALduino_b2h($newBitData); # output with length before
SIGNALduino_Log3 $name, 4, "$name: OSV1 protocol id $id translated to RFXSensor format";
SIGNALduino_Log3 $name, 4, "$name: converted to hex: $osv1hex";
return (1,$osv1hex);
}
sub SIGNALduino_AS()
{
my ($name,$bitData,$id,$mcbitnum) = @_;
my $debug = AttrVal($name,"debug",0);
if(index($bitData,"1100",16) >= 0) # $rawData =~ m/^A{2,3}/)
{ # Valid AS detected!
my $message_start = index($bitData,"1100",16);
Debug "$name: AS protocol detected \n" if ($debug);
my $message_end=index($bitData,"1100",$message_start+16);
$message_end = length($bitData) if ($message_end == -1);
my $message_length = $message_end - $message_start;
return (-1," message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $message_length < $ProtocolListSIGNALduino{$id}{length_min} );
return (-1," message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $message_length > $ProtocolListSIGNALduino{$id}{length_max} );
my $msgbits =substr($bitData,$message_start);
my $ashex=sprintf('%02X', oct("0b$msgbits"));
SIGNALduino_Log3 $name, 5, "$name: AS protocol converted to hex: ($ashex) with length ($message_length) bits \n";
return (1,$bitData);
}
return (-1,undef);
}
sub SIGNALduino_Hideki()
{
my ($name,$bitData,$id,$mcbitnum) = @_;
my $debug = AttrVal($name,"debug",0);
Debug "$name: search in $bitData \n" if ($debug);
my $message_start = index($bitData,"10101110");
my $invert = 0;
if ($message_start < 0) {
$bitData =~ tr/01/10/; # invert message
$message_start = index($bitData,"10101110"); # 0x75 but in reverse order
$invert = 1;
}
if ($message_start >= 0 ) # 0x75 but in reverse order
{
Debug "$name: Hideki protocol (invert=$invert) detected \n" if ($debug);
# Todo: Mindest Laenge fuer startpunkt vorspringen
# Todo: Wiederholung auch an das Modul weitergeben, damit es dort geprueft werden kann
my $message_end = index($bitData,"10101110",$message_start+71); # pruefen auf ein zweites 0x75, mindestens 72 bit nach 1. 0x75, da der Regensensor minimum 8 Byte besitzt je byte haben wir 9 bit
$message_end = length($bitData) if ($message_end == -1);
my $message_length = $message_end - $message_start;
return (-1,"message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $message_length < $ProtocolListSIGNALduino{$id}{length_min} );
return (-1,"message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $message_length > $ProtocolListSIGNALduino{$id}{length_max} );
my $hidekihex;
my $idx;
for ($idx=$message_start; $idx<$message_end; $idx=$idx+9)
{
my $byte = "";
$byte= substr($bitData,$idx,8); ## Ignore every 9th bit
Debug "$name: byte in order $byte " if ($debug);
$byte = scalar reverse $byte;
Debug "$name: byte reversed $byte , as hex: ".sprintf('%X', oct("0b$byte"))."\n" if ($debug);
$hidekihex=$hidekihex.sprintf('%02X', oct("0b$byte"));
}
if ($invert == 0) {
SIGNALduino_Log3 $name, 4, "$name: receive Hideki protocol not inverted";
} else {
SIGNALduino_Log3 $name, 4, "$name: receive Hideki protocol inverted";
}
SIGNALduino_Log3 $name, 4, "$name: Hideki protocol converted to hex: $hidekihex with " .$message_length ." bits, messagestart $message_start";
return (1,$hidekihex); ## Return only the original bits, include length
}
SIGNALduino_Log3 $name, 4, "$name: hideki start pattern (10101110) not found";
return (-1,"Start pattern (10101110) not found");
}
sub SIGNALduino_Maverick()
{
my ($name,$bitData,$id,$mcbitnum) = @_;
my $debug = AttrVal($name,"debug",0);
if ($bitData =~ m/^.*(101010101001100110010101).*/)
{ # Valid Maverick header detected
my $header_pos=$+[1];
SIGNALduino_Log3 $name, 4, "$name: Maverick protocol detected: header_pos = $header_pos";
my $hex=SIGNALduino_b2h(substr($bitData,$header_pos,26*4));
return (1,$hex); ## Return the bits unchanged in hex
} else {
return return (-1," header not found");
}
}
sub SIGNALduino_OSPIR()
{
my ($name,$bitData,$id,$mcbitnum) = @_;
my $debug = AttrVal($name,"debug",0);
if ($bitData =~ m/^.*(1{14}|0{14}).*/)
{ # Valid Oregon PIR detected
my $header_pos=$+[1];
SIGNALduino_Log3 $name, 4, "$name: Oregon PIR protocol detected: header_pos = $header_pos";
my $hex=SIGNALduino_b2h($bitData);
return (1,$hex); ## Return the bits unchanged in hex
} else {
return return (-1," header not found");
}
}
sub SIGNALduino_MCRAW()
{
my ($name,$bitData,$id,$mcbitnum) = @_;
return (-1," message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $mcbitnum > $ProtocolListSIGNALduino{$id}{length_max} );
my $hex=SIGNALduino_b2h($bitData);
return (1,$hex); ## Return the bits unchanged in hex
}
sub SIGNALduino_SomfyRTS()
{
my ($name, $bitData,$id,$mcbitnum) = @_;
#(my $negBits = $bitData) =~ tr/10/01/; # Todo: eventuell auf pack umstellen
if (defined($mcbitnum)) {
SIGNALduino_Log3 $name, 4, "$name: Somfy bitdata: $bitData ($mcbitnum)";
if ($mcbitnum == 57) {
$bitData = substr($bitData, 1, 56);
SIGNALduino_Log3 $name, 4, "$name: Somfy bitdata: _$bitData (" . length($bitData) . "). Bit am Anfang entfernt";
}
}
my $encData = SIGNALduino_b2h($bitData);
#SIGNALduino_Log3 $name, 4, "$name: Somfy RTS protocol enc: $encData";
return (1, $encData);
}
sub SIGNALduino_TestLength
{
my ($name, $id, $message_length, $logMsg) = @_;
if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $message_length < $ProtocolListSIGNALduino{$id}{length_min}) {
SIGNALduino_Log3 $name, 4, "$name: $logMsg: message with length=$message_length is to short" if ($logMsg ne "");
return (0, "message is to short");
}
elsif (defined($ProtocolListSIGNALduino{$id}{length_max}) && $message_length > $ProtocolListSIGNALduino{$id}{length_max}) {
SIGNALduino_Log3 $name, 4, "$name: $logMsg: message with length=$message_length is to long" if ($logMsg ne "");
return (0, "message is to long");
}
return (1,"");
}
# - - - - - - - - - - - -
#=item SIGNALduino_filterMC()
#This functons, will act as a filter function. It will decode MU data via Manchester encoding
#
# Will return $count of ???, modified $rawData , modified %patternListRaw,
# =cut
sub SIGNALduino_filterMC($$$%)
{
## Warema Implementierung : Todo variabel gestalten
my ($name,$id,$rawData,%patternListRaw) = @_;
my $debug = AttrVal($name,"debug",0);
my ($ht, $hasbit, $value) = 0;
$value=1 if (!$debug);
my @bitData;
my @sigData = split "",$rawData;
foreach my $pulse (@sigData)
{
next if (!defined($patternListRaw{$pulse}));
#SIGNALduino_Log3 $name, 4, "$name: pulese: ".$patternListRaw{$pulse};
if (SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs},abs($patternListRaw{$pulse}),$ProtocolListSIGNALduino{$id}{clockabs}*0.5))
{
# Short
$hasbit=$ht;
$ht = $ht ^ 0b00000001;
$value='S' if($debug);
#SIGNALduino_Log3 $name, 4, "$name: filter S ";
} elsif ( SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs}*2,abs($patternListRaw{$pulse}),$ProtocolListSIGNALduino{$id}{clockabs}*0.5)) {
# Long
$hasbit=1;
$ht=1;
$value='L' if($debug);
#SIGNALduino_Log3 $name, 4, "$name: filter L ";
} elsif ( SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{syncabs}+(2*$ProtocolListSIGNALduino{$id}{clockabs}),abs($patternListRaw{$pulse}),$ProtocolListSIGNALduino{$id}{clockabs}*0.5)) {
$hasbit=1;
$ht=1;
$value='L' if($debug);
#SIGNALduino_Log3 $name, 4, "$name: sync L ";
} else {
# No Manchester Data
$ht=0;
$hasbit=0;
#SIGNALduino_Log3 $name, 4, "$name: filter n ";
}
if ($hasbit && $value) {
$value = lc($value) if($debug && $patternListRaw{$pulse} < 0);
my $bit=$patternListRaw{$pulse} > 0 ? 1 : 0;
#SIGNALduino_Log3 $name, 5, "$name: adding value: ".$bit;
push @bitData, $bit ;
}
}
my %patternListRawFilter;
$patternListRawFilter{0} = 0;
$patternListRawFilter{1} = $ProtocolListSIGNALduino{$id}{clockabs};
#SIGNALduino_Log3 $name, 5, "$name: filterbits: ".@bitData;
$rawData = join "", @bitData;
return (undef ,$rawData, %patternListRawFilter);
}
# - - - - - - - - - - - -
#=item SIGNALduino_filterSign()
#This functons, will act as a filter function. It will remove the sign from the pattern, and compress message and pattern
#
# Will return $count of combined values, modified $rawData , modified %patternListRaw,
# =cut
sub SIGNALduino_filterSign($$$%)
{
my ($name,$id,$rawData,%patternListRaw) = @_;
my $debug = AttrVal($name,"debug",0);
my %buckets;
# Remove Sign
%patternListRaw = map { $_ => abs($patternListRaw{$_})} keys %patternListRaw; ## remove sign from all
my $intol=0;
my $cnt=0;
# compress pattern hash
foreach my $key (keys %patternListRaw) {
#print "chk:".$patternListRaw{$key};
#print "\n";
$intol=0;
foreach my $b_key (keys %buckets){
#print "with:".$buckets{$b_key};
#print "\n";
# $value - $set <= $tolerance
if (SIGNALduino_inTol($patternListRaw{$key},$buckets{$b_key},$buckets{$b_key}*0.25))
{
#print"\t". $patternListRaw{$key}."($key) is intol of ".$buckets{$b_key}."($b_key) \n";
$cnt++;
eval "\$rawData =~ tr/$key/$b_key/";
#if ($key == $msg_parts{clockidx})
#{
# $msg_pats{syncidx} = $buckets{$key};
# }
# elsif ($key == $msg_parts{syncidx})
# {
# $msg_pats{syncidx} = $buckets{$key};
# }
$buckets{$b_key} = ($buckets{$b_key} + $patternListRaw{$key}) /2;
#print"\t recalc to ". $buckets{$b_key}."\n";
delete ($patternListRaw{$key}); # deletes the compressed entry
$intol=1;
last;
}
}
if ($intol == 0) {
$buckets{$key}=abs($patternListRaw{$key});
}
}
return ($cnt,$rawData, %patternListRaw);
#print "rdata: ".$msg_parts{rawData}."\n";
#print Dumper (%buckets);
#print Dumper (%msg_parts);
#modify msg_parts pattern hash
#$patternListRaw = \%buckets;
}
# - - - - - - - - - - - -
#=item SIGNALduino_compPattern()
#This functons, will act as a filter function. It will remove the sign from the pattern, and compress message and pattern
#
# Will return $count of combined values, modified $rawData , modified %patternListRaw,
# =cut
sub SIGNALduino_compPattern($$$%)
{
my ($name,$id,$rawData,%patternListRaw) = @_;
my $debug = AttrVal($name,"debug",0);
my %buckets;
# Remove Sign
#%patternListRaw = map { $_ => abs($patternListRaw{$_})} keys %patternListRaw; ## remove sing from all
my $intol=0;
my $cnt=0;
# compress pattern hash
foreach my $key (keys %patternListRaw) {
#print "chk:".$patternListRaw{$key};
#print "\n";
$intol=0;
foreach my $b_key (keys %buckets){
#print "with:".$buckets{$b_key};
#print "\n";
# $value - $set <= $tolerance
if (SIGNALduino_inTol($patternListRaw{$key},$buckets{$b_key},$buckets{$b_key}*0.4))
{
#print"\t". $patternListRaw{$key}."($key) is intol of ".$buckets{$b_key}."($b_key) \n";
$cnt++;
eval "\$rawData =~ tr/$key/$b_key/";
#if ($key == $msg_parts{clockidx})
#{
# $msg_pats{syncidx} = $buckets{$key};
# }
# elsif ($key == $msg_parts{syncidx})
# {
# $msg_pats{syncidx} = $buckets{$key};
# }
$buckets{$b_key} = ($buckets{$b_key} + $patternListRaw{$key}) /2;
#print"\t recalc to ". $buckets{$b_key}."\n";
delete ($patternListRaw{$key}); # deletes the compressed entry
$intol=1;
last;
}
}
if ($intol == 0) {
$buckets{$key}=$patternListRaw{$key};
}
}
return ($cnt,$rawData, %patternListRaw);
#print "rdata: ".$msg_parts{rawData}."\n";
#print Dumper (%buckets);
#print Dumper (%msg_parts);
#modify msg_parts pattern hash
#$patternListRaw = \%buckets;
}
################################################
# the new Log with integrated loglevel checking
sub SIGNALduino_Log3($$$)
{
my ($dev, $loglevel, $text) = @_;
my $name =$dev;
$name= $dev->{NAME} if(defined($dev) && ref($dev) eq "HASH");
if (AttrVal($name,"eventlogging",0)) {
DoTrigger($dev,"$name $loglevel: $text");
}
return Log3($name,$loglevel,$text);
}
################################################
# Helper to get a reference of the protocolList Hash
sub SIGNALduino_getProtocolList()
{
return \%ProtocolListSIGNALduino
}
sub SIGNALduino_FW_getProtocolList
{
my $name = shift;
my $hash = $defs{$name};
my $id;
my $ret;
my $devText = "";
my $blackTxt = "";
my %BlacklistIDs;
my @IdList = ();
my $comment;
my $blacklist = AttrVal($name,"blacklist_IDs","");
if (length($blacklist) > 0) { # Blacklist in Hash wandeln
#SIGNALduino_Log3 $name, 5, "$name getProtocolList: attr blacklistIds=$blacklist";
%BlacklistIDs = map { $_ => 1 } split(",", $blacklist);;
}
my $whitelist = AttrVal($name,"whitelist_IDs","#");
if (AttrVal($name,"blacklist_IDs","") ne "") { # wenn es eine blacklist gibt, dann "." an die Ueberschrift anhaengen
$blackTxt = ".";
}
my ($develop,$devFlag) = SIGNALduino_getAttrDevelopment($name); # $devFlag = 1 -> alle developIDs y aktivieren
$devText = "development version - " if ($devFlag == 1);
my %activeIdHash;
@activeIdHash{@{$hash->{msIdList}}, @{$hash->{muIdList}}, @{$hash->{mcIdList}}} = (undef);
#SIGNALduino_Log3 $name,4, "$name IdList: $mIdList";
my %IDsNoDispatch;
if (defined($hash->{IDsNoDispatch})) {
%IDsNoDispatch = map { $_ => 1 } split(",", $hash->{IDsNoDispatch});
#SIGNALduino_Log3 $name,4, "$name IdList IDsNoDispatch=" . join ', ' => map "$_" => keys %IDsNoDispatch;
}
foreach $id (keys %ProtocolListSIGNALduino)
{
push (@IdList, $id);
}
@IdList = sort { $a <=> $b } @IdList;
$ret = "
";
$ret .="
$devText";
if (substr($whitelist,0,1) ne "#") {
$ret .="whitelist active$blackTxt
";
}
else {
$ret .="whitelist not active (save activate it)$blackTxt";
}
$ret .= "
act.
dev
ID
Msg Type
modulname
protocolname
# comment
";
$ret .="";
my $oddeven="odd";
my $checked;
my $checkAll;
foreach $id (@IdList)
{
my $msgtype = "";
my $chkbox;
if (exists ($ProtocolListSIGNALduino{$id}{format}) && $ProtocolListSIGNALduino{$id}{format} eq "manchester")
{
$msgtype = "MC";
}
elsif (exists $ProtocolListSIGNALduino{$id}{sync})
{
$msgtype = "MS";
}
elsif (exists ($ProtocolListSIGNALduino{$id}{clockabs}))
{
$msgtype = "MU";
}
$checked="";
if (substr($whitelist,0,1) ne "#") { # whitelist aktiv, dann ermitteln welche ids bei select all nicht checked sein sollen
$checkAll = "SDcheck";
if (exists($BlacklistIDs{$id})) {
$checkAll = "SDnotCheck";
}
elsif (exists($ProtocolListSIGNALduino{$id}{developId})) {
if ($devFlag == 1 && $ProtocolListSIGNALduino{$id}{developId} eq "p") {
$checkAll = "SDnotCheck";
}
elsif ($devFlag == 0 && $ProtocolListSIGNALduino{$id}{developId} eq "y" && $develop !~ m/y$id/) {
$checkAll = "SDnotCheck";
}
elsif ($devFlag == 0 && $ProtocolListSIGNALduino{$id}{developId} eq "m") {
$checkAll = "SDnotCheck";
}
}
}
else {
$checkAll = "SDnotCheck";
}
if (exists($activeIdHash{$id}))
{
$checked="checked";
if (substr($whitelist,0,1) eq "#") { # whitelist nicht aktiv, dann entspricht select all dem $activeIdHash
$checkAll = "SDcheck";
}
}
if ($devFlag == 0 && exists($ProtocolListSIGNALduino{$id}{developId}) && $ProtocolListSIGNALduino{$id}{developId} eq "p") {
$chkbox="
";
}
else {
$chkbox=sprintf("", $checkAll, $id, $checked);
}
$comment = SIGNALduino_getProtoProp($id,"comment","");
if (exists($IDsNoDispatch{$id})) {
$comment .= " (dispatch is only with a active whitelist possible)";
}
$ret .= sprintf("
";
return $ret;
}
sub SIGNALduino_querygithubreleases
{
my ($hash) = @_;
my $name = $hash->{NAME};
my $param = {
url => "https://api.github.com/repos/RFD-FHEM/SIGNALDuino/releases",
timeout => 5,
hash => $hash, # Muss gesetzt werden, damit die Callback funktion wieder $hash hat
method => "GET", # Lesen von Inhalten
header => "User-Agent: perl_fhem\r\nAccept: application/json", # Den Header gemaess abzufragender Daten aendern
callback => \&SIGNALduino_githubParseHttpResponse, # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten
command => "queryReleases"
};
HttpUtils_NonblockingGet($param); # Starten der HTTP Abfrage. Es gibt keinen Return-Code.
}
#return -10 = hardeware attribute is not set
sub SIGNALduino_githubParseHttpResponse($$$)
{
my ($param, $err, $data) = @_;
my $hash = $param->{hash};
my $name = $hash->{NAME};
my $hardware=AttrVal($name,"hardware",undef);
if($err ne "") # wenn ein Fehler bei der HTTP Abfrage aufgetreten ist
{
Log3 $name, 3, "error while requesting ".$param->{url}." - $err (command: $param->{command}"; # Eintrag fuers Log
#readingsSingleUpdate($hash, "fullResponse", "ERROR"); # Readings erzeugen
}
elsif($data ne "" && defined($hardware)) # wenn die Abfrage erfolgreich war ($data enthaelt die Ergebnisdaten des HTTP Aufrufes)
{
my $json_array = decode_json($data);
#print Dumper($json_array);
if ($param->{command} eq "queryReleases") {
#Log3 $name, 3, "url ".$param->{url}." returned: $data"; # Eintrag fuers Log
my $releaselist="";
if (ref($json_array) eq "ARRAY") {
foreach my $item( @$json_array ) {
next if (AttrVal($name,"updateChannelFW","stable") eq "stable" && $item->{prerelease});
#Debug " item = ".Dumper($item);
foreach my $asset (@{$item->{assets}})
{
next if ($asset->{name} !~ m/$hardware/i);
$releaselist.=$item->{tag_name}."," ;
last;
}
}
}
$releaselist =~ s/,$//;
$hash->{additionalSets}{flash} = $releaselist;
} elsif ($param->{command} eq "getReleaseByTag" && defined($hardware)) {
#Debug " json response = ".Dumper($json_array);
my @fwfiles;
foreach my $asset (@{$json_array->{assets}})
{
my %fileinfo;
if ( $asset->{name} =~ m/$hardware/i)
{
$fileinfo{filename} = $asset->{name};
$fileinfo{dlurl} = $asset->{browser_download_url};
$fileinfo{create_date} = $asset->{created_at};
#Debug " firmwarefiles = ".Dumper(@fwfiles);
push @fwfiles, \%fileinfo;
my $set_return = SIGNALduino_Set($hash,$name,"flash",$asset->{browser_download_url}); # $hash->{SetFn
if(defined($set_return))
{
SIGNALduino_Log3 $name, 3, "$name: Error while trying to download firmware: $set_return";
}
last;
}
}
}
} elsif (!defined($hardware)) {
SIGNALduino_Log3 $name, 5, "$name: SIGNALduino_githubParseHttpResponse hardware is not defined";
} # wenn
# Damit ist die Abfrage zuende.
# Evtl. einen InternalTimer neu schedulen
FW_directNotify("#FHEMWEB:$FW_wname", "location.reload('true')", "");
return 0;
}
1;
=pod
=item summary supports the same low-cost receiver for digital signals
=item summary_DE Unterstuetzt den gleichnamigen Low-Cost Empfaenger fuer digitale Signale
=begin html
SIGNALduino
The SIGNALduino ia based on an idea from mdorenka published at FHEM Forum. With the opensource firmware (see this link) it is capable to receive and send different protocols over different medias. Currently are 433Mhz protocols implemented.
The following device support is currently available:
Wireless switches
ITv1 & ITv3/Elro and other brands using pt2263 or arctech protocol--> uses IT.pm In the ITv1 protocol is used to sent a default ITclock from 250 and it may be necessary in the IT-Modul to define the attribute ITclock
ELV FS10 -> 10_FS10
ELV FS20 -> 10_FS20
Temperature / humidity sensors
PEARL NC7159, LogiLink WS0002,GT-WT-02,AURIOL,TCM97001, TCM27 and many more -> 14_CUL_TCM97001
Oregon Scientific v2 and v3 Sensors -> 41_OREGON.pm
Temperatur / humidity sensors suppored -> 14_SD_WS07
It is possible to attach more than one device in order to get better reception, fhem will filter out duplicate messages. See more at the global section with attribute dupTimeout
Note: this module require the Device::SerialPort or Win32::SerialPort module. It can currently only attatched via USB.
Define
define <name> SIGNALduino <device>
USB-connected devices (SIGNALduino):
<device> specifies the serial port to communicate with the SIGNALduino. The name of the serial-device depends on your distribution, under linux the cdc_acm kernel module is responsible, and usually a /dev/ttyACM0 or /dev/ttyUSB0 device will be created. If your distribution does not have a cdc_acm module, you can force usbserial to handle the SIGNALduino by the following command:
modprobe usbserial
vendor=0x03eb
product=0x204b
In this case the device is most probably /dev/ttyUSB0.
You can also specify a baudrate if the device name contains the @ character, e.g.: /dev/ttyACM0@57600
This is also the default baudrate.
It is recommended to specify the device via a name which does not change:
e.g. via by-id devicename: /dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0@57600
If the baudrate is "directio" (e.g.: /dev/ttyACM0@directio), then the perl module Device::SerialPort is not needed, and fhem opens the device with simple file io. This might work if the operating system uses sane defaults for the serial parameters, e.g. some Linux distributions and OSX.
Internals
IDsNoDispatch: Here are protocols entryls listed by their numeric id for which not communication to a logical module is enabled. To enable, look at the menu option Display protocollist.
versionmodule: This shows the version of the SIGNALduino FHEM module itself.
version: This shows the version of the SIGNALduino microcontroller.
Set
freq / bWidth / patable / rAmpl / sens
Only with CC1101 receiver.
Set the sduino frequency / bandwidth / PA table / receiver-amplitude / sensitivity
Use it with care, it may destroy your hardware and it even may be
illegal to do so. Note: The parameters used for RFR transmission are
not affected.
cc1101_freq sets both the reception and transmission frequency. Note: Although the CC1101 can be set to frequencies between 315 and 915 MHz, the antenna interface and the antenna is tuned for exactly one frequency. Default is 433.920 MHz (or 868.350 MHz). If not set, frequency from cc1101_frequency attribute will be set.
cc1101_bWidth can be set to values between 58 kHz and 812 kHz. Large values are susceptible to interference, but make possible to receive inaccurately calibrated transmitters. It affects tranmission too. Default is 325 kHz.
cc1101_patable change the PA table (power amplification for RF sending)
cc1101_rAmpl is receiver amplification, with values between 24 and 42 dB. Bigger values allow reception of weak signals. Default is 42.
cc1101_sens is the decision boundary between the on and off values, and it is 4, 8, 12 or 16 dB. Smaller values allow reception of less clear signals. Default is 4 dB.
close
Closes the connection to the device.
disableMessagetype
Allows you to disable the message processing for
messages with sync (syncedMS),
messages without a sync pulse (unsyncedMU)
manchester encoded messages (manchesterMC)
The new state will be saved into the eeprom of your arduino.
enableMessagetype
Allows you to enable the message processing for
messages with sync (syncedMS)
messages without a sync pulse (unsyncedMU)
manchester encoded messages (manchesterMC)
The new state will be saved into the eeprom of your arduino.
flash [hexFile|url]
The SIGNALduino needs the right firmware to be able to receive and deliver the sensor data to fhem. In addition to the way using the arduino IDE to flash the firmware into the SIGNALduino this provides a way to flash it directly from FHEM. You can specify a file on your fhem server or specify a url from which the firmware is downloaded There are some requirements:
avrdude must be installed on the host On a Raspberry PI this can be done with: sudo apt-get install avrdude
the hardware attribute must be set if using any other hardware as an Arduino nano This attribute defines the command, that gets sent to avrdude to flash the uC.
If you encounter a problem, look into the logfile
Example:
flash via Version Name: Versions are provided via get availableFirmware
flash via hexFile: set sduino flash ./FHEM/firmware/SIGNALduino_mega2560.hex
flash via url for Nano with CC1101: set sduino flash https://github.com/RFD-FHEM/SIGNALDuino/releases/download/3.3.1-RC7/SIGNALDuino_nanocc1101.hex
To activate the bootloader of the radino there are 2 variants.
1) modules that contain a BSL-button:
apply supply voltage
press & hold BSL- and RESET-Button
release RESET-button, release BSL-button
(repeat these steps if your radino doesn't enter bootloader mode right away.)
2) force bootloader:
pressing reset button twice
In bootloader mode, the radino gets a different USB ID.
If the bootloader is enabled, it signals with a flashing LED. Then you have 8 seconds to flash.
reset
This will do a reset of the usb port and normaly causes to reset the uC connected.
raw
Issue a SIGNALduino firmware command, without waiting data returned by
the SIGNALduino. See the SIGNALduino firmware code for details on SIGNALduino
commands. With this line, you can send almost any signal via a transmitter connected
To send some raw data look at these examples:
P#binarydata#R#C (#C is optional)
Example 1: set sduino raw SR;R=3;P0=500;P1=-9000;P2=-4000;P3=-2000;D=0302030 sends the data in raw mode 3 times repeated
Example 2: set sduino raw SM;R=3;P0=500;C=250;D=A4F7FDDE sends the data manchester encoded with a clock of 250uS
Example 3: set sduino raw SC;R=3;SR;P0=5000;SM;P0=500;C=250;D=A4F7FDDE sends a combined message of raw and manchester encoded repeated 3 times
sendMsg
This command will create the needed instructions for sending raw data via the signalduino. Insteaf of specifying the signaldata by your own you specify
a protocol and the bits you want to send. The command will generate the needed command, that the signalduino will send this.
It is also supported to specify the data in hex. prepend 0x in front of the data part.
Please note, that this command will work only for MU or MS protocols. You can't transmit manchester data this way.
Input args are:
P#binarydata#R#C (#C is optional)
Example binarydata: set sduino sendMsg P0#0101#R3#C500 Will generate the raw send command for the message 0101 with protocol 0 and instruct the arduino to send this three times and the clock is 500.
SR;R=3;P0=500;P1=-9000;P2=-4000;P3=-2000;D=03020302;
P#0xhexdata#R#C (#C is optional)
Example 0xhexdata: set sduino sendMsg P29#0xF7E#R4 Generates the raw send command with the hex message F7E with protocl id 29 . The message will be send four times.
SR;R=4;P0=-8360;P1=220;P2=-440;P3=-220;P4=440;D=01212121213421212121212134;
Get
availableFirmware
Retrieves available firmware versions from github and displays them in set flash command.
ccconf
Read some CUL radio-chip (cc1101) registers (frequency, bandwidth, etc.),
and display them in human readable form.
Only with cc1101 receiver.
ccpatable
read cc1101 PA table (power amplification for RF sending)
Only with cc1101 receiver.
ccreg
read cc1101 registers (99 reads all cc1101 registers)
Only with cc1101 receiver.
cmds
Depending on the firmware installed, SIGNALduinos have a different set of
possible commands. Please refer to the sourcecode of the firmware of your
SIGNALduino to interpret the response of this command. See also the raw-
command.
config
Displays the configuration of the SIGNALduino protocol category. | example: MS=1;MU=1;MC=1;Mred=0
freeram
Displays the free RAM.
ping
Check the communication with the SIGNALduino.
raw
Issue a SIGNALduino firmware command, and wait for one line of data returned by
the SIGNALduino. See the SIGNALduino firmware code for details on SIGNALduino
commands. With this line, you can send almost any signal via a transmitter connected
uptime
Displays information how long the SIGNALduino is running. A FHEM reboot resets the timer.
version
return the SIGNALduino firmware version
Attributes
addvaltrigger
Create triggers for additional device values. Right now these are RSSI, RAWMSG and DMSG.
blacklist_IDs
The blacklist works only if a whitelist not exist.
cc1101_frequency
Since the PA table values are frequency-dependent, at 868 MHz a value greater 800 required.
debug
This will bring the module in a very verbose debug output. Usefull to find new signals and verify if the demodulation works correctly.
development
The development attribute is only available in development version of this Module for backwart compatibility. Use the whitelistIDs Attribute instead. Setting this attribute to 1 will enable all protocols which are flagged with developID=Y.
To check which protocols are flagged, open via FHEM webinterface in the section "Information menu" the option "Display protocollist". Look at the column "dev" where the flags are noted.
doubleMsgCheck_IDs
This attribute allows it, to specify protocols which must be received two equal messages to call dispatch to the modules.
You can specify multiple IDs wih a colon : 0,3,7,12
eventlogging
With this attribute you can control if every logmessage is also provided as event. This allows to generate event for every log messages.
Set this to 0 and logmessages are only saved to the global fhem logfile if the loglevel is higher or equal to the verbose attribute.
Set this to 1 and every logmessages is also dispatched as event. This allows you to log the events in a seperate logfile.
flashCommand
This is the command, that is executed to performa the firmware flash. Do not edit, if you don't know what you are doing.
If the attribute not defined, it uses the default settings. If the user defines the attribute manually, the system uses the specifications!
It contains some place-holders that automatically get filled with the according values:
[BAUDRATE]
is the speed (e.g. 57600)
[PORT]
is the port the Signalduino is connectd to (e.g. /dev/ttyUSB0) and will be used from the defenition
[HEXFILE]
is the .hex file that shall get flashed. There are three options (applied in this order):
- passed in set flash as first argument
- taken from the hexFile attribute
- the default value defined in the module
[LOGFILE]
The logfile that collects information about the flash process. It gets displayed in FHEM after finishing the flash process
hardware
When using the flash command, you should specify what hardware you have connected to the usbport. Doing not, can cause failures of the device.
ESP_1M: ESP8266 with 1 MB flash and CC1101 receiver
ESP32: ESP32
nano: Arduino Nano 328 with cheap receiver
nanoCC1101: Arduino Nano 328 wirh CC110x receiver
miniculCC1101: Arduino pro Mini with CC110x receiver and cables as a minicul
promini: Arduino Pro Mini 328 with cheap receiver
radinoCC1101: Arduino compatible radino with cc1101 receiver
maxMuMsgRepeat
MU signals can contain multiple repeats of the same message. The results are all send to a logical module. You can limit the number of scanned repetitions. Defaukt is 4, so after found 4 repeats, the demoduation is aborted.
minsecs
This is a very special attribute. It is provided to other modules. minsecs should act like a threshold. All logic must be done in the logical module.
If specified, then supported modules will discard new messages if minsecs isn't past.
noMsgVerbose
With this attribute you can control the logging of debug messages from the io device.
If set to 3, this messages are logged if global verbose is set to 3 or higher.
longids
Comma separated list of device-types for SIGNALduino that should be handled using long IDs. This additional ID allows it to differentiate some weather sensors, if they are sending on the same channel. Therfor a random generated id is added. If you choose to use longids, then you'll have to define a different device after battery change.
Default is to not to use long IDs for all devices.
Examples:
# Do not use any long IDs for any devices:
attr sduino longids 0
# Use any long IDs for all devices (this is default):
attr sduino longids 1
# Use longids for BTHR918N devices.
# Will generate devices names like BTHR918N_f3.
attr sduino longids BTHR918N
rawmsgEvent
When set to "1" received raw messages triggers events
suppressDeviceRawmsg
When set to 1, the internal "RAWMSG" will not be updated with the received messages
updateChannelFW
The module can search for new firmware versions (SIGNALDuino and SIGNALESP). Depending on your choice, only stable versions are displayed or also prereleases are available for flash. The option testing does also provide the stable ones.
stable: only versions marked as stable are available. These releases are provided very infrequently
testing: These versions needs some verifications and are provided in shorter intervals
Reload the available Firmware via get availableFirmware manually.
whitelist_IDs
This attribute allows it, to specify whichs protocos are considured from this module. Protocols which are not considured, will not generate logmessages or events. They are then completly ignored. This makes it possible to lower ressource usage and give some better clearnes in the logs. You can specify multiple whitelistIDs wih a colon : 0,3,7,12 With a # at the beginnging whitelistIDs can be deactivated.
Not using this attribute or deactivate it, will process all stable protocol entrys. Protocols which are under development, must be activated explicit via this Attribute.
WS09_CRCAUS
0: CRC-Check WH1080 CRC = 0 on, default
2: CRC = 49 (x031) WH1080, set OK
Information menu
Display protocollist
Shows the current implemented protocols from the SIGNALduino and to what logical FHEM Modul data is sent.
Additional there is an checkbox symbol, which shows you if a protocol will be processed. This changes the Attribute whitlistIDs for you in the background. The attributes whitelistIDs and blacklistIDs affects this state.
Protocols which are flagged in the row dev, are under development
If a row is flagged via 'm', then the logical module which provides you with an interface is still under development. Per default, these protocols will not send data to logcial module. To allow communication to a logical module you have to enable the protocol.
If a row is flagged via 'p', then this protocol entry is reserved or in early development state.
If a row is flalged via 'y' then this protocol isn't fully tested or reviewed.
If you are using blacklistIDs, then you also can not activate them via the button, delete the attribute blacklistIDs if you want to control enabled protocols via this menu.
=end html
=begin html_DE
SIGNALduino
Der SIGNALduino ist basierend auf einer Idee von "mdorenka" und veröffentlicht im FHEM Forum.
Mit der OpenSource-Firmware (SIGNALDuino und SIGNALESP) ist dieser fähig zum Empfangen und Senden verschiedener Protokolle auf 433 und 868 Mhz.
Folgende Geräte werden zur Zeit unterstützt:
Funk-Schalter
ITv1 & ITv3/Elro und andere Marken mit dem pt2263-Chip oder welche das arctech Protokoll nutzen --> IT.pm Das ITv1 Protokoll benutzt einen Standard ITclock von 250 und es kann vorkommen, das in dem IT-Modul das Attribut "ITclock" zu setzen ist.
ELV FS10 -> 10_FS10
ELV FS20 -> 10_FS20
Temperatur-, Luftfeuchtigkeits-, Luftdruck-, Helligkeits-, Regen- und Windsensoren:
PEARL NC7159, LogiLink WS0002,GT-WT-02,AURIOL,TCM97001, TCM27 und viele anderen -> 14_CUL_TCM97001.pm
Oregon Scientific v2 und v3 Sensoren -> 41_OREGON.pm
Temperatur / Feuchtigkeits Sensoren unterstützt -> 14_SD_WS07.pm
Es ist möglich, mehr als ein Gerät anzuschließen, um beispielsweise besseren Empfang zu erhalten. FHEM wird doppelte Nachrichten herausfiltern.
Mehr dazu im dem global Abschnitt unter dem Attribut dupTimeout
Hinweis: Dieses Modul erfordert das Device::SerialPort oder Win32::SerialPort
Modul. Es kann derzeit nur über USB angeschlossen werden.
<device> spezifiziert den seriellen Port für die Kommunikation mit dem SIGNALduino.
Der Name des seriellen Geräts hängt von Ihrer Distribution ab. In Linux ist das cdc_acm Kernel_Modul dafür verantwortlich und es wird ein /dev/ttyACM0 oder /dev/ttyUSB0 Gerät angelegt. Wenn deine Distribution kein cdc_acm Module besitzt, kannst du usbserial nutzen um den SIGNALduino zu betreiben mit folgenden Kommandos:
modprobe usbserial
vendor=0x03eb
product=0x204b
In diesem Fall ist das Gerät höchstwahrscheinlich /dev/ttyUSB0.
Sie können auch eine Baudrate angeben, wenn der Gerätename das @ enthält, Beispiel: /dev/ttyACM0@57600 Dies ist auch die Standard-Baudrate.
Es wird empfohlen, das Gerät über einen Namen anzugeben, der sich nicht ändert. Beispiel via by-id devicename: /dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0@57600
Wenn die Baudrate "directio" (Bsp: /dev/ttyACM0@directio), dann benutzt das Perl Modul nicht Device::SerialPort und FHEM öffnet das Gerät mit einem file io. Dies kann funktionieren, wenn das Betriebssystem die Standardwerte für die seriellen Parameter verwendet. Bsp: einige Linux Distributionen und
OSX.
Internals
IDsNoDispatch: Hier werden protokoll Einträge mit ihrer numerischen ID aufgelistet, för welche keine Weitergabe von Daten an logische Module aktiviert wurde. Um die weiterhabe zu aktivieren, kann die Meüoption Display protocollist verwendet werden.
versionmodule: Hier wird die Version des SIGNALduino FHEM Modules selbst angezeigt.
version: Hier wird die Version des SIGNALduino microcontrollers angezeigt.
SET
cc1101_freq / cc1101_bWidth / cc1101_patable / cc1101_rAmpl / cc1101_sens
(NUR bei Verwendung eines cc110x Funk-Moduls)
Stellt die SIGNALduino-Frequenz / Bandbreite / PA-Tabelle / Empfänger-Amplitude / Empfindlichkeit ein.
Verwenden Sie es mit Vorsicht. Es kann Ihre Hardware zerstören und es kann sogar illegal sein, dies zu tun.
Hinweis: Die für die RFR-Übertragung verwendeten Parameter sind nicht betroffen.
cc1101_freq , legt sowohl die Empfangsfrequenz als auch die Übertragungsfrequenz fest.
Hinweis: Obwohl der CC1101 auf Frequenzen zwischen 315 und 915 MHz eingestellt werden kann, ist die Antennenschnittstelle und die Antenne auf genau eine Frequenz abgestimmt. Standard ist 433.920 MHz (oder 868.350 MHz). Wenn keine Frequenz angegeben wird, dann wird die Frequenz aus dem Attribut cc1101_frequency geholt.
cc1101_bWidth , kann auf Werte zwischen 58 kHz und 812 kHz eingestellt werden. Große Werte sind störanfällig, ermöglichen jedoch den Empfang von ungenau kalibrierten Sendern. Es wirkt sich auch auf die Übertragung aus. Standard ist 325 kHz.
cc1101_patable , Änderung der PA-Tabelle (Leistungsverstärkung für HF-Senden)
cc1101_rAmpl , ist die Empfängerverstärkung mit Werten zwischen 24 und 42 dB. Größere Werte erlauben den Empfang schwacher Signale. Der Standardwert ist 42.
cc1101_sens , ist die Entscheidungsgrenze zwischen den Ein- und Aus-Werten und beträgt 4, 8, 12 oder 16 dB. Kleinere Werte erlauben den Empfang von weniger klaren Signalen. Standard ist 4 dB.
close
Beendet die Verbindung zum Gerät.
enableMessagetype
Ermöglicht die Aktivierung der Nachrichtenverarbeitung für
Nachrichten mit sync (syncedMS),
Nachrichten ohne einen sync pulse (unsyncedMU)
Manchester codierte Nachrichten (manchesterMC)
Der neue Status wird in den eeprom vom Arduino geschrieben.
disableMessagetype
Ermöglicht das Deaktivieren der Nachrichtenverarbeitung für
Nachrichten mit sync (syncedMS)
Nachrichten ohne einen sync pulse (unsyncedMU)
Manchester codierte Nachrichten (manchesterMC)
Der neue Status wird in den eeprom vom Arduino geschrieben.
flash [hexFile|url]
Der SIGNALduino benötigt die richtige Firmware, um die Sensordaten zu empfangen und zu liefern. Unter Verwendung der Arduino IDE zum Flashen der Firmware in den SIGNALduino bietet dies eine Möglichkeit, ihn direkt von FHEM aus zu flashen. Sie können eine Datei auf Ihrem fhem-Server angeben oder eine URL angeben, von der die Firmware heruntergeladen wird. Es gibt einige Anforderungen:
avrdude muss auf dem Host installiert sein. Auf einem Raspberry PI kann dies getan werden mit: sudo apt-get install avrdude
Das Hardware-Attribut muss festgelegt werden, wenn eine andere Hardware als Arduino Nano verwendet wird. Dieses Attribut definiert den Befehl, der an avrdude gesendet wird, um den uC zu flashen.
Bei Problem mit dem Flashen, können im Logfile interessante Informationen zu finden sein.
Beispiele:
flash mittels Versionsnummer: Versionen können mit get availableFirmware abgerufen werden
flash via hexFile: set sduino flash ./FHEM/firmware/SIGNALduino_mega2560.hex
flash via url für einen Nano mit CC1101: set sduino flash https://github.com/RFD-FHEM/SIGNALDuino/releases/download/3.3.1-RC7/SIGNALDuino_nanocc1101.hex
Um den Bootloader vom radino zu aktivieren gibt es 2 Varianten.
1) Module welche einen BSL-Button besitzen:
Spannung anlegen
druecke & halte BSL- und RESET-Button
RESET-Button loslassen und danach den BSL-Button loslassen
(Wiederholen Sie diese Schritte, wenn Ihr radino nicht sofort in den Bootloader-Modus wechselt.)
2) Bootloader erzwingen:
durch zweimaliges druecken der Reset-Taste
Im Bootloader-Modus erhält der radino eine andere USB ID.
Wenn der Bootloader aktiviert ist, signalisiert er das mit dem Blinken einer LED. Dann hat man ca. 8 Sekunden Zeit zum flashen.
raw
Geben Sie einen SIGNALduino-Firmware-Befehl aus, ohne auf die vom SIGNALduino zurückgegebenen Daten zu warten. Ausführliche Informationen zu SIGNALduino-Befehlen finden Sie im SIGNALduino-Firmware-Code. Mit dieser Linie können Sie fast jedes Signal über einen angeschlossenen Sender senden.
Um einige Rohdaten zu senden, schauen Sie sich diese Beispiele an: P#binarydata#R#C (#C is optional)
Beispiel 1: set sduino raw SR;R=3;P0=500;P1=-9000;P2=-4000;P3=-2000;D=0302030 , sendet die Daten im Raw-Modus dreimal wiederholt
Beispiel 2: set sduino raw SM;R=3;P0=500;C=250;D=A4F7FDDE , sendet die Daten Manchester codiert mit einem clock von 250µS
Beispiel 3: set sduino raw SC;R=3;SR;P0=5000;SM;P0=500;C=250;D=A4F7FDDE , sendet eine kombinierte Nachricht von Raw und Manchester codiert 3 mal wiederholt
NUR für DEBUG Nutzung | Befehle sind abhaenging vom Firmwarestand!
(Hinweis: Die falsche Benutzung kann zu Fehlfunktionen des SIGNALduino´s führen!)
CED -> Debugausgaben ein
CDD -> Debugausgaben aus
CDL -> LED aus
CEL -> LED ein
CER -> Einschalten der Datenkomprimierung (config: Mred=1)
CDR -> Abschalten der Datenkomprimierung (config: Mred=0)
CSmscnt=[Wert] -> Wiederholungszaehler fuer den split von MS Nachrichten
CSmuthresh=[Wert] -> Schwellwert fuer den split von MU Nachrichten (0=aus)
CSmcmbl=[Wert] -> minbitlen fuer MC-Nachrichten
CSfifolimit=[Wert] -> Schwellwert fuer debug Ausgabe der Pulsanzahl im FIFO Puffer
reset
Öffnet die Verbindung zum Gerät neu und initialisiert es.
sendMsg
Dieser Befehl erstellt die erforderlichen Anweisungen zum Senden von Rohdaten über den SIGNALduino. Sie können die Signaldaten wie Protokoll und die Bits angeben, die Sie senden möchten.
Alternativ ist es auch moeglich, die zu sendenden Daten in hexadezimaler Form zu uebergeben. Dazu muss ein 0x vor den Datenteil geschrieben werden.
Bitte beachte, dieses Kommando funktioniert nur fuer MU oder MS Protokolle nach dieser Vorgehensweise:
Argumente sind:
P#binarydata#R#C (#C is optional)
Beispiel binarydata: set sduino sendMsg P0#0101#R3#C500 Wird eine sende Kommando fuer die Bitfolge 0101 anhand der protocol id 0 erzeugen. Als Takt wird 500 verwendet.
SR;R=3;P0=500;P1=-9000;P2=-4000;P3=-2000;D=03020302;
P#0xhexdata#R#C (#C is optional)
Beispiel 0xhexdata: set sduino sendMsg P29#0xF7E#R4 Wird eine sende Kommando fuer die Hexfolge F7E anhand der protocol id 29 erzeugen. Die Nachricht soll 4x gesenset werden.
SR;R=4;P0=-8360;P1=220;P2=-440;P3=-220;P4=440;D=01212121213421212121212134;
Get
availableFirmware
Ruft die verfügbaren Firmware-Versionen von Github ab und macht diese im set flash Befehl auswählbar.
ccconf
Liest sämtliche radio-chip (cc1101) Register (Frequenz, Bandbreite, etc.) aus und zeigt die aktuelle Konfiguration an.
(NUR bei Verwendung eines cc1101 Empfänger)
ccpatable
Liest die cc1101 PA Tabelle aus (power amplification for RF sending).
(NUR bei Verwendung eines cc1101 Empfänger)
ccreg
Liest das cc1101 Register aus (99 liest alle aus).
(NUR bei Verwendung eines cc1101 Empfänger)
close
Beendet die Verbindung zum SIGNALduino.
cmds
Abhängig von der installierten Firmware besitzt der SIGNALduino verschiedene Befehle. Bitte beachten Sie den Quellcode der Firmware Ihres SIGNALduino, um die Antwort dieses Befehls zu interpretieren.
config
Zeigt Ihnen die aktuelle Konfiguration der SIGNALduino Protokollkathegorie an. | Bsp: MS=1;MU=1;MC=1;Mred=0
freeram
Zeigt den freien RAM an.
ping
Prüft die Kommunikation mit dem SIGNALduino.
raw
Abhängig von der installierten Firmware! Somit können Sie einen SIGNALduino-Firmware-Befehl direkt ausführen.
uptime
Zeigt Ihnen die Information an, wie lange der SIGNALduino läuft. Ein FHEM Neustart setzt den Timer zurück.
version
Zeigt Ihnen die Information an, welche aktuell genutzte Software Sie mit dem SIGNALduino verwenden.
Attributes
addvaltrigger
Generiert Trigger für zusätzliche Werte. Momentan werden DMSG , RAWMSG und RSSI unterstüzt.
blacklist_IDs
Dies ist eine durch Komma getrennte Liste. Die Blacklist funktioniert nur, wenn keine Whitelist existiert! Hier kann man ID´s eintragen welche man nicht ausgewertet haben möchte.
cc1101_frequency
Frequenzeinstellung des cc1101. | Bsp: 433.920 / 868.350
debug
Dies bringt das Modul in eine sehr ausführliche Debug-Ausgabe im Logfile. Somit lassen sich neue Signale finden und Signale überprüfen, ob die Demodulation korrekt funktioniert.
development
development
Das development Attribut ist nur in den Entwicklungsversionen des FHEM Modules aus Grüden der Abwärtskompatibilität vorhanden. Bei Setzen des Attributes auf "1" werden alle Protokolle aktiviert, welche mittels developID=y markiert sind.
Wird das Attribut auf 1 gesetzt, so werden alle in Protokolle die mit dem developID Flag "y" markiert sind aktiviert. Die Flags (Spalte dev) können über das Webfrontend im Abschnitt "Information menu" mittels "Display protocollist" eingesehen werden.
doubleMsgCheck_IDs
Dieses Attribut erlaubt es, Protokolle anzugeben, die zwei gleiche Nachrichten enthalten müssen, um diese an die Module zu übergeben. Sie können mehrere IDs mit einem Komma angeben: 0,3,7,12
flashCommand
Dies ist der Befehl, der ausgeführt wird, um den Firmware-Flash auszuführen. Nutzen Sie dies nicht, wenn Sie nicht wissen, was Sie tun!
Wurde das Attribut nicht definiert, so verwendet es die Standardeinstellungen. Sobald der User das Attribut manuell definiert, nutzt das System diese Vorgaben!
nanoCC1101: Arduino Nano für einen CC110x-Empfänger
miniculCC1101: Arduino pro Mini mit einen CC110x-Empfänger entsprechend dem minicul verkabelt
promini: Arduino Pro Mini 328 für "Billig"-Empfänger
radinoCC1101: Ein Arduino Kompatibler Radino mit cc1101 receiver
Notwendig für den Befehl flash. Hier sollten Sie angeben, welche Hardware Sie mit dem usbport verbunden haben. Andernfalls kann es zu Fehlfunktionen des Geräts kommen. Wichtig ist auch das Attribut updateChannelFW
longids
Durch Komma getrennte Liste von Device-Typen für Empfang von langen IDs mit dem SIGNALduino. Diese zusätzliche ID erlaubt es Wettersensoren, welche auf dem gleichen Kanal senden zu unterscheiden. Hierzu wird eine zufällig generierte ID hinzugefügt. Wenn Sie longids verwenden, dann wird in den meisten Fällen nach einem Batteriewechsel ein neuer Sensor angelegt. Standardmäßig werden keine langen IDs verwendet.
Folgende Module verwenden diese Funktionalität: 14_Hideki, 41_OREGON, 14_CUL_TCM97001, 14_SD_WS07.
Beispiele:
# Keine langen IDs verwenden (Default Einstellung):
attr sduino longids 0
# Immer lange IDs verwenden:
attr sduino longids 1
# Verwende lange IDs für SD_WS07 Devices.
# Device Namen sehen z.B. so aus: SD_WS07_TH_3.
attr sduino longids SD_WS07
maxMuMsgRepeat
In MU Signalen können mehrere Wiederholungen stecken. Diese werden einzeln ausgewertet und an ein logisches Modul uebergeben. Mit diesem Attribut kann angepasst werden, wie viele Wiederholungen gesucht werden. Standard ist 4.
minsecs
Es wird von anderen Modulen bereitgestellt. Minsecs sollte wie eine Schwelle wirken. Wenn angegeben, werden unterstützte Module neue Nachrichten verworfen, wenn minsecs nicht vergangen sind.
noMsgVerbose
Mit diesem Attribut können Sie die Protokollierung von Debug-Nachrichten vom io-Gerät steuern. Wenn dieser Wert auf 3 festgelegt ist, werden diese Nachrichten protokolliert, wenn der globale Verbose auf 3 oder höher eingestellt ist.
eventlogging
Mit diesem Attribut können Sie steuern, ob jede Logmeldung auch als Ereignis bereitgestellt wird. Dies ermöglicht das Erzeugen eines Ereignisses fuer jede Protokollnachricht.
Setze dies auf 0 und Logmeldungen werden nur in der globalen Fhem-Logdatei gespeichert, wenn der Loglevel höher oder gleich dem Verbose-Attribut ist.
Setze dies auf 1 und jede Logmeldung wird auch als Ereignis versendet. Dadurch können Sie die Ereignisse in einer separaten Protokolldatei protokollieren.
rawmsgEvent
Bei der Einstellung "1", lösen empfangene Rohnachrichten Ereignisse aus.
suppressDeviceRawmsg
Bei der Einstellung "1" wird das interne "RAWMSG" nicht mit den empfangenen Nachrichten aktualisiert.
updateChannelFW
Das Modul sucht nach Verfügbaren Firmware Versionen (GitHub) und bietet diese via dem Befehl flash zum Flashen an. Mit dem Attribut kann festgelegt werden, ob nur stabile Versionen ("Latest Release") angezeigt werden oder auch Vorabversionen ("Pre-release") einer neuen Firmware.
Die Option testing inkludiert auch die stabilen Versionen.
stable: Als stabil getestete Versionen, erscheint nur sehr selten
testing: Neue Versionen, welche noch getestet werden muss
Die Liste der verfügbaren Versionen muss manuell mittels get availableFirmware neu geladen werden.
Notwendig für den Befehl flash. Hier sollten Sie angeben, welche Hardware Sie mit dem USB-Port verbunden haben. Andernfalls kann es zu Fehlfunktionen des Geräts kommen.
whitelist_IDs
Dieses Attribut erlaubt es, festzulegen, welche Protokolle von diesem Modul aus verwendet werden. Protokolle, die nicht beachtet werden, erzeugen keine Logmeldungen oder Ereignisse. Sie werden dann vollständig ignoriert. Dies ermöglicht es, die Ressourcennutzung zu reduzieren und bessere Klarheit in den Protokollen zu erzielen. Sie können mehrere WhitelistIDs mit einem Komma angeben: 0,3,7,12. Mit einer # am Anfang können WhitelistIDs deaktiviert werden.
Wird dieses Attribut nicht verwrndet oder deaktiviert, werden alle stabilen Protokolleinträge verarbeitet. Protokolleinträge, welche sich noch in Entwicklung befinden müssen explizit über dieses Attribut aktiviert werden.
WS09_CRCAUS
0: CRC-Check WH1080 CRC = 0 on, Standard
2: CRC = 49 (x031) WH1080, set OK
Information menu
Display protocollist
Zeigt Ihnen die aktuell implementierten Protokolle des SIGNALduino an und an welches logische FHEM Modul Sie übergeben werden.
Außerdem wird mit checkbox Symbolen angezeigt ob ein Protokoll verarbeitet wird. Durch Klick auf das Symbol, wird im Hintergrund das Attribut whitlelistIDs angepasst. Die Attribute whitelistIDs und blacklistIDs beeinflussen den dargestellten Status.
Protokolle die in der Spalte dev markiert sind, befinden sich in Entwicklung.
Wemm eine Zeile mit 'm' markiert ist, befindet sich das logische Modul, welches eine Schnittstelle bereitstellt in Entwicklung. Im Standard übergeben diese Protokolle keine Daten an logische Module. Um die Kommunikation zu ermöglichenm muss der Protokolleintrag aktiviert werden.
Wemm eine Zeile mit 'p' markiert ist, wurde der Protokolleintrag reserviert oder befindet sich in einem frühen Entwicklungsstadium.
Wemm eine Zeile mit 'y' markiert ist, wurde das Protkokoll noch nicht ausgiebig getestet und überprüft.
Protokolle, welche in dem blacklistIDs Attribut eingetragen sind, können nicht über das Menü aktiviert werden. Dazu bitte das Attribut blacklistIDs entfernen.