JSON an SetList übergeben

Begonnen von JensS, 26 August 2021, 19:34:46

Vorheriges Thema - Nächstes Thema

JensS

Hallo,

mein Saugroboter empfängt seine Anweisungen als JSON per MQTT.
waehle_Zone_Esstisch:noArg xiaomi {"set_properties": [{"siid": 6, "piid": 2, "value":"-0.25,-2.4,-0.25,-0.1,2.2,-0.1,2.2,-2.4"}]}
sauge_gewaehlte_Zone:noArg xiaomi {"action": {"siid": 6, "aiid": 5}}
sauge_alles:noArg xiaomi {"action": {"siid": 2, "aiid": 1}}
waehle_Raueme:noArg xiaomi {"set_properties": [{"siid": 6, "piid": 2, "value":"1,2"}]}
sauge_Raeume::noArg xiaomi {"action": {"siid": 4, "aiid": 13}}
...

Nun würde ich gern vereinfachte Anweisungen "set Sauger sauge (Esstisch|alles|Raeume)" bzw. "set Sauger waehle (Zone|Raeume) (Esstisch|Wohnzimmer und Kueche)" nutzen.
Ist das im MQTT2DEVICE machbar oder muss ich einen anderen Weg suchen?

Gruß Jens
Debian auf APU2C4, HM-CFG-USB2, SIGNALduino, HM-ES-PMSw1-Pl, TFA 30.3121, TFA 30.3125, ITS-150, PIR-5000, configurable Firmata USB & LAN, 1-wire: DS-18B20, DS-18S20, DS-2408, DS-2413, diverse I2C-Komponenten, zigbee2mqtt, ESPEasy etc.

Otto123

#1
Hallo Jens,

ich würde sagen: ja ist machbar. Ich bin nicht ganz sicher mit wieviel Aufwand in der "Tiefe".

Schau Dir mal das Template worx_landroid an, da mach ich sowas. Im Artverwandten Template rockroboRE mach ich sowas noch mit einer externen myUtils Datei.

Oder ich habe deine Frage mangels mehr Info nicht richtig verstanden. Weil dein Code sieht ja schon aus wie setList?

Ich weiß nicht ob man in der zweiten Ebene (nach dem ersten Hauptkommando sauge) set Sauger sauge (Esstisch|alles|Raeume)" eine Klappliste hinbekommt. Aber per Argument geht es auf alle Fälle

Gruß Otto
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

Beta-User

(ok, doppelt, aber teilweise evtl. noch ergänzend hilfreich?)
Zitat von: JensS am 26 August 2021, 19:34:46
Ist das im MQTT2DEVICE machbar oder muss ich einen anderen Weg suchen?
Na ja, vermutlich ist MQTT2_DEVICE jedenfalls mit eine der einfacheren Werkzeuge, mit denen man sowas (näherungsweise!) umsetzen kann...

Eine einfache Option, Vorgaben für die zweite setter-Ebene (Esstisch,alles,Räume) zu machen, ist eine komma-separierte Liste hinter dem setternamen (statt noArg), das dürfte bekannt sein. Die Auswahl auch auf der 2. Ebene einzugrenzen, geht mWn. nur mehr oder weniger mit Gewalt im Modulcode selbst (für Eingeweihte: vgl. z.B. in RHASSPY der setter für update).
Evtl. kannst du cmdIcon+webCmd nutzen, um in FHEMWEB ein akzeptables Ergebnis zu erzielen?

Ansonsten ist es vermutlich schwierig, diese ganzen - scheinbar sehr individuellen, aber statischen - Vorgaben irgendwie allgemeingültig zu vercoden; was mir dazu einfiele, wäre das ganze mit Perl-Code zu lösen (muss "topic payload" zurückgeben), und da "$EVTPARTx" auszuwerten und dann via hash-lookup eben den passenden fertigen JSON-String rauszusuchen. Schwierig wird das ganze, wenn du nicht sicherstellen kannst, wie viele $EVTPARTx der Code verstehen muss; dann musst du $EVENT übergeben und das ganze dann selbst auswerten (=>myUtils-Code)...

