Alternativen für Szenen, die durch Updates unterbrochen wurden

EDIT: Diskussionen verschoben von Gladys Assistant 4.85.0 : widget Photo, navigation dans les graphiques, chauffe-eau & HomeKit - #21 par Will_71, um ein spezifisches Thema zu widmen.


Gut gemacht an alle für all diese Neuerungen und Verbesserungen :heart_eyes:

Ich habe einen Punkt, der mich bei fast jedem Update stört: Szenen, die ein Warten laufen haben.

Um es einfach zu machen, starte ich die Poolpumpe für eine von mir definierte Dauer und habe daher eine Aktion Warten von X Stunden. Leider, wenn ein Update kommt, springt mein Warten einfach weg und wenn ich nicht aufpasse, kann der Pool 8 Stunden statt 3 Stunden laufen :frowning:

Abgesehen davon, MQTT-Variablen für das Verfolgen einer laufenden Szene zu verwenden (was ich tun müsste), Zeitstempel zu erstellen, die ich auch speichere, und ein Skript beim (Neu)Start von Gladys (gibt es eigentlich einen Auslöser beim Booten?), gäbe es nicht etwas (neu?), um diese Szenen dort wieder aufzunehmen, wo sie angehalten wurden?

Danke für das Feedback, und du hast einen echten Limitierung der aktuellen Implementierung aufgedeckt :slight_smile:

Technisch gesehen ist der Block „Warten“ einfach ein Timer im Speicher des Gladys-Prozesses. Nichts wird in der Datenbank gespeichert: weder, dass eine Szene läuft, noch, wo sie in ihrer Aktionsliste steht. Daher geht nach jedem Neustart (Update, Reboot, Stromausfall) alles, was nach dem Warten kommt, verloren. Das ist kein Bug auf deiner Seite, das ist so heute.

Und ja, der Trigger „Gladys startet“ existiert tatsächlich, du findest ihn in der Liste der Trigger.

Aber ich würde dir eher raten, dich so zu organisieren, dass du ihn nicht brauchst.

Das Klügste in deinem Fall ist, dass Gladys den Timer überhaupt nicht hält, sondern die Steckdose selbst. Die meisten Geräte können „schalte dich ein und schalte dich nach X Sekunden wieder aus“. Das hängt davon ab, was du hast:

  • Shelly, mit der HTTP-Anfrage-Aktion: http://<ip>/relay/0?turn=on&timer=10800 (Gen1) oder http://<ip>/rpc/Switch.Set?id=0&on=true&toggle_after=10800 (Gen2+)
  • Zigbee2MQTT, mit der Zigbee2MQTT-Aktion: auf zigbee2mqtt/<deine_pumpe>/set, schickst du {"state":"ON","on_time":10800,"off_wait_time":0}. Das funktioniert bei vielen Steckdosen und Modulen von Tuya/Moes/Aqara.
  • Tasmota: PulseTime 10900; Power ON (bei Werten über 111 entspricht PulseTime Wert − 100 in Sekunden)

Deine Szene besteht aus einer einzigen Aktion, kein Warten mehr. Und der riesige Vorteil für eine Poolpumpe: Selbst wenn dein Gladys ausgeschaltet ist oder der Mini-PC nicht neu startet, schaltet die Pumpe sich trotzdem aus.

Falls dein Gerät das nicht kann, ist der zweite Ansatz ein Countdown statt eines Wartens.

Du erstellst ein MQTT-Nummer-Feature, z. B. pumpen_minuten_restant. Deine Start-Szene schaltet die Pumpe ein und setzt den Wert auf 180. Daneben erstellst du eine Überwachungsszene mit einem geplanten Trigger im Intervallmodus alle 5 Minuten, die den Wert abruft, nur fortfährt, wenn er > 0 ist, ihn mit der Formel {{0.last_value}} - 5 neu schreibt und, wenn er auf 0 fällt, die Pumpe ausschaltet. Der Formelmodus funktioniert sowohl bei „Wert setzen“ als auch in den Bedingungen, also alles wird mit der Maus erledigt.

Der Vorteil ist, dass es sich selbst repariert: Kein Boot-Skript oder Start-Trigger nötig, der nächste Cron-Lauf holt die Situation wieder ein. Im schlimmsten Fall verlierst du die 5 Minuten des aktuellen Ticks.

