mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-03 16:56:54 +00:00
00_MQTT2_SERVER.pm: $DEVICETOPIC and autocreate (Forum #90145)
git-svn-id: https://svn.fhem.de/fhem/trunk@17152 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
be871c97b4
commit
4e3f65a1ca
@ -37,6 +37,7 @@ MQTT2_SERVER_Initialize($)
|
||||
my @attrList = qw(
|
||||
disable:0,1
|
||||
disabledForIntervals
|
||||
autocreate
|
||||
rawEvents:0,1
|
||||
SSL:0,1
|
||||
);
|
||||
@ -364,7 +365,8 @@ MQTT2_SERVER_doPublish($$$$;$)
|
||||
if($src->{cid}) { # "real" MQTT client
|
||||
my $cid = $src->{cid};
|
||||
$cid =~ s,[^a-z0-9._],_,gi;
|
||||
Dispatch($tgt, "$cid:$tp:$val", undef, 1);
|
||||
my $ac = AttrVal($tgt->{NAME}, "autocreate", undef) ? "autocreate:":"";
|
||||
Dispatch($tgt, "$ac$cid:$tp:$val", undef, !$ac);
|
||||
my $re = AttrVal($tgt->{NAME}, "rawEvents", undef);
|
||||
DoTrigger($tgt->{NAME}, "$tp:$val") if($re && $tp =~ m/$re/);
|
||||
}
|
||||
@ -412,8 +414,10 @@ MQTT2_SERVER_calcRemainingLength($)
|
||||
my ($l) = @_;
|
||||
my @r;
|
||||
while($l > 0) {
|
||||
unshift(@r, $l % 128);
|
||||
my $eb = $l % 128;
|
||||
$l = int($l/128);
|
||||
$eb += 128 if($l);
|
||||
push(@r, $eb);
|
||||
}
|
||||
return pack("C*", @r);
|
||||
}
|
||||
@ -527,6 +531,13 @@ MQTT2_SERVER_getStr($$)
|
||||
<li>SSL<br>
|
||||
Enable SSL (i.e. TLS)
|
||||
</li><br>
|
||||
|
||||
<a name="autocreate"></a>
|
||||
<li>autocreate<br>
|
||||
If set, MQTT2_DEVICES will be automatically created upon receiving an
|
||||
unknown message.
|
||||
</li><br>
|
||||
|
||||
</ul>
|
||||
</ul>
|
||||
=end html
|
||||
|
@ -22,6 +22,7 @@ MQTT2_DEVICE_Initialize($)
|
||||
no warnings 'qw';
|
||||
my @attrList = qw(
|
||||
IODev
|
||||
devicetopic
|
||||
disable:0,1
|
||||
disabledForIntervals
|
||||
readingList:textField-long
|
||||
@ -30,7 +31,8 @@ MQTT2_DEVICE_Initialize($)
|
||||
);
|
||||
use warnings 'qw';
|
||||
$hash->{AttrList} = join(" ", @attrList)." ".$readingFnAttributes;
|
||||
$modules{MQTT2_DEVICE}{defptr} = ();
|
||||
my %h = ( re=>{}, cid=>{});
|
||||
$modules{MQTT2_DEVICE}{defptr} = \%h;
|
||||
}
|
||||
|
||||
|
||||
@ -42,9 +44,12 @@ MQTT2_DEVICE_Define($$)
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
my $name = shift @a;
|
||||
my $type = shift @a; # always MQTT2_DEVICE
|
||||
shift(@a) if(@a && $a[0] eq "autocreated");
|
||||
$hash->{CID} = shift(@a) if(@a);
|
||||
|
||||
return "wrong syntax for $name: define <name> MQTT2_DEVICE" if(int(@a));
|
||||
return "wrong syntax for $name: define <name> MQTT2_DEVICE [clientid]"
|
||||
if(int(@a));
|
||||
$hash->{DEVICETOPIC} = $name;
|
||||
$modules{MQTT2_DEVICE}{defptr}{cid}{$hash->{CID}} = $hash if($hash->{CID});
|
||||
|
||||
AssignIoPort($hash);
|
||||
return undef;
|
||||
@ -56,7 +61,7 @@ MQTT2_DEVICE_Parse($$)
|
||||
{
|
||||
my ($iodev, $msg) = @_;
|
||||
my $ioname = $iodev->{NAME};
|
||||
my @ret;
|
||||
my %fnd;
|
||||
|
||||
sub
|
||||
checkForGet($$$)
|
||||
@ -69,21 +74,35 @@ MQTT2_DEVICE_Parse($$)
|
||||
}
|
||||
}
|
||||
|
||||
my $autocreate;
|
||||
if($msg =~ m/^autocreate:(.*)/) {
|
||||
$msg = $1;
|
||||
$autocreate = 1;
|
||||
}
|
||||
|
||||
my ($cid, $topic, $value) = split(":", $msg, 3);
|
||||
my $dp = $modules{MQTT2_DEVICE}{defptr};
|
||||
my $dp = $modules{MQTT2_DEVICE}{defptr}{re};
|
||||
foreach my $re (keys %{$dp}) {
|
||||
next if(!("$topic:$value" =~ m/^$re$/s ||
|
||||
"$cid:$topic:$value" =~ m/^$re$/s));
|
||||
my $reAll = $re;
|
||||
$reAll =~ s/\$DEVICETOPIC/\.\*/g;
|
||||
|
||||
next if(!("$topic:$value" =~ m/^$reAll$/s ||
|
||||
"$cid:$topic:$value" =~ m/^$reAll$/s));
|
||||
foreach my $dev (keys %{$dp->{$re}}) {
|
||||
next if(IsDisabled($dev));
|
||||
my $hash = $defs{$dev};
|
||||
my $reRepl = $re;
|
||||
$reRepl =~ s/\$DEVICETOPIC/$hash->{DEVICETOPIC}/g;
|
||||
next if(!("$topic:$value" =~ m/^$reRepl$/s ||
|
||||
"$cid:$topic:$value" =~ m/^$reRepl$/s));
|
||||
|
||||
my @retData;
|
||||
my $code = $dp->{$re}{$dev};
|
||||
Log3 $dev, 4, "MQTT2_DEVICE_Parse: $dev $topic => $code";
|
||||
my $hash = $defs{$dev};
|
||||
|
||||
if($code =~ m/^{.*}$/s) {
|
||||
$code = EvalSpecials($code,
|
||||
("%TOPIC"=>$topic, "%EVENT"=>$value, "%NAME"=>$hash->{NAME}));
|
||||
$code = EvalSpecials($code, ("%TOPIC"=>$topic, "%EVENT"=>$value,
|
||||
"%DEVICETOPIC"=>$hash->{DEVICETOPIC}, "%NAME"=>$hash->{NAME}));
|
||||
my $ret = AnalyzePerlCommand(undef, $code);
|
||||
if($ret && ref $ret eq "HASH") {
|
||||
readingsBeginUpdate($hash);
|
||||
@ -101,32 +120,35 @@ MQTT2_DEVICE_Parse($$)
|
||||
checkForGet($hash, $code, $value);
|
||||
}
|
||||
|
||||
push @ret, $dev;
|
||||
$fnd{$dev} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# autocreate, init readingList if message is a json string
|
||||
# deactivated, as there are a lot of messages to be catched
|
||||
# if(!@ret) {
|
||||
# my $nn = "MQTT2_$cid";
|
||||
# if(!$defs{$nn} && $cid !~ m/mosqpub.*/) {
|
||||
# PrioQueue_add(sub{
|
||||
# return if(!$defs{$nn});
|
||||
# if($value =~ m/^{.*}$/) {
|
||||
# my %ret = json2nameValue($msg);
|
||||
# if(keys %ret) {
|
||||
# CommandAttr(undef,
|
||||
# "$nn readingList $cid:$topic:.* { json2nameValue(\$EVENT) }");
|
||||
# }
|
||||
# }
|
||||
# $defs{$nn}{autocreated_on} = $msg;
|
||||
# }, undef);
|
||||
# return "UNDEFINED $nn MQTT2_DEVICE autocreated"
|
||||
# }
|
||||
# return "";
|
||||
# }
|
||||
# autocreate and expand readingList
|
||||
if($autocreate && !%fnd) {
|
||||
return "" if($cid =~ m/mosqpub.*/);
|
||||
my $cidHash = $modules{MQTT2_DEVICE}{defptr}{cid}{$cid};
|
||||
my $nn = $cidHash ? $cidHash->{NAME} : "MQTT2_$cid";
|
||||
PrioQueue_add(sub{
|
||||
return if(!$defs{$nn});
|
||||
my $add;
|
||||
if($value =~ m/^{.*}$/) {
|
||||
my $ret = json2nameValue($value);
|
||||
$add = "{ json2nameValue(\$EVENT) }" if(keys %{$ret});
|
||||
}
|
||||
if(!$add) {
|
||||
$topic =~ m,[^/]*/(.*),;
|
||||
$add = ($1 ? $1 : $topic);
|
||||
}
|
||||
my $rl = AttrVal($nn, "readingList", "");
|
||||
$rl .= "\n" if($rl);
|
||||
CommandAttr(undef, "$nn readingList $rl$cid:$topic:.* $add");
|
||||
}, undef);
|
||||
return "UNDEFINED $nn MQTT2_DEVICE $cid" if(!$cidHash);
|
||||
return "";
|
||||
}
|
||||
|
||||
return @ret;
|
||||
return keys %fnd;
|
||||
}
|
||||
|
||||
sub
|
||||
@ -170,6 +192,7 @@ MQTT2_DEVICE_Get($@)
|
||||
$cmd .= " ".join(" ",@a) if(@a);
|
||||
}
|
||||
|
||||
$cmd =~ s/\$DEVICETOPIC/$hash->{DEVICETOPIC}/g;
|
||||
IOWrite($hash, split(" ",$cmd,2));
|
||||
return undef;
|
||||
}
|
||||
@ -198,6 +221,8 @@ MQTT2_DEVICE_Set($@)
|
||||
shift @a;
|
||||
$cmd .= " ".join(" ",@a) if(@a);
|
||||
}
|
||||
|
||||
$cmd =~ s/\$DEVICETOPIC/$hash->{DEVICETOPIC}/g;
|
||||
IOWrite($hash, split(" ",$cmd,2));
|
||||
return undef;
|
||||
}
|
||||
@ -207,6 +232,12 @@ sub
|
||||
MQTT2_DEVICE_Attr($$)
|
||||
{
|
||||
my ($type, $dev, $attrName, $param) = @_;
|
||||
my $hash = $defs{$dev};
|
||||
|
||||
if($attrName eq "devicetopic") {
|
||||
$hash->{DEVICETOPIC} = ($type eq "del" ? $hash->{NAME} : $param);
|
||||
return undef;
|
||||
}
|
||||
|
||||
if($attrName =~ m/(.*)List/) {
|
||||
my $atype = $1;
|
||||
@ -217,6 +248,7 @@ MQTT2_DEVICE_Attr($$)
|
||||
}
|
||||
|
||||
return "$dev attr $attrName: more parameters needed" if(!$param); #90145
|
||||
|
||||
foreach my $el (split("\n", $param)) {
|
||||
my ($par1, $par2) = split(" ", $el, 2);
|
||||
next if(!$par1);
|
||||
@ -226,8 +258,9 @@ MQTT2_DEVICE_Attr($$)
|
||||
|
||||
if($atype eq "reading") {
|
||||
if($par2 =~ m/^{.*}$/) {
|
||||
my $ret = perlSyntaxCheck($par2,
|
||||
("%TOPIC"=>1, "%EVENT"=>"0 1 2 3 4 5 6 7 8 9", "%NAME"=>$dev));
|
||||
my $ret = perlSyntaxCheck($par2,
|
||||
("%TOPIC"=>1, "%EVENT"=>"0 1 2 3 4 5 6 7 8 9",
|
||||
"%NAME"=>$dev, "%DEVICETOPIC"=>$hash->{DEVICETOPIC}));
|
||||
return $ret if($ret);
|
||||
} else {
|
||||
return "unsupported character in readingname $par2"
|
||||
@ -249,7 +282,7 @@ sub
|
||||
MQTT2_DEVICE_delReading($)
|
||||
{
|
||||
my ($name) = @_;
|
||||
my $dp = $modules{MQTT2_DEVICE}{defptr};
|
||||
my $dp = $modules{MQTT2_DEVICE}{defptr}{re};
|
||||
foreach my $re (keys %{$dp}) {
|
||||
if($dp->{$re}{$name}) {
|
||||
delete($dp->{$re}{$name});
|
||||
@ -264,7 +297,7 @@ MQTT2_DEVICE_addReading($$)
|
||||
my ($name, $param) = @_;
|
||||
foreach my $line (split("\n", $param)) {
|
||||
my ($re,$code) = split(" ", $line,2);
|
||||
$modules{MQTT2_DEVICE}{defptr}{$re}{$name} = $code;
|
||||
$modules{MQTT2_DEVICE}{defptr}{re}{$re}{$name} = $code;
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,6 +318,7 @@ MQTT2_DEVICE_Undef($$)
|
||||
{
|
||||
my ($hash, $arg) = @_;
|
||||
MQTT2_DEVICE_delReading($arg);
|
||||
delete $modules{MQTT2_DEVICE}{defptr}{cid}{$hash->{CID}} if($hash->{CID});
|
||||
return undef;
|
||||
}
|
||||
|
||||
@ -331,6 +365,13 @@ MQTT2_DEVICE_Undef($$)
|
||||
<b>Attributes</b>
|
||||
<ul>
|
||||
|
||||
<a name="devicetopic"></a>
|
||||
<li>devicetopic value<br>
|
||||
replace $DEVICETOPIC in the topic part of readingList, setList and
|
||||
getList with value. if not set, $DEVICETOPIC will be replaced with the
|
||||
name of the device.
|
||||
</li><br>
|
||||
|
||||
<li><a href="#disable">disable</a><br>
|
||||
<a href="#disabledForIntervals">disabledForIntervals</a></li><br>
|
||||
|
||||
@ -352,10 +393,10 @@ MQTT2_DEVICE_Undef($$)
|
||||
</code><br>
|
||||
Notes:
|
||||
<ul>
|
||||
<li>in the perl expression the variables $TOPIC and $EVENT are
|
||||
available (the letter containing the whole message), as well as
|
||||
$EVTPART0, $EVTPART1, ... each containing a single word of the
|
||||
message.</li>
|
||||
<li>in the perl expression the variables $TOPIC, $NAME, $DEVICETOPIC
|
||||
and $EVENT are available (the letter containing the whole message),
|
||||
as well as $EVTPART0, $EVTPART1, ... each containing a single word of
|
||||
the message.</li>
|
||||
<li>the helper function json2nameValue($EVENT) can be used to parse a
|
||||
json encoded value. Importing all values from a Sonoff device with a
|
||||
Tasmota firmware can be done with:
|
||||
|
Loading…
x
Reference in New Issue
Block a user