(Ich weiß, das ist ziemlich kryptisch; bei Bedarf nachfragen, vorher aber mal in dem von Otto genannten Beispielen oder dem sonos2mqtt-Thread von Otto123 stöbern und den aktuellen ebus-myUtils-Code (betr. Temperatur-Listen aus weekproflie) anschauen (oder den für die zigbee2tasmota-Thermostat-Geschichte). Da wird sowas gemacht, und man kann zumindest erkennen, was aus MQTT2_DEVICE an myUtils übergeben wird und wie dann die Rückgabe in etwa aussieht...
Wäre ggf. noch was für den "Workshop", ist aber mAn. wirklich was für "Fortgeschrittene").
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

JensS

Danke euch beiden! In der nächsten Woche wage ich mich dann ran.

Gruß Jens
Debian auf APU2C4, HM-CFG-USB2, SIGNALduino, HM-ES-PMSw1-Pl, TFA 30.3121, TFA 30.3125, ITS-150, PIR-5000, configurable Firmata USB & LAN, 1-wire: DS-18B20, DS-18S20, DS-2408, DS-2413, diverse I2C-Komponenten, zigbee2mqtt, ESPEasy etc.

supernova1963

Nur zum "Mitlesen" und lernen ...

Ich bin gespannt auf die korrekte Umsetzung bzw. Lösung ...

Mein nicht getesteter laienhafter Vorschlag für das setList Attribut:
attr Sauger setList sauge_Raeume:noArg xiaomi {"action": {"siid": 4, "aiid": 13}}\
sauge_Zonen:noArg xiaomi {"action": {"siid": 6, "aiid": 5}}\
waehle_Zone:Esstisch { waehleZone($EVENT) }\
waehle_Raum:Wohnzimmer,Esszimmer,Küche { waehleRaum($EVENT) }\
waehle_Raeume { waehleRaum($EVENT) }\
waehle_Zonen { waehleZone($EVENT) }


Mein nicht getesteter laienhafter Vorschlag für 99_myXiaomiUtils.pm:

##############################################
# $Id: myXiaomiUtils.pm
#
# Save this file as 99_myUtils.pm, and create your own functions in the new
# file. They are then available in every Perl expression.

package main;

use strict;
use warnings;

sub
myXiaomiUtils_Initialize($$)
{
  my ($hash) = @_;
}

# Enter you functions below _this_ line.


########################################################################
# Raumnamen bzw. Name von mehreren Leerzeichen getrennte Räume in
# einen publish Befehl übersetzen. Übergeben wird in der setList $EVENT.
sub
waehleRaum($)

{
my ($COMD,$ROOM1,$ROOM2,$ROOM3,$ROOM4,$ROOM5) = split(/ /,@_);
my $set_topic = "xiaomi";
my $set_json = '{"set_properties": [{"siid": 6, "piid": 2, "value":"';

# Räume definieren

my %rid = (Wohnzimmer=>1, Esszimmer=>2, Kueche=>3);

# ENDE Definitionen

        #   Überprüfen der übergebenen Raumnamen als Leerzeichen getrennte Parameter
if ($ROOM1 eq "" || !defined($ROOM1) ) {
return undef;
}
else {
$set_json = $set_json.$rid{$ROOM1},
}

if ($ROOM2 eq "" || !defined($ROOM2) ) {
$set_json = $set_json.'"}]}';
}
else {
$set_json =  $set_json.','.$rid{$ROOM2};
}
if ($ROOM3 eq "" || !defined($ROOM3) ) {
$set_json = $set_json.'"}]}';
}
else {
$set_json =  $set_json.','.$rid{$ROOM3};
}
if ($ROOM4 eq "" || !defined($ROOM4) ) {
$set_json = $set_json.'"}]}';
}
else {
$set_json =  $set_json.','.$rid{$ROOM4};
}
if ($ROOM5 eq "" || !defined($ROOM5) ) {
$set_json = $set_json.'"}]}';
}
else {
$set_json =  $set_json.','.$rid{$ROOM5}.'"}]}';
}

# Übergabe des auszuführenden publish Befehls
return $set_topic." ".$set_json;

}

# Ende waehle Raum / Räume
########################################################################