Und wenn du damit zufrieden bist, ist das Einfachste zwei geplante Szenen, Start um 10 Uhr und Stop um 13 Uhr. Für eine Poolpumpe reicht das oft und ist unzerstörbar. Wenn du die Dauer an die Wassertemperatur anpasst, kannst du sogar 3 Stop-Szenen (12 Uhr, 13 Uhr, 14 Uhr) mit jeweils einer Bedingung zur Temperatur machen, das ist etwas grob, aber es funktioniert immer.

Das Prinzip, das man sich merken sollte: Das Warten ist für kurze Verzögerungen innerhalb einer Sequenz gedacht, z. B. 2 Sekunden zwischen zwei Befehlen oder 30 Sekunden, bevor ein Zustand überprüft wird. Sobald du einige Minuten überschreitest, und vor allem, wenn eine Ausschaltaktion im Spiel ist, muss man entweder den Timer auf das Gerät auslagern oder einen gespeicherten Zustand verwenden, der regelmäßig gelesen wird.

Das heißt aber nicht, dass dein Grundanliegen nicht legitim ist: Lange Warten zu persistieren, um sie beim Neustart neu zu planen, ist machbar. Wenn du eine Funktionsanfrage dazu stellen möchtest, zögere nicht.

Eine ausgezeichnete Methode, die mir überhaupt nicht in den Sinn gekommen wäre.
Ich habe einen NodOn SIN-4-1-21 und es scheint, dass dies möglich ist:

On mit zeitgesteuertem Ausschalten

Beim Einstellen des Zustands auf EIN ist es möglicherweise möglich, ein automatisches Ausschalten nach einer bestimmten Zeitdauer zu spezifizieren. Dazu muss der Payload eine zusätzliche Eigenschaft on_time hinzugefügt werden, die die Zeit in Sekunden angibt, die der Zustand eingeschaltet bleiben soll.

Zusätzlich kann der Payload eine Eigenschaft off_wait_time hinzugefügt werden, um die Abkühlzeit in Sekunden zu spezifizieren, während der der Schalter nicht auf andere Befehle mit zeitgesteuertem Ausschalten reagiert.

Die Unterstützung hängt von der Firmware des Schalters ab. Einige Geräte benötigen möglicherweise sowohl on_time als auch off_wait_time, um zu funktionieren.

Beispiele: {"state" : "ON", "on_time": 300}, {"state" : "ON", "on_time": 300, "off_wait_time": 120}.
Und da ich mir am Ende des „Warten“ eine Nachricht schicke, muss ich mir eine Überwachungsszene erstellen, die alle Minuten überprüft, ob das Modul ein- oder ausgeschaltet ist.

Danke für den Tipp!

Ich habe es mit der Variablenberechnung {"state":"ON","on_time": 1.1. Piscine (filtration_duree_cycle) *3600 ,"off_wait_time":0} versucht und es scheint nicht funktioniert zu haben :frowning:

Muss ich eine temporäre MQTT-Variable verwenden?
Und das Problem ist, dass ich keine Möglichkeit habe, den gesendeten Befehl zu sehen (nichts in den Gladys-Logs, nichts in Z2M).

EDIT: Letztendlich funktioniert {"state":"ON","on_time":10800,"off_wait_time":0} auch nicht :frowning:

Nach einigen Tests sollte die Aktion Zigbee2mqtt-Nachricht senden nicht verwendet werden, sondern MQTT-Nachricht senden, sonst funktioniert es nicht.
@pierre-gilles gibt es einen spezifischen Unterschied zwischen den beiden Aktionen?

Ich habe {"state":"ON","on_time":60,"off_wait_time":10} in MQTT (nicht zigbee2mqtt) getestet und es funktioniert, 1 Minute später schaltet die Pumpe wie erwartet ab.

Ich habe {"state":"ON","on_time":10800,"off_wait_time":10} getestet und hier gibt es ein Problem, entweder bei Gladys oder z2m, denn alles wird mit 10 multipliziert und es gibt einen Out-of-Range-Fehler:

z2m: Publish 'set' 'state' to 'relais_03' failed: 'RangeError [ERR_OUT_OF_RANGE]: ZCL command 0x84b4dbfffe08ce6e/1 genOnOff.onWithTimedOff({"ctrlbits":0,"ontime":108000,"offwaittime":100}, {"timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":false,"direction":0,"reservedBits":0,"writeUndiv":false}) failed (The value of "value" is out of range. It must be >= 0 and <= 65535. Received 108000)'

