mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-04 05:16:45 +00:00
bugfix: *:retain in mqttPublish without function (qos too)
improvement: $uid variable in expressions (mqttPublish) bugfix: replace vars in _evalValue2 feature: supports multiple topics pro reading (mqttPublish) git-svn-id: https://svn.fhem.de/fhem/trunk@19477 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
9726ddaf30
commit
e7765ddb60
@ -30,6 +30,30 @@
|
|||||||
#
|
#
|
||||||
# CHANGE LOG
|
# CHANGE LOG
|
||||||
#
|
#
|
||||||
|
# 27.05.2019 1.2.1
|
||||||
|
# bugfix : fixed *:retain in mqttPublish ohne Funktion (auch qos)
|
||||||
|
# jetzt werden *:xxx Angaben aus mqttPublish und auch
|
||||||
|
# mqttDefaultPublis (in der GenericBridge) ausgewertet
|
||||||
|
#
|
||||||
|
# 26.05.2019 1.2.0
|
||||||
|
# improvement: Unterstuetzung fuer Variable $uid in expression-Anweisungen
|
||||||
|
# (mqttPublish)
|
||||||
|
#
|
||||||
|
# 24.05.2019 1.1.9
|
||||||
|
# improvement: Aufnahme Methoden in Import: toJSON, TimeNow
|
||||||
|
# bugfix : Ersetzen von (Pseudo)Variablen in _evalValue2 ohne Auswirkung
|
||||||
|
# (falsche Variable verwendet)
|
||||||
|
#
|
||||||
|
# 23.05.2019 1.1.8
|
||||||
|
# feature : Unterstuetzung von mehrfachen Topics fuer eine und dieselbe
|
||||||
|
# reading (mqttPublish).
|
||||||
|
# Die Definitionen muessen einen durch '!' getrennten
|
||||||
|
# einmaligen Postfix erhalten: reading!postfix:topic=test/test
|
||||||
|
#
|
||||||
|
# 21.05.2019 1.1.7
|
||||||
|
# cleanup : Unnoetige 'stopic'-code bei 'publish'
|
||||||
|
# ('stopic' ist nur was fuer subscribe)
|
||||||
|
#
|
||||||
# 07.03.2019 1.1.7
|
# 07.03.2019 1.1.7
|
||||||
# fix : Anpassung fuer MQTT2*
|
# fix : Anpassung fuer MQTT2*
|
||||||
# (https://forum.fhem.de/index.php?topic=98249.new#new)
|
# (https://forum.fhem.de/index.php?topic=98249.new#new)
|
||||||
@ -272,6 +296,7 @@
|
|||||||
#
|
#
|
||||||
# [done]
|
# [done]
|
||||||
# - global base (sollte in $base verwendet werden koennen)
|
# - global base (sollte in $base verwendet werden koennen)
|
||||||
|
# - Support for MQTT2_SERVER
|
||||||
#
|
#
|
||||||
# [i like it]
|
# [i like it]
|
||||||
# - resend / interval, Warteschlange
|
# - resend / interval, Warteschlange
|
||||||
@ -282,7 +307,6 @@
|
|||||||
# - QOS for subscribe (fertig?), defaults(qos, fertig?), alias mapping
|
# - QOS for subscribe (fertig?), defaults(qos, fertig?), alias mapping
|
||||||
# - global subscribe
|
# - global subscribe
|
||||||
# - global excludes
|
# - global excludes
|
||||||
# - Support for MQTT2_SERVER
|
|
||||||
# - commands per mqtt fuer die Bridge: Liste der Geraete, Infos dazu etc.
|
# - commands per mqtt fuer die Bridge: Liste der Geraete, Infos dazu etc.
|
||||||
# - mqttOptions (zuschaltbare optionen im Form eines Perl-Routine) (json, ttl)
|
# - mqttOptions (zuschaltbare optionen im Form eines Perl-Routine) (json, ttl)
|
||||||
#
|
#
|
||||||
@ -299,7 +323,7 @@
|
|||||||
# Bugs:
|
# Bugs:
|
||||||
#
|
#
|
||||||
# [done]
|
# [done]
|
||||||
# - Zeilenumbruch wird nicht als Trennen zw. topic-Definitionen erkannt, nur mit einem zusaetzlichen Leerzeichen
|
# - Zeilenumbruch wird nicht als Trenner zw. topic-Definitionen erkannt, nur mit einem zusaetzlichen Leerzeichen
|
||||||
# - Keys enthalten Zeilenumbrueche (topic, expression) => Namen der Readings etc. trimmen bzw. Parser anpassen
|
# - Keys enthalten Zeilenumbrueche (topic, expression) => Namen der Readings etc. trimmen bzw. Parser anpassen
|
||||||
# - Variablen in Expression funktionieren nicht, wenn Topic kein perl-Expression ist
|
# - Variablen in Expression funktionieren nicht, wenn Topic kein perl-Expression ist
|
||||||
# - atopic wird in devInfo nicht dargestellt
|
# - atopic wird in devInfo nicht dargestellt
|
||||||
@ -319,7 +343,7 @@ use warnings;
|
|||||||
|
|
||||||
#my $DEBUG = 1;
|
#my $DEBUG = 1;
|
||||||
my $cvsid = '$Id$';
|
my $cvsid = '$Id$';
|
||||||
my $VERSION = "version 1.1.7 by hexenmeister\n$cvsid";
|
my $VERSION = "version 1.2.1 by hexenmeister\n$cvsid";
|
||||||
|
|
||||||
my %sets = (
|
my %sets = (
|
||||||
);
|
);
|
||||||
@ -434,6 +458,8 @@ BEGIN {
|
|||||||
InternalTimer
|
InternalTimer
|
||||||
RemoveInternalTimer
|
RemoveInternalTimer
|
||||||
json2nameValue
|
json2nameValue
|
||||||
|
toJSON
|
||||||
|
TimeNow
|
||||||
IOWrite
|
IOWrite
|
||||||
CTRL_ATTR_NAME_DEFAULTS
|
CTRL_ATTR_NAME_DEFAULTS
|
||||||
CTRL_ATTR_NAME_ALIAS
|
CTRL_ATTR_NAME_ALIAS
|
||||||
@ -489,7 +515,7 @@ sub defineGlobalTypeExclude($;$);
|
|||||||
sub defineGlobalDevExclude($;$);
|
sub defineGlobalDevExclude($;$);
|
||||||
sub defineDefaultGlobalExclude($);
|
sub defineDefaultGlobalExclude($);
|
||||||
sub isTypeDevReadingExcluded($$$$$);
|
sub isTypeDevReadingExcluded($$$$$);
|
||||||
sub getDevicePublishRecIntern($$$$$);
|
sub getDevicePublishRecIntern($$$$$$$);
|
||||||
sub getDevicePublishRec($$$);
|
sub getDevicePublishRec($$$);
|
||||||
sub isConnected($);
|
sub isConnected($);
|
||||||
sub ioDevConnect($);
|
sub ioDevConnect($);
|
||||||
@ -957,6 +983,8 @@ sub CreateSingleDeviceTableAttrAlias($$$$) {
|
|||||||
# Params: Bridge-Hash, Dev-Name (im Map, ist auch = DevName),
|
# Params: Bridge-Hash, Dev-Name (im Map, ist auch = DevName),
|
||||||
# Internes Map mit allen Definitionen fuer alle Gerate,
|
# Internes Map mit allen Definitionen fuer alle Gerate,
|
||||||
# Attribute-Value zum Parsen
|
# Attribute-Value zum Parsen
|
||||||
|
# NB: stopic gibt es beim 'publish' nicht
|
||||||
|
# ?: internal-topic? - keine Verwendung bis jetzt
|
||||||
sub CreateSingleDeviceTableAttrPublish($$$$) {
|
sub CreateSingleDeviceTableAttrPublish($$$$) {
|
||||||
my($hash, $dev, $map, $attrVal) = @_;
|
my($hash, $dev, $map, $attrVal) = @_;
|
||||||
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] CreateSingleDeviceTableAttrPublish: $dev, $attrVal, ".Dumper($map));
|
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] CreateSingleDeviceTableAttrPublish: $dev, $attrVal, ".Dumper($map));
|
||||||
@ -981,6 +1009,7 @@ sub CreateSingleDeviceTableAttrPublish($$$$) {
|
|||||||
if(!defined($ident) or !defined($name)) { next; }
|
if(!defined($ident) or !defined($name)) { next; }
|
||||||
if(($ident eq 'topic') or ($ident eq 'readings-topic') or
|
if(($ident eq 'topic') or ($ident eq 'readings-topic') or
|
||||||
($ident eq 'atopic') or ($ident eq 'attr-topic') or
|
($ident eq 'atopic') or ($ident eq 'attr-topic') or
|
||||||
|
#($ident eq 'stopic') or ($ident eq 'set-topic') or # stopic nur bei subscribe
|
||||||
($ident eq 'qos') or ($ident eq 'retain') or
|
($ident eq 'qos') or ($ident eq 'retain') or
|
||||||
($ident eq 'expression') or
|
($ident eq 'expression') or
|
||||||
($ident eq 'resendOnConnect') or
|
($ident eq 'resendOnConnect') or
|
||||||
@ -992,7 +1021,7 @@ sub CreateSingleDeviceTableAttrPublish($$$$) {
|
|||||||
$map->{$dev}->{':publish'}->{$namePart}->{$ident}=$val;
|
$map->{$dev}->{':publish'}->{$namePart}->{$ident}=$val;
|
||||||
|
|
||||||
$map->{$dev}->{':publish'}->{$namePart}->{'mode'} = 'R' if (($ident eq 'topic') or ($ident eq 'readings-topic'));
|
$map->{$dev}->{':publish'}->{$namePart}->{'mode'} = 'R' if (($ident eq 'topic') or ($ident eq 'readings-topic'));
|
||||||
$map->{$dev}->{':publish'}->{$namePart}->{'mode'} = 'S' if (($ident eq 'stopic') or ($ident eq 'set-topic'));
|
#$map->{$dev}->{':publish'}->{$namePart}->{'mode'} = 'S' if (($ident eq 'stopic') or ($ident eq 'set-topic'));
|
||||||
$map->{$dev}->{':publish'}->{$namePart}->{'mode'} = 'A' if (($ident eq 'atopic') or ($ident eq 'attr-topic'));
|
$map->{$dev}->{':publish'}->{$namePart}->{'mode'} = 'A' if (($ident eq 'atopic') or ($ident eq 'attr-topic'));
|
||||||
|
|
||||||
$autoResend->{$namePart} = $val if $ident eq 'autoResendInterval';
|
$autoResend->{$namePart} = $val if $ident eq 'autoResendInterval';
|
||||||
@ -1030,25 +1059,37 @@ sub updatePubTime($$$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# sucht zu den gegebenen device und reading die publish-Eintraege (topic, qos, retain)
|
# sucht zu den gegebenen device und reading die publish-Eintraege (topic, qos, retain)
|
||||||
|
# liefert Liste der passenden dev-hashes
|
||||||
# verwendet device-record und beruecksichtigt defaults und globals
|
# verwendet device-record und beruecksichtigt defaults und globals
|
||||||
# parameter: $hash, device-name, reading-name
|
# parameter: $hash, device-name, reading-name
|
||||||
sub getDevicePublishRec($$$) {
|
sub getDevicePublishRec($$$) {
|
||||||
my($hash, $dev, $reading) = @_;
|
my($hash, $dev, $reading) = @_;
|
||||||
|
my $ret = [];
|
||||||
my $map = $hash->{+HS_TAB_NAME_DEVICES};
|
my $map = $hash->{+HS_TAB_NAME_DEVICES};
|
||||||
return undef unless defined $map;
|
return $ret unless defined $map;
|
||||||
|
|
||||||
my $devMap = $map->{$dev};
|
|
||||||
my $globalMap = $map->{':global'};
|
my $globalMap = $map->{':global'};
|
||||||
|
my $devMap = $map->{$dev};
|
||||||
|
|
||||||
return getDevicePublishRecIntern($hash, $devMap, $globalMap, $dev, $reading);
|
foreach my $key (keys %{$devMap->{':publish'}} ) {
|
||||||
|
my($keyRName,$keyPostfix) = split("!",$key);
|
||||||
|
if($keyRName eq $reading) {
|
||||||
|
my $devRec = getDevicePublishRecIntern($hash, $devMap, $globalMap, $dev, $key, $reading, $keyPostfix);
|
||||||
|
#$devRec->{'postfix'}=defined($keyPostfix)?$keyPostfix:'';
|
||||||
|
push(@$ret, $devRec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
# sucht zu den gegebenen device und reading die publish-Eintraege (topic, qos, retain)
|
# sucht zu den gegebenen device und reading die publish-Eintraege (topic, qos, retain)
|
||||||
# in den uebergebenen Maps
|
# in den uebergebenen Maps
|
||||||
# verwendet device-record und beruecksichtigt defaults und globals
|
# verwendet device-record und beruecksichtigt defaults und globals
|
||||||
# parameter: $hash, map, globalMap, device-name, reading-name
|
# parameter: $hash, map, globalMap, device-name, reading-name
|
||||||
sub getDevicePublishRecIntern($$$$$) {
|
sub getDevicePublishRecIntern($$$$$$$) {
|
||||||
my($hash, $devMap, $globalMap, $dev, $reading) = @_;
|
my($hash, $devMap, $globalMap, $dev, $readingKey, $reading, $postFix) = @_;
|
||||||
|
|
||||||
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] getDevicePublishRec> params> devmap: ".Dumper($devMap));
|
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] getDevicePublishRec> params> devmap: ".Dumper($devMap));
|
||||||
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] getDevicePublishRec> params> globalmap: ".Dumper($globalMap));
|
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] getDevicePublishRec> params> globalmap: ".Dumper($globalMap));
|
||||||
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] getDevicePublishRec> params> dev: ".Dumper($dev));
|
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] getDevicePublishRec> params> dev: ".Dumper($dev));
|
||||||
@ -1061,12 +1102,16 @@ sub getDevicePublishRecIntern($$$$$) {
|
|||||||
my $globalPublishMap = $globalMap->{':publish'};
|
my $globalPublishMap = $globalMap->{':publish'};
|
||||||
|
|
||||||
# reading map
|
# reading map
|
||||||
my $readingMap = $publishMap->{$reading} if defined $publishMap;
|
my $readingMap = $publishMap->{$readingKey} if defined $publishMap;
|
||||||
my $wildcardReadingMap = $publishMap->{'*'} if defined $publishMap;
|
my $wildcardReadingMap = $publishMap->{'*'} if defined $publishMap;
|
||||||
#my $defaultReadingMap = $devMap->{':defaults'} if defined $devMap;
|
#my $defaultReadingMap = $devMap->{':defaults'} if defined $devMap;
|
||||||
|
|
||||||
# global reading map
|
# global reading map
|
||||||
my $globalReadingMap = $globalPublishMap->{$reading} if defined $globalPublishMap;
|
my $globalReadingMap = undef;
|
||||||
|
if (defined $globalPublishMap) {
|
||||||
|
$globalReadingMap = $globalPublishMap->{$readingKey};
|
||||||
|
$globalReadingMap = $globalPublishMap->{$reading} unless defined $globalReadingMap;
|
||||||
|
}
|
||||||
my $globalWildcardReadingsMap = $globalPublishMap->{'*'} if defined $globalPublishMap;
|
my $globalWildcardReadingsMap = $globalPublishMap->{'*'} if defined $globalPublishMap;
|
||||||
|
|
||||||
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] getDevicePublishRec> readingMap ".Dumper($readingMap));
|
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] getDevicePublishRec> readingMap ".Dumper($readingMap));
|
||||||
@ -1093,7 +1138,7 @@ sub getDevicePublishRecIntern($$$$$) {
|
|||||||
|
|
||||||
# qos & retain & expression
|
# qos & retain & expression
|
||||||
#my($qos, $retain, $expression) = retrieveQosRetainExpression($globalWildcardReadingsMap, $globalReadingMap, $wildcardReadingMap, $readingMap);
|
#my($qos, $retain, $expression) = retrieveQosRetainExpression($globalWildcardReadingsMap, $globalReadingMap, $wildcardReadingMap, $readingMap);
|
||||||
my($qos, $retain, $expression) = retrieveQosRetainExpression($globalMap->{':defaults'}, $globalReadingMap, $devMap->{':defaults'}, $readingMap);
|
my($qos, $retain, $expression) = retrieveQosRetainExpression($globalMap->{':defaults'}, $globalReadingMap, $globalWildcardReadingsMap, $wildcardReadingMap, $devMap->{':defaults'}, $readingMap);
|
||||||
|
|
||||||
# wenn kein topic und keine expression definiert sind, kann auch nicht gesendet werden, es muss nichts mehr ausgewertet werden
|
# wenn kein topic und keine expression definiert sind, kann auch nicht gesendet werden, es muss nichts mehr ausgewertet werden
|
||||||
return unless (defined($topic) or defined($atopic) or defined( $expression));
|
return unless (defined($topic) or defined($atopic) or defined( $expression));
|
||||||
@ -1109,10 +1154,12 @@ sub getDevicePublishRecIntern($$$$$) {
|
|||||||
# map name
|
# map name
|
||||||
my $name = undef;
|
my $name = undef;
|
||||||
if (defined($devMap) and defined($devMap->{':alias'})) {
|
if (defined($devMap) and defined($devMap->{':alias'})) {
|
||||||
$name = $devMap->{':alias'}->{'pub:'.$reading};
|
$name = $devMap->{':alias'}->{'pub:'.$readingKey};
|
||||||
|
$name = $devMap->{':alias'}->{'pub:'.$reading} unless defined $name;
|
||||||
}
|
}
|
||||||
if (defined($globalMap) and defined($globalMap->{':alias'}) and !defined($name)) {
|
if (defined($globalMap) and defined($globalMap->{':alias'}) and !defined($name)) {
|
||||||
$name = $globalMap->{':alias'}->{'pub:'.$reading};
|
$name = $globalMap->{':alias'}->{'pub:'.$readingKey};
|
||||||
|
$name = $globalMap->{':alias'}->{'pub:'.$reading} unless defined $name;
|
||||||
}
|
}
|
||||||
$name = $reading unless defined $name;
|
$name = $reading unless defined $name;
|
||||||
|
|
||||||
@ -1120,25 +1167,25 @@ sub getDevicePublishRecIntern($$$$$) {
|
|||||||
my $mode = $readingMap->{'mode'};
|
my $mode = $readingMap->{'mode'};
|
||||||
|
|
||||||
# compute defaults
|
# compute defaults
|
||||||
my $combined = computeDefaults($hash, 'pub:', $globalMap, $devMap, {'device'=>$dev,'reading'=>$reading,'name'=>$name,'mode'=>$mode});
|
my $combined = computeDefaults($hash, 'pub:', $globalMap, $devMap, {'device'=>$dev,'reading'=>$reading,'name'=>$name,'mode'=>$mode,'postfix'=>$postFix});
|
||||||
# $topic evaluieren (avialable vars: $device (device name), $reading (oringinal name), $name ($reading oder alias, if defined), defaults)
|
# $topic evaluieren (avialable vars: $device (device name), $reading (oringinal name), $name ($reading oder alias, if defined), defaults)
|
||||||
$combined->{'base'} = '' unless defined $combined->{'base'}; # base leer anlegen wenn nicht definiert
|
$combined->{'base'} = '' unless defined $combined->{'base'}; # base leer anlegen wenn nicht definiert
|
||||||
|
|
||||||
if(defined($topic) and ($topic =~ m/^{.*}$/)) {
|
if(defined($topic) and ($topic =~ m/^{.*}$/)) {
|
||||||
$topic = _evalValue2($hash->{NAME},$topic,{'topic'=>$topic,'device'=>$dev,'reading'=>$reading,'name'=>$name,%$combined}) if defined $topic;
|
$topic = _evalValue2($hash->{NAME},$topic,{'topic'=>$topic,'device'=>$dev,'reading'=>$reading,'name'=>$name,'postfix'=>$postFix,%$combined}) if defined $topic;
|
||||||
}
|
}
|
||||||
if(defined($atopic) and ($atopic =~ m/^{.*}$/)) {
|
if(defined($atopic) and ($atopic =~ m/^{.*}$/)) {
|
||||||
$atopic = _evalValue2($hash->{NAME},$atopic,{'topic'=>$atopic,'device'=>$dev,'reading'=>$reading,'name'=>$name,%$combined}) if defined $atopic;
|
$atopic = _evalValue2($hash->{NAME},$atopic,{'topic'=>$atopic,'device'=>$dev,'reading'=>$reading,'name'=>$name,'postfix'=>$postFix,%$combined}) if defined $atopic;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {'topic'=>$topic,'atopic'=>$atopic,'qos'=>$qos,'retain'=>$retain,
|
return {'topic'=>$topic,'atopic'=>$atopic,'qos'=>$qos,'retain'=>$retain,
|
||||||
'expression'=>$expression,'name'=>$name,'mode'=>$mode,
|
'expression'=>$expression,'name'=>$name,'mode'=>$mode, 'postfix'=>$postFix,
|
||||||
'resendOnConnect'=>$resendOnConnect,'.defaultMap'=>$combined};
|
'resendOnConnect'=>$resendOnConnect,'.defaultMap'=>$combined};
|
||||||
}
|
}
|
||||||
|
|
||||||
# sucht Qos, Retain, Expression Werte unter Beruecksichtigung von Defaults und Globals
|
# sucht Qos, Retain, Expression Werte unter Beruecksichtigung von Defaults und Globals
|
||||||
sub retrieveQosRetainExpression($$$$) {
|
sub retrieveQosRetainExpression($$$$$$) {
|
||||||
my($globalDefaultReadingMap, $globalReadingMap, $defaultReadingMap, $readingMap) = @_;
|
my($globalDefaultReadingMap, $globalReadingMap, $wildcardDefaultReadingMap, $wildcardReadingMap, $defaultReadingMap, $readingMap) = @_;
|
||||||
my $qos=undef;
|
my $qos=undef;
|
||||||
my $retain = undef;
|
my $retain = undef;
|
||||||
my $expression = undef;
|
my $expression = undef;
|
||||||
@ -1159,6 +1206,12 @@ sub retrieveQosRetainExpression($$$$) {
|
|||||||
# }
|
# }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(defined $wildcardReadingMap) {
|
||||||
|
$qos = $wildcardReadingMap->{'qos'} unless defined $qos;
|
||||||
|
$retain = $wildcardReadingMap->{'retain'} unless defined $retain;
|
||||||
|
$expression = $wildcardReadingMap->{'expression'} unless defined $expression;
|
||||||
|
}
|
||||||
|
|
||||||
if(defined $defaultReadingMap) {
|
if(defined $defaultReadingMap) {
|
||||||
$qos = $defaultReadingMap->{'pub:qos'} unless defined $qos;
|
$qos = $defaultReadingMap->{'pub:qos'} unless defined $qos;
|
||||||
$retain = $defaultReadingMap->{'pub:retain'} unless defined $retain;
|
$retain = $defaultReadingMap->{'pub:retain'} unless defined $retain;
|
||||||
@ -1174,8 +1227,8 @@ sub retrieveQosRetainExpression($$$$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(defined $globalReadingMap) {
|
if(defined $globalReadingMap) {
|
||||||
$qos = $globalReadingMap->{'qos'};
|
$qos = $globalReadingMap->{'qos'} unless defined $qos; # warum stand hier nicht unless defined?
|
||||||
$retain = $globalReadingMap->{'retain'};
|
$retain = $globalReadingMap->{'retain'} unless defined $retain; # s.o.?
|
||||||
$expression = $globalReadingMap->{'expression'} unless defined $expression;
|
$expression = $globalReadingMap->{'expression'} unless defined $expression;
|
||||||
# if(defined($globalReadingMap->{':defaults'})) {
|
# if(defined($globalReadingMap->{':defaults'})) {
|
||||||
# $qos = $globalReadingMap->{':defaults'}->{'pub:qos'} unless defined $qos;
|
# $qos = $globalReadingMap->{':defaults'}->{'pub:qos'} unless defined $qos;
|
||||||
@ -1184,6 +1237,12 @@ sub retrieveQosRetainExpression($$$$) {
|
|||||||
# }
|
# }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(defined $wildcardDefaultReadingMap) {
|
||||||
|
$qos = $wildcardDefaultReadingMap->{'qos'} unless defined $qos;
|
||||||
|
$retain = $wildcardDefaultReadingMap->{'retain'} unless defined $retain;
|
||||||
|
$expression = $wildcardDefaultReadingMap->{'expression'} unless defined $expression;
|
||||||
|
}
|
||||||
|
|
||||||
if(defined $globalDefaultReadingMap) {
|
if(defined $globalDefaultReadingMap) {
|
||||||
$qos = $globalDefaultReadingMap->{'pub:qos'} unless defined $qos;
|
$qos = $globalDefaultReadingMap->{'pub:qos'} unless defined $qos;
|
||||||
$retain = $globalDefaultReadingMap->{'pub:retain'} unless defined $retain;
|
$retain = $globalDefaultReadingMap->{'pub:retain'} unless defined $retain;
|
||||||
@ -1263,6 +1322,7 @@ sub _evalValue2($$;$$) {
|
|||||||
my $device = '';
|
my $device = '';
|
||||||
my $reading = '';
|
my $reading = '';
|
||||||
my $name = '';
|
my $name = '';
|
||||||
|
#my $room = '';
|
||||||
if(defined($map)) {
|
if(defined($map)) {
|
||||||
foreach my $param (keys %{$map}) {
|
foreach my $param (keys %{$map}) {
|
||||||
my $val = $map->{$param};
|
my $val = $map->{$param};
|
||||||
@ -1277,17 +1337,20 @@ sub _evalValue2($$;$$) {
|
|||||||
$device = $val;
|
$device = $val;
|
||||||
} elsif ($pname eq '$name') {
|
} elsif ($pname eq '$name') {
|
||||||
$name = $val;
|
$name = $val;
|
||||||
|
# } elsif ($pname eq '$room') {
|
||||||
|
# $room = $val;
|
||||||
} else {
|
} else {
|
||||||
#Log3('xxx',1,"MQTT_GENERIC_BRIDGE:DEBUG:> replace2: $ret : $pname => $val");
|
#Log3('xxx',1,"MQTT_GENERIC_BRIDGE:DEBUG:> replace2: $ret : $pname => $val");
|
||||||
$ret =~ s/\Q$pname\E/$val/g;
|
#$ret =~ s/\Q$pname\E/$val/g;
|
||||||
#Log3('xxx',1,"MQTT_GENERIC_BRIDGE:DEBUG:> replace2 done: $ret");
|
$s2 =~ s/\Q$pname\E/$val/g;
|
||||||
|
#Log3('xxx',1,"MQTT_GENERIC_BRIDGE:DEBUG:> replace2 done: $s2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#Log3('xxx',1,"MQTT_GENERIC_BRIDGE:DEBUG:> eval2 expr: $ret");
|
#Log3('xxx',1,"MQTT_GENERIC_BRIDGE:DEBUG:> eval2 expr: $s2");
|
||||||
#$ret = eval($ret) unless $noEval;
|
#$ret = eval($ret) unless $noEval;
|
||||||
$s2 = eval($s2) unless $noEval;
|
$s2 = eval($s2) unless $noEval;
|
||||||
#Log3('xxx',1,"MQTT_GENERIC_BRIDGE:DEBUG:> eval2 done: $ret");
|
#Log3('xxx',1,"MQTT_GENERIC_BRIDGE:DEBUG:> eval2 done: $s2");
|
||||||
if ($@) {
|
if ($@) {
|
||||||
Log3($mod,2,"MQTT_GENERIC_BRIDGE: evalValue: user value ('".$str."'') eval error: ".$@);
|
Log3($mod,2,"MQTT_GENERIC_BRIDGE: evalValue: user value ('".$str."'') eval error: ".$@);
|
||||||
$ret=$s1.''.$s3;
|
$ret=$s1.''.$s3;
|
||||||
@ -1845,7 +1908,10 @@ sub Get($$$@) {
|
|||||||
$res.=$dname."\n";
|
$res.=$dname."\n";
|
||||||
$res.=" publish:\n";
|
$res.=" publish:\n";
|
||||||
foreach my $rname (sort keys %{$hash->{+HS_TAB_NAME_DEVICES}->{$dname}->{':publish'}}) {
|
foreach my $rname (sort keys %{$hash->{+HS_TAB_NAME_DEVICES}->{$dname}->{':publish'}}) {
|
||||||
my $pubRec = getDevicePublishRec($hash, $dname, $rname);
|
#my $pubRec = getDevicePublishRec($hash, $dname, $rname);
|
||||||
|
my $pubRecList = getDevicePublishRec($hash, $dname, $rname);
|
||||||
|
if(defined($pubRecList)) {
|
||||||
|
foreach my $pubRec (@$pubRecList) {
|
||||||
if(defined($pubRec)) {
|
if(defined($pubRec)) {
|
||||||
my $expression = $pubRec->{'expression'};
|
my $expression = $pubRec->{'expression'};
|
||||||
my $mode = $pubRec->{'mode'};
|
my $mode = $pubRec->{'mode'};
|
||||||
@ -1863,7 +1929,10 @@ sub Get($$$@) {
|
|||||||
$topic = 'undefined' unless defined $topic;
|
$topic = 'undefined' unless defined $topic;
|
||||||
my $qos = $pubRec->{'qos'};
|
my $qos = $pubRec->{'qos'};
|
||||||
my $retain = $pubRec->{'retain'};
|
my $retain = $pubRec->{'retain'};
|
||||||
$res.= sprintf(' %-16s => %s', $rname, $topic);
|
my $postFix = $pubRec->{'postfix'};
|
||||||
|
my $dispName = $rname;
|
||||||
|
if(defined($postFix) and ($postFix ne '')) {$dispName.='!'.$postFix;}
|
||||||
|
$res.= sprintf(' %-16s => %s', $dispName, $topic);
|
||||||
$res.= " (";
|
$res.= " (";
|
||||||
$res.= "mode: $mode";
|
$res.= "mode: $mode";
|
||||||
$res.= "; qos: $qos";
|
$res.= "; qos: $qos";
|
||||||
@ -1871,6 +1940,8 @@ sub Get($$$@) {
|
|||||||
$res.= ")\n";
|
$res.= ")\n";
|
||||||
$res.= " exp: $expression\n" if defined ($expression);
|
$res.= " exp: $expression\n" if defined ($expression);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$res.=" subscribe:\n";
|
$res.=" subscribe:\n";
|
||||||
my @resa;
|
my @resa;
|
||||||
@ -2330,9 +2401,10 @@ sub publishDeviceUpdate($$$$$) {
|
|||||||
return if(isTypeDevReadingExcluded($hash, 'pub', $type, $devn, $reading));
|
return if(isTypeDevReadingExcluded($hash, 'pub', $type, $devn, $reading));
|
||||||
|
|
||||||
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] publishDeviceUpdate for $devn, $reading, $value");
|
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] publishDeviceUpdate for $devn, $reading, $value");
|
||||||
my $pubRec = getDevicePublishRec($hash, $devn, $reading);
|
my $pubRecList = getDevicePublishRec($hash, $devn, $reading);
|
||||||
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] publishDeviceUpdate pubRec: ".Dumper($pubRec));
|
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> [$hash->{NAME}] publishDeviceUpdate pubRec: ".Dumper($pubRec));
|
||||||
|
if(defined($pubRecList)) {
|
||||||
|
foreach my $pubRec (@$pubRecList) {
|
||||||
if(defined($pubRec)) {
|
if(defined($pubRec)) {
|
||||||
# my $msgid;
|
# my $msgid;
|
||||||
|
|
||||||
@ -2368,10 +2440,18 @@ sub publishDeviceUpdate($$$$$) {
|
|||||||
# $device, $reading, $name (und fuer alle Faelle $topic) in $defMap packen, so zur Verfügung stellen (für eval)reicht wegen _evalValue2 wohl nicht
|
# $device, $reading, $name (und fuer alle Faelle $topic) in $defMap packen, so zur Verfügung stellen (für eval)reicht wegen _evalValue2 wohl nicht
|
||||||
my $name = $reading; # TODO: Name-Mapping
|
my $name = $reading; # TODO: Name-Mapping
|
||||||
my $device = $devn;
|
my $device = $devn;
|
||||||
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> DEBUG: >>> expression: $expression");
|
#if(!defined($defMap->{'room'})) {
|
||||||
my $ret = _evalValue2($hash->{NAME},$expression,{'topic'=>$topic,'device'=>$devn,'reading'=>$reading,'name'=>$name,%$defMap},1);
|
# $defMap->{'room'} = AttrVal($devn,'room','');
|
||||||
|
#}
|
||||||
|
if(!defined($defMap->{'uid'}) and defined($defs{$devn})) {
|
||||||
|
$defMap->{'uid'} = $defs{$devn}->{'FUUID'};
|
||||||
|
$defMap->{'uid'} = '' unless defined $defMap->{'uid'};
|
||||||
|
}
|
||||||
|
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> DEBUG: >>> expression: $expression : ".Dumper($defMap));
|
||||||
|
my $ret = _evalValue2($hash->{NAME},$expression,{'topic'=>$topic,'device'=>$devn,'reading'=>$reading,'name'=>$name,'time'=>TimeNow(),%$defMap},1);
|
||||||
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> DEBUG: <<< expression: ".Dumper($ret));
|
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> DEBUG: <<< expression: ".Dumper($ret));
|
||||||
$ret = eval($ret);
|
$ret = eval($ret);
|
||||||
|
#Log3($hash->{NAME},1,"MQTT_GENERIC_BRIDGE:DEBUG:> DEBUG: <<< eval expression: ".Dumper($ret));
|
||||||
if(ref($ret) eq 'HASH') {
|
if(ref($ret) eq 'HASH') {
|
||||||
$redefMap = $ret;
|
$redefMap = $ret;
|
||||||
} elsif(ref($ret) eq 'ARRAY') {
|
} elsif(ref($ret) eq 'ARRAY') {
|
||||||
@ -2399,7 +2479,7 @@ sub publishDeviceUpdate($$$$$) {
|
|||||||
$updated = 1 unless defined $r;
|
$updated = 1 unless defined $r;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
my $r = doPublish($hash,$devn,$reading,$topic,$message,$qos,$retain,$resendOnConnect) if defined $topic;
|
my $r = doPublish($hash,$devn,$reading,$topic,$message,$qos,$retain,$resendOnConnect) if defined $topic and defined $message;
|
||||||
$updated = 1 unless defined $r;
|
$updated = 1 unless defined $r;
|
||||||
}
|
}
|
||||||
if($updated) {
|
if($updated) {
|
||||||
@ -2408,6 +2488,8 @@ sub publishDeviceUpdate($$$$$) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Routine fuer FHEM Attr
|
# Routine fuer FHEM Attr
|
||||||
sub Attr($$$$) {
|
sub Attr($$$$) {
|
||||||
@ -2944,8 +3026,10 @@ sub onmessage($$$) {
|
|||||||
If a '*' is used instead of a read name, this definition applies to all readings for which no explicit information was provided.<br/>
|
If a '*' is used instead of a read name, this definition applies to all readings for which no explicit information was provided.<br/>
|
||||||
Topic can also be written as a 'readings-topic'.<br/>
|
Topic can also be written as a 'readings-topic'.<br/>
|
||||||
Attributes can also be sent ("atopic" or "attr-topic").
|
Attributes can also be sent ("atopic" or "attr-topic").
|
||||||
|
If you wont to send several messages (meaningfully to different topics) for an event, the respective definitions must be defined by appending
|
||||||
|
unique suffixes (separated from the reading name by a !-sign): reading!1:topic=... reading!2:topic=.... <br/>
|
||||||
It is possible to define expressions (reading: expression = ...). <br/>
|
It is possible to define expressions (reading: expression = ...). <br/>
|
||||||
The expressions could usefully change variables ($value, $topic, $qos, $retain, $message), or return a value of != undef.<br/>
|
The expressions could usefully change variables ($value, $topic, $qos, $retain, $message, $uid), or return a value of != undef.<br/>
|
||||||
The return value is used as a new message value, the changed variables have priority.<br/>
|
The return value is used as a new message value, the changed variables have priority.<br/>
|
||||||
If the return value is undef, setting / execution is suppressed. <br/>
|
If the return value is undef, setting / execution is suppressed. <br/>
|
||||||
If the return is a hash (topic only), its key values are used as the topic, and the contents of the messages are the values from the hash.</p>
|
If the return is a hash (topic only), its key values are used as the topic, and the contents of the messages are the values from the hash.</p>
|
||||||
@ -2967,8 +3051,9 @@ sub onmessage($$$) {
|
|||||||
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"message: $value"}<br/>
|
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"message: $value"}<br/>
|
||||||
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={$value="message: $value"}<br/>
|
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={$value="message: $value"}<br/>
|
||||||
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"/TEST/Topic1"=>"$message", "/TEST/Topic2"=>"message: $message"}<br/>
|
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"/TEST/Topic1"=>"$message", "/TEST/Topic2"=>"message: $message"}<br/>
|
||||||
attr <dev> mqttPublish *:resendOnConnect=last
|
attr <dev> mqttPublish *:resendOnConnect=last<br/>
|
||||||
|
attr <dev> mqttPublish temperature:topic={"$base/temperature/01/value"} temperature!json:topic={"$base/temperature/01/json"}
|
||||||
|
temperature!json:expression={toJSON({value=>$value,type=>"temperature",unit=>"°C",format=>"00.0"})}<br/>
|
||||||
</code></p>
|
</code></p>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
@ -3340,9 +3425,11 @@ sub onmessage($$$) {
|
|||||||
indem sie, mittels '|' getrennt, zusammen angegeben werden.<br/>
|
indem sie, mittels '|' getrennt, zusammen angegeben werden.<br/>
|
||||||
Wird anstatt eines Readingsnamen ein '*' verwendet, gilt diese Definition fuer alle Readings,
|
Wird anstatt eines Readingsnamen ein '*' verwendet, gilt diese Definition fuer alle Readings,
|
||||||
fuer die keine explizite Angaben gemacht wurden.<br/>
|
fuer die keine explizite Angaben gemacht wurden.<br/>
|
||||||
Ebenso koennen auch Attributwerte gesendet werden ('atopic' oder 'attr-topic').
|
Ebenso koennen auch Attributwerte gesendet werden ('atopic' oder 'attr-topic').<br/>
|
||||||
|
Sollten fuer ein Event mehrere Nachrichten (sinnvollerweise an verschiedene Topics) versendet werden, muessen jeweilige Definitionen durch Anhaengen von
|
||||||
|
einmaligen Suffixen (getrennt von dem Readingnamen durch ein !-Zeichen) unterschieden werden: reading!1:topic=... reading!2:topic=....<br/>
|
||||||
Weiterhin koennen auch Expressions (reading:expression=...) definiert werden. <br/>
|
Weiterhin koennen auch Expressions (reading:expression=...) definiert werden. <br/>
|
||||||
Die Expressions koenne sinnvollerweise entweder Variablen ($value, $topic, $qos, $retain, $message) veraendern, oder einen Wert != undef zurrueckgeben.<br/>
|
Die Expressions koenne sinnvollerweise entweder Variablen ($value, $topic, $qos, $retain, $message, $uid) veraendern, oder einen Wert != undef zurrueckgeben.<br/>
|
||||||
Der Rueckhgabe wert wird als neue Nachricht-Value verwendet, die Aenderung der Variablen hat dabei jedoch Vorrang.<br/>
|
Der Rueckhgabe wert wird als neue Nachricht-Value verwendet, die Aenderung der Variablen hat dabei jedoch Vorrang.<br/>
|
||||||
Ist der Rueckgabewert undef, dann wird das Setzen/Ausfuehren unterbunden. <br/>
|
Ist der Rueckgabewert undef, dann wird das Setzen/Ausfuehren unterbunden. <br/>
|
||||||
Ist die Rueckgabe ein Hash (nur 'topic'), werden seine Schluesselwerte als Topic verwendet,
|
Ist die Rueckgabe ein Hash (nur 'topic'), werden seine Schluesselwerte als Topic verwendet,
|
||||||
@ -3366,7 +3453,9 @@ sub onmessage($$$) {
|
|||||||
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"message: $value"}<br/>
|
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"message: $value"}<br/>
|
||||||
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={$value="message: $value"}<br/>
|
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={$value="message: $value"}<br/>
|
||||||
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"/TEST/Topic1"=>"$message", "/TEST/Topic2"=>"message: $message"}</br>
|
attr <dev> mqttPublish *:topic={"$base/$name"} reading:expression={"/TEST/Topic1"=>"$message", "/TEST/Topic2"=>"message: $message"}</br>
|
||||||
attr <dev> mqttPublish [...] *:resendOnConnect=last
|
attr <dev> mqttPublish [...] *:resendOnConnect=last<br/>
|
||||||
|
attr <dev> mqttPublish temperature:topic={"$base/temperature/01/value"} temperature!json:topic={"$base/temperature/01/json"}
|
||||||
|
temperature!json:expression={toJSON({value=>$value,type=>"temperature",unit=>"°C",format=>"00.0"})}<br/>
|
||||||
</code></p>
|
</code></p>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user