########################################################################
# Zonenname bzw. Namen von mehreren Leerzeichen getrennte Zonen in
# einen publish Befehl übersetzen. Übergeben wird in der setList $EVENT.
sub
waehleZone($)
{
my ($COMD,$ZONE1,$ZONE2,$ZONE3,$ZONE4,$ZONE5) = split(/ /,@_);
my $set_topic = "xiaomi";
my $set_json = '{"set_properties": [{"siid": 6, "piid": 2, "value":"';

# Zonen definieren

my %zid = (Esstisch=>"-0.25,-2.4,-0.25,-0.1,2.2,-0.1,2.2,-2.4");

# ENDE Definitionen

# Überprüfen der übergebenen Zonennamen als Leerzeichen getrennte Parameter
if ($ZONE1 eq "" || !defined($ZONE1) ) {
return undef;
}
else {
$set_json = $set_json.$zid{$ZONE1},
}

if ($ZONE2 eq "" || !defined($ZONE2) ) {
$set_json = $set_json.'"}]}';
}
else {
$set_json =  $set_json.','.$zid{$ZONE2};
}
if ($ZONE3 eq "" || !defined($ZONE3) ) {
$set_json = $set_json.'"}]}';
}
else {
$set_json =  $set_json.','.$zid{$ZONE3};
}
if ($ZONE4 eq "" || !defined($ZONE4) ) {
$set_json = $set_json.'"}]}';
}
else {
$set_json =  $set_json.','.$zid{$ZONE4};
}
if ($ZONE5 eq "" || !defined($ZONE5) ) {
$set_json = $set_json.'"}]}';
}
else {
$set_json =  $set_json.','.$zid{$ZONE5}.'"}]}';
}

return $set_topic." ".$set_json;

}
# Ende waehle Zone / Zonen
########################################################################

1;


Beta-User

Zitat von: supernova1963 am 27 August 2021, 18:24:02
Mein nicht getesteter laienhafter Vorschlag für das setList Attribut:
Sieht auf den ersten Blick ok aus :) .

ZitatMein nicht getesteter laienhafter Vorschlag für 99_myXiaomiUtils.pm:
Im Prinzip dürfte das Mindestziel erreicht sein, aber über Details zum Coding "könnte" man dann durchaus nochmal etwas intensiver nachdenken (wäre eigentlich ein guter Kandidat für einen peer review im (User-) Perl-Bereich ;) ).
Kurzfassung, was mir an Ansatzpunkten im Kopf wäre (muß nicht immer klappen):  "split" geschickter  wählen (\s+), elsif/else durch direktes return vermeiden und das "innere" Zusammenbauen in eine (1..@arr)-Schleife verpacken...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

supernova1963

Zitat von: Beta-User am 28 August 2021, 10:54:45
Sieht auf den ersten Blick ok aus :) .
Im Prinzip dürfte das Mindestziel erreicht sein, aber über Details zum Coding "könnte" man dann durchaus nochmal etwas intensiver nachdenken (wäre eigentlich ein guter Kandidat für einen peer review im (User-) Perl-Bereich ;) ).
Kurzfassung, was mir an Ansatzpunkten im Kopf wäre (muß nicht immer klappen):  "split" geschickter  wählen (\s+), elsif/else durch direktes return vermeiden und das "innere" Zusammenbauen in eine (1..@arr)-Schleife verpacken...

Neuer Versuch 99_myXiaomiUtils.pm "besser" zu machen (immer noch rein theoretisch!):

##############################################
# $Id: myXiaomiUtils.pm
#
# Save this file as 99_myUtils.pm, and create your own functions in the new
# file. They are then available in every Perl expression.

package main;

use strict;
use warnings;

sub
myXiaomiUtils_Initialize($$)
{
  my ($hash) = @_;
}

# Enter you functions below _this_ line.


########################################################################
# Raumnamen bzw. Name von mehreren Leerzeichen getrennten Räumen in
# einen publish Befehl übersetzen. Übergeben wird im Attribut des MQTT2_DEVICE setList { waehleRaum($EVENT) }.
sub
waehleRaum($)
{
#Parameter $EVENT: $EVTPART0='COMMAND' $EVTPART1 $EVTPART2 $EVTPART3 $EVTPART4 $EVTPART5 ...
my @evtparts = split(/\s+/,@_);
# Das erste Element in $EVENT ist der Befehl und wird entfernt
@evtparts = splice(@evtparts, 0, 1);
my $set_topic = "xiaomi";
my $set_json = '{"set_properties": [{"siid": 6, "piid": 2, "value":"';
my $i = 0;

# Räume definieren

my %rid = (Wohnzimmer=>1, Esszimmer=>2, Kueche=>3);

# ENDE Definitionen

# Erster und letzter Parameter werden separat zu $set_json hinzugefügt
foreach my $room (@evtparts) {
if ($i == 0) {
$set_json = $set_json.$rid{$room};
}
elsif ($i == @evtparts -1) {
$set_json =  $set_json.','.$rid{$room}.'"}]}';
}
else {
$set_json =  $set_json.','.$rid{$room};
}
i = i + 1;
}

# Übergabe des auszuführenden publish Befehls
return $set_topic." ".$set_json;
}

