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