stdClass und Array direkt via JSON-RPC abrufen

Hallo zusammen,

ich arbeite grade an einem Modul dass ein paar öffentliche Funktionen anbietet die Zustandsdaten von einem Gerät als Objekt zurückliefern. Innerhalb von Symcon funktioniert es soweit ich das bisher sehe einwandfrei stdClass und/oder Array als Rückgabetyp von Funktionen zu nutzen, in der Doku habe ich auch nichts gefunden was dagegen spricht.

Über JSON-RPC kann ich allerdings diese Funktionen nicht aufrufen, hier fliegt in beiden Fällen ein Fehler weil intern versucht wird die Objekte/Arrays direkt in strings zu konvertieren (ohne json_encode zu verwenden);

stdClass:

{
    "jsonrpc": "2.0",
    "error": {
        "code": -32603,
        "message": "<br />\n<b>Fatal error</b>:  Uncaught Error: Object of class stdClass could not be converted to string in /-:3\nStack trace:\n#0 {main}\n  thrown in <b>/-</b> on line <b>3</b><br />\n"
    },
    "id": null
}

Array:

{
    "jsonrpc": "2.0",
    "error": {
        "code": -32603,
        "message": "<br />\n<b>Notice</b>:  Array to string conversion in <b>/-</b> on line <b>3</b><br />\n"
    },
    "id": null
}

Ich würde mir wünschen dass Objekte & Arrays direkt als json ausgegeben werden können.

Bei einigen Systemfunktionen wie zb WFC_GetSnapshot funktioniert die Ausgabe als Objekt über JSON-RPC so wie ich mir das vorstelle; intern liefern sie in Symcon allerdings auch „nur“ einen string… ist das eine fixe interne Ausnahme, oder kann man das auch selber so hinbekommen?

Workaround ist ansonsten natürlich klar, ich kann in meinen Funktionen mit json_encode einen String zurückgeben und dann wieder dekodieren, das mache ich jetzt auch; direkt über Objekte zu gehen wäre aber imo deutlich „schöner“, ausser ich übersehe etwas was dagegen spricht :slight_smile:

Ohne den genauen Anwendungszweck zu kennen solltest Du für Dich erst mal entscheiden was für Deine Anforderungen der geeignetere Weg ist, über die Websocket Schnittstelle oder über JSON-RPC.

Weis nicht ob ich das als Workaround bezeichnen würde, das wäre aber auch mein Vorgehen die Daten als JSON zu senden und auf der Seite von IP-Symcon dann daraus einfach ein Array oder ein Standard Objekt zu machen.

Viele wichtiger finde ich persönlich, sich je nach individuellen Anwendungszweck von vorn herein für die richtige Schnittstelle zu entscheiden, also JSON-RPC oder Websocket.

Vorweg: Herzlich Willkommen im Forum!

Die Anbindung der JSON-RPC ist jetzt nicht gerade mein Thema, ich kann mir aber vorstellen, dass du hier einen Bug entdeckt hast. Ich habe das auf jeden Fall mal notiert und wir schauen was da nicht klappt.

Ob die JSON-RPC jetzt die richtige Wahl ist, weiß ich nicht. Das können wir gerne mal gemeinsam diskutieren, dann müsstest du aber ein bisschen über dein Projekt schreiben. Bis zum Fix hättest du alternativ aber auch ein paar Möglichkeiten um den Fehler zu umgehen:

  • Alternativfunktionen, die das Ergebnis JSON-codiert zurückgeben
  • Aufruf von IPS_RunScriptTextWait und im SkriptText den Rückgabewert codieren
  • Sicherlich noch weitere Möglichkeiten, aber die zwei fallen mir auf die Schnelle ein

Danke für die Antworten!

Ich hatte den Anwendungsfall bewusst erstmal nicht dazugeschrieben, weil ich hier grade noch etwas am experimentieren bin, und ich nur erstmal den Fehler dokumentieren wollte.

Konkret geht es darum im WebFront in HTMLBoxen eigene kleine Visualisierungen einzubetten die sich sowohl aktualisieren als auch ein paar Knöpfe zum schalten enthalten sollen. Möchte dazu möglichst keine eigenen Schnitstellen erstellen müssen, sondern alles mit vorhandenen Mitteln machen. Habe zb ein Modul für ChromeCast gebaut, und möchte die Wiedergabe anzeigen; sieht aktuell so aus:

Ich lege die fraglichen Objekte aus der ursprünglichen Frage jetzt direkt json_encodiert immer bei einem Update in einer Variable ab… dann kann alles über die bestehenden WFC JSON-RPC calls, sowie die WFC WebSocket Schnittstelle (Updates) gemacht werden, und das WebFront Passwort reicht aus.

Wenn du ein Modul im Hintergrund hast, dann wären meine Empfehlungen zweierlei:

  1. Mache so viel wie möglich im Modul via PHP, ganz ohne API. Da kannst du beispielsweise den Inhalt der HTML-Box neu setzen und benötigst dafür keine API
  2. Verwende einen WebHook: Dein Modul kann seinen eigenen Webhook anlegen, an den du dann von dir definierte Datensätze schicken kannst und passend darauf antworten kannst.

In dem Fall würde ich Websocket nutzten, weil Du ja ständig aktualisierst. Insbesondere bei der Zeit macht es aber eher Sinn die eigentliche Abfrage nur zyklisch im Hintergrund alle paar Sekunden zu machen, die Zeit selber aber dann unabhängig davon im Webseitenelement hochzählen zu lassen. Ich bekomme von bestimmten Systemen auch nicht ständig die aktuelle Zeit.

Wenn Du eine Vorlage brauchst oder etwas als Grundlage nehmen willst, kannst Du auch so was wie

nutzten und das in eine HTMLBox dann einbauen.

Ja, das hochzählen der Zeit sollte auf jeden Fall im Client passieren; habe ich momentan in meiner Lösung auch schon so gebaut. In einer Variable steht nur der Zustand, die aktuelle Position und ein Timestamp, die Updates davon erhalte ich über den WFC Websocket, und das Frontend zählt dann bis zum nächsten Update die Zeit selber weiter.

Verstehe ich dich richtig dass du eine eigene WebSocket Verbindung erstellen & nutzen würdest? Über den ServerSocket, und da z.B. das IPSNetwork Modul? Out of the Box gibt es ja ansonsten nur einen WebSocket Client so wie ich das sehe.

Du willst ja aber nicht aus IP-Symcon eine Websocket Verbindung zu einem Gerät aufbauen, dazu bräuchtest Du dann ganz normal einen Websocket Client IO.

Was Du an sich umsetzt, ist ja aus einer HTMLBox per Javascript Dinge aufzurufen.
Da reicht ja der Zugriff über den Websocket Datenaustausch aus.

Ansonsten kannst Du Dir ja einfach selbst ein Webhook bauen, siehe z.B. HookServe als grundlegendes Beispiel.

Alles klar, danke. An genau der verlinkten WebFront WebSocket Schnittstelle hänge ich schon dran, das klappt auch super :slight_smile: