Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Visualisierung
  4. [Gelöst] Datenpunkte im JSON-Format und deren Visualisierung

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    16
    1
    1.8k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    884

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    2.1k

[Gelöst] Datenpunkte im JSON-Format und deren Visualisierung

Geplant Angeheftet Gesperrt Verschoben Visualisierung
4 Beiträge 2 Kommentatoren 933 Aufrufe 4 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • ZarelloZ Offline
    ZarelloZ Offline
    Zarello
    schrieb am zuletzt editiert von Zarello
    #1

    Hallo,

    nachdem ich nun sehr viel gesucht habe und nichts wirklich passendes gefunden habe, schreibe ich nun hier in der Hoffnung, dass ich die ganz simple, existierende Lösung übersehen habe:

    Ich habe über zigbee2mqtt einige Geräte eingebunden. Die Geräte stellen ihre Daten als Datenpunkt im JSON-Format über den MQTT-Adapter zur Verfügung, soweit alles super.
    Nun möchte ich natürlich die Daten dieser Geräte auf einer Visualisierung anzeigen und diese auch darüber ansteuern.
    Leider habe ich bisher keinen einfachen Weg gefunden, wie ich diese Werte direkt anzeigen kann und erst recht nicht, wie ich entsprechende Steuerbefehle zurückschreiben kann.
    Konkret:
    Unter dem Datenpunkt mqtt.0.zigbee2mqtt.Lampe wird mir der Wert {"brightness":0,"color_mode":"color_temp","color_temp":450,"linkquality":47,"state":"OFF","update":{"state":"available"},"update_available":true} geliefert und wenn ich die Lampenhelligkeit einstellen möchte, muss ich z.B. an den Datenpunkt mqtt.0.zigbee2mqtt.Lampe.set den Wert {"brightness":50} schicken.

    Die einzige Möglichkeit, die ich bisher gefunden habe, ist, dass ich für jeden Wert, den ich auslesen möchte und für jeden Wert, den ich einstellen möchte, einen eigenen Datenpunkt anlege und die entsprechenden Daten bei Änderung über ein kleines Skript übertrage. Abgesehen davon, dass dies unheimlich viele kleine Skripte werden, die alle händisch angelegt werden müssen (in blockly zumindest, in JavaScript geht es womöglich einfacher), müssen diese Scripte natürlich auch die ganze Zeit reagieren, wenn sich Werte ändern, unabhängig davon, ob die Oberfläche zur Zeit irgendwo dargestellt wird.

    Habe ich da irgend etwas übersehen? Gibt es eine Möglichkeit beim Eintragen von Datenpunkten in Vis direkt einen Wert aus dem JSON-Format zu extrahieren und evtl. die Möglichkeit, den eingestellten Wert in Vis über eine Formatanweisung in einen entsprechenden JSON-Wert zu übersetzen?

    OpenHAB bietet diese Möglichkeiten, jedoch wollte ich gucken, ob mir ioBroker nicht besser gefällt und mehr Möglichkeiten bietet. Bisher macht ioBroker auch einen deutlich besseren Eindruck als OpenHAB, mit einer Lösung für dieses kleine Problem würde ich sofort wechseln.

    ZarelloZ OliverIOO 2 Antworten Letzte Antwort
    0
    • ZarelloZ Zarello

      Hallo,

      nachdem ich nun sehr viel gesucht habe und nichts wirklich passendes gefunden habe, schreibe ich nun hier in der Hoffnung, dass ich die ganz simple, existierende Lösung übersehen habe:

      Ich habe über zigbee2mqtt einige Geräte eingebunden. Die Geräte stellen ihre Daten als Datenpunkt im JSON-Format über den MQTT-Adapter zur Verfügung, soweit alles super.
      Nun möchte ich natürlich die Daten dieser Geräte auf einer Visualisierung anzeigen und diese auch darüber ansteuern.
      Leider habe ich bisher keinen einfachen Weg gefunden, wie ich diese Werte direkt anzeigen kann und erst recht nicht, wie ich entsprechende Steuerbefehle zurückschreiben kann.
      Konkret:
      Unter dem Datenpunkt mqtt.0.zigbee2mqtt.Lampe wird mir der Wert {"brightness":0,"color_mode":"color_temp","color_temp":450,"linkquality":47,"state":"OFF","update":{"state":"available"},"update_available":true} geliefert und wenn ich die Lampenhelligkeit einstellen möchte, muss ich z.B. an den Datenpunkt mqtt.0.zigbee2mqtt.Lampe.set den Wert {"brightness":50} schicken.

      Die einzige Möglichkeit, die ich bisher gefunden habe, ist, dass ich für jeden Wert, den ich auslesen möchte und für jeden Wert, den ich einstellen möchte, einen eigenen Datenpunkt anlege und die entsprechenden Daten bei Änderung über ein kleines Skript übertrage. Abgesehen davon, dass dies unheimlich viele kleine Skripte werden, die alle händisch angelegt werden müssen (in blockly zumindest, in JavaScript geht es womöglich einfacher), müssen diese Scripte natürlich auch die ganze Zeit reagieren, wenn sich Werte ändern, unabhängig davon, ob die Oberfläche zur Zeit irgendwo dargestellt wird.

      Habe ich da irgend etwas übersehen? Gibt es eine Möglichkeit beim Eintragen von Datenpunkten in Vis direkt einen Wert aus dem JSON-Format zu extrahieren und evtl. die Möglichkeit, den eingestellten Wert in Vis über eine Formatanweisung in einen entsprechenden JSON-Wert zu übersetzen?

      OpenHAB bietet diese Möglichkeiten, jedoch wollte ich gucken, ob mir ioBroker nicht besser gefällt und mehr Möglichkeiten bietet. Bisher macht ioBroker auch einen deutlich besseren Eindruck als OpenHAB, mit einer Lösung für dieses kleine Problem würde ich sofort wechseln.

      ZarelloZ Offline
      ZarelloZ Offline
      Zarello
      schrieb am zuletzt editiert von Zarello
      #2

      Inzwischen habe ich ein "kleines" Skript geschrieben, welches entsprechende Datenpunkte aus den Zigbee-Geräten unter mqtt.0 erzeugt (falls sie nicht existieren). Die Datenpunkte liegen unter javascript.0.MQTT und sind per Default nur lesbar. Die entsprechenden Einstellungen können natürlich an den Elementen geändert werden. Wenn ein Datenpunkt auch schreibbar geschaltet wird, muss das Skript neu gestartet werden, damit die entsprechenden Subscriptions erstellt werden.
      Es muss auch ein Datenpunkt 0_userdata.0.WriteZigbeeData angelegt werden (boolean), mit dem im Zweifelsfall die Aktualisierungen unterbrochen werden können.

      Das Skript versucht die Daten, die an einem entsprechend schreibbar geschalteten Datenpunkt gesetzt werden, auf mqtt zurück zu schreiben. Hierbei können natürlich Rückkopplungseffekte auftreten. Ich habe im Skript versucht diese weitestgehend abzufangen. Falls es schief geht, kann man 0_userdata.0.WriteZigbeeData auf false setzen um diese Rückkopplung zu unterbrechen.

      Außerdem können im Skript am Anfang Kanäle für Geräte definiert werden, falls diese nicht automatisch erkannt wurden und es können auch Einstellungen für Datenpunkte vorgegeben werden.
      Dabei habe ich auch eine Möglichkeit zur Parameterkonvertierung und zur bedingten Übertragung eingebaut. Ersteres, da ich Elemente habe welche in MQTT "ON" oder "OFF" als Wert haben, jedoch in ioBroker natürlich als boolean dargestellt werden sollen. Zweiteres, um Rückkopplungen bei z.B. einer Lampe zu vermeiden. Die Lampe unterstützt "color" und "color_temp" als Kanäle. Wird "color_temp" gesetzt, so ändert sich auch der Wert von "color", wodurch es hier eine Rückkopplung geben würde, da dementsprechend der geänderte Wert von "color" darauf folgend wieder an MQTT geschrieben werden würde.

      Hier das Skript, vielleicht hilft es ja irgend jemandem. Für Anregungen oder Änderungsvorschläge bin ich immer dankbar.

      // Datenpunkt (boolean) über den das Kopieren der MQTT-Zustände auf die endsprechenden Datenpunkte aktiviert/deaktiviert werden kann.
      // Dieser Datenpunkt muss existieren
      const WriteZigbeeDataActivated = "0_userdata.0.WriteZigbeeData"
      
      // Datenpunkt (boolean) über den weitere Logs dieses Skripts aktiviert werden können.
      const LogDebugZigbeeDataActivated = "0_userdata.0.WriteZigbeeDebug"
      
      /* Eine Map von zigbee2mqtt-Werten eines Elements, mit den Default-Eigenschaften, die ein Element dieses Namens haben soll. Siehe auch DATA_POINTS
       */
      const GENERAL_DATA_POINTS = {"battery": {"type":"number"},
                                   "linkquality": {"type":"number"},
                                   "humidity": {"type": "number"},
                                   "temperature": {"type": "number"}
                                  };
      
      /* DATA_POINTS
       * Eine Map von zigbee2mqtt-Elementen zu deren anzulegenden Datenpunkten.
       * Die Datenpunkte sind dabei wiederum eine Map mit entsprechenden Einträgen für den Namen des Datenpunktes zu seinen Eigenschaften.
       * Die Eigenschaften sind dabei Werte, die in das "common"-Feld des zu erzeugenden Datenpunktes geschrieben werden.
       * Dabei sind die Defaults: {"read": true, "write": false, "type": "mixed"}
       * Wird statt einer Map der Wert null angegeben, so werden die Defaults unter Berücksichtigung von GENERAL_DATA_POINTS verwendet.
       * 
       * Mögliche weitere Felder, welche bei der Übersetzung zwischen MQTT-Datum und Datenpunkt verwendet werden, sind:
       * "trans": [[0,"OFF"],[1,"ON"]]
       *          Eine Liste von Wertepaaren, mit jeweils Index 0: Wert des Datenpunktes, Index 1: Wert des MQTT-Datums
       * "condition_zigbee_get": ["color_mode","color_temp"]
       *          Eine Liste mit zwei Werten, der erste Wert gibt einen anderes MQTT-Datum dieses Geräts an, welches, wenn es vorhanden ist, den zweiten Wert enthalten muss, damit
       *          der dazugehörige Datenpunkt bei Veränderung auch gesetzt wird.
       * 
       * Zigbee-Elemente, die hier nicht aufgeführt sind, werden beim Start dieses Skripts auch übertragen. Dabei werden sämtliche aktuell enthaltene MQTT-Daten einfach mit
       * den Defaults als Datenpunkte angelegt.
       */
      const DATA_POINTS = {"Steckdose1": {"state": {"type": "boolean", "trans": [[0,"OFF"],[1,"ON"]]}, "linkquality": null},
                           "WZSubwoofer": {"state": {"type": "boolean", "trans": [[0,"OFF"],[1,"ON"]]}, "linkquality": null},
                           "SwitchIO1": {"action": null, "battery": null, "linkquality": null},
                           "SwitchLamp1": {"action": null, "battery": null, "linkquality": null},
                           "SwitchRollo1": {"action": null, "battery": null, "linkquality": null},
                           "SwitchRollo2": {"action": null, "battery": null, "linkquality": null},
                           "RolloWZLinks": {"position": {"write": true, "type": "number"}, "battery": null, "linkquality": null},
                           "RolloWZRechts": {"position": {"write": true, "type": "number"}, "battery": null, "linkquality": null},
                           "LichtPanelWZ": {"brightness": {"write": true, "type": "number"},
                                            "color": {"write": true, "condition_zigbee_get": ["color_mode","xy"]},
                                            "color_mode": {},
                                            "color_temp": {"write": true, "type": "number", "condition_zigbee_get": ["color_mode","color_temp"]},
                                            "state": {"type": "boolean", "trans": [[0,"OFF"],[1,"ON"]]},
                                            "linkquality": null}
                          };
      
      // Basis der zu erzeugenden Datenpunkte
      var js_base = "javascript.0.";
      // Verzeichnis in der Basis, in dem die Datenpunkte erzeugt werden sollen
      var dest_base = "MQTT.";
      
      /**********************
       * Konfiguration Ende
       **********************/
      
      // Aufsammeln der Zigbee-Datenpunkte. Falls es mehrere Zigbee-Instanzen gibt muss dies hier angepasst werden.
      var states = $('state[id=mqtt.0.zigbee2mqtt.*]');
      
      function writeZigbeeData () {
          try {
              var obj = getObject (WriteZigbeeDataActivated);
              if (obj.type == "state" && obj.common.type == "boolean") {
                  var state = getState (WriteZigbeeDataActivated);
                  return state.val;
              }
      
              return false;
          } catch (err) {
              console.log ("Get zigbee write state failed: " + err.message);
              throw err;
          }
      }
      
      function debugLogActive () {
          try {
              var obj = getObject (LogDebugZigbeeDataActivated);
              if (obj.type == "state" && obj.common.type == "boolean") {
                  var state = getState (LogDebugZigbeeDataActivated);
                  return state.val;
              }
          } catch (err) {}
          return false;
      }
      
      function debugLog (msg) {
          if (debugLogActive ())
              console.log (msg);
      }
      
      function getGeneralDataPoint (name) {
          try {
              let dp = GENERAL_DATA_POINTS[name];
      
              if (dp != undefined) {
                  if (dp["read"] == undefined) dp["read"] = true;
                  if (dp["write"] == undefined) dp["write"] = false;
                  if (dp["type"] == undefined) dp["type"] = "mixed";
                  return dp;
              }
          } catch (err) {
          }
      
          return {read: true, write: false, "type": "mixed"};
      }
      
      function getDataPoints (dp_name, zigbee_state) {
          try {
              let dp = DATA_POINTS[dp_name];
      
              if (dp != undefined) {
                  for (v in dp) {
                      if (dp[v] == null) {
                          dp[v] = getGeneralDataPoint (v);
                      }
                      if (dp[v]["read"] == undefined) dp[v]["read"] = true;
                      if (dp[v]["write"] == undefined) dp[v]["write"] = false;
                      if (dp[v]["type"] == undefined) dp[v]["type"] = "mixed";
                  }
                  return dp;
              }
          } catch (err) { }
      
          let dps = {};
          for (var v in zigbee_state) {
              debugLog ("  v[" + String (v) + "]: " + JSON.stringify (zigbee_state[v]));
      
              dps[v] = getGeneralDataPoint (v);
          }
          return dps;
      }
      
      function convertToDataPointType (datapoint, value) {
          if (!existsObject (datapoint))
              return value;
      
          try {
              let t = getObject (datapoint).common.type;
      
              switch (t) {
                  case "number":
                      return Number (value);
      
                  case "boolean":
                      switch (value) {
                          case "ON":
                          case "true":
                          case "True":
                          case true:
                          case 1:
                              return true;
                      }
                      return false;
              }
          } catch (err) {}
      
          return JSON.stringify (value);
      }
      
      if (!writeZigbeeData ()) {
          console.log ("Set zigbee state deactivated");
      }
      
      // Als erstes die Datenpunkte anlegen.
      for (var j = 0; j <= states.length; j++) {
          // Nicht definierte, .set-Datenpunkte, die Bridge und nicht existierende Datenpunkte ignorieren
          if (states[j] == undefined || states[j].startsWith ("mqtt.0.zigbee2mqtt.bridge") || states[j].endsWith (".set"))
              continue;
          if (!existsObject (states[j]))
              continue;
      
          // Fixe Codierung ab welchem Zeichen die Namen der Zigbee-Geräte zu finden sind - wäre besser dynamisch, ist mir aber gerade zu aufwendig.
          let zigbee_name = states[j].substr (19);
      
          debugLog (String (j) + ": " + JSON.stringify (zigbee_name));
          let device_name = dest_base + zigbee_name;
          let state = JSON.parse (getState (states[j]).val);
      
          debugLog ("state of " + zigbee_name + ": " + JSON.stringify (state));
      
          // Das Gerät selber auch als Datenpunkt anlegen
          if (!existsState (device_name)) {
              let obj = { read: true, write: true,
                              desc: "Automatically created from " + states[j],
                        };
      
              createState (device_name, "", obj);
              console.log ("Create " + device_name);
          }
      
          let datapoints = getDataPoints (zigbee_name, state);
      
          for (var dp in datapoints) {
              debugLog ("  v[" + String (dp) + "]: " + JSON.stringify (datapoints[dp]));
      
              var datapoint_name = device_name + "." + dp;
              if (!existsState (datapoint_name)) {
                  let obj = datapoints[dp];
                  obj.desc = "Automatically created from " + states[j] + "[\"" + dp + "\"]";
                  createState (datapoint_name, "", obj);
                  console.log ("Create " + datapoint_name);
              }
          }
      }
      
      for (let j = 0; j <= states.length; j++) {
          if (states[j] == undefined || states[j].startsWith ("mqtt.0.zigbee2mqtt.bridge") || states[j].endsWith (".set"))
              continue;
          if (!existsObject (states[j]))
              continue;
      
          // Fixe Codierung ab welchem Zeichen die Namen der Zigbee-Geräte zu finden sind - wäre besser dynamisch, ist mir aber gerade zu aufwendig.
          let zigbee_name = states[j].substr (19);
          let device_name = dest_base + zigbee_name;
      
          let state = JSON.parse (getState (states[j]).val);
          let read_dps = []
      
          let datapoints = getDataPoints (zigbee_name, state);
      
          for (let dp in datapoints) {
              debugLog ("  v[" + String (dp) + "]: " + JSON.stringify (state[dp]));
      
              let datapoint_name = device_name + "." + dp;
              if (!existsState (datapoint_name))
                  continue;
      
              let obj = getObject (js_base + datapoint_name);
              try {
                  if (obj.common.write) {
                      console.log ("Subscribe: " + js_base + datapoint_name);
                      const zigbeeObject = states[j];
                      const control_name = dp;
                      const dp_name = js_base + datapoint_name;
                      on({id: js_base + datapoint_name, change: "ne"}, async function (obj2) {
                        try {
                            if (getState (WriteZigbeeDataActivated).val) {
      
                                let value = obj2.state.val;
                                let oldValue = obj2.oldState.val;
      
                                // Nur übertragen, wenn es eine relevante Änderung gab - Überprüfung über Strings, damit die Werte entsprechend gerundet werden.
                                if (JSON.stringify (value) != JSON.stringify (oldValue)) {
                                    let obj = getObject (dp_name);
                                    let v = getState(dp_name).val;
                                    try {
                                        let trans = obj.common.trans;
                                        //console.log ("find " + JSON.stringify (v) + " in " + JSON.stringify (trans));
                                        for (let l in trans)
                                          if (trans[l][0] == v) {
                                              v = trans[l][1];
                                              //console.log ("  translated to " + JSON.stringify (v) + " (l=" + JSON.stringify (trans[l]) + ")");
                                              break;
                                          }
                                    } catch (err) {
                                        //console.log ("error trans: " + err.message);
                                    }
                                    let v2 = JSON.stringify (v);
                                    //console.log ("Set zigbee state " + zigbeeObject + ".set: " + '{"' + control_name + '":' + v2 + '}' + " value: " + JSON.stringify (value) + " oldV: " + JSON.stringify (oldValue));
                                    setState(zigbeeObject + ".set", ('{"' + control_name + '":' + v2 + '}'));
                                }
                            } else  {
                                console.log ("Set zigbee state deactivated");
                            }
                        } catch (err) {
                            console.log ("Set zigbee state failed: " + err.message);
                        }
                      });
                  }
                  if (obj.common.read)
                      read_dps.push (dp);
              } catch (err) {
                  console.log ("Object " + datapoint_name + " err: " + err.message);
              }
          }
      
          if (read_dps.length > 0) {
              console.log ("Subscribe: " + states[j]);
              const zigbeeObject = states[j];
              const dev_name = js_base + device_name;
              const control_names = read_dps;
              on({id: states[j], change: "ne"}, async function (obj) {
                let value = obj.state.val;
                let oldValue = obj.oldState.val;
                for (let v in control_names) {
                    let datapoint_name = dev_name + "." + control_names[v];
                    let val = getState(zigbeeObject).val;
                    let v2 = jsonataExpression((function () { try {return JSON.parse(val);} catch(e) {return {};}})(),control_names[v]);
                    let dp_obj = getObject (datapoint_name);
                    try {
                        let trans = dp_obj.common.trans;
                        for (let l in trans)
                            if (trans[l][1] == v2) {
                                v2 = trans[l][0];
                                break;
                            }
                    } catch (err) {}
                    try {
                        let cond = dp_obj.common.condition_zigbee_get;
                        let vc = jsonataExpression((function () { try {return JSON.parse(val);} catch(e) {return {};}})(),cond[0]);
                        if (vc != cond[1]) {
                            debugLog ("Skip js state " + datapoint_name + ": " + JSON.stringify (v2) + " from: " + zigbeeObject + ": " + getState(zigbeeObject).val + " [" + control_names[v] + "]");
                            continue;
                        }
                    } catch (err) {}
                    let v3 = convertToDataPointType (datapoint_name, v2)
                    if (getState (datapoint_name).val != v3) {
                        debugLog ("Set js state " + datapoint_name + ": " + JSON.stringify (v2) + " from: " + zigbeeObject + ": " + getState(zigbeeObject).val + " [" + control_names[v] + "]");
                        setState(datapoint_name, v3, true);
                    }
                }
              });
          }
      }
      
      

      Edit: Bugfix im Script

      ZarelloZ 1 Antwort Letzte Antwort
      0
      • ZarelloZ Zarello

        Hallo,

        nachdem ich nun sehr viel gesucht habe und nichts wirklich passendes gefunden habe, schreibe ich nun hier in der Hoffnung, dass ich die ganz simple, existierende Lösung übersehen habe:

        Ich habe über zigbee2mqtt einige Geräte eingebunden. Die Geräte stellen ihre Daten als Datenpunkt im JSON-Format über den MQTT-Adapter zur Verfügung, soweit alles super.
        Nun möchte ich natürlich die Daten dieser Geräte auf einer Visualisierung anzeigen und diese auch darüber ansteuern.
        Leider habe ich bisher keinen einfachen Weg gefunden, wie ich diese Werte direkt anzeigen kann und erst recht nicht, wie ich entsprechende Steuerbefehle zurückschreiben kann.
        Konkret:
        Unter dem Datenpunkt mqtt.0.zigbee2mqtt.Lampe wird mir der Wert {"brightness":0,"color_mode":"color_temp","color_temp":450,"linkquality":47,"state":"OFF","update":{"state":"available"},"update_available":true} geliefert und wenn ich die Lampenhelligkeit einstellen möchte, muss ich z.B. an den Datenpunkt mqtt.0.zigbee2mqtt.Lampe.set den Wert {"brightness":50} schicken.

        Die einzige Möglichkeit, die ich bisher gefunden habe, ist, dass ich für jeden Wert, den ich auslesen möchte und für jeden Wert, den ich einstellen möchte, einen eigenen Datenpunkt anlege und die entsprechenden Daten bei Änderung über ein kleines Skript übertrage. Abgesehen davon, dass dies unheimlich viele kleine Skripte werden, die alle händisch angelegt werden müssen (in blockly zumindest, in JavaScript geht es womöglich einfacher), müssen diese Scripte natürlich auch die ganze Zeit reagieren, wenn sich Werte ändern, unabhängig davon, ob die Oberfläche zur Zeit irgendwo dargestellt wird.

        Habe ich da irgend etwas übersehen? Gibt es eine Möglichkeit beim Eintragen von Datenpunkten in Vis direkt einen Wert aus dem JSON-Format zu extrahieren und evtl. die Möglichkeit, den eingestellten Wert in Vis über eine Formatanweisung in einen entsprechenden JSON-Wert zu übersetzen?

        OpenHAB bietet diese Möglichkeiten, jedoch wollte ich gucken, ob mir ioBroker nicht besser gefällt und mehr Möglichkeiten bietet. Bisher macht ioBroker auch einen deutlich besseren Eindruck als OpenHAB, mit einer Lösung für dieses kleine Problem würde ich sofort wechseln.

        OliverIOO Offline
        OliverIOO Offline
        OliverIO
        schrieb am zuletzt editiert von
        #3

        @zarello

        https://forum.iobroker.net/topic/31521/test-widget-json-template?_=1638915795778

        da könntest auch mal schauen

        Meine Adapter und Widgets
        TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
        Links im Profil

        1 Antwort Letzte Antwort
        0
        • ZarelloZ Zarello

          Inzwischen habe ich ein "kleines" Skript geschrieben, welches entsprechende Datenpunkte aus den Zigbee-Geräten unter mqtt.0 erzeugt (falls sie nicht existieren). Die Datenpunkte liegen unter javascript.0.MQTT und sind per Default nur lesbar. Die entsprechenden Einstellungen können natürlich an den Elementen geändert werden. Wenn ein Datenpunkt auch schreibbar geschaltet wird, muss das Skript neu gestartet werden, damit die entsprechenden Subscriptions erstellt werden.
          Es muss auch ein Datenpunkt 0_userdata.0.WriteZigbeeData angelegt werden (boolean), mit dem im Zweifelsfall die Aktualisierungen unterbrochen werden können.

          Das Skript versucht die Daten, die an einem entsprechend schreibbar geschalteten Datenpunkt gesetzt werden, auf mqtt zurück zu schreiben. Hierbei können natürlich Rückkopplungseffekte auftreten. Ich habe im Skript versucht diese weitestgehend abzufangen. Falls es schief geht, kann man 0_userdata.0.WriteZigbeeData auf false setzen um diese Rückkopplung zu unterbrechen.

          Außerdem können im Skript am Anfang Kanäle für Geräte definiert werden, falls diese nicht automatisch erkannt wurden und es können auch Einstellungen für Datenpunkte vorgegeben werden.
          Dabei habe ich auch eine Möglichkeit zur Parameterkonvertierung und zur bedingten Übertragung eingebaut. Ersteres, da ich Elemente habe welche in MQTT "ON" oder "OFF" als Wert haben, jedoch in ioBroker natürlich als boolean dargestellt werden sollen. Zweiteres, um Rückkopplungen bei z.B. einer Lampe zu vermeiden. Die Lampe unterstützt "color" und "color_temp" als Kanäle. Wird "color_temp" gesetzt, so ändert sich auch der Wert von "color", wodurch es hier eine Rückkopplung geben würde, da dementsprechend der geänderte Wert von "color" darauf folgend wieder an MQTT geschrieben werden würde.

          Hier das Skript, vielleicht hilft es ja irgend jemandem. Für Anregungen oder Änderungsvorschläge bin ich immer dankbar.

          // Datenpunkt (boolean) über den das Kopieren der MQTT-Zustände auf die endsprechenden Datenpunkte aktiviert/deaktiviert werden kann.
          // Dieser Datenpunkt muss existieren
          const WriteZigbeeDataActivated = "0_userdata.0.WriteZigbeeData"
          
          // Datenpunkt (boolean) über den weitere Logs dieses Skripts aktiviert werden können.
          const LogDebugZigbeeDataActivated = "0_userdata.0.WriteZigbeeDebug"
          
          /* Eine Map von zigbee2mqtt-Werten eines Elements, mit den Default-Eigenschaften, die ein Element dieses Namens haben soll. Siehe auch DATA_POINTS
           */
          const GENERAL_DATA_POINTS = {"battery": {"type":"number"},
                                       "linkquality": {"type":"number"},
                                       "humidity": {"type": "number"},
                                       "temperature": {"type": "number"}
                                      };
          
          /* DATA_POINTS
           * Eine Map von zigbee2mqtt-Elementen zu deren anzulegenden Datenpunkten.
           * Die Datenpunkte sind dabei wiederum eine Map mit entsprechenden Einträgen für den Namen des Datenpunktes zu seinen Eigenschaften.
           * Die Eigenschaften sind dabei Werte, die in das "common"-Feld des zu erzeugenden Datenpunktes geschrieben werden.
           * Dabei sind die Defaults: {"read": true, "write": false, "type": "mixed"}
           * Wird statt einer Map der Wert null angegeben, so werden die Defaults unter Berücksichtigung von GENERAL_DATA_POINTS verwendet.
           * 
           * Mögliche weitere Felder, welche bei der Übersetzung zwischen MQTT-Datum und Datenpunkt verwendet werden, sind:
           * "trans": [[0,"OFF"],[1,"ON"]]
           *          Eine Liste von Wertepaaren, mit jeweils Index 0: Wert des Datenpunktes, Index 1: Wert des MQTT-Datums
           * "condition_zigbee_get": ["color_mode","color_temp"]
           *          Eine Liste mit zwei Werten, der erste Wert gibt einen anderes MQTT-Datum dieses Geräts an, welches, wenn es vorhanden ist, den zweiten Wert enthalten muss, damit
           *          der dazugehörige Datenpunkt bei Veränderung auch gesetzt wird.
           * 
           * Zigbee-Elemente, die hier nicht aufgeführt sind, werden beim Start dieses Skripts auch übertragen. Dabei werden sämtliche aktuell enthaltene MQTT-Daten einfach mit
           * den Defaults als Datenpunkte angelegt.
           */
          const DATA_POINTS = {"Steckdose1": {"state": {"type": "boolean", "trans": [[0,"OFF"],[1,"ON"]]}, "linkquality": null},
                               "WZSubwoofer": {"state": {"type": "boolean", "trans": [[0,"OFF"],[1,"ON"]]}, "linkquality": null},
                               "SwitchIO1": {"action": null, "battery": null, "linkquality": null},
                               "SwitchLamp1": {"action": null, "battery": null, "linkquality": null},
                               "SwitchRollo1": {"action": null, "battery": null, "linkquality": null},
                               "SwitchRollo2": {"action": null, "battery": null, "linkquality": null},
                               "RolloWZLinks": {"position": {"write": true, "type": "number"}, "battery": null, "linkquality": null},
                               "RolloWZRechts": {"position": {"write": true, "type": "number"}, "battery": null, "linkquality": null},
                               "LichtPanelWZ": {"brightness": {"write": true, "type": "number"},
                                                "color": {"write": true, "condition_zigbee_get": ["color_mode","xy"]},
                                                "color_mode": {},
                                                "color_temp": {"write": true, "type": "number", "condition_zigbee_get": ["color_mode","color_temp"]},
                                                "state": {"type": "boolean", "trans": [[0,"OFF"],[1,"ON"]]},
                                                "linkquality": null}
                              };
          
          // Basis der zu erzeugenden Datenpunkte
          var js_base = "javascript.0.";
          // Verzeichnis in der Basis, in dem die Datenpunkte erzeugt werden sollen
          var dest_base = "MQTT.";
          
          /**********************
           * Konfiguration Ende
           **********************/
          
          // Aufsammeln der Zigbee-Datenpunkte. Falls es mehrere Zigbee-Instanzen gibt muss dies hier angepasst werden.
          var states = $('state[id=mqtt.0.zigbee2mqtt.*]');
          
          function writeZigbeeData () {
              try {
                  var obj = getObject (WriteZigbeeDataActivated);
                  if (obj.type == "state" && obj.common.type == "boolean") {
                      var state = getState (WriteZigbeeDataActivated);
                      return state.val;
                  }
          
                  return false;
              } catch (err) {
                  console.log ("Get zigbee write state failed: " + err.message);
                  throw err;
              }
          }
          
          function debugLogActive () {
              try {
                  var obj = getObject (LogDebugZigbeeDataActivated);
                  if (obj.type == "state" && obj.common.type == "boolean") {
                      var state = getState (LogDebugZigbeeDataActivated);
                      return state.val;
                  }
              } catch (err) {}
              return false;
          }
          
          function debugLog (msg) {
              if (debugLogActive ())
                  console.log (msg);
          }
          
          function getGeneralDataPoint (name) {
              try {
                  let dp = GENERAL_DATA_POINTS[name];
          
                  if (dp != undefined) {
                      if (dp["read"] == undefined) dp["read"] = true;
                      if (dp["write"] == undefined) dp["write"] = false;
                      if (dp["type"] == undefined) dp["type"] = "mixed";
                      return dp;
                  }
              } catch (err) {
              }
          
              return {read: true, write: false, "type": "mixed"};
          }
          
          function getDataPoints (dp_name, zigbee_state) {
              try {
                  let dp = DATA_POINTS[dp_name];
          
                  if (dp != undefined) {
                      for (v in dp) {
                          if (dp[v] == null) {
                              dp[v] = getGeneralDataPoint (v);
                          }
                          if (dp[v]["read"] == undefined) dp[v]["read"] = true;
                          if (dp[v]["write"] == undefined) dp[v]["write"] = false;
                          if (dp[v]["type"] == undefined) dp[v]["type"] = "mixed";
                      }
                      return dp;
                  }
              } catch (err) { }
          
              let dps = {};
              for (var v in zigbee_state) {
                  debugLog ("  v[" + String (v) + "]: " + JSON.stringify (zigbee_state[v]));
          
                  dps[v] = getGeneralDataPoint (v);
              }
              return dps;
          }
          
          function convertToDataPointType (datapoint, value) {
              if (!existsObject (datapoint))
                  return value;
          
              try {
                  let t = getObject (datapoint).common.type;
          
                  switch (t) {
                      case "number":
                          return Number (value);
          
                      case "boolean":
                          switch (value) {
                              case "ON":
                              case "true":
                              case "True":
                              case true:
                              case 1:
                                  return true;
                          }
                          return false;
                  }
              } catch (err) {}
          
              return JSON.stringify (value);
          }
          
          if (!writeZigbeeData ()) {
              console.log ("Set zigbee state deactivated");
          }
          
          // Als erstes die Datenpunkte anlegen.
          for (var j = 0; j <= states.length; j++) {
              // Nicht definierte, .set-Datenpunkte, die Bridge und nicht existierende Datenpunkte ignorieren
              if (states[j] == undefined || states[j].startsWith ("mqtt.0.zigbee2mqtt.bridge") || states[j].endsWith (".set"))
                  continue;
              if (!existsObject (states[j]))
                  continue;
          
              // Fixe Codierung ab welchem Zeichen die Namen der Zigbee-Geräte zu finden sind - wäre besser dynamisch, ist mir aber gerade zu aufwendig.
              let zigbee_name = states[j].substr (19);
          
              debugLog (String (j) + ": " + JSON.stringify (zigbee_name));
              let device_name = dest_base + zigbee_name;
              let state = JSON.parse (getState (states[j]).val);
          
              debugLog ("state of " + zigbee_name + ": " + JSON.stringify (state));
          
              // Das Gerät selber auch als Datenpunkt anlegen
              if (!existsState (device_name)) {
                  let obj = { read: true, write: true,
                                  desc: "Automatically created from " + states[j],
                            };
          
                  createState (device_name, "", obj);
                  console.log ("Create " + device_name);
              }
          
              let datapoints = getDataPoints (zigbee_name, state);
          
              for (var dp in datapoints) {
                  debugLog ("  v[" + String (dp) + "]: " + JSON.stringify (datapoints[dp]));
          
                  var datapoint_name = device_name + "." + dp;
                  if (!existsState (datapoint_name)) {
                      let obj = datapoints[dp];
                      obj.desc = "Automatically created from " + states[j] + "[\"" + dp + "\"]";
                      createState (datapoint_name, "", obj);
                      console.log ("Create " + datapoint_name);
                  }
              }
          }
          
          for (let j = 0; j <= states.length; j++) {
              if (states[j] == undefined || states[j].startsWith ("mqtt.0.zigbee2mqtt.bridge") || states[j].endsWith (".set"))
                  continue;
              if (!existsObject (states[j]))
                  continue;
          
              // Fixe Codierung ab welchem Zeichen die Namen der Zigbee-Geräte zu finden sind - wäre besser dynamisch, ist mir aber gerade zu aufwendig.
              let zigbee_name = states[j].substr (19);
              let device_name = dest_base + zigbee_name;
          
              let state = JSON.parse (getState (states[j]).val);
              let read_dps = []
          
              let datapoints = getDataPoints (zigbee_name, state);
          
              for (let dp in datapoints) {
                  debugLog ("  v[" + String (dp) + "]: " + JSON.stringify (state[dp]));
          
                  let datapoint_name = device_name + "." + dp;
                  if (!existsState (datapoint_name))
                      continue;
          
                  let obj = getObject (js_base + datapoint_name);
                  try {
                      if (obj.common.write) {
                          console.log ("Subscribe: " + js_base + datapoint_name);
                          const zigbeeObject = states[j];
                          const control_name = dp;
                          const dp_name = js_base + datapoint_name;
                          on({id: js_base + datapoint_name, change: "ne"}, async function (obj2) {
                            try {
                                if (getState (WriteZigbeeDataActivated).val) {
          
                                    let value = obj2.state.val;
                                    let oldValue = obj2.oldState.val;
          
                                    // Nur übertragen, wenn es eine relevante Änderung gab - Überprüfung über Strings, damit die Werte entsprechend gerundet werden.
                                    if (JSON.stringify (value) != JSON.stringify (oldValue)) {
                                        let obj = getObject (dp_name);
                                        let v = getState(dp_name).val;
                                        try {
                                            let trans = obj.common.trans;
                                            //console.log ("find " + JSON.stringify (v) + " in " + JSON.stringify (trans));
                                            for (let l in trans)
                                              if (trans[l][0] == v) {
                                                  v = trans[l][1];
                                                  //console.log ("  translated to " + JSON.stringify (v) + " (l=" + JSON.stringify (trans[l]) + ")");
                                                  break;
                                              }
                                        } catch (err) {
                                            //console.log ("error trans: " + err.message);
                                        }
                                        let v2 = JSON.stringify (v);
                                        //console.log ("Set zigbee state " + zigbeeObject + ".set: " + '{"' + control_name + '":' + v2 + '}' + " value: " + JSON.stringify (value) + " oldV: " + JSON.stringify (oldValue));
                                        setState(zigbeeObject + ".set", ('{"' + control_name + '":' + v2 + '}'));
                                    }
                                } else  {
                                    console.log ("Set zigbee state deactivated");
                                }
                            } catch (err) {
                                console.log ("Set zigbee state failed: " + err.message);
                            }
                          });
                      }
                      if (obj.common.read)
                          read_dps.push (dp);
                  } catch (err) {
                      console.log ("Object " + datapoint_name + " err: " + err.message);
                  }
              }
          
              if (read_dps.length > 0) {
                  console.log ("Subscribe: " + states[j]);
                  const zigbeeObject = states[j];
                  const dev_name = js_base + device_name;
                  const control_names = read_dps;
                  on({id: states[j], change: "ne"}, async function (obj) {
                    let value = obj.state.val;
                    let oldValue = obj.oldState.val;
                    for (let v in control_names) {
                        let datapoint_name = dev_name + "." + control_names[v];
                        let val = getState(zigbeeObject).val;
                        let v2 = jsonataExpression((function () { try {return JSON.parse(val);} catch(e) {return {};}})(),control_names[v]);
                        let dp_obj = getObject (datapoint_name);
                        try {
                            let trans = dp_obj.common.trans;
                            for (let l in trans)
                                if (trans[l][1] == v2) {
                                    v2 = trans[l][0];
                                    break;
                                }
                        } catch (err) {}
                        try {
                            let cond = dp_obj.common.condition_zigbee_get;
                            let vc = jsonataExpression((function () { try {return JSON.parse(val);} catch(e) {return {};}})(),cond[0]);
                            if (vc != cond[1]) {
                                debugLog ("Skip js state " + datapoint_name + ": " + JSON.stringify (v2) + " from: " + zigbeeObject + ": " + getState(zigbeeObject).val + " [" + control_names[v] + "]");
                                continue;
                            }
                        } catch (err) {}
                        let v3 = convertToDataPointType (datapoint_name, v2)
                        if (getState (datapoint_name).val != v3) {
                            debugLog ("Set js state " + datapoint_name + ": " + JSON.stringify (v2) + " from: " + zigbeeObject + ": " + getState(zigbeeObject).val + " [" + control_names[v] + "]");
                            setState(datapoint_name, v3, true);
                        }
                    }
                  });
              }
          }
          
          

          Edit: Bugfix im Script

          ZarelloZ Offline
          ZarelloZ Offline
          Zarello
          schrieb am zuletzt editiert von
          #4

          Okay, es geht auch deutlich einfacher wie hier von @hydrotec beschrieben. Einfach bei zigbee2mqtt die richtige Konfiguration einstellen.

          Da ich inzwischen den Zigbee-Adapter ans Laufen bekommen habe, habe ich nun eine andere Lösung für dieses Problem gefunden.
          Zwar ist dadurch die Migration von OpenHAB zu ioBroker nicht ganz so sanft verlaufen, da ich sämtliche Skripte von OpenHAB auf einen Schlag umstellen musste und nicht von OpenHAB und ioBroker gemeinsam auf die Zigbee-Geräte zugreifen konnte, aber dafür funktioniert jetzt auch alles problemlos.

          Dementsprechend stelle ich diesen Thread mal auf gelöst.

          1 Antwort Letzte Antwort
          0
          Antworten
          • In einem neuen Thema antworten
          Anmelden zum Antworten
          • Älteste zuerst
          • Neuste zuerst
          • Meiste Stimmen


          Support us

          ioBroker
          Community Adapters
          Donate

          613

          Online

          32.6k

          Benutzer

          82.1k

          Themen

          1.3m

          Beiträge
          Community
          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
          ioBroker Community 2014-2025
          logo
          • Anmelden

          • Du hast noch kein Konto? Registrieren

          • Anmelden oder registrieren, um zu suchen
          • Erster Beitrag
            Letzter Beitrag
          0
          • Home
          • Aktuell
          • Tags
          • Ungelesen 0
          • Kategorien
          • Unreplied
          • Beliebt
          • GitHub
          • Docu
          • Hilfe