# Ende waehle Raum / Räume
########################################################################

########################################################################
# Zonenname bzw. Namen von mehreren Leerzeichen getrennte Zonen in
# einen publish Befehl übersetzen. Übergeben wird im Attribut des MQTT2_DEVICE setList { waehleZone($EVENT) }.
sub
waehleZone($)
{
#Parameter $EVENT: COMMAND $EVTPART1 $EVTPART2 $EVTPART3 $EVTPART4 $EVTPART5 ...
my @evtparts = split(/\s+/,@_);
# Das erste Element in $EVENT ist der Befehl und wird entfernt
@evtparts = splice(@evtparts, 0, 1);
my $set_topic = "xiaomi";
my $set_json = '{"set_properties": [{"siid": 6, "piid": 2, "value":"';
my $i = 0;
# Zonen definieren

my %zid = (Esstisch=>"-0.25,-2.4,-0.25,-0.1,2.2,-0.1,2.2,-2.4");

# ENDE Definitionen

#   Überprüfen der übergebenen Zonennamen als Leerzeichen getrennte Parameter  
foreach my $zone (@evtparts) {
if ($i == 0) {
$set_json = $set_json.$zid{$zone};
}
elsif ($i == @evtparts -1) {
$set_json =  $set_json.','.$zid{$zone}.'"}]}';
}
else {
$set_json =  $set_json.','.$zid{$zone};
}
i = i + 1;
}

# Übergabe des auszuführenden publish Befehls
return $set_topic." ".$set_json;

}

####################################

1;


@JensS: Ich bin nach-wie-vor gespannt auf die tatsächlich funktionierende Lösung

Beta-User

@JensS: Bitte melden, wenn es zu OT ist (wie gesagt, ich fände das eigentlich in Perl für FHEM-User besser aufgehoben)...

Folgende Anmerkungen @supernova1963:
- "splice" ist eine nette Idee, hier aber eine "Spatzenkanone". Will man das erste Element aus einer Liste (ich finde "Liste" anschaulicher als "Array") löschen, ist "shift" m.E. das (schnellere und einfacherer) Mittel der Wahl - man muss das nicht zwingend dazu nutzen, einer Variable einen Wert zuzuweisen (den des gelöschten Elements); (vgl. auch "pop", und ergänzend noch push und unshift)
- zum split könnte man auch noch ein paar Takte sagen, spare ich mir im Moment;
- Es stellt sich die Frage, warum man überhaupt die Liste verändert, wenn man hinterher - im Prinzip - eine nummerische Schleife bauen will. Da kann man auch direkt "for (1..@evtparts-1) {" schreiben, dann man man die "Durchlaufnummer" in $_ stehen, und kann darüber ($evtparts[$_]) auf die Raumnamen in der Liste zugreifen.
- "zerstörend" auf die Liste zuzugreifen ist aber auch möglich und hier ggf. sogar eine gute Idee. Dann kann man nämlich die "Rest-Liste" für eine "while"-Schleife verwenden und das jeweils erste Element wieder innerhalb der Schleife per shift in eine Variable holen.

Sonstige Kritik:
- es gibt keine Prüfungen, ob
-- überhaupt ein Raum angegeben ist (return if @evtparts < 2;)
-- ein angegebener Raum gültig ist (next if !defined $rid{$room};)
Wegen letzterem Punkt würde ich den "finalen String" $set_json zunächst nicht belegen und erst nach der Schleife (siehe "qq") zusammenbauen, wenn der dann einen Wert hat.
(Schon klar, dass das kryptisch ist, viel Spaß beim knobeln ;) ).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

supernova1963