diff --git a/fhem/FHEM/10_MQTT2_DEVICE.pm b/fhem/FHEM/10_MQTT2_DEVICE.pm
index 79e9a46b1..aee30a8f7 100644
--- a/fhem/FHEM/10_MQTT2_DEVICE.pm
+++ b/fhem/FHEM/10_MQTT2_DEVICE.pm
@@ -28,6 +28,7 @@ MQTT2_DEVICE_Initialize($)
disable:0,1
disabledForIntervals
getList:textField-long
+ jsonMap:textField-long
model
readingList:textField-long
setList:textField-long
@@ -112,7 +113,8 @@ MQTT2_DEVICE_Parse($$)
if($code =~ m/^{.*}$/s) {
$code = EvalSpecials($code, ("%TOPIC"=>$topic, "%EVENT"=>$value,
- "%DEVICETOPIC"=>$hash->{DEVICETOPIC}, "%NAME"=>$hash->{NAME}));
+ "%DEVICETOPIC"=>$hash->{DEVICETOPIC}, "%NAME"=>$hash->{NAME},
+ "%JSONMAP","\$defs{$dev}{JSONMAP}"));
my $ret = AnalyzePerlCommand(undef, $code);
if($ret && ref $ret eq "HASH") {
readingsBeginUpdate($hash);
@@ -165,7 +167,7 @@ MQTT2_DEVICE_Parse($$)
if(keys %{$ret}) {
$topic =~ m,.*/([^/]+),;
my $prefix = ($1 && $1 !~m/^0x[0-9a-f]+$/i) ? "${1}_" : ""; # 91394
- $add = "{ json2nameValue(\$EVENT, '$prefix') }";
+ $add = "{ json2nameValue(\$EVENT, '$prefix', \$JSONMAP) }";
}
}
if(!$add) {
@@ -345,7 +347,8 @@ MQTT2_DEVICE_Attr($$)
if($par2 =~ m/^{.*}$/) {
my $ret = perlSyntaxCheck($par2,
("%TOPIC"=>1, "%EVENT"=>"0 1 2 3 4 5 6 7 8 9",
- "%NAME"=>$dev, "%DEVICETOPIC"=>$hash->{DEVICETOPIC}));
+ "%NAME"=>$dev, "%DEVICETOPIC"=>$hash->{DEVICETOPIC},
+ "%JSONMAP"=>""));
return $ret if($ret);
} else {
return "unsupported character in readingname $par2"
@@ -385,6 +388,17 @@ MQTT2_DEVICE_Attr($$)
}
}
+ if($attrName eq "jsonMap") {
+ if($type eq "set") {
+ my @ret = split(/[: \r\n]/, $param);
+ return "jsonMap: Odd number of elements" if(int(@ret) % 2);
+ my %ret = @ret;
+ $hash->{JSONMAP} = \%ret;
+ } else {
+ delete $hash->{JSONMAP};
+ }
+ }
+
return undef;
}
@@ -577,6 +591,21 @@ zigbee2mqtt_devStateIcon255($)
+
+
jsonMap oldReading1:newReading1 oldReading2:newReading2...
+ space or newline separated list of oldReading:newReading pairs.
+ Used in the automatically generated readingList json2nameValue function
+ to map the generated reading name to a better one. E.g.
+
+ attr m2d jsonMap SENSOR_AM2301_Humidity:Humidity
+ attr m2d readingList tele/sonoff/SENSOR:.* { json2nameValue($EVENT, 'SENSOR_', $JSONMAP) }
+
+ The special newReading value of 0 will prevent creating a reading for
+ oldReading.
+
+
+
+
readingList <regexp> [readingName|perl-Expression] ...
@@ -596,9 +625,9 @@ zigbee2mqtt_devStateIcon255($)
Notes:
- 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.
+ $JSONMAP and $EVENT are available (the letter containing the whole
+ message), as well as $EVTPART0, $EVTPART1, ... each containing a
+ single word of the message.
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:
diff --git a/fhem/fhem.pl b/fhem/fhem.pl
index 00f130352..94206fc3c 100755
--- a/fhem/fhem.pl
+++ b/fhem/fhem.pl
@@ -132,7 +132,8 @@ sub getAllGets($;$);
sub getAllSets($;$);
sub getPawList($);
sub getUniqueId();
-sub json2nameValue($;$);
+sub json2nameValue($;$$);
+sub json2reading($$;$$);
sub latin1ToUtf8($);
sub myrename($$$);
sub notifyRegexpChanged($$);
@@ -4918,13 +4919,15 @@ toJSON($)
}
#############################
-# will return a hash of name:value pairs.
-# Note: doesnt know arrays, just objects and simple types
+# will return a hash of name:value pairs. in is a json_string, prefix will be
+# prepended to each name, map is a hash for mapping the names
sub
-json2nameValue($;$)
+json2nameValue($;$$)
{
- my ($in,$prefix) = @_;
+ my ($in, $prefix, $map) = @_;
$prefix = "" if(!defined($prefix));
+ $map = eval $map if($map && !ref($map)); # passing hash through AnalyzeCommand
+ $map = {} if(!$map);
my %ret;
sub
@@ -4974,22 +4977,34 @@ json2nameValue($;$)
return ($t, ""); # error
}
- sub eObj($$$$$);
sub
- eObj($$$$$)
+ setVal($$$$$)
{
- my ($ret,$name,$val,$in,$prefix) = @_;
+ my ($ret,$map,$prefix,$name,$val) = @_;
+ $name = "$prefix$name";
+ if(defined($map->{$name})) {
+ return if(!$map->{$name});
+ $name = $map->{$name};
+ }
+ $ret->{$name} = $val;
+ };
+
+ sub eObj($$$$$$);
+ sub
+ eObj($$$$$$)
+ {
+ my ($ret,$map,$name,$val,$in,$prefix) = @_;
if($val =~ m/^"/) {
($val, $in) = lStr($val);
$val =~ s/\\u([0-9A-F]{4})/chr(hex($1))/gsie; # toJSON reverse
- $ret->{"$prefix$name"} = $val;
+ setVal($ret, $map, $prefix, $name, $val);
} elsif($val =~ m/^{/) { # }
($val, $in) = lObj($val, '{', '}');
my $r2 = json2nameValue($val);
foreach my $k (keys %{$r2}) {
- $ret->{"$prefix${name}_$k"} = $r2->{$k};
+ setVal($ret, $map, $prefix, "${name}_$k", $r2->{$k});
}
} elsif($val =~ m/^\[/) {
@@ -4997,21 +5012,22 @@ json2nameValue($;$)
my $idx = 1;
$val =~ s/^\s*//;
while($val) {
- $val = eObj($ret, $name."_$idx", $val, $val, $prefix);
+ $val = eObj($ret, $map, $name."_$idx", $val, $val, $prefix);
$val =~ s/^\s*,\s*//;
$val =~ s/\s*$//;
$idx++;
}
+
} elsif($val =~ m/^([0-9.-]+)(.*)$/s) {
- $ret->{"$prefix$name"} = $1;
+ setVal($ret, $map, $prefix, $name, $1);
$in = $2;
} elsif($val =~ m/^(true|false)(.*)$/s) {
- $ret->{"$prefix$name"} = $1;
+ setVal($ret, $map, $prefix, $name, $1);
$in = $2;
} elsif($val =~ m/^(null)(.*)$/s) {
- $ret->{"$prefix$name"} = undef;
+ setVal($ret, $map, $prefix, $name, undef);
$in = $2;
} else {
@@ -5026,7 +5042,7 @@ json2nameValue($;$)
while($in =~ m/^\s*"([^"]+)"\s*:\s*(.*)$/s) {
my ($name,$val) = ($1,$2);
$name =~ s/[^a-z0-9._\-\/]/_/gsi;
- $in = eObj(\%ret, $name, $val, $in, $prefix);
+ $in = eObj(\%ret, $map, $name, $val, $in, $prefix);
$in =~ s/^\s*,\s*//;
}
return \%ret;
@@ -5034,15 +5050,15 @@ json2nameValue($;$)
# generate readings from the json string (parsed by json2reading) for $hash
sub
-json2reading($$)
+json2reading($$;$$)
{
- my ($hash, $json) = @_;
+ my ($hash, $json, $prefix, $map) = @_;
$hash = $defs{$hash} if(ref($hash) ne "HASH");
return "json2reading: first arg is not a FHEM device"
if(!$hash || ref $hash ne "HASH" || !$hash->{TYPE});
- my $ret = json2nameValue($json);
+ my $ret = json2nameValue($json, $prefix, $map);
if($ret && ref $ret eq "HASH") {
readingsBeginUpdate($hash);
foreach my $k (keys %{$ret}) {