Ideen?

Ich führe meine Tests fort und die Variablen funktionieren nicht:


und in den z2m-Logs:

z2m: Ungültige Nachricht 'undefined', überspringen...

nicht besonders aussagekräftig…

Danke für all diese Tests, du hast mehrere Dinge aufgedeckt, und es gibt mindestens einen Fehler auf unserer Seite. Ich gehe der Reihe nach vor.

1. Der Unterschied zwischen den beiden Aktionen

Im Code tun MQTT-Nachricht senden und Zigbee2mqtt-Nachricht senden genau dasselbe: Dein Text wird in den Variablenmotor gegeben und dann unverändert veröffentlicht. Der einzige Unterschied ist der verwendete MQTT-Client: Die MQTT-Aktion veröffentlicht auf den Broker, der im MQTT-Dienst konfiguriert ist, die Zigbee2mqtt-Aktion veröffentlicht auf die eigene Verbindung des Zigbee2mqtt-Dienstes (standardmäßig Mosquitto, das für Z2M reserviert ist, mqtt://localhost:1884).

Wenn dein Z2M außerhalb von Gladys mit deinem eigenen Broker läuft, geht die Zigbee2mqtt-Aktion also potenziell ins Leere: Niemand hört zu, und da das Protokoll auf debug steht, siehst du tatsächlich nichts. Du hast nichts übersehen. Auch zu beachten: Diese Aktion fügt keinen Präfix zigbee2mqtt/ hinzu, du musst das vollständige Topic zigbee2mqtt/relais_03/set schreiben — der Platzhalter gladys/my-topic ist irreführend, wir werden ihn korrigieren.

Kurz gesagt: In deiner Konfiguration bleibst du bei MQTT-Nachricht senden, das ist die richtige Wahl.

2. Das ×10 und der RangeError

Hier liegt es weder an Gladys noch an einem Z2M-Fehler: Es ist das Zigbee-Protokoll. Der ZCL-Befehl genOnOff.onWithTimedOff gibt ontime und offwaittime in Zehnteilen einer Sekunde auf einem 16-Bit-Ganzzahlwert an. Zigbee2MQTT macht also on_time × 10, und die Obergrenze ist 65535.

Mit anderen Worten: Das absolute Maximum sind 6553 Sekunden, also 1 Stunde 49 Minuten. Deine 3 Stunden werden nie in einem einzigen Befehl durchgehen, egal welchen Weg du nutzt. Deshalb ist dein 10800 auch mit der Zigbee2mqtt-Aktion gescheitert, zusätzlich zum Broker-Problem.

3. Variablen im Payload

Das Nachrichtenfeld akzeptiert Variablen, aber mit zwei wichtigen Einschränkungen:

  • die Syntax ist {{ }} (tippe {{ in das Feld, die Autovervollständigung erscheint), und die Variable muss von einer Aktion Letzten Zustand abrufen kommen, die vorher in einer früheren Gruppe platziert wurde;
  • keine Berechnungen sind in diesem Feld möglich. Im Gegensatz zu Wert festlegen oder Bedingungen gibt es hier keinen Formelmotor: {{0.0.last_value}}*3600 wird wörtlich als 3*3600 gesendet, nicht als 10800.

Und wenn die Variable nicht aufgelöst wird, wird sie durch eine leere Zeichenkette ersetzt, was ein kaputtes JSON wie {"state":"ON","on_time":,"off_wait_time":0} erzeugt — daher die Ablehnung auf der Z2M-Seite. Wir sollten den tatsächlich veröffentlichten Payload klar loggen, das ist eine echte Debug-Lücke. In der Zwischenzeit, um zu sehen, was wirklich rausgeht:

mosquitto_sub -h <dein_broker> -t 'zigbee2mqtt/relais_03/set' -v

Um deine Multiplikation durchzuführen, musst du sie aus dem Payload herausnehmen: eine Aktion Wert festlegen im Formelmodus auf einem MQTT-Nummer-Feature (pompe_on_time), mit der Formel {{...}}*3600, dann ein Letzten Zustand abrufen auf diesem Feature, und schließlich {{x.y.last_value}} im JSON.

4. Achtung, ein Fehler auf unserer Seite bei den Formeln

Bei der Überprüfung dieses Punktes habe ich festgestellt, dass unser Formelmotor ohne die Funktion subtract instanziiert wird: die Subtraktion funktioniert nicht. Die Formel {{0.0.last_value}} - 5, die ich dir oben gegeben habe, wirft eine Ausnahme, die stillschweigend verschluckt wird (die Aktion scheitert, die Szene geht weiter, nichts passiert). Meine Entschuldigung, das war falsch.

In der Zwischenzeit ist die Umgehung, {{0.0.last_value}} + -5 zu schreiben, was funktioniert. +, *, /, round() und mod sind OK.

Ticket erstellt: Scene formula engine: subtraction is not supported (`Function subtract missing in provided namespace "math"`) · Issue #2823 · GladysAssistant/Gladys · GitHub

5. Was ich dir schließlich empfehle: Der Countdown + Watchdog

Angesichts der Obergrenze von 1 Stunde 49 Minuten kombiniert der beste Ansatz die beiden Ideen, und es ist sogar besser als das, was ich ursprünglich vorgeschlagen habe, weil es auch bei einem Gladys-Ausfall nicht kaputt geht.

Erstelle ein MQTT-Nummer-Feature pompe_minutes_restantes.

Szene „Pumpe starten“:

  • Wert festlegen: pompe_minutes_restantes = 180
  • MQTT-Nachricht senden auf zigbee2mqtt/relais_03/set: {"state":"ON","on_time":900,"off_wait_time":0}

Szene „Pumpenüberwachung“, geplanter Auslöser im Intervall alle 10 Minuten:

  • Letzten Zustand abrufen von pompe_minutes_restantes
  • Wenn / Sonst auf > 0:
    • dann: Wert festlegen = {{0.0.last_value}} + -10, dann {"state":"ON","on_time":900,"off_wait_time":0} erneut veröffentlichen
    • sonst: {"state":"OFF"} veröffentlichen

Der Grundsatz: Das Relais erhält nie mehr als eine 15-Minuten-Genehmigung, die die Überwachungsszene so lange erneuert, wie der Countdown positiv ist. Das Ergebnis ist, dass die Pumpe sich nach maximal 15 Minuten von selbst ausschaltet, wenn Gladys für ein Update, einen Neustart oder einen Absturz abgeschaltet wird, und beim Neustart wird der Countdown dort fortgesetzt, wo er war, da er in der Datenbank gespeichert ist. Kein Warten mehr, und nichts mehr zu reparieren beim Booten.

Lass off_wait_time auf 0: Es ist eine Schutzzeit, während der das Modul neue Befehle on with timed off ablehnt, es würde die erneute Aktivierung verhindern.

6. Deine Überwachungsszene alle Minuten

Nicht nötig. Der NodOn meldet seinen Zustand an Z2M, wenn er sich selbst ausschaltet, also reicht eine Szene mit dem Auslöser Ein Gerät ändert seinen Zustand auf dem Feature des Relais, Bedingung „ist ausgeschaltet“, um dir deine Benachrichtigung am Ende zu senden.

Ich erstelle die Tickets für die fehlende Subtraktion, das Log des veröffentlichten Payloads und den Z2M-Topic-Placeholder.

https://github.com/GladysAssistant/Gladys/issues/2825

https://github.com/GladysAssistant/Gladys/issues/2826

Danke @pierre-gilles für die Erklärungen, ich verstehe den Unterschied zwischen den MQTT- und Z2M-Aktionen.
In meinem Fall habe ich die Z2M-Integration extern mit einem externen MQTT, und die MQTT-Integration von Gladys zeigt auf das externe MQTT, daher greifen beide Aktionen in denselben Endkorb.
Das bedeutet, dass ich, wenn ich eine der beiden Befehle verwende, das gleiche Ergebnis erhalten sollte, aber das ist nicht der Fall, da es mit der MQTT-Aktion funktioniert und nicht mit Z2M.

Ich sehe, dass Claude geantwortet hat, denn in einigen Aussagen sehe ich Wölfe :face_with_raised_eyebrow:

Und was ich überhaupt nicht verstehe, ist, dass ich mit 60 (Ausschalten nach 1 Minute), 1000 (Ausschalten nach etwa 16 Minuten) und 3600 (Ausschalten nach 1 Stunde) getestet habe, und keine dieser Zahlen wurden mit 10 multipliziert, da die Ausschaltungen korrekt waren.

Ja, aber.
Ich habe einen Zwischenschritt, um die Berechnung zu vermeiden:




Und die gesendete Nachricht zeigt mir die neu berechnete Zeit in Sekunden an, aber es funktioniert nicht im Payload.
Und ich teste mit 1 Stunde, um sicherzustellen, dass ich keinen Out-of-Range-Fehler habe.

Ich werde Punkt 5 genauer untersuchen, das scheint eine gute Idee zu sein, und ich werde auf die Subtraktion achten, bis dahin.

Ich entschuldige mich, ich bin gerade nur ein bisschen flach mit Claude, aber mit all der Arbeit an den externen Integrationen kann ich dir nicht mehr bieten :smiley:

Du hast recht mit beiden Punkten, und bei einem davon habe ich mich geirrt. Ich korrigiere das.

Das ×10: Deine Tests bestätigen die Erklärung, sie widersprechen ihr nicht.

Meine Formulierung war schlecht. Das ×10 ist nichts, das sich zu deiner Dauer „hinzufügt“, es ist eine Einheitsumrechnung: Das Feld ZCL wird in Zehntelsekunden ausgedrückt, daher konvertiert Zigbee2MQTT deine Sekunden in Zehntel, bevor es sendet, und das Modul konvertiert zurück beim Empfang. Ergebnis: Deine Dauer wird korrekt eingehalten — genau das, was du gemessen hast:

on_time gesendeter Wert Ausschaltung
60 600 1 min :check_mark:
1000 10000 16 min 40 s :check_mark:
3600 36000 1 h :check_mark:
10800 108000 > 65535 → RangeError ✘

Der Code befindet sich hier, in den Z2M-Konvertern:

{ctrlbits: 0, ontime: Math.round(onTime * 10), offwaittime: Math.round(offWaitTime * 10)}

Der einzige Moment, in dem das sichtbar wird, ist, wenn das Ergebnis 65535 übersteigt, die Grenze einer 16-Bit-Ganzzahl — und genau das ist die Fehlermeldung, die du erhalten hast. Die Obergrenze beträgt also 6553 Sekunden, also 1 h 49 min. Deine 3600 funktionieren, deine 10800 werden nie funktionieren. (Übrigens begrenzt Z2M diesen Wert für andere Parameter desselben Typs, aber nicht für on_time, daher der plötzliche Fehler statt einer stillen Begrenzung; das würde einen Ticket bei ihnen verdienen.)

Die Log-Meldung Invalid message 'undefined' bedeutet nicht das, was man denkt.

Ich habe den Code von Z2M überprüft:

const message = this.parseMessage(parsedTopic, data);

if (!message) {

logger.error(`Invalid message '${message}', skipping...`);

Er zeigt das Ergebnis des Parsings an, nicht die empfangene Nachricht. Da das Parsing fehlgeschlagen ist, hat dieses Ergebnis immer den Wert undefined. Mit anderen Worten, diese Log-Meldung wird undefined anzeigen, unabhängig vom Payload: Es ist nicht Gladys, die dir das Wort undefined geschickt hat. Die einzige nützliche Information ist „die empfangene JSON war nicht gültig“. Deshalb sagte ich dir, dass du mosquitto_sub verwenden sollst: Es ist heute der einzige Weg, den tatsächlichen Payload zu sehen.

Der Editor ist hingegen nicht schuld.

Ich habe die Spur eines durch das Variablenfeld beschädigten Textes überprüft (unsichtbare Zeichen, neu codierte Anführungszeichen): Ich habe die Komponente in einem Browser mit deiner Konfiguration neu gespielt, der Text kommt identisch bis auf das Zeichen, einschließlich geschweifte Klammern und Anführungszeichen. Hier liegt das Problem nicht.

Aber ich habe eine echte Falle gefunden, und sie könnte deine sein.

Wenn die Variable das letzte Element deines JSON ist, landest du mit drei geschweiften Klammern zusammen:

{"state":"ON","on_time":{{1.1. Piscine ...}}}

Dieses }}} wird als Schließung einer anderen Variablensyntax interpretiert, der Template-Motor stürzt ab, und der Fehler wird stillschweigend verschluckt: nichts wird veröffentlicht. Zwei sofortige Umgehungen, beide getestet:

  • einen Leerraum vor die letzte geschweifte Klammer setzen: ..."on_time":{{variable}} }
  • oder einfach nicht mit der Variable enden: {"on_time":{{variable}},"state":"ON","off_wait_time":0}

Was ich brauche, um deinen Fall zu klären

Die Screenshots erlauben mir nicht, die genauen Zeichen zu sehen. Kannst du mir Folgendes kopieren und einfügen, als Text:

  1. den genauen Inhalt des Nachrichtenfeldes deiner MQTT-Aktion;
  2. das genaue Topic;
  3. und, wenn möglich, die Ausgabe von mosquitto_sub -h <dein_broker> -t 'zigbee2mqtt/relais_03/set' -v, während du die Szene ausführst.

Damit wissen wir in dreißig Sekunden, ob es sich um }}}, eine leere Variable oder etwas anderes handelt.

Zu MQTT vs Z2M mit demselben Broker: Du hast recht, meine Erklärung hält nicht stand.

Wenn beide auf denselben externen Broker zeigen, sollten beide Aktionen tatsächlich dasselbe Ergebnis produzieren. Es bleiben zwei Spuren:

  • das Topic. Die Zigbee2mqtt-Aktion fügt keinen Präfix hinzu, im Gegensatz zu dem, was ihr Name suggeriert. Hast du in beiden Aktionen zigbee2mqtt/relais_03/set geschrieben? Wenn du in der Z2M-Aktion relais_03/set eingegeben hattest, würde das alles erklären.
  • die Verbindung. Der Zigbee2mqtt-Dienst öffnet seine eigene MQTT-Sitzung mit den Anmeldedaten, die in seiner Integration eingegeben wurden — getrennt von denen des MQTT-Dienstes. Wenn diese Anmeldedaten von deinem Broker abgelehnt werden, stellt die MQTT-Bibliothek die Nachrichten in eine Warteschlange, ohne jemals einen sichtbaren Fehler zu melden. Wird deine Zigbee2mqtt-Integration in Gladys als verbunden angezeigt?

