From 1b4e4b397ac3be782b5eec12c436309dc32ca360 Mon Sep 17 00:00:00 2001
From: eisler
Date: Sun, 29 Apr 2018 12:53:05 +0000
Subject: [PATCH] 00_MQTT: topics and payload patch (Forum: #86270)
git-svn-id: https://svn.fhem.de/fhem/trunk@16674 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/CHANGED | 1 +
fhem/FHEM/00_MQTT.pm | 56 +++++++++++++++++++++++--------------
fhem/FHEM/10_MQTT_BRIDGE.pm | 2 ++
fhem/FHEM/10_MQTT_DEVICE.pm | 7 +++--
4 files changed, 43 insertions(+), 23 deletions(-)
diff --git a/fhem/CHANGED b/fhem/CHANGED
index b3fc28246..717d4e109 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,6 @@
# 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.
+ - bugfix: 00_MQTT: topics and payload patch
- bugfix: 73_GardenaSmartBridge: fix fetch token after rereadcfg
- feature: 60_allergy: alternative data source for extended 5 day forecast
- new: 74_HusqvarnaAutomower.pm: New module to control your
diff --git a/fhem/FHEM/00_MQTT.pm b/fhem/FHEM/00_MQTT.pm
index 754727155..a87adfb54 100644
--- a/fhem/FHEM/00_MQTT.pm
+++ b/fhem/FHEM/00_MQTT.pm
@@ -242,11 +242,12 @@ sub Set($@) {
};
}
-sub parseParams($;$$) {
+sub parseParams($;$$$$) {
- my ( $cmd, $separator, $joiner ) = @_;
+ my ( $cmd, $separator, $joiner, $keyvalueseparator, $acceptedkeys ) = @_;
$separator = ' ' if ( !$separator );
$joiner = $separator if ( !$joiner ); # needed if separator is a regexp
+ $keyvalueseparator = ':' if(!$keyvalueseparator);
my ( @a, %h );
my @params;
@@ -260,7 +261,7 @@ sub parseParams($;$$) {
while (@params) {
my $param = shift(@params);
next if ( $param eq "" );
- my ( $key, $value ) = split( ':', $param, 2 );
+ my ( $key, $value ) = split( $keyvalueseparator, $param, 2 );
if ( !defined($value) ) {
$value = $key;
@@ -272,6 +273,16 @@ sub parseParams($;$$) {
$value = $param;
$key = undef;
}
+ # the key can not start with a ' or "
+ elsif ( $key =~ m/^\s*('|")/ ) {
+ $value = $param;
+ $key = undef;
+ }
+ # accept known keys only (if defined $acceptedkeys)
+ elsif (defined($acceptedkeys) and !defined($acceptedkeys->{$key})) {
+ $value = $param;
+ $key = undef;
+ }
#collect all parts until the closing ' or "
while ( $param && $value =~ m/^('|")/ && $value !~ m/$1$/ ) {
@@ -321,22 +332,16 @@ sub parseParams($;$$) {
sub parsePublishCmdStr($) {
my ($str) = @_;
- if(defined($str) && $str=~m/\s*(?:({.*})\s+)?(.*)/) {
- my $exp = $1;
- my $rest = $2;
- if ($rest){
- my @lwa = split("[ \t]+",$rest);
- unshift (@lwa,$exp) if($exp);
- return parsePublishCmd(@lwa);
- }
- }
- return undef;
+ return undef unless defined($str);
+
+ my @lwa = split("[ \t]+",$str);
+ return parsePublishCmd(@lwa);
}
sub parsePublishCmd(@) {
my @a = @_;
- my ( $aa, $bb ) = parseParams(\@a);
-
+ my ( $aa, $bb ) = parseParams(\@a,undef,undef,undef,{qos=>1,retain=>1});
+
my $qos = 0;
my $retain = 0;
my $topic = undef;
@@ -356,7 +361,7 @@ sub parsePublishCmd(@) {
while ( scalar(@xaa) > 0 ) {
my $av = shift @xaa;
- if ( $av =~ /\{.*\}/ ) {
+ if (!defined($expression) and $av =~ /^\{.*\}$/ and scalar(@xaa)>0) {
$expression = $av;
next;
}
@@ -695,6 +700,7 @@ sub send_message($$$@) {
sub topic_to_regexp($) {
my $t = shift;
$t =~ s|#$|.\*|;
+ $t =~ s|\$|\\\$|g;
$t =~ s|\/\.\*$|.\*|;
$t =~ s|\/|\\\/|g;
$t =~ s|(\+)([^+]*$)|(+)$2|;
@@ -705,6 +711,7 @@ sub topic_to_regexp($) {
sub client_subscribe_topic($$;$$) {
my ($client,$topic,$qos,$retain) = @_;
push @{$client->{subscribe}},$topic unless grep {$_ eq $topic} @{$client->{subscribe}};
+ $client->{subscribeQos}->{$topic}=$qos;
my $expr = topic_to_regexp($topic);
push @{$client->{subscribeExpr}},$expr unless grep {$_ eq $expr} @{$client->{subscribeExpr}};
if ($main::init_done) {
@@ -723,6 +730,7 @@ sub client_subscribe_topic($$;$$) {
sub client_unsubscribe_topic($$) {
my ($client,$topic) = @_;
$client->{subscribe} = [grep { $_ ne $topic } @{$client->{subscribe}}];
+ delete $client->{subscribeQos}->{$topic};
my $expr = topic_to_regexp($topic);
$client->{subscribeExpr} = [grep { $_ ne $expr} @{$client->{subscribeExpr}}];
if ($main::init_done) {
@@ -744,6 +752,7 @@ sub Client_Define($$) {
$client->{".qos"}->{'*'} = 0;
$client->{".retain"}->{'*'} = "0";
$client->{subscribe} = [];
+ $client->{subscribeQos} = {};
$client->{subscribeExpr} = [];
AssignIoPort($client);
@@ -875,13 +884,15 @@ sub client_attr($$$$$) {
sub client_start($) {
my $client = shift;
- my $name = $client->{NAME};
- if (! (defined AttrVal($name,"stateFormat",undef))) {
- $main::attr{$name}{stateFormat} = "transmission-state";
- }
+ CallFn($client->{NAME},"OnClientStartFn",($client));
+
+ #my $name = $client->{NAME};
+ #if (! (defined AttrVal($name,"stateFormat",undef))) {
+ # $main::attr{$name}{stateFormat} = "transmission-state";
+ #}
if (@{$client->{subscribe}}) {
my $msgid = send_subscribe($client->{IODev},
- topics => [map { [$_ => $client->{".qos"}->{$_} || MQTT_QOS_AT_MOST_ONCE] } @{$client->{subscribe}}],
+ topics => [map { [$_ => $client->{subscribeQos}->{$_} || MQTT_QOS_AT_MOST_ONCE] } @{$client->{subscribe}}],
);
$client->{message_ids}->{$msgid}++;
readingsSingleUpdate($client,"transmission-state","subscribe sent",1);
@@ -892,6 +903,7 @@ sub client_start($) {
sub client_stop($) {
my $client = shift;
+
if (@{$client->{subscribe}}) {
my $msgid = send_unsubscribe($client->{IODev},
topics => [@{$client->{subscribe}}],
@@ -899,6 +911,8 @@ sub client_stop($) {
$client->{message_ids}->{$msgid}++;
readingsSingleUpdate($client,"transmission-state","unsubscribe sent",1);
}
+
+ CallFn($client->{NAME},"OnClientStopFn",($client));
};
1;
diff --git a/fhem/FHEM/10_MQTT_BRIDGE.pm b/fhem/FHEM/10_MQTT_BRIDGE.pm
index 3b8d84962..b61562b14 100644
--- a/fhem/FHEM/10_MQTT_BRIDGE.pm
+++ b/fhem/FHEM/10_MQTT_BRIDGE.pm
@@ -39,6 +39,8 @@ sub MQTT_BRIDGE_Initialize($) {
my $hash = shift @_;
+ require "$main::attr{global}{modpath}/FHEM/00_MQTT.pm";
+
# Consumer
$hash->{DefFn} = "MQTT::Client_Define";
$hash->{UndefFn} = "MQTT::Client_Undefine";
diff --git a/fhem/FHEM/10_MQTT_DEVICE.pm b/fhem/FHEM/10_MQTT_DEVICE.pm
index f99497fda..52e3960e9 100644
--- a/fhem/FHEM/10_MQTT_DEVICE.pm
+++ b/fhem/FHEM/10_MQTT_DEVICE.pm
@@ -35,6 +35,8 @@ sub MQTT_DEVICE_Initialize($) {
my $hash = shift @_;
+ require "$main::attr{global}{modpath}/FHEM/00_MQTT.pm";
+
# Consumer
$hash->{DefFn} = "MQTT::DEVICE::Define";
$hash->{UndefFn} = "MQTT::Client_Undefine";
@@ -188,7 +190,7 @@ sub Attr($$$$) {
};
$attribute =~ /^publishSet(_?)(.*)/ and do {
if ($command eq "set") {
- my ( $aa, $bb ) = parseParams($value);
+ my ( $aa, $bb ) = parseParams($value,undef,undef,undef,{});
my @values = @{$aa};
my $topic = pop @values;
$hash->{publishSets}->{$2} = {
@@ -306,7 +308,8 @@ sub onmessage($$$) {
attr <name> autoSubscribeReadings <topic>
specify a mqtt-topic pattern with wildcard (e.c. 'myhouse/kitchen/+') and MQTT_DEVICE automagically creates readings based on the wildcard-match
- e.g a message received with topic 'myhouse/kitchen/temperature' would create and update a reading 'temperature'
+ e.g a message received with topic 'myhouse/kitchen/temperature' would create and update a reading 'temperature'.
+ Please note that topics with spaces will not work here!
attr <name> subscribeReading_<reading> [{Perl-expression}] [qos:?] [retain:?] <topic>