Kombination mehrerer Readings

Begonnen von Superposchi, 01 April 2023, 21:45:25

Vorheriges Thema - Nächstes Thema

Superposchi

Ich suche eine Möglichkeit die Inhalte aus mehreren Readings in ein neues Reading zu übergeben.
Dabei soll berücksichtigt werden, dass die Einzelreadings vor der Übernahme überprüft werden ob sie etwas beinhalten oder nicht.

Mir fällt dazu nur ein Userreading ein, das per if und ReadingsVal die Inhalte überprüft und ggf. übernimmt.

Ich scheitere aber aktuell daran, dass die einzelnen Readings mit Komma getrennt werden wenn ein Reading davor und danach vorhanden ist.

Bisher sieht mein Code folgendermaßen aus:
userreadings command {ReadingsVal ("Device", "Reading", "") ReadingsVal ("Device", "Reading", "") ReadingsVal ("Device", "Reading", "") ReadingsVal ("Device", "Reading", "")}
Gibt es eventuell auch andere Lösungen?

Hintergrund:
Ich aktiviere per ftui einzelne Räume (die Segment-Nr wird dabei in ein Reading geschrieben) die vom Saugroboter gereinigt werden sollen. Dazu muss der abgesetzte Set-Befehl folgendermaßen aussehen:
set saugroboter Segment 15, 18, 11

Adimarantis

Hilft dir da sprintf?

userreadings command {sprintf("%s %s",ReadingsVal(..),ReadingsVal());}
Wenn du was prüfen willst dann kannst du da mit Perl Variablen, if-then und dann am Schluss mit return sprintf(...) arbeiten.
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

Superposchi

Ich sehe aktuell für das sprintf keinen Sinn, da die Readings ja nicht formatiert werden müssen.

Es geht ausschließlich um die Prüfung ob das Reading einen Wert hat oder nicht bzw. für das Komma zu prüfen ob das Reading davor und dahinter einen Wert haben.