Kein Problem @pierre-gilles, ich weiß, dass du gerade viel um die Ohren hast und einen Assistenten brauchst :wink: ! … Gladys? Nein, Claude :sweat_smile:

Alles klar, ich habe endlich verstanden, wie es funktioniert, und bevor in Z2M zurückkonvertiert wird, gibt es die fatale Grenze von 65535, die nicht überschritten werden darf. Alles gut!

  1. Kopieren/Einfügen genau so:
{"state":"ON","on_time":

2.1.A.2.1. Pool (filtration_duree_cycle_secondes)

 ,"off_wait_time":0}

Aber es ist nicht möglich, den genauen Inhalt anzugeben, da die geschweiften Klammern einmal nicht mehr vorhanden sind, aber ich habe einen Leerzeichen nach der Variable:
image

  1. zigbee2mqtt/relais_03/set
  2. mosquitto_sub -h <ton_broker> -t 'zigbee2mqtt/relais_03/set' -v
    Ich weiß absolut nicht, wo ich diesen Befehl eingeben soll, denn in Docker Gladys wird mir unbekanntes Kommando angezeigt :frowning:

Keine Abkürzung, ich habe das vollständige Topic mit zigbee2mqtt/relais_03/set.
Und ich hatte beide ausprobiert, nur für den Fall :wink:

