2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 09:16:53 +00:00

00_SIGNALduino.pm: Updated to 3.3.1 (serval fixes and improvements)

git-svn-id: https://svn.fhem.de/fhem/trunk@13215 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
sidey79 2017-01-23 20:09:44 +00:00
parent 67a94658aa
commit 44d6bebff7
4 changed files with 414 additions and 98 deletions

View File

@ -1,5 +1,12 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
- changed: 00_SIGNALduino.pm: version 3.3.1
needs less cpu time for parsing messages
new command to query protocolids
improve send queue: Send not before response of previous
warnings and some errors fixed
compatibel with last changes from IT module
-changed: 14_SD_WS.pm: new sensor bresser temeo supported
- new: 98_QRCode.pm: Creating QRCodes for various purposes.
QRCodes ar generated by a web service.
- bugfix: 98_DOIFtools.pm: fixed Error: >name< has no TYPE, but following

View File

@ -1,14 +1,14 @@
##############################################
# $Id$
#
# v3.3.0 (Development release 3.3)
# v3.3.1 (release 3.3)
# The module is inspired by the FHEMduino project and modified in serval ways for processing the incomming messages
# see http://www.fhemwiki.de/wiki/SIGNALDuino
# It was modified also to provide support for raw message handling which can be send from the SIGNALduino
# The purpos is to use it as addition to the SIGNALduino which runs on an arduno nano or arduino uno.
# It routes Messages serval Modules which are already integrated in FHEM. But there are also modules which comes with it.
# N. Butzek, S. Butzek, 2014-2015
# S.Butzek 2016
# S.Butzek,Ralf9 2016-2017
package main;
@ -18,19 +18,22 @@ use warnings;
use Time::HiRes qw(gettimeofday);
use Data::Dumper qw(Dumper);
use Scalar::Util qw(looks_like_number);
no warnings 'portable';
#use POSIX qw( floor); # can be removed
#use Math::Round qw();
use constant {
SDUINO_INIT_WAIT_XQ => 1.5, # wait disable device
SDUINO_VERSION => "v3.3.1",
SDUINO_INIT_WAIT_XQ => 1.5, # wait disable device
SDUINO_INIT_WAIT => 2,
SDUINO_INIT_MAXRETRY => 3,
SDUINO_CMD_TIMEOUT => 10,
SDUINO_KEEPALIVE_TIMEOUT => 60,
SDUINO_KEEPALIVE_MAXRETRY => 3,
SDUINO_WRITEQUEUE_NEXT => 0.3,
SDUINO_WRITEQUEUE_TIMEOUT => 2,
};
@ -55,6 +58,7 @@ my %gets = ( # Name, Data to send to the SIGNALduino, Regexp for the answer
"ITParms" => ["ip",'.*'],
"ping" => ["P",'^OK$'],
"config" => ["CG",'^MS.*MU.*MC.*'],
"protocolIDs" => ["none",'none'],
# "ITClock" => ["ic", '\d+'],
# "FAParms" => ["fp", '.*' ],
# "TCParms" => ["dp", '.*' ],
@ -84,13 +88,13 @@ my $clientsSIGNALduino = ":IT:"
."Hideki:"
."SD_WS07:"
."SD_WS09:"
." :" # Zeilenumbruch
."SD_WS:"
."RFXX10REC:"
."Dooya:"
."SOMFY:"
# ."SD_UT:" ## BELL 201.2 TXA
."SD_WS_Maverick:"
# ."BresserTemeo:"
."SIGNALduino_un:"
;
@ -105,13 +109,12 @@ my %matchListSIGNALduino = (
"7:Hideki" => "^P12#75[A-F0-9]+",
"10:SD_WS07" => "^P7#[A-Fa-f0-9]{6}F[A-Fa-f0-9]{2}",
"11:SD_WS09" => "^P9#[A-Fa-f0-9]+",
"12:SD_WS" => '^W\d+#.*',
"12:SD_WS" => '^W\d+x{0,1}#.*',
"13:RFXX10REC" => '^(20|29)[A-Fa-f0-9]+',
"14:Dooya" => '^P16#[A-Fa-f0-9]+',
"15:SOMFY" => '^YsA[0-9A-F]+',
"16:SD_WS_Maverick" => '^P47#[A-Fa-f0-9]+',
# "17:SD_UT" => '^u30#.*', ## BELL 201.2 TXA
# "44:BresserTemeo" => '^P44x{0,1}#[A-F0-9]{18}', # Bresser Temeo Trend (3CH Thermo-/Hygro)
"X:SIGNALduino_un" => '^[uP]\d+#.*',
);
@ -120,6 +123,7 @@ my %ProtocolListSIGNALduino = (
"0" =>
{
name => 'weather1', # Logilink, NC, WS, TCM97001 etc.
comment => 'Logilink, NC, WS, TCM97001 etc',
id => '0',
one => [1,-8],
zero => [1,-4],
@ -156,6 +160,7 @@ my %ProtocolListSIGNALduino = (
"2" =>
{
name => 'AS', # Self build arduino sensor
comment => 'Self build arduino sensor',
id => '2',
one => [1,-2],
zero => [1,-1],
@ -231,7 +236,7 @@ my %ProtocolListSIGNALduino = (
clockabs => 220, # -1 = auto
format => 'twostate', # tristate can't be migrated from bin into hex!
preamble => 'u6#', # Append to converted message
clientmodule => 'undef', # not used now
#clientmodule => '', # not used now
#modulematch => '^u......', # not used now
length_min => '24',
@ -239,6 +244,7 @@ my %ProtocolListSIGNALduino = (
"7" => ## weather sensors like EAS800z
{
name => 'weatherID7',
comment => 'EAS800z, FreeTec NC-7344',
id => '7',
one => [1,-4],
zero => [1,-2],
@ -246,7 +252,7 @@ my %ProtocolListSIGNALduino = (
clockabs => 484,
format => 'twostate',
preamble => 'P7#', # prepend to converted message
clientmodule => 'undef', # not used now
clientmodule => 'SD_WS07', # not used now
modulematch => '^P7#.{6}F.{2}', # not used now
length_min => '35',
length_max => '40',
@ -262,7 +268,7 @@ my %ProtocolListSIGNALduino = (
clockabs => 470, #
format => 'pwm', #
preamble => 'TX', # prepend to converted message
clientmodule => 'ittx', # not used now
clientmodule => 'CUL_TX', # not used now
modulematch => '^TX......', # not used now
length_min => '43',
length_max => '44',
@ -272,6 +278,7 @@ my %ProtocolListSIGNALduino = (
"9" => ## Funk Wetterstation CTW600
{
name => 'CTW 600',
comment => 'Funk Wetterstation CTW600',
id => '9',
zero => [3,-2],
one => [1,-2],
@ -280,7 +287,7 @@ my %ProtocolListSIGNALduino = (
clockabs => 480, # -1 = auto undef=noclock
format => 'pwm', # tristate can't be migrated from bin into hex!
preamble => 'P9#', # prepend to converted message
clientmodule => 'undef', # not used now
clientmodule => 'SD_WS09', # not used now
#modulematch => '^u9#.....', # not used now
length_min => '70',
length_max => '120',
@ -292,6 +299,7 @@ my %ProtocolListSIGNALduino = (
id => '10',
clockrange => [300,520], # min , max
format => 'manchester', # tristate can't be migrated from bin into hex!
clientmodule => 'OREGON',
modulematch => '^(3[8-9A-F]|[4-6][0-9A-F]|7[0-8]).*',
length_min => '64',
length_max => '220',
@ -305,7 +313,7 @@ my %ProtocolListSIGNALduino = (
clockrange => [380,425], # min , max
format => 'manchester', # tristate can't be migrated from bin into hex!
preamble => 'P2#', # prepend to converted message
#clientmodule => '14_SD_AS', # not used now
clientmodule => 'SD_AS', # not used now
modulematch => '^P2#.{7,8}',
length_min => '52',
length_max => '56',
@ -318,7 +326,7 @@ my %ProtocolListSIGNALduino = (
clockrange => [420,510], # min, max better for Bresser Sensors, OK for hideki/Hideki/TFA too
format => 'manchester',
preamble => 'P12#', # prepend to converted message
#clientmodule => '14_hideki', # not used now
clientmodule => 'hideki', # not used now
modulematch => '^P12#75.+', # not used now
length_min => '72',
length_max => '104',
@ -383,7 +391,7 @@ my %ProtocolListSIGNALduino = (
clockabs => 280,
format => 'twostate',
preamble => 'P16#', # prepend to converted message
#clientmodule => '', # not used now
clientmodule => 'Dooya', # not used now
#modulematch => '', # not used now
length_min => '39',
length_max => '40',
@ -655,7 +663,7 @@ my %ProtocolListSIGNALduino = (
format => 'twostate', # not used now
preamble => 'W33#', # prepend to converted message
postamble => '', # Append to converted message
clientmodule => '', # not used now
clientmodule => 'SD_WS', # not used now
#modulematch => '', # not used now
length_min => '42',
length_max => '44',
@ -671,7 +679,7 @@ my %ProtocolListSIGNALduino = (
format => 'twostate', # not used now
preamble => 'u34#', # prepend to converted message
postamble => '', # Append to converted message
clientmodule => '', # not used now
#clientmodule => '', # not used now
#modulematch => '', # not used now
length_min => '40',
length_max => '40',
@ -687,7 +695,7 @@ my %ProtocolListSIGNALduino = (
format => 'twostate', # not used now
preamble => 'u35#', # prepend to converted message
postamble => '', # Append to converted message
clientmodule => '', # not used now
#clientmodule => '', # not used now
#modulematch => '', # not used now
length_min => '28',
length_max => '32',
@ -703,7 +711,7 @@ my %ProtocolListSIGNALduino = (
format => 'twostate', # not used now
preamble => 'u36#', # prepend to converted message
postamble => '', # Append to converted message
clientmodule => '', # not used now
#clientmodule => '', # not used now
#modulematch => '', # not used now
length_min => '24',
length_max => '24',
@ -719,7 +727,7 @@ my %ProtocolListSIGNALduino = (
format => 'twostate', # not used now
preamble => 'W37#', # prepend to converted message
postamble => '', # Append to converted message
clientmodule => '', # not used now
clientmodule => 'SD_WS', # not used now
#modulematch => '', # not used now
length_min => '40',
length_max => '44',
@ -770,20 +778,21 @@ my %ProtocolListSIGNALduino = (
start => [1,-2],
clockabs => 250,
preamble => 'u40#', # prepend to converted message
clientmodule => '', # not used now
#clientmodule => '', # not used now
#modulematch => '', # not used now
length_min => '10',
},
"41" => ## Elro (Smartwares) Doorbell DB200
{
name => 'elro doorbell',
comment => 'Elro (Smartwares) Doorbell DB200',
id => '41',
zero => [1,-3],
one => [3,-1],
sync => [1,-15],
clockabs => 450,
preamble => 'u41#', # prepend to converted message
clientmodule => '', # not used now
#clientmodule => '', # not used now
#modulematch => '', # not used now
length_min => '20',
},
@ -796,7 +805,7 @@ my %ProtocolListSIGNALduino = (
start => [-28],
clockabs => 550,
preamble => 'u42#', # prepend to converted message
clientmodule => '', # not used now
#clientmodule => '', # not used now
#modulematch => '',
length_min => '24',
},
@ -807,7 +816,7 @@ my %ProtocolListSIGNALduino = (
clockrange => [610,670], # min , max
format => 'manchester',
preamble => 'Ys',
#clientmodule => '', # not used now
clientmodule => 'SOMFY', # not used now
modulematch => '^YsA[0-9A-F]{13}',
length_min => '56',
length_max => '56',
@ -823,8 +832,9 @@ my %ProtocolListSIGNALduino = (
zero => [4,-4],
one => [4,-8],
start => [8,-8],
preamble => 'P44#',
clientmodule => 'BresserTemeo',
preamble => 'W44#',
clientmodule => 'SD_WS',
modulematch => '^W44#[A-F0-9]{18}',
length_min => '64',
length_max => '72',
},
@ -836,8 +846,9 @@ my %ProtocolListSIGNALduino = (
zero => [4,-4],
one => [4,-8],
start => [8,-12],
preamble => 'P44x#',
clientmodule => 'BresserTemeo',
preamble => 'W44x#',
clientmodule => 'SD_WS',
modulematch => '^W44x#[A-F0-9]{18}',
length_min => '64',
length_max => '72',
},
@ -866,7 +877,7 @@ my %ProtocolListSIGNALduino = (
clockabs => 250, # -1=auto
format => 'twostate', # not used now
preamble => 'u46#',
clientmodule => '', # not used now
#clientmodule => '', # not used now
#modulematch => '', # not used now
length_min => '16',
length_max => '18',
@ -879,7 +890,7 @@ my %ProtocolListSIGNALduino = (
clockrange => [220,260],
format => 'manchester',
preamble => 'P47#', # prepend to converted message
#clientmodule => '', # not used now
clientmodule => 'SD_WS_Maverick', # not used now
modulematch => '^P47#.*', # not used now
length_min => '100',
length_max => '108',
@ -925,7 +936,7 @@ my %ProtocolListSIGNALduino = (
# start => [1,-25], # Wenn das startsignal empfangen wird, fehlt das 1 bit
format => 'twostate',
preamble => 'W50#', # prepend to converted message
#clientmodule => '', # not used now
clientmodule => 'SD_WS', # not used now
modulematch => '^W50#.*', # not used now
length_min => '47',
length_max => '48',
@ -1104,6 +1115,7 @@ sub
SIGNALduino_Shutdown($)
{
my ($hash) = @_;
#DevIo_SimpleWrite($hash, "XQ\n",2);
SIGNALduino_SimpleWrite($hash, "XQ"); # Switch reception off, it may hang up the SIGNALduino
return undef;
}
@ -1279,7 +1291,10 @@ SIGNALduino_Set($@)
$sendData = $intro . "SM;" . ($repeats > 0 ? "R=$repeats;" : "") . "C=$clock;D=$data;" . $outro; # SM;R=2;C=400;D=AFAFAF;
Log3 $name, 5, "$name: sendmsg Preparing manchester protocol=$protocol, repeats=$repeats, clock=$clock data=$data";
} else {
if ($protocol == 3) {
if ($protocol == 3 || substr($data,0,2) eq "is") {
if (substr($data,0,2) eq "is") {
$data = substr($data,2); # is am Anfang entfernen
}
$data = SIGNALduino_ITV1_tristateToBit($data);
Log3 $name, 5, "$name: sendmsg IT V1 convertet tristate to bits=$data";
}
@ -1363,29 +1378,67 @@ SIGNALduino_Get($@)
if (IsDummy($name))
{
if (($arg !~ m/;/) && ($arg !~ m/=/)) {
if ($arg =~ m/^V\d\.\d\..*/) {
Log3 $name, 4, "$name/msg get version: $arg";
$hash->{version} = "V " . substr($arg,1);
return "";
}
else {
Log3 $name, 4, "$name/msg get dispatch: $arg";
Dispatch($hash, $arg, undef);
return "";
}
}
if ($arg =~ /^M[CSU];.*/)
{
$arg="\002$arg\003"; ## Add start end end marker if not already there
Log3 $name, 5, "$name/msg adding start and endmarker to message";
}
if ($arg =~ /^\002.*\003$/)
{
}
if ($arg =~ /\002M.;.*;\003$/)
{
Log3 $name, 4, "$name/msg get raw: $arg";
return SIGNALduino_Parse($hash, $hash, $hash->{NAME}, $arg);
}
else {
my $arg2 = "";
if ($arg =~ m/^version=/) { # set version
$arg2 = substr($arg,8);
$hash->{version} = "V " . $arg2;
}
elsif ($arg =~ m/^regexp=/) { # set fileRegexp for get raw messages from file
$arg2 = substr($arg,7);
$hash->{fileRegexp} = $arg2;
delete($hash->{fileRegexp}) if (!$arg2);
}
elsif ($arg =~ m/^file=/) {
$arg2 = substr($arg,5);
my $n = 0;
if (open(my $fh, '<', $arg2)) {
my $fileRegexp = $hash->{fileRegexp};
while (my $row = <$fh>) {
if ($row =~ /.*\002M.;.*;\003$/) {
chomp $row;
$row =~ s/.*\002(M.;.*;)\003/$1/;
if (!defined($fileRegexp) || $row =~ m/$fileRegexp/) {
$n += 1;
$row="\002$row\003";
Log3 $name, 4, "$name/msg fileGetRaw: $row";
SIGNALduino_Parse($hash, $hash, $hash->{NAME}, $row);
}
}
}
return $n . " raw Nachrichten eingelesen";
} else {
return "Could not open file $arg2";
}
}
elsif ($arg eq '?') {
my $ret;
$ret = "dummy get raw\n\n";
$ret .= "raw message e.g. MS;P0=-392;P1=...\n";
$ret .= "dispatch message e.g. P7#6290DCF37\n";
$ret .= "version=x.x.x sets version. e.g. (version=3.2.0) to get old MC messages\n";
$ret .= "regexp= set fileRegexp for get raw messages from file. e.g. regexp=^MC\n";
$ret .= "file= gets raw messages from file in the fhem directory\n";
return $ret;
}
else {
Log3 $name, 4, "$name/msg get dispatch: $arg";
Dispatch($hash, $arg, undef);
}
return "";
}
}
return "No $a[1] for dummies" if(IsDummy($name));
@ -1404,6 +1457,71 @@ SIGNALduino_Get($@)
}
}
elsif ($a[1] eq "protocolIDs")
{
my $id;
my $ret;
my $s;
my $moduleId;
my @IdList = ();
foreach $id (keys %ProtocolListSIGNALduino)
{
next if ($id eq 'id');
push (@IdList, $id);
}
@IdList = sort { $a <=> $b } @IdList;
$ret = " ID modulname protocolname # comment\n\n";
foreach $id (@IdList)
{
$ret .= sprintf("%3s",$id) . " ";
if (exists ($ProtocolListSIGNALduino{$id}{format}) && $ProtocolListSIGNALduino{$id}{format} eq "manchester")
{
$ret .= "MC";
}
elsif (exists $ProtocolListSIGNALduino{$id}{sync})
{
$ret .= "MS";
}
elsif (exists ($ProtocolListSIGNALduino{$id}{clockabs}))
{
$ret .= "MU";
}
if (exists ($ProtocolListSIGNALduino{$id}{clientmodule}))
{
$moduleId .= "$id,";
$s = $ProtocolListSIGNALduino{$id}{clientmodule};
if (length($s) < 15)
{
$s .= substr(" ",length($s) - 15);
}
$ret .= " $s";
}
else
{
$ret .= " ";
}
if (exists ($ProtocolListSIGNALduino{$id}{name}))
{
$ret .= " $ProtocolListSIGNALduino{$id}{name}";
}
if (exists ($ProtocolListSIGNALduino{$id}{comment}))
{
$ret .= " # $ProtocolListSIGNALduino{$id}{comment}";
}
$ret .= "\n";
}
$moduleId =~ s/,$//;
return "$a[1]: \n\n$ret\nIds with modules: $moduleId";
}
#SIGNALduino_SimpleWrite($hash, $gets{$a[1]}[0] . $arg);
SIGNALduino_AddSendQueue($hash, $gets{$a[1]}[0] . $arg);
@ -1510,6 +1628,7 @@ sub SIGNALduino_SimpleWrite_XQ($) {
Log3 $hash, 3, "$name/init: disable receiver (XQ)";
SIGNALduino_SimpleWrite($hash, "XQ");
#DevIo_SimpleWrite($hash, "XQ\n",2);
}
@ -1536,6 +1655,7 @@ sub SIGNALduino_StartInit($)
else {
$hash->{getcmd}->{cmd} = "version";
SIGNALduino_SimpleWrite($hash, "V");
#DevIo_SimpleWrite($hash, "V\n",2);
$hash->{DevState} = 'waitInit';
RemoveInternalTimer($hash);
InternalTimer(gettimeofday() + SDUINO_CMD_TIMEOUT, "SIGNALduino_CheckCmdResp", $hash, 0);
@ -1569,10 +1689,11 @@ sub SIGNALduino_CheckCmdResp($)
}
else {
readingsSingleUpdate($hash, "state", "opened", 1);
Log3 $name, 2, "$name: initialized";
Log3 $name, 2, "$name: initialized. " . SDUINO_VERSION;
$hash->{DevState} = 'initialized';
delete($hash->{initResetFlag}) if defined($hash->{initResetFlag});
SIGNALduino_SimpleWrite($hash, "XE"); # Enable receiver
#DevIo_SimpleWrite($hash, "XE\n",2);
Log3 $hash, 3, "$name/init: enable receiver (XE)";
delete($hash->{initretry});
# initialize keepalive
@ -1658,7 +1779,7 @@ sub SIGNALduino_AddSendQueue($$)
#Log3 $hash , 5, Dumper($hash->{QUEUE});
InternalTimer(gettimeofday() + 0.1, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name", 1) if (@{$hash->{QUEUE}} == 1);
InternalTimer(gettimeofday() + 0.1, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name") if (@{$hash->{QUEUE}} == 1);
}
@ -1670,15 +1791,23 @@ SIGNALduino_SendFromQueue($$)
if($msg ne "") {
SIGNALduino_XmitLimitCheck($hash,$msg);
#DevIo_SimpleWrite($hash, $msg,2);
#DevIo_SimpleWrite($hash, $msg . "\n", 2);
SIGNALduino_SimpleWrite($hash,$msg);
if ($msg =~ m/^S(R|C|M);/) {
$hash->{getcmd}->{cmd} = 'sendraw';
Log3 $hash, 4, "$name SendFromQueue: msg=$msg"; # zu testen der Queue, kann wenn es funktioniert auskommentiert werden
}
}
##############
# Write the next buffer not earlier than 0.23 seconds
# else it will be sent too early by the SIGNALduino, resulting in a collision, or may the last command is not finished
InternalTimer(gettimeofday() + SDUINO_WRITEQUEUE_NEXT, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name", 1);
if (defined($hash->{getcmd}->{cmd}) && $hash->{getcmd}->{cmd} eq 'sendraw') {
InternalTimer(gettimeofday() + SDUINO_WRITEQUEUE_TIMEOUT, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name");
} else {
InternalTimer(gettimeofday() + SDUINO_WRITEQUEUE_NEXT, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name");
}
}
####################################
@ -1691,6 +1820,11 @@ SIGNALduino_HandleWriteQueue($)
#my @arr = @{$hash->{QUEUE}};
if (defined($hash->{getcmd}->{cmd}) && $hash->{getcmd}->{cmd} eq 'sendraw') {
Log3 $name, 4, "$name/HandleWriteQueue: sendraw no answer (timeout)";
delete($hash->{getcmd});
}
if(@{$hash->{QUEUE}}) {
my $msg= shift(@{$hash->{QUEUE}});
@ -1726,14 +1860,22 @@ SIGNALduino_Read($)
($rmsg,$SIGNALduinodata) = split("\n", $SIGNALduinodata, 2);
$rmsg =~ s/\r//;
Log3 $name, 4, "$name/msg READ: $rmsg";
if ( $rmsg && !SIGNALduino_Parse($hash, $hash, $name, $rmsg) && $hash->{getcmd} )
if ( $rmsg && !SIGNALduino_Parse($hash, $hash, $name, $rmsg) && defined($hash->{getcmd}) && defined($hash->{getcmd}->{cmd}))
{
my $regexp=$gets{$hash->{getcmd}->{cmd}}[1];
my $regexp;
if ($hash->{getcmd}->{cmd} eq 'sendraw') {
$regexp = '^S(R|C|M);';
}
else {
$regexp = $gets{$hash->{getcmd}->{cmd}}[1];
}
if(!defined($regexp) || $rmsg =~ m/$regexp/) {
if (defined($hash->{keepalive})) {
$hash->{keepalive}{ok} = 1;
$hash->{keepalive}{retry} = 0;
}
Log3 $name, 5, "$name/msg READ: regexp=$regexp cmd=$hash->{getcmd}->{cmd} msg=$rmsg";
if ($hash->{getcmd}->{cmd} eq 'version') {
my $msg_start = index($rmsg, 'V 3.');
if ($msg_start > 0) {
@ -1746,13 +1888,22 @@ SIGNALduino_Read($)
SIGNALduino_CheckCmdResp($hash);
}
}
$rmsg = SIGNALduino_parseResponse($hash,$hash->{getcmd}->{cmd},$rmsg);
readingsSingleUpdate($hash, $hash->{getcmd}->{cmd}, $rmsg, 0);
if (defined($hash->{getcmd}->{asyncOut})) {
#Log3 $name, 4, "$name/msg READ: asyncOutput";
my $ao = asyncOutput( $hash->{getcmd}->{asyncOut}, $hash->{getcmd}->{cmd}.": " . $rmsg );
if ($hash->{getcmd}->{cmd} eq 'sendraw') {
# zu testen der sendeQueue, kann wenn es funktioniert auf verbose 5
Log3 $name, 4, "$name/read sendraw answer: $rmsg";
delete($hash->{getcmd});
RemoveInternalTimer("HandleWriteQueue:$name");
SIGNALduino_HandleWriteQueue("x:$name");
}
else {
$rmsg = SIGNALduino_parseResponse($hash,$hash->{getcmd}->{cmd},$rmsg);
readingsSingleUpdate($hash, $hash->{getcmd}->{cmd}, $rmsg, 0);
if (defined($hash->{getcmd}->{asyncOut})) {
#Log3 $name, 4, "$name/msg READ: asyncOutput";
my $ao = asyncOutput( $hash->{getcmd}->{asyncOut}, $hash->{getcmd}->{cmd}.": " . $rmsg );
}
delete($hash->{getcmd});
}
delete($hash->{getcmd});
} else {
Log3 $name, 4, "$name/msg READ: Received answer ($rmsg) for ". $hash->{getcmd}->{cmd}." does not match $regexp";
}
@ -1780,15 +1931,16 @@ sub SIGNALduino_KeepAlive($){
}
else {
$hash->{keepalive}{retry} ++;
Log3 $name,4 , "$name/KeepAlive: get ping";
Log3 $name,3 , "$name/KeepAliveOk: " . $hash->{keepalive}{ok} . " retry = " . $hash->{keepalive}{retry} . " -> get ping";
$hash->{getcmd}->{cmd} = "ping";
SIGNALduino_SimpleWrite($hash, "P");
SIGNALduino_AddSendQueue($hash, "P");
#SIGNALduino_SimpleWrite($hash, "P");
}
}
Log3 $name,4 , "$name/keepalive retry = " . $hash->{keepalive}{retry};
$hash->{keepalive}{ok} = 0;
InternalTimer(gettimeofday() + SDUINO_KEEPALIVE_TIMEOUT, "SIGNALduino_KeepAlive", $hash, 1);
InternalTimer(gettimeofday() + SDUINO_KEEPALIVE_TIMEOUT, "SIGNALduino_KeepAlive", $hash);
}
@ -1842,7 +1994,7 @@ sub SIGNALduino_PatternExists
#my $patt_id;
# Calculate tolernace for search
#my $tol=abs(abs($searchpattern)>=2 ?$searchpattern*0.3:$searchpattern*1.5);
my $tol=abs(abs($searchpattern)>3 ? abs($searchpattern)>16 ? $searchpattern*0.17 : $searchpattern*0.3 : 1); #tol is minimum 1 or higer, depending on our searched pulselengh
my $tol=abs(abs($searchpattern)>3 ? abs($searchpattern)>16 ? $searchpattern*0.18 : $searchpattern*0.3 : 1); #tol is minimum 1 or higer, depending on our searched pulselengh
Debug "tol: looking for ($searchpattern +- $tol)" if($debug);
@ -2390,12 +2542,13 @@ sub SIGNALduino_Parse_MU($$$$@)
Debug "Found matched one" if ($debug && $valid);
my $oneStr=$pstr if ($valid);
$patternLookupHash{$pstr}="1" if ($valid); ## Append one to our lookuptable
Debug "added $pstr " if ($debug && $valid);
$valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList,\$rawData)) >=0;
Debug "Found matched zero" if ($debug && $valid);
my $zeroStr=$pstr if ($valid);
$patternLookupHash{$pstr}="0" if ($valid); ## Append zero to our lookuptable
Debug "added $pstr " if ($debug && $valid);
@ -2424,14 +2577,23 @@ sub SIGNALduino_Parse_MU($$$$@)
my @msgStartLst;
my $startStr="";
my $start_regex;
my $oneStr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList,\$rawData);
my $zeroStr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList,\$rawData);
#my $oneStr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList,\$rawData);
#my $zeroStr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList,\$rawData);
if (@msgStartLst = SIGNALduino_getProtoProp($id,"start"))
{
$startStr=SIGNALduino_PatternExists($hash,@msgStartLst,\%patternList,\$rawData);
Debug "msgStartLst: ".Dumper(@msgStartLst) if ($debug);
if ( ($startStr=SIGNALduino_PatternExists($hash,@msgStartLst,\%patternList,\$rawData)) eq -1)
{
Log3 $name, 5, "$name: start pattern for MU Protocol id $id -> $ProtocolListSIGNALduino{$id}{name} mismatches, aborting" ;
$valid=0;
next;
};
}
$start_regex="$startStr($oneStr|$zeroStr)";
Debug "Regex is: $start_regex" if ($debug);
$rawData =~ /$start_regex/;
if (defined($-[0] && $-[0] > 0)) {
$message_start=$-[0]+ length($startStr);
@ -2527,7 +2689,9 @@ sub SIGNALduino_Parse_MU($$$$@)
$rawData =~ /$regex/;
if (defined($-[0]) && ($-[0] > 0)) {
$i=$-[0]+ $i+ length($startStr);
#$i=$-[0]+ $i+ length($startStr);
$i=$-[0]+ $i;
$i=$i-$signal_width if ($i>0 && length($startStr) == 0); #Todo:
Debug "$name: found restart at Position $i ($regex)\n" if ($debug);
} else {
@ -2599,7 +2763,7 @@ SIGNALduino_Parse_MC($$$$@)
$bitData= unpack("B$blen", pack("H$hlen", $rawData));
}
Debug "$name: extracted data $bitData (bin)\n" if ($debug); ## Convert Message from hex to bits
Log3 $name, 5, "$name: extracted data $bitData (bin)\n";
Log3 $name, 5, "$name: extracted data $bitData (bin)";
my $method = $ProtocolListSIGNALduino{$id}{method};
if (!exists &$method)
@ -2638,8 +2802,8 @@ SIGNALduino_Parse($$$$@)
#print Dumper(\%ProtocolListSIGNALduino);
return undef if !($rmsg=~ m/^\002M.;.*;\003/); ## Check if a Data Message arrived and if it's complete (start & end control char are received)
return undef if !($rmsg=~ s/^\002(M.;.*;)\003/$1/); ## Check if a Data Message arrived and if it's complete (start & end control char are received)
# cut off start end end character from message for further processing they are not needed
if (defined($hash->{keepalive})) {
$hash->{keepalive}{ok} = 1;
$hash->{keepalive}{retry} = 0;
@ -2648,21 +2812,15 @@ SIGNALduino_Parse($$$$@)
my $debug = AttrVal($iohash->{NAME},"debug",0);
$rmsg=~ s/^\002(M.;.*;)\003/$1/; # cut off start end end character from message for further processing they are not needed
Debug "$name: incomming message: ($rmsg)\n" if ($debug);
my %signal_parts=SIGNALduino_Split_Message($rmsg,$name); ## Split message and save anything in an hash %signal_parts
#Debug "raw data ". $signal_parts{rawData};
my @msg_parts = SIGNALduino_splitMsg($rmsg,';'); ## Split message parts by ";"
my $dispatched;
# Message Synced type -> M#
if ($rmsg=~ m/^M\d+;(P\d=-?\d+;){4,7}D=\d+;CP=\d;SP=\d;/)
{
Log3 $name, 3, "$name: You are using an outdated version of signalduino code on your arduino. Please update";
return undef;
}
if (@{$hash->{msIdList}} && $rmsg=~ m/^MS;(P\d=-?\d+;){3,8}D=\d+;CP=\d;SP=\d;/)
{
$dispatched= SIGNALduino_Parse_MS($hash, $iohash, $name, $rmsg,%signal_parts);
@ -2755,6 +2913,7 @@ SIGNALduino_Attr(@)
my $hash = $defs{$name};
my $debug = AttrVal($name,"debug",0);
$aVal= "" if (!defined($aVal));
Log3 $name, 4, "$name: Calling Getting Attr sub with args: $cmd $aName = $aVal";
if( $aName eq "Clients" ) { ## Change clientList
@ -2929,15 +3088,21 @@ sub SIGNALduino_OSV2()
my $message_length;
#$bitData =~ tr/10/01/;
if ($bitData =~ m/^.?(10){12,16}.?10011001/)
if ($bitData =~ m/^.?(01){12,17}.?10011001/)
{ # Valid OSV2 detected!
$preamble_pos=index($bitData,"10011001",24);
#$preamble_pos=index($bitData,"10011001",24);
$preamble_pos=$+[1];
Log3 $name, 4, "$name: OSV2 protocol detected: preamble_pos = $preamble_pos";
return return (-1," sync not found") if ($preamble_pos <=24);
$message_end=index($bitData,"101010101010101010101010101010110011001",$preamble_pos+44);
$message_end = length($bitData) if ($message_end <$preamble_pos);
$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;
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} );
@ -2947,9 +3112,9 @@ sub SIGNALduino_OSV2()
my $osv2bits="";
my $osv2hex ="";
for ($idx=$preamble_pos;$idx<length($bitData);$idx=$idx+16)
for ($idx=$preamble_pos;$idx<$message_end;$idx=$idx+16)
{
if (length($bitData)-$idx < 16 )
if ($message_end-$idx < 8 )
{
last;
}
@ -2959,11 +3124,17 @@ sub SIGNALduino_OSV2()
my $rvosv2byte="";
for (my $p=1;$p<length($osv2byte);$p=$p+2)
for (my $p=0;$p<length($osv2byte);$p=$p+2)
{
$rvosv2byte = substr($osv2byte,$p,1).$rvosv2byte;
}
$osv2hex=$osv2hex.sprintf('%02X', oct("0b$rvosv2byte"));
$rvosv2byte =~ tr/10/01/;
if (length($rvosv2byte) eq 8) {
$osv2hex=$osv2hex.sprintf('%02X', oct("0b$rvosv2byte")) ;
} else {
$osv2hex=$osv2hex.sprintf('%X', oct("0b$rvosv2byte")) ;
}
$osv2bits = $osv2bits.$rvosv2byte;
}
$osv2hex = sprintf("%02X", length($osv2hex)*4).$osv2hex;
@ -3132,13 +3303,19 @@ sub SIGNALduino_Maverick()
my ($name,$bitData,$id) = @_;
my $debug = AttrVal($name,"debug",0);
## Todo: Some checks and may be a lengh filter or some checks
my $hex=SIGNALduino_b2h($bitData);
if ($bitData =~ m/^.*(101010101001100110010101).*/)
{ # Valid Maverick header detected
my $header_pos=$+[1];
Log3 $name, 4, "$name: Maverick protocol detected: header_pos = $header_pos";
return (1,$hex); ## Return the bits unchanged in hex
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_SomfyRTS()
@ -3305,7 +3482,7 @@ sub SIGNALduino_compPattern($$$%)
=pod
=item summary supports the same low-cost receiver for digital signals
=item summary_DE Unterst&uumltzt den gleichnamigen Low-Cost Empfaenger fuer digitale Signale
=item summary_DE Unterst&uumltzt den gleichnamigen Low-Cost Empf&aumlnger fuer digitale Signale
=begin html
<a name="SIGNALduino"></a>
@ -3466,7 +3643,9 @@ With a # at the beginnging whitelistIDs can be deactivated.
For sending IT Signals for wireless switches, the number of repeats and the base duration can be set.
With the get command, you can verify what is programmed into the uC.
</li><br>
<li>protocolIDs<br>
display a list of the protocol IDs
</li><br>
</ul>
<a name="SIGNALduinoset"></a>
<b>SET</b>
@ -3478,6 +3657,17 @@ With a # at the beginnging whitelistIDs can be deactivated.
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<protocol id>#binarydata#R<num of repeats>#C<optional clock> (#C is optional)
<br>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
<br>Example 2: set sduino raw SM;R=3;P0=500;C=250;D=A4F7FDDE sends the data manchester encoded with a clock of 250uS
<br>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
<br>;
</p>
</li><br>
<li>reset<br>
This will do a reset of the usb port and normaly causes to reset the uC connected.
@ -3513,6 +3703,7 @@ With a # at the beginnging whitelistIDs can be deactivated.
<br>SR;R=3;P0=500;P1=-9000;P2=-4000;P3=-2000;D=03020302;
</p>
</li><br>
<li>enableMessagetype<br>
Allows you to enable the message processing for

View File

@ -19,7 +19,7 @@ sub SD_WS_Initialize($)
{
my ($hash) = @_;
$hash->{Match} = '^[W]\d+#.*';
$hash->{Match} = '^W\d+x{0,1}#.*';
$hash->{DefFn} = "SD_WS_Define";
$hash->{UndefFn} = "SD_WS_Undef";
$hash->{ParseFn} = "SD_WS_Parse";
@ -29,7 +29,8 @@ sub SD_WS_Initialize($)
$hash->{AutoCreate} =
{
"SD_WS37_TH.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"},
"SD_WS50_SM.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"}
"SD_WS50_SM.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"},
"BresserTemeo.*" => { ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", FILTER => "%NAME", GPLOT => "temp4hum4:Temp/Hum,", autocreateThreshold => "2:180"}
};
@ -140,7 +141,7 @@ sub SD_WS_Parse($$)
Log3 $name, 4, "SD_WS_Parse: Protocol: $protocol, rawData: $rawData";
if ($protocol == "37") # Bresser 7009994
if ($protocol eq "37") # Bresser 7009994
{
# 0 7 8 9 10 12 22 25 31
# 01011010 0 0 01 01100001110 10 0111101 11001010
@ -170,7 +171,120 @@ sub SD_WS_Parse($$)
Log3 $iohash, 4, "$name converted to bits: " . $bitData2;
Log3 $iohash, 4, "$name decoded protocolid: $protocol ($SensorTyp) sensor id=$id, channel=$channel, rawTemp=$rawTemp, temp=$temp, hum=$hum";
}
elsif ($protocol != "37" && defined($decodingSubs{$protocol})) # alles was nicht Protokoll #37 ist, durch den hash decodieren
elsif ($protocol eq "44" || $protocol eq "44x") # BresserTemeo
{
# 0 4 8 12 20 24 28 32 36 40 44 52 56 60
# 0101 0111 1001 00010101 0010 0100 0001 1010 1000 0110 11101010 1101 1011 1110 110110010
# hhhh hhhh ?bcc iiiiiiii sttt tttt tttt xxxx xxxx ?BCC IIIIIIII Syyy yyyy yyyy
# - h humidity / -x checksum
# - t temp / -y checksum
# - c Channel / C checksum
# - i 8 bit random id (aendert sich beim Batterie- und Kanalwechsel) / - I checksum
# - b battery indicator (0=>OK, 1=>LOW) / - B checksum
# - s Test/Sync (0=>Normal, 1=>Test-Button pressed) / - S checksum
$model= "BresserTemeo";
$SensorTyp = "BresserTemeo";
#my $binvalue = unpack("B*" ,pack("H*", $rawData));
my $binvalue = $bitData;
if (length($binvalue) != 72) {
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: length error (72 bits expected)!!!";
return "";
}
# Check what Humidity Prefix (*sigh* Bresser!!!)
if ($protocol eq "44")
{
$binvalue = "0".$binvalue;
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: Humidity <= 79 Flag";
}
else
{
$binvalue = "1".$binvalue;
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: Humidity > 79 Flag";
}
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: new bin $binvalue";
my $checksumOkay = 1;
my $hum1Dec = SD_WS_binaryToNumber($binvalue, 0, 3);
my $hum2Dec = SD_WS_binaryToNumber($binvalue, 4, 7);
my $checkHum1 = SD_WS_binaryToNumber($binvalue, 32, 35) ^ 0b1111;
my $checkHum2 = SD_WS_binaryToNumber($binvalue, 36, 39) ^ 0b1111;
if ($checkHum1 != $hum1Dec || $checkHum2 != $hum2Dec)
{
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error in Humidity";
}
else
{
$hum = $hum1Dec.$hum2Dec;
if ($hum < 1 || $hum > 100)
{
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: Humidity Error. Humidity=$hum";
return "";
}
}
my $temp1Dec = SD_WS_binaryToNumber($binvalue, 21, 23);
my $temp2Dec = SD_WS_binaryToNumber($binvalue, 24, 27);
my $temp3Dec = SD_WS_binaryToNumber($binvalue, 28, 31);
my $checkTemp1 = SD_WS_binaryToNumber($binvalue, 53, 55) ^ 0b111;
my $checkTemp2 = SD_WS_binaryToNumber($binvalue, 56, 59) ^ 0b1111;
my $checkTemp3 = SD_WS_binaryToNumber($binvalue, 60, 63) ^ 0b1111;
$temp = $temp1Dec.$temp2Dec.".".$temp3Dec;
if ($checkTemp1 != $temp1Dec || $checkTemp2 != $temp2Dec || $checkTemp3 != $temp3Dec)
{
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error in Temperature";
$checksumOkay = 0;
}
if ($temp > 60)
{
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: Temperature Error. temp=$temp";
return "";
}
$bat = substr($binvalue,9,1);
my $checkBat = substr($binvalue,41,1) ^ 0b1;
if ($bat != $checkBat)
{
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error in Bat";
$bat = undef;
}
else
{
$bat = ($bat == 0) ? "ok" : "low";
}
$channel = SD_WS_binaryToNumber($binvalue, 10, 11);
my $checkChannel = SD_WS_binaryToNumber($binvalue, 42, 43) ^ 0b11;
$id = SD_WS_binaryToNumber($binvalue, 12, 19);
my $checkId = SD_WS_binaryToNumber($binvalue, 44, 51) ^ 0b11111111;
if ($channel != $checkChannel || $id != $checkId)
{
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error in Channel or Id";
$checksumOkay = 0;
}
if ($checksumOkay == 0)
{
Log3 $iohash, 4, "SD_WS_Parse BresserTemeo: checksum error!!! These Values seem incorrect: temp=$temp, channel=$channel, id=$id";
return "";
}
$id = sprintf('%02X', $id); # wandeln nach hex
Log3 $iohash, 4, "$name SD_WS_Parse: model=$model, temp=$temp, hum=$hum, channel=$channel, id=$id, bat=$bat";
}
elsif (defined($decodingSubs{$protocol})) # durch den hash decodieren
{
$SensorTyp=$decodingSubs{$protocol}{sensortype};
@ -224,6 +338,8 @@ sub SD_WS_Parse($$)
my $hash = $def;
$name = $hash->{NAME};
return "" if(IsIgnored($name));
Log3 $name, 4, "SD_WS: $name ($rawData)";
if (!defined(AttrVal($hash->{NAME},"event-min-interval",undef)))
@ -353,7 +469,7 @@ sub SD_WS_binaryToNumber
<ul>
<li>Bresser 7009994</li>
<li>Opus XT300</li>
<li>BresserTemeo</li>
</ul>
<br>
Neu empfangene Sensoren werden in FHEM per autocreate angelegt.

View File

@ -151,6 +151,8 @@ SD_WS07_Parse($$)
my $hash = $def;
$name = $hash->{NAME};
return "" if(IsIgnored($name));
Log3 $name, 4, "SD_WS07: $name ($rawData)";
if (!defined(AttrVal($hash->{NAME},"event-min-interval",undef)))