From bee096a00c3cb7fc5d1f8b8cc617ada2265b8ba0 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>