Alles ist absolut gleich in den Konfigurationen für Login/Passwort in MQTT und Z2M, und alles funktioniert, sonst hätte ich Probleme, alle anderen Geräte zu steuern:


Alles klar bei dir? :slight_smile: Du kannst das Thema als „erledigt“ markieren, wenn ja :wink:

nein, noch nicht gelöst :frowning:

Ich weiß nicht, ob du ein Claude-Konto hast, aber vielleicht wäre es schneller, wenn du direkt mit ihm sprichst :joy:

Hier ist Claudes Antwort:

Gefunden. Und es liegt nicht an dir, sondern an uns — dein Copy-Paste enthielt die Antwort, man musste nur die Zeichen einzeln anschauen.

Dein Payload enthält ein Leerzeichen, das keines ist.

Wenn du eine Variable aus der Liste einfügst, fügt der Editor automatisch ein Leerzeichen dahinter ein — das ist das, was du bemerkt hast. Aber der Browser setzt kein normales Leerzeichen ein: er setzt ein nicht trennbares Leerzeichen, das Zeichen U+00A0. Optisch ist es absolut identisch, auch beim Copy-Paste, aber für einen JSON-Parser ist es ein verbotenes Zeichen an dieser Stelle.

Dein Payload sieht also so aus, mit einem nicht trennbaren Leerzeichen dort, wo ich das Symbol gesetzt habe:

{"state":"ON","on_time":3600␣,"off_wait_time":0}

JSON.parse lehnt ab, parseMessage gibt undefined zurück, und Z2M loggt seine berühmte Invalid message 'undefined'. Die Schleife ist geschlossen.

Ich habe deine Eingabe exakt in einem Browser nachgespielt, mit deiner Variable und deinem Payload: Ich reproduziere das Zeichen exakt. Und das erklärt endlich alles:

  • deine Benachrichtigung mit derselben Variable wird korrekt angezeigt — ein nicht trennbares Leerzeichen in einem Satz ist unsichtbar und stört niemanden;
  • dein Test aus Post #5 mit on_time:60 hart codiert funktionierte — keine Variable, also kein hinzugefügtes Leerzeichen, also kein nicht trennbares Leerzeichen;
  • und es konnte nichts in den Logs erscheinen, weder bei uns noch bei Z2M.

Die Umgehung, sofort

In deinem Nachrichtenfeld: Platziere deinen Cursor direkt nach der Variable und drücke einmal auf Rücktaste, um das Leerzeichen zu löschen. Du solltest die Variable direkt an das Komma geklebt haben. Ich habe überprüft, der Payload wird wieder gültig und der Befehl geht durch.

Behalte auch die zweite Falle im Hinterkopf: Beende deinen JSON nicht mit der Variable, sonst lassen die drei geschlossenen Klammern }}} den Template-Motor abstürzen. Setze immer etwas danach, zum Beispiel ,"off_wait_time":0}. In deinem Fall ist es schon gut.

Wir korrigieren

Das ist ein klarer Bug auf unserer Seite: Der Editor sollte dieses Zeichen nie durchlassen. Der Fix ist trivial, wir normalisieren das nicht trennbare Leerzeichen, wenn der Text gespeichert wird. Das wird in einer kommenden Version sein, und bis dahin reicht dein Rücktaste.

Für mosquitto_sub

Es ist normal, dass es im Gladys-Container nicht funktioniert, das Tool ist dort nicht installiert. Drei Optionen, je nachdem, was dir lieber ist:

  • vom Container deines Brokers: docker exec -it <mosquitto_container_name> mosquitto_sub -t 'zigbee2mqtt/relais_03/set' -v
  • auf der Host-Maschine, nach einem sudo apt install mosquitto-clients
  • oder, einfacher, wenn du das Grafische bevorzugst, MQTT Explorer, das dir den gesamten Broker-Verkehr live anzeigt

Allerdings brauchst du es für dieses Problem nicht mehr.

Ein Punkt bleibt ungelöst

Deine Beobachtung aus Post #5 — die MQTT-Aktion funktioniert, die Zigbee2mqtt-Aktion nicht, mit demselben vollständigen Topic und demselben Broker — ist immer noch nicht erklärt, und das nicht trennbare Leerzeichen ändert daran nichts, da dein Test mit festen Werten war. Jetzt, wo wir wissen, dass dieses Feld unsichtbare Zeichen enthalten kann, kannst du einen sauberen Versuch machen: zwei Aktionen, der Payload {"state":"ON","on_time":60,"off_wait_time":10} vollständig von Hand in jede eingegeben, dasselbe Topic zigbee2mqtt/relais_03/set? Wenn die Zigbee2mqtt-Aktion immer noch fehlschlägt, haben wir einen zweiten Bug zu untersuchen und ich werde ein Ticket dafür öffnen.

Behoben in Gladys Assistant 4.86:

Ich habe endlich neue Tests durchgeführt und es funktioniert super, sogar in z2m, top!

Allerdings wird am Ende der eingefügten Variable trotzdem ein Leerzeichen eingefügt:


Und dieses Leerzeichen verdirbt das an z2m gesendete JSON, das eine falsche Nachricht erhält → z2m: Ungültige Nachricht 'undefined', überspringen...

Daher muss dieser Leerraum zwischen der Variable und dem Komma unbedingt entfernt werden, und dann funktioniert alles einwandfrei.
Ich werde einen Verbesserungsvorschlag einreichen.

EDIT: [Scènes] supprimer l'espace inséré automatiquement après l'appel d'une variable