Mit
{/if (ReadingsVal("Device", "Wohnzimmer", "") eq "18")(ReadingsVal("Device", "Wohnzimmer", "")}kann ich ja prüfen ob das Reading den Wert hat und übernehmen (bei Abwahl würde ich das Raum-Reading einfach auf 0 setzen).

Mein Problem si d die Kommas dazwischen.

Adimarantis

Dann so:
my $var=sprintf("%s,%s,%s",ReadingsVal("D","R1"," "),ReadingsVal("D","R2"," "),ReadingsVal("D","R3"," "));
$var =~ s/\, //g;
return $var;
Wenn jetzt R2 undefiniert ist (oder was steht denn dann drin?) wird ein Leerzeichen zurückgeliefert.
Dann steht in var "1, ,3"
Das replace ersetzt dann alle ", " mit nichts, und damit wird "1,3" zurückgeliefert.
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

Superposchi

#4
Hab das jetzt folgendermaßen ergänzt:
comman3 my $var=sprintf("%s,%s,%s",ReadingsVal("saugroboter","Room_Wohnzimmer"," "),ReadingsVal("saugroboter","Room_Schlafzimmer"," "),ReadingsVal("saugroboter","Room_Kueche"," "));
$var =~ s/\, //g;
return $var;
Davor stehen noch andere Readingseinträge die jeweils mit Komma getrennt sind.

P.S. Es wird aber nicht mehr geprüft ob das Reading den richtigen Inhalt hat oder nicht.

Adimarantis

Zitat von: Superposchi am 01 April 2023, 23:26:40Davor stehen noch andere Readingseinträge die jeweils mit Komma getrennt sind.
Was meinst du damit? Hast du mehr als 3? Dann musst du halt das sprintf entsprechend erweitern.
ZitatP.S. Es wird aber nicht mehr geprüft ob das Reading den richtigen Inhalt hat oder nicht.
Daher ja die Frage "oder was steht da drin?".
Woran erkennt man "richtigen Inhalt" und "oder nicht"?
Ist das reading dann undefiniert? Ist es leer?
Je nachdem sollte man einfach das Replace anpassen können, so dass es ohne Prüfung funktioniert.
Wenn es z.B. leer ist dann
$var =~ s/\,,/,/g;Also immer Doppelkommata durch einzelne ersetzen.
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

TomLee

Vermutlich auf die Gefahr hin das mein Vorschlag es einfach anzugehen, nur weitere Probleme verursacht, trotzdem ein Beispiel wie ich es angehen würde und verstanden habe:

defmod du_test dummy
attr du_test readingList bla
attr du_test setList on off bla
attr du_test userReadings segments:(on|off) {my @r = ('Schlafzimmer','Kueche','Wohnzimmer');;\
my @a;;\
for (@r){\
push (@a,ReadingsNum($name,$_,0)) if ReadingsNum($name,$_,0) > 0;;}\
return join q(,), @a;;\
}

setstate du_test on
setstate du_test 2023-04-02 12:14:08 Kueche 0
setstate du_test 2023-04-02 12:13:22 Schlafzimmer 11
setstate du_test 2023-04-02 11:32:54 Wohnzimmer 17
setstate du_test 2023-04-02 12:14:15 segments 11,17
setstate du_test 2023-04-02 12:14:15 state on

Superposchi

Also mit dem zusätzlichen Dummy halte ich es wirklich für Umständlicher, außerdem ist mir noch nicht klar wie dabei die Nummer dem Reading zugeordnet werden soll.

Hab jetzt erstmal eine Teillösung so, dass ich ein UserReading "Roomlist" erstellen lasse wo mit Hilfe von @Adimarantis Code die Nummern der Räume gelistet werden. Einzig wenn kein Raum ausgewählt ist, zeigt dieses Reading (Fehlerhafterweise) "0" an.

Dazu werde ich ein UserReading "Commandline" erstellen, bei dem das Reading "command" (in dem die Auswahl "start/segment" aus dem Dropdownfeld und dem Reading Roomlist kombiniert werden, wenn das Reading "command" "segment" als Inhalt hat.

Kann aber gerade nichts testen, da meine SSD auf der der Fhem-Server läuft Probleme macht.

betateilchen

#8
Zitat von: Superposchi am 01 April 2023, 22:44:51Mit
{/if (ReadingsVal("Device", "Wohnzimmer", "") eq "18")(ReadingsVal("Device", "Wohnzimmer", "")}kann ich ja prüfen ob das Reading den Wert hat und übernehmen

Warum übernimmst Du dann nicht einfach die 18 sondern machst nochmal einen Funktionsaufruf von ReadingsVal() für das gleiche Reading, das Du vorher schon auf 18 geprüft hast? Da kommt doch kein anderes Ergebnis raus.

{ ReadingsNum("Device", "Wohnzimmer", 0) == 18 ? 18 : 0 }

Und diese Abfrage baust Du für jeden Raum in die vorgeschlagene Ausgabe mit sprintf().

Noch einfacher: warum machst Du nicht eine Abfrage auf

ReadingsVal("saugroboter","Segment","")
Da stehen doch alle festgelegten Werte drin, die Du stattdessen lieber einzeln abfragen willst. Das macht doch überhaupt keinen Sinn.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

#9
defmod device dummy
attr device userReadings command { sprintf("%s %s %s", ReadingsNum("device","wohnzimmer",0) == 18 ? 18 : undef,\
ReadingsNum("device","flur",0) == 15 ? 15 : undef, \
ReadingsNum("device","kueche",0) == 12 ? 12 : undef) }

Danach kann man mit

setreading device wohnzimmer 18
setreading device flur 15
setreading device kueche 12

Die Werte im reading "command" auftauchen lassen.

Du darfst diesen Dateianhang nicht ansehen.

Und wenn einer der Werte die Bedingung nicht erfüllt, dann bleibt er aus der Liste einfach draußen.
Setze ich z.B. kueche auf 10, tauchen in command nur noch 18 und 15 auf.

Du darfst diesen Dateianhang nicht ansehen.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

TomLee

Jetzt mach ich ein Bierchen auf, hoffentlich wird das lustig heut.

@Superposchi

Vorausgesetzt ich verstehe dich richtig, das userReadings (der Ausführungsteil ) aus dem dummy soll deine bisherige Lösung ersetzen und gibt nur die Werte der Readings zurück die auch in FTUI ausgewählt sind (also nicht 0 sind). Die Liste des Array @r musst du natürlich an die Readingnamen deiner "Zonen-Readings" anpassen.

Superposchi

Also meine Lösung sieht aktuell folgendermaßen aus:
Roomlist
{my $var=sprintf("%s, %s, %s, %s, %s",ReadingsVal("saugroboter","Room_Wohnzimmer"," "),ReadingsVal("saugroboter","Room_Schlafzimmer"," "),ReadingsVal("saugroboter","Room_Kueche"," "),ReadingsVal("saugroboter","Room_Diele"," "),ReadingsVal("saugroboter","Room_Bad"," "));
$var =~ s/\, 0//g;
return $var;},
comandline
{my $var=sprintf("%s %s",ReadingsVal("saugroboter","command",""),ReadingsVal("saugroboter","Roomlist",""));
$var =~ s/\ 0//g;
return $var;}
Alles ist im Device des Saugroboters, nicht in irgendeinem Dummy.
Dazu existieren noch die Readings "Room_Wohnzimmer", "Room_Schlafzimmer", "Room_Kueche", "Room_Diele" und "Room_Bad" mit entweder der passenden Segment-Nr oder 0 (gesetzt aus FTUI3). Dazu gibt es noch ein notify, dass die Readings der Räume beim Wechsel des command-Readings (start/segment) alle auf 0 setzt.
Das einzige Problem ist jetzt noch, dass im FTUI3 die Checkboxen beim "Rücksetzen" nicht aktualisiert werden, aber das ist wohl eine Frage für das entsprechende Unterforum.

@betateilchen
Deine Lösung macht im Prinzip ja das gleiche, nur das zusätzlich noch geprüft wird, ob die Room-Readings die richtigen Werte besitzen.
Muss ich mal ausprobieren ob das Vorteile hat oder eher Nachteile. Das mit der Abfrage wollte ich ja ursprünglich machen, weil ich die Segment-Nr direkt in das Reading "Commandline" schreiben lassen wollte ohne den Umweg des Readings "Roomlist". Aber das hatte immer das Problem, dass ich das commandowort (start oder segment) nicht davor bekommen habe. Im Moment sehe ich bei deiner Lösung das Problem, dass ich die "%s %s %s" mit Kommas trennen muss (der saugroboter verlangt den Befehl ja in der Form "set saugroboter segment 18, 16, 19". Wenn dann ein Raum ausgeklammert wird könnte es zu einem 18, , 19 kommen, was dann wieder einen Fehler verursachen würde.

@TomLee
Ganz ehrlich, ich verstehe Null, was du da gerade schreibst. Was ist bitte der Ausführungsteil eines userReadings? Wieso soll irgendetwas etwas anderes ersetzen? Es gibt nichts anderes.

betateilchen

#12
Zitat von: Superposchi am 02 April 2023, 20:50:51Aber das hatte immer das Problem, dass ich das commandowort (start oder segment) nicht davor bekommen habe. Im Moment sehe ich bei deiner Lösung das Problem, dass ich die "%s %s %s" mit Kommas trennen muss (der saugroboter verlangt den Befehl ja in der Form "set saugroboter segment 18, 16, 19". Wenn dann ein Raum ausgeklammert wird könnte es zu einem 18, , 19 kommen, was dann wieder einen Fehler verursachen würde.

Du siehst einfach den Wald vor lauter Bäumen nicht und denkst viel zu kompliziert.

attr device userReadings command { sprintf("segment %s%s%s", ReadingsNum("device","wohnzimmer",0) == 18 ? "18," : undef,\
ReadingsNum("device","flur",0) == 15 ? "15," : undef, \
ReadingsNum("device","kueche",0) == 12 ? "12" : undef) }

Falls Dein Saugroboter mit einem Komma am Ende (das kann jetzt noch passieren) nicht klarkommt, musst Du das halt noch per regex entfernen.

attr device userReadings command { my $c = sprintf("segment %s%s%s", ReadingsNum("device","wohnzimmer",0) == 18 ? "18," : undef,\
ReadingsNum("device","flur",0) == 15 ? "15," : undef, \
ReadingsNum("device","kueche",0) == 12 ? "12" : undef);; \
$c =~ s/,$//;;\
return $c }
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

TomLee


Ersetze (wenn du deine Probleme mit deiner SSD in den Griff bekommen hast) bitte mal :
Roomlist
{my $var=sprintf("%s, %s, %s, %s, %s",ReadingsVal("saugroboter","Room_Wohnzimmer"," "),ReadingsVal("saugroboter","Room_Schlafzimmer"," "),ReadingsVal("saugroboter","Room_Kueche"," "),ReadingsVal("saugroboter","Room_Diele"," "),ReadingsVal("saugroboter","Room_Bad"," "));
$var =~ s/\, 0//g;
return $var;}

durch den meinen gezeigten Ausführungsteil des dummys (die Readingnamen hab ich jetzt angepasst ) :

Roomlist {my @r = ('Room_Wohnzimmer','Room_Schlafzimmer','Room_Kueche','Room_Bad');
my @a;
for (@r){
push (@a,ReadingsNum($name,$_,0)) if ReadingsNum($name,$_,0) > 0;}
return join q(, ), @a;
},

...

Kommt das Ergebnis zurück was du erwarten würdest ?

Superposchi

So, habe endlich die SSD wieder am Laufen. Keine Ahnung was da los war, wurde nur "Fehler" angezeigt.
Aber wenn die Kiste ständig läuft kann man ja auch nicht einfach aufschrauben und rumbasteln. Im Endeffekt hat ein hin- und herstecken in den anderen M.2-Slot und wiederherstellen des Raid gereicht.

Zum Thema:
Macht ja eigentlich das gleiche was meine Lösung auch macht, bis auf die 0 wenn gar kein Raum ausgewählt ist. Das wiederum bewirkt aber beim Reading Commandline, dass direkt ausgelesen werden kann.

Jetzt muss ich nur noch einen Weg finden den Inhalt des Readings Commandline als Set-Befehl beim Button davor abzusetzen.

Hat eventuell einer eine Lösung wie ich die Ansicht der Checkboxen im FTUI3 resettet bekomme. Die Readings stehen auf 0, werden aber trotzdem noch als Wert angezeigt nachdem das Notify die Readings auf Null gesetzt hat.