Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. [Script] JUDO Wasserenthärtung - Connectivity-Modul API

    NEWS

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    [Script] JUDO Wasserenthärtung - Connectivity-Modul API

    This topic has been deleted. Only users with topic management privileges can see it.
    • B
      Bongo last edited by Bongo

      Vielleicht ist das Programm für den Einen oder Anderen hilfreich. Deshalb möchte ich es der Community zur Verfügung stellen.

      Ziel – Was kann das Programm?

      • Nutzung der JUDO API über das Connectivity-Modul. Keine Cloud!
      • Auslesen der Werte:
        Gerätetyp, Gerätenummer, SW-Version Gerätesteuerung, Inbetriebnahme Datum, Betriebsstundenzähler, Wunschwasserhärte, Weichwassermenge.
        Gesamtwassermenge (Wasserverbrauch) Tagesstatistik, Wochenstatistik, Monatsstatistik, Jahresstatistik.
      • Berechnen der Werte mit Unterstützung der Fa. JUDO:
        Gesamtwassermenge (Wasserverbrauch), Anzahl der Regenerierungen, Salzvorrat, Minerallösungsvorrat, gesamter Salzverbrauch, gesamter Minerallösungsverbrauch.
      • Warnung für das Nachfüllen und des Salz- und Minerallösungsvorrates. Auch für Sprachassistent, Nachricht und VIS nutzbar.
      • Pflegestatus in Textform der Pflegemaßnahmen für Sprachassistent, Nachricht und VIS.

      Datenpunkte:
      Workspace.gif

      Vorraussetzung

      • JUDO SOFTwell Enthärtungsanlage. Funktioniert vermutlich auch für andere Gerätetypen. Bei höherwertigeren Geräten können zum Beispiel der Salzvorrat und andere Werte direkt über die API gelesen werden. Bei SOFTwell fehlt der Sensor, deshalb wird es hier berechnet.
      • Das JUDO Connectivity-Modul kann man per LAN oder WLAN mit dem Heimnetzwerk zu verbinden.
        Es ermöglicht die Kommunikation über REST API.
      • Einstellung in der Javascript Instanz:
        Zusätzliche NPM-Module: moment
      • Optional: Dosierpumpe JUDO Julia 4 (so wie ich sie habe) oder ähnliche zur Wassersteinverhütung und Korrosionsminderung in Kalt- und Warmwasser-Versorgungsanlagen.
        Diese hat keine Schnittstelle. Aber der Minerallösungsverbrauch kann über die Rohwassermenge berechnet werden.

      Bedienung und Konfiguration

      • Vor dem ersten Start bitte die Voraussetzungen prüfen.
      • Im Programm im Abschnitt Settings die Variablen der Kanäle und Datenpunkte richtig setzen.
      • Programm starten. Alle Datenpunkte werden angelegt.
      • Nach dem Start können folgende Datenpunkte manuell geändert werden:
        ** regenerierungen
        Entweder 0 belassen oder den Wert aus der ju-control.app übertragen.
        ** salzvorrat
        Der Salzvorrat wird initial eingegeben. Bei SOFTwell P ist der maximale Salzvorrat 50 kg. Wenn er noch halb voll ist muss 25 kg eingeben werden.
        Wenn nachgefüllt werden muss und es sind noch 2 kg enthalten dann wird bei einem 25 kg Sack der Wert auf 27 kg erhöht.
        ** mineralvorrat
        Auch der Minerallösungsvorrat wird initial eingegeben. Bei der Dosierpumpe JUDO Julia 4 ist der maximale Wert 6 Liter. Wenn es noch halb voll sind es 3 Liter. Wenn der Behälter ersetzt wird muss hier wieder 6 Liter eingeben werden.
        ** salzverbrauchgesamt und mineralverbrauchgesamt
        Wenn man die beiden Werte für den bisherigen Verbrauch weiß, kann man sie eintragen. Ansonsten bleiben sie 0.

      Bekannte Probleme

      • Der API Zugriff für die Tagesstatistik verursachte bei mir an manchen Tagen eine Fehlermeldung.
        Ich habe das der Fa. JUDO gemeldet und das Problem wurde auch erkannt. In einer der nächsten Firmware Updates soll das behoben werden.
        Bis dahin kann man über die Konstante tagesStatistikEin = false in den Settings den API-Aufruf deaktivieren.
        Bei false wird stattdessen die Tagesstatistik berechnet.
      • Die Berechnung der Gesamtwassermenge (Wasserverbrauch) ergibt ca. 1,5% mehr als im Vergleich mit meinem Hauswasserzähler. Das finde ich aber akzeptabel.
      • Hardwareversion, Connectifity-Modul Softwareversion, Nächste Wartung, Gesamt-Regenerationsanzahl und Anzahl Wartungen werden in der ju-control.app angezeigt. Es gibt aber keinen entsprechenden API-Aufruf. Dies wurde auch der Fa. JUDO gemeldet. Eventuell gibt in einer der nächsten Firmware Updates eine Änderung.
      • Die API wird alle 5 Minuten abgerufen. Zwischen den einzelnen API-Aufrufen sind immer 10 Sekunden Pause. Das Modul scheint keine zu schnellen Zugriffe hintereinander zu vertragen.

      Script
      JUDO Wasserenthärtung.js:

      //
      // JUDO Wasserenthärtung.js
      //
      // 09.10.2024 Version 1.0
      // Initialversion
      //
      //
      //--------------------------- Settings ------------------------
      const tagesStatistikEin = false;        // Manchmal verursacht die Tagesstatistik einen Neustart des Moduls. Für diesen Tag auf false.
                                              // Bei false wird die Tagesstatistik nicht über die API geholt sondern wird berechnet.
      const user =                    "admin";
      const password =                "xxxxxxxxx"; // Standard "Connectivity"
      const url =                     "http://192.168.178.50";
      const dpUserdata =              "0_userdata.0.Judo.";
      const rohWasserhaerte =         21;     // für die Berechnung der Gesamtwassermenge
      const kapazitaet =              4950;   // für die Berechnung der Regenerierungen. Wert für das Gerät laut Fa. JUDO.
      const salzVerbrauch =           180;    // Salzverbrauch je Regenerierung in g
      const salzVorratsbehaelter =    50;     // max. Füllmenge in kg
      const mineralVorratsbehaelter = 6;      // max. Füllmenge des Minerallösungsbehälter in l
      const rohwasserVerbrauchProMineralVorratsbehaelter = 64; // Rohwasserverbrauch je Minerallösungsbehälter (6l) in m³ (aus Betriebsanleitung. DIP-Schalter norm)
      const pflegeNotwendigSalz =     5       // In %. Bei Gleichstand oder Unterschreitung des Füllzustandes des Salzbehälters ist Pflege notwendig.
      const pflegeNotwendigMineral =  5       // In %. Bei Gleichstand oder Unterschreitung des Füllzustandes des Mineralflüssigkeitbehälters ist Pflege notwendig.
      //--------------------------- Settings end --------------------
      
      //--------------------------- Datenpunkte mit API -------------
      const myConfig = {
        "row": [
          {
            "dp": "rohwasserhaerte",                  // Aus Setting
            "name": "Lokale Wasserhärte",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "°dH",
          },
          {
            "dp": "zaehlerWeichwasserRegenerierung",  // Hilfsdatenpunkt nötig für Berechnungen
            "name": "Zähler des Weichwassers bis zur nächsten Regenerierung",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "m³"
          },
          {
            "dp": "zaehlerZeitspanne",                // Hilfsdatenpunkt für Berechnungen Tagesstatistik
            "name": "Aktuelle Zeitspanne",
            "read": true, "write": false,
            "type": "string", "role": "value",
            "value": "", "unit": ""
          },
          {
            "dp": "zaehlerZeitspanneWasser",          // Hilfsdatenpunkt für Berechnungen Tagesstatistik
            "name": "Wasserverbrauch in der aktuellen Zeitspanne",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "m³"
          },
          {
            "dp": "regenerierungen",                  // wenn bekannt wird es initial manuell im Datenpunkt gesetzt und dann berechnet
            "name": "Anzahl der Regenerierungen",
            "read": true, "write": true,
            "type": "number", "role": "value",
            "value": "0", "unit": ""
          },
          {
            "dp": "salzvorrat",                       // wird initial und nach dem Auffüllen manuell im Datenpunkt gesetzt und dann berechnet
            "name": "Verfügbares Salz im Behälter",
            "read": true, "write": true,
            "type": "number", "role": "value",
            "value": "0", "unit": "kg"
          },
          {
            "dp": "salzfuellstand",                  // wird berechnet
            "name": "Füllstand des Salzvorratsbehälters",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "%"
          },
          {
            "dp": "salzverbrauchgesamt",              // wenn bekannt wird initial manuell im Datenpunkt gesetzt und dann berechnet
            "name": "Gesamter Salzverbrauch",
            "read": true, "write": true,
            "type": "number", "role": "value",
            "value": "0", "unit": "kg"
          },
          {
            "dp": "mineralvorrat",                       // wird initial und nach dem Auffüllen manuell im Datenpunkt gesetzt und dann berechnet
            "name": "Verfügbare Minerallösung im Behälter",
            "read": true, "write": true,
            "type": "number", "role": "value",
            "value": "0", "unit": "l"
          },
          {
            "dp": "mineralfuellstand",                  // wird berechnet
            "name": "Füllstand des Minerallösungsbehälters",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "%"
          },
          {
            "dp": "mineralverbrauchgesamt",              // wenn bekannt wird initial manuell im Datenpunkt gesetzt und dann berechnet
            "name": "Gesamter Verbrauch der Minerallösung",
            "read": true, "write": true,
            "type": "number", "role": "value",
            "value": "0", "unit": "l"
          },
          {
            "dp": "pflege",                               // Datenpunkt ob Pflege für Salzvorrat oder Mineralvorrat notwendig
            "name": "Pflege Salzvorrat oder Mineralvorrat notwendig?",
            "read": true, "write": false,
            "type": "boolean", "role": "switch",
            "value": false, "unit": ""
          },
          {
            "dp": "pflege-salz",                          // Datenpunkt ob Pflege für Salz notwendig
            "name": "Pflege des Salzvorrates notwendig?",
            "read": true, "write": false,
            "type": "boolean", "role": "switch",
            "value": false, "unit": ""
          },
          {
            "dp": "pflege-mineral",                       // Datenpunkt ob Pflege für Minerallösung notwendig
            "name": "Pflege des Mineralvorrates notwendig?",
            "read": true, "write": false,
            "type": "boolean", "role": "switch",
            "value": false, "unit": ""
          },
          {
            "dp": "pflege-speak",                         // Datenpunkt für Pflegeanfrage
            "name": "Status der Wasserenthärtungsanlage",
            "read": true, "write": true,
            "type": "string", "role": "value",
            "value": "", "unit": ""
          },
          {
            "dp": "geraetetyp",
            "name": "Gerätetyp",
            "read": true, "write": false,
            "type": "string", "role": "value",
            "value": "", "unit": "",
            "api": "/api/rest/FF00",
            "geraetetyp": {"51": "i-soft SAVE+","66": "i-soft K SAVE+","50": "i-soft","67": "i-soft K",
            "52": "SOFTwell P","53": "SOFTwell S","54": "SOFTwell K","71": "SOFTwell KP","72": "SOFTwell KS",
            "68x": "ZEWA i-SAVE","68y": "ZEWA i-SAFE FILT","68z": "PROM-i-SAFE"}
          },
          {
            "dp": "geraetenummer",
            "name": "Gerätenummer",
            "read": true, "write": false,
            "type": "string", "role": "value",
            "value": "", "unit": "",
            "api": "/api/rest/0600"
          },
          {
            "dp": "software-version",
            "name": "SW-Version Gerätesteuerung",
            "read": true, "write": false,
            "type": "string", "role": "value",
            "value": "", "unit": "",
            "api": "/api/rest/0100"
          },
          {
            "dp": "inbetriebnahmedatum",
            "name": "Inbetriebnahmedatum",
            "read": true, "write": false,
            "type": "string", "role": "value",
            "value": "", "unit": "",
            "api": "/api/rest/0E00"
          },
          {
            "dp": "betriebsstundenzaehler",
            "name": "Betriebsstundenzähler",
            "read": true, "write": false,
            "type": "string", "role": "value",
            "value": "", "unit": "",
            "api": "/api/rest/2500"
          },
          {
            "dp": "gesamtwassermenge",
            "name": "Gesamtwassermenge",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "m³"
      //      "api": "/api/rest/2800"         // Wird von Softwell nicht unterstützt. Stattdessen über Weichwassermenge mit Formel berechnet.
          },
          {
            "dp": "weichwassermenge",
            "name": "Weichwassermenge",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "m³",
            "api": "/api/rest/2900"
          },
          {
            "dp": "wunschwasserhaerte",
            "name": "Wunschwasserhärte",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "°dH",
            "api": "/api/rest/5100"
          },
          {
            "dp": "WasserTag.00-03",
            "name": "Täglicher Wasserverbrauch 00:00 Uhr bis 03:00 Uhr",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter",
            "api": "/api/rest/FB00"
          },
          {
            "dp": "WasserTag.03-06",
            "name": "Täglicher Wasserverbrauch 03:00 Uhr bis 06:00 Uhr",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserTag.06-09",
            "name": "Täglicher Wasserverbrauch 06:00 Uhr bis 09:00 Uhr",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserTag.09-12",
            "name": "Täglicher Wasserverbrauch 09:00 Uhr bis 12:00 Uhr",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserTag.12-15",
            "name": "Täglicher Wasserverbrauch 12:00 Uhr bis 15:00 Uhr",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserTag.15-18",
            "name": "Täglicher Wasserverbrauch 15:00 Uhr bis 18:00 Uhr",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserTag.18-21",
            "name": "Täglicher Wasserverbrauch 18:00 Uhr bis 21:00 Uhr",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserTag.21-00",
            "name": "Täglicher Wasserverbrauch 21:00 Uhr bis 00:00 Uhr",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserWoche.01-montag",
            "name": "Wasserverbrauch der aktuellen Woche am Montag",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter",
            "api": "/api/rest/FC00"
          },
          {
            "dp": "WasserWoche.02-dienstag",
            "name": "Wasserverbrauch der aktuellen Woche am Dienstag",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserWoche.03-mittwoch",
            "name": "Wasserverbrauch der aktuellen Woche am Mittwoch",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserWoche.04-donnerstag",
            "name": "Wasserverbrauch der aktuellen Woche am Donnerstag",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserWoche.05-freitag",
            "name": "Wasserverbrauch der aktuellen Woche am Freitag",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserWoche.06-samstag",
            "name": "Wasserverbrauch der aktuellen Woche am Samstag",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserWoche.07-sonntag",
            "name": "Wasserverbrauch der aktuellen Woche am Sonntag",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.01",
            "name": "Wasserverbrauch im aktuellen Monat Tag 1",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter",
            "api": "/api/rest/FD00"
          },
          {
            "dp": "WasserMonat.02",
            "name": "Wasserverbrauch im aktuellen Monat Tag 2",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.03",
            "name": "Wasserverbrauch im aktuellen Monat Tag 3",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.04",
            "name": "Wasserverbrauch im aktuellen Monat Tag 4",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.05",
            "name": "Wasserverbrauch im aktuellen Monat Tag 5",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.06",
            "name": "Wasserverbrauch im aktuellen Monat Tag 6",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.07",
            "name": "Wasserverbrauch im aktuellen Monat Tag 7",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.08",
            "name": "Wasserverbrauch im aktuellen Monat Tag 8",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.09",
            "name": "Wasserverbrauch im aktuellen Monat Tag 9",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.10",
            "name": "Wasserverbrauch im aktuellen Monat Tag 10",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.11",
            "name": "Wasserverbrauch im aktuellen Monat Tag 11",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.12",
            "name": "Wasserverbrauch im aktuellen Monat Tag 12",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.13",
            "name": "Wasserverbrauch im aktuellen Monat Tag 13",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.14",
            "name": "Wasserverbrauch im aktuellen Monat Tag 14",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.15",
            "name": "Wasserverbrauch im aktuellen Monat Tag 15",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.16",
            "name": "Wasserverbrauch im aktuellen Monat Tag 16",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.17",
            "name": "Wasserverbrauch im aktuellen Monat Tag 17",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.18",
            "name": "Wasserverbrauch im aktuellen Monat Tag 18",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.19",
            "name": "Wasserverbrauch im aktuellen Monat Tag 19",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.20",
            "name": "Wasserverbrauch im aktuellen Monat Tag 20",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.21",
            "name": "Wasserverbrauch im aktuellen Monat Tag 21",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.22",
            "name": "Wasserverbrauch im aktuellen Monat Tag 22",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.23",
            "name": "Wasserverbrauch im aktuellen Monat Tag 23",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.24",
            "name": "Wasserverbrauch im aktuellen Monat Tag 24",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.25",
            "name": "Wasserverbrauch im aktuellen Monat Tag 25",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.26",
            "name": "Wasserverbrauch im aktuellen Monat Tag 26",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.27",
            "name": "Wasserverbrauch im aktuellen Monat Tag 27",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.28",
            "name": "Wasserverbrauch im aktuellen Monat Tag 28",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.29",
            "name": "Wasserverbrauch im aktuellen Monat Tag 29",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.30",
            "name": "Wasserverbrauch im aktuellen Monat Tag 30",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserMonat.31",
            "name": "Wasserverbrauch im aktuellen Monat Tag 31",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.01-Januar",
            "name": "Wasserverbrauch des aktuellen Jahres im Jannuar",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter",
            "api": "/api/rest/FE00"
          },
          {
            "dp": "WasserJahr.02-Februar",
            "name": "Wasserverbrauch des aktuellen Jahres im Februar",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.03-März",
            "name": "Wasserverbrauch des aktuellen Jahres im März",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.04-April",
            "name": "Wasserverbrauch des aktuellen Jahres im April",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.05-Mai",
            "name": "Wasserverbrauch des aktuellen Jahres im Mai",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.06-Juni",
            "name": "Wasserverbrauch des aktuellen Jahres im Juni",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.07-Juli",
            "name": "Wasserverbrauch des aktuellen Jahres im Juli",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.08-August",
            "name": "Wasserverbrauch des aktuellen Jahres im August",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.09-September",
            "name": "Wasserverbrauch des aktuellen Jahres im September",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.10-Oktober",
            "name": "Wasserverbrauch des aktuellen Jahres im Oktober",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.11-November",
            "name": "Wasserverbrauch des aktuellen Jahres im November",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
          {
            "dp": "WasserJahr.12-Dezember",
            "name": "Wasserverbrauch des aktuellen Jahres im Dezember",
            "read": true, "write": false,
            "type": "number", "role": "value",
            "value": "0", "unit": "Liter"
          },
      ]
      }
      //--------------------------- Datenpunkte mit API end ---------
      
      const moment = require('moment'); 
      init();
      async function init() {
          await createMyConfig(myConfig, dpUserdata);
          await await sleep(2*1000);
          setState(dpUserdata+"rohwasserhaerte",rohWasserhaerte,true);
          schedule("*/5 * * * *", async function () {   // Jede 5. Minute starten
              try {
                  await getAPI(myConfig, url, dpUserdata);
              } catch (error) {
                  return;
              }
          });
          //
          // Zurücksetzen der Tagesstatistik bei Tageswechsel um 0 Uhr
          //
          schedule("0 0 * * *", async function () {   // Jden Tag um 0 Uhr
              try {
                  if (!tagesStatistikEin) {
                      resetTagesStatistik();
                  }
              } catch (error) {
                  return;
              }
          });
          //
          // Bei Änderung der Weichwassermenge wird berechnet:
          // Gesamtwassermenge, Anzahl der Regenerationen, Regenerierungs-Salzverbrauch, Füllstand des Salzvorratsbehälters
          // 
          on({ id: dpUserdata + "weichwassermenge", change: "ne" }, async (dp) => {
              var weichWassermenge = dp.state.val;
              var weichWassermengeOld = dp.oldState.val;
              var weichWasserhaerte = getState(dpUserdata+"wunschwasserhaerte").val;
              //
              // Gesamtwassermenge
              //
              var gesamtWassermenge = (weichWassermenge*rohWasserhaerte)/(rohWasserhaerte-weichWasserhaerte);
              setState(dpUserdata+"gesamtwassermenge",gesamtWassermenge,true);
              //
              // Anzahl der Regenerationen
              //
              var weichwasserBisZurRegenerierung = (kapazitaet/rohWasserhaerte)/1000;     // in m³
              var zaehlerWeichwasserRegenerierung = getState(dpUserdata+"zaehlerWeichwasserRegenerierung").val;
              if (zaehlerWeichwasserRegenerierung >= weichwasserBisZurRegenerierung){
                  // Wenn weichwasserBisZurRegenerierung 2- oder mehrfach innerhalb eines Abfragezyklus überschritten wird,
                  // müsste das hier noch berücksichtigt werden. Da es vermutlich sehr selten vorkommt, wird es vernachlässigt.
                  //
                  // Zähler für Weichwasserregenerierung zurück setzen
                  //
                  zaehlerWeichwasserRegenerierung = zaehlerWeichwasserRegenerierung-weichwasserBisZurRegenerierung;
                  setState(dpUserdata+"zaehlerWeichwasserRegenerierung",zaehlerWeichwasserRegenerierung,true);
                  //
                  // Anzahl Regenerierungen
                  //
                  var regenerierungen = getState(dpUserdata+"regenerierungen").val;
                  regenerierungen++;
                  setState(dpUserdata+"regenerierungen",regenerierungen,true);
                  //
                  // Salzmenge reduzieren - Salzvorrat
                  //
                  var salzvorrat = getState(dpUserdata+"salzvorrat").val;
                  salzvorrat = salzvorrat - (salzVerbrauch/1000);                 // in kg
                  setState(dpUserdata+"salzvorrat",salzvorrat,true);
                  //
                  // Regenerierungs-Salzverbrauch
                  //
                  var salzverbrauchgesamt = getState(dpUserdata+"salzverbrauchgesamt").val + (salzVerbrauch/1000); // in kg
                  setState(dpUserdata+"salzverbrauchgesamt",salzverbrauchgesamt,true);
              } else {
                  zaehlerWeichwasserRegenerierung = zaehlerWeichwasserRegenerierung + (weichWassermenge-weichWassermengeOld);
                  setState(dpUserdata+"zaehlerWeichwasserRegenerierung",zaehlerWeichwasserRegenerierung,true);
              }
          });
          //
          // Bei Änderung der Gesamtwassermenge wird berechnet:
          // Minerallösungsverbrauch, Tagesstatistik
          //
          on({ id: dpUserdata + "gesamtwassermenge", change: "ne" }, async (dp) => {
              var gesamtWassermenge = dp.state.val;
              var gesamtWassermengeOld = dp.oldState.val;
              //
              // Zähler für Rohwasser erhöhen
              //
              //
              // Mineralverbrauch
              //
              var rohwasser = dp.state.val - dp.oldState.val;
              var mineralVerbrauch = mineralVorratsbehaelter/(rohwasserVerbrauchProMineralVorratsbehaelter/rohwasser);
              //
              // Mineralvorrat reduzieren
              //
              setState(dpUserdata+"mineralvorrat",getState(dpUserdata+"mineralvorrat").val - mineralVerbrauch,true);
              //
              // Minerallösung Gesamt erhohen
              //
              setState(dpUserdata+"mineralverbrauchgesamt",getState(dpUserdata+"mineralverbrauchgesamt").val + mineralVerbrauch,true);
              //
              // Tagesstatistik
              //
              if (!tagesStatistikEin) {
                  // Wenn nicht über API
                  setTagesStatistik(gesamtWassermenge-gesamtWassermengeOld);
              };
          });
          //
          // Salzfüllstand berechnen wenn sich Salzvorrat geändert hat
          //
          on({ id: dpUserdata + "salzvorrat", change: "ne" }, async (dp) => {
              //
              // Füllstand des Salzvorratsbehälters
              //
              var salzvorrat = dp.state.val;
              var salzfuellstand = salzvorrat/(salzVorratsbehaelter/100);
              setState(dpUserdata+"salzfuellstand",salzfuellstand,true);
              //
              // Prüfen ob Pflege für Salzbehälter notwendig ist
              //
              if (salzfuellstand <= pflegeNotwendigSalz) {
                  setState(dpUserdata+"pflege-salz",true,true);
              } else {
                  setState(dpUserdata+"pflege-salz",false,true);
              }
          });
          //
          // Mineralfüllstand berechnen wenn sich Mineralvorrat geändert hat
          //
          on({ id: dpUserdata + "mineralvorrat", change: "ne" }, async (dp) => {
              //
              // Füllstand des Mineralvorratsbehälters
              //
              var mineralvorrat = dp.state.val;
              var mineralfuellstand = mineralvorrat/(mineralVorratsbehaelter/100);
              setState(dpUserdata+"mineralfuellstand",mineralfuellstand,true);
              //
              // Prüfen ob Pflege für Minerallösungsbehälter notwendig ist
              //
              if (mineralfuellstand <= pflegeNotwendigMineral) {
                  setState(dpUserdata+"pflege-mineral",true,true);
              } else {
                  setState(dpUserdata+"pflege-mineral",false,true);
              }
          });
          //
          // Pflege triggern
          //
      //    const maintenance = [dpUserdata + "pflege-salz", dpUserdata + "pflege-mineral"]
          const maintenance = [dpUserdata + "salzvorrat", dpUserdata + "mineralvorrat"]
          on({ id: maintenance, change: "ne" }, async (dp) => { // triggert bei Änderung der Datenpunkte
              var pflegeSpeak = "";
              var mineralfuellstandInt = Math.round(getState(dpUserdata + "mineralfuellstand").val);
              var salzfuellstandInt = Math.round(getState(dpUserdata + "salzfuellstand").val);
              var maintenance = false;
              if(getState(dpUserdata + "pflege-salz").val && getState(dpUserdata + "pflege-mineral").val){
                  // Salz und Mineral
                  pflegeSpeak = pflegeSpeak + "Wasserenthärtungsanlage Salzbehälter und Minerallösungsbehälter benötigen Pflege. Füllstand des Salzbehälters ist "+salzfuellstandInt+
                  " % und der Füllstand des Minerallösungsbehälters ist "+mineralfuellstandInt+" %.";
                  maintenance = true;
              } else if (getState(dpUserdata + "pflege-salz").val && !getState(dpUserdata + "pflege-mineral").val){
                  // Nur Salz
                  pflegeSpeak = pflegeSpeak + "Wasserenthärtungsanlage Salzbehälter benötigt Pflege. Füllstand des Salzbehälter ist "+salzfuellstandInt+
                  " % und der Füllstand des Minerallösungsbehälters ist "+mineralfuellstandInt+" %.";
                  maintenance = true;
              } else if (!getState(dpUserdata + "pflege-salz").val && getState(dpUserdata + "pflege-mineral").val){
                  // Nur Mineral
                  pflegeSpeak = pflegeSpeak + "Wasserenthärtungsanlage Minerallösungsbehälter benötigt Pflege. Füllstand des Minerallösungsbehälters ist "+mineralfuellstandInt+
                  " % und der Füllstand des Salzbehälter ist "+salzfuellstandInt+" %.";
                  maintenance = true;
              } else if (!getState(dpUserdata + "pflege-salz").val && !getState(dpUserdata + "pflege-mineral").val){
                  // Keine Pflege notwendig
                  pflegeSpeak = pflegeSpeak + "An der Wasserenthärtungsanlage ist keine Pflegemaßnahmen notwendig. Füllstand des Salzbehälters ist "+salzfuellstandInt+
                  " % und der Füllstand des Minerallösungsbehälters ist "+mineralfuellstandInt+" %.";
                  maintenance = false;
              }
              // Pflege notwendig?
              setState(dpUserdata + "pflege", maintenance,true);
              setState(dpUserdata + "pflege-speak", pflegeSpeak,true);
          });
      }
      /**
       * Objekt erzeugen
       * @param {Object} MyConfig Json-Objekt
       * @param {String} dpUserdata Workspace
       */
      async function createMyConfig(MyConfig, dpUserdata) {
          // Config scannen
          for (var i = 0; i < MyConfig.row.length; i++) {
              //console.log('Erzeuge: '+myConfig.row[i].dp);
              await createMyState(dpUserdata + myConfig.row[i].dp, myConfig.row[i].name, myConfig.row[i].name, myConfig.row[i].read, myConfig.row[i].write, myConfig.row[i].type, myConfig.row[i].role, myConfig.row[i].unit, "", myConfig.row[i].value);
          }
      }
      /**
       * Wert über API holen, umwandeln und setzen
       * @param {Object} myConfig Json-Objekt
       * @param {String} url URL der API
       * @param {String} dpUserdata Workspace
       */
      async function getAPI(myConfig, url, dpUserdata) {
          // Config scannen
          for (var i = 0; i < myConfig.row.length; i++) {
              var myapi = myConfig.row[i].api;
              // API anpassen
              switch (myapi) {
                  case "/api/rest/FB00":                          // Tagesstatistik 
                      // Datum übergeben
                      var date = new Date();
                      var day = date.getDate();
                      var month = date.getMonth();
                      var month = month + 1;
                      var year = date.getFullYear();
                      var hexday = day.toString(16).padStart(2, '0');
                      var hexmonth = month.toString(16).padStart(2, '0');
                      var hexyear = year.toString(16).padStart(4, '0');
                      var formattedDate = hexday + hexmonth + hexyear;
                      myapi = myConfig.row[i].api + formattedDate;
                      //console.log("myapi: "+myapi);
                      break;
                  case "/api/rest/FC00":                          // Wochenstatistik 
                      // Kalenderwoche und Jahr übergeben
                      var now = new moment();
                      var kw = now.isoWeek();
                      var hexkw = kw.toString(16).padStart(2, '0');
                      var date = new Date();
                      var year = date.getFullYear();
                      var hexyear = year.toString(16).padStart(4, '0');
                      var formattedDate = hexkw + hexyear;
                      myapi = myConfig.row[i].api + formattedDate;
                      //console.log("myapi: "+myapi);
                      break;
                  case "/api/rest/FD00":                          // Monatsstatistik 
                      // Monat und Jahr übergeben
                      var date = new Date();
                      var month = date.getMonth();
                      var month = month + 1;
                      var year = date.getFullYear();
                      var hexmonth = month.toString(16).padStart(2, '0');
                      var hexyear = year.toString(16).padStart(4, '0');
                      var formattedDate = hexmonth + hexyear;
                      myapi = myConfig.row[i].api + formattedDate;
                      //console.log("myapi: "+myapi);
                      break;
                  case "/api/rest/FE00":                          // Jahresstatistik 
                      // Jahr übergeben
                      var date = new Date();
                      var year = date.getFullYear();
                      var hexyear = year.toString(16).padStart(4, '0');
                      var formattedDate = hexyear;
                      myapi = myConfig.row[i].api + formattedDate;
                      //console.log("myapi: "+myapi);
                      break;
              } // endSwitch
              if (typeof myapi !== "undefined") {             // Wenn es eine api gibt
                  if (myConfig.row[i].api != "/api/rest/FB00" || tagesStatistikEin) {
                      await httpGet(url + myapi,
                          {
                              timeout: 2000,
                              basicAuth: {
                                  user: user,
                                  password: password,
                              },
                          },
                          (err, response) => {
                              if (!err) {
                                  if (response.statusCode === 200) {
                                      var apiObj = JSON.parse(`${response.data}`);
                                      //console.log("myapi: " + myapi);
                                      setMyState(dpUserdata + myConfig.row[i].dp, apiObj.data, myConfig.row[i].api, i)
                                  } else {
                                      console.log(`StatusCode: ${response.statusCode}`);
                                  }
                              } else {
                                  console.error(err);
                              }
                          }
                      ); // end await httpGet
                  }      // iif (myConfig.row[i].api == "/api/rest/FB00" && tagesStatistikEin){
                  await sleep(10 * 1000);
              }
          }
      }
      /**
       * Wenn nicht über API wird die Tagesstatistik berechnet
       * @param {number} incrementWasser Gesamtwasserverbrauch seit der letzten Berechnung.
       */
      async function setTagesStatistik(incrementWasser) {
          // Aktuelles 1/8 Zeitspanne berechnen
          let zeitspanne = "";
          let date = new Date();
          let stunde = parseInt(formatDate(date, "S"));
          if (stunde >= 0 && stunde < 3){
              zeitspanne = "00-03";
          } else if (stunde >= 3 && stunde < 6) {
              zeitspanne = "03-06";
          } else if (stunde >= 6 && stunde < 9) {
              zeitspanne = "06-09";
          } else if (stunde >= 9 && stunde < 12) {
              zeitspanne = "09-12";
          } else if (stunde >= 12 && stunde < 15) {
              zeitspanne = "12-15";
          } else if (stunde >= 15 && stunde < 18) {
              zeitspanne = "15-18";
          } else if (stunde >= 18 && stunde < 21) {
              zeitspanne = "18-21";
          } else if (stunde >= 21) {
              zeitspanne = "21-00";
          };
          // Verbrauch aktualisieren
          if (getState(dpUserdata+"zaehlerZeitspanne").val == zeitspanne){
              // Verbrauch aktualisieren innerhalb der selben Zeitspanne
              let zaehlerZeitspanneWasser = getState(dpUserdata+"zaehlerZeitspanneWasser").val+incrementWasser;
              setState(dpUserdata+"zaehlerZeitspanneWasser", zaehlerZeitspanneWasser, true);
              setState(dpUserdata+"WasserTag."+zeitspanne, Math.round((zaehlerZeitspanneWasser*1000)), true);
          } else {
              // Verbrauch aktualisieren bei neuer Zeitspanne
              setState(dpUserdata+"zaehlerZeitspanneWasser", incrementWasser, true);
              setState(dpUserdata+"WasserTag."+zeitspanne, Math.round((incrementWasser*1000)), true);
              setState(dpUserdata+"zaehlerZeitspanne", zeitspanne, true);
          };
      }
      /**
       * Zurücksetzen der Tagesstatistik bei Tageswechsel um 0 Uhr
       */
      async function resetTagesStatistik() {
          // Tageswechsel -> Zeitspannen auf 0 setzen
          setState(dpUserdata + "WasserTag." + "00-03", 0, true);
          setState(dpUserdata + "WasserTag." + "03-06", 0, true);
          setState(dpUserdata + "WasserTag." + "06-09", 0, true);
          setState(dpUserdata + "WasserTag." + "09-12", 0, true);
          setState(dpUserdata + "WasserTag." + "12-15", 0, true);
          setState(dpUserdata + "WasserTag." + "15-18", 0, true);
          setState(dpUserdata + "WasserTag." + "18-21", 0, true);
          setState(dpUserdata + "WasserTag." + "21-00", 0, true);
          setState(dpUserdata + "zaehlerZeitspanneWasser", 0, true);
      }
      /**
       * Objekt setzen
       * @param {String} state Objektpfad
       * @param {any} value Inhalt  
       * @param {String} api API Case
       * @param {number} index des Json Objekts
       */
      async function setMyState(state, value, api, index) {
          //console.log("api: "+api);
          switch (api) {
              case "/api/rest/FF00":                // Gerätetyp
                  var valDez = parseInt(value, 16);
                  value = myConfig.row[index].geraetetyp[valDez];
                  //console.log(value);
                  setState(state, value, true);
                  break;
              case "/api/rest/0600":                  // Gerätenummer
                  // Byte Reihenfolge umkehren
                  var reverseValue = value.substring(4 * 2 - 1 * 2, 4 * 2 - 0 * 2);
                  reverseValue = reverseValue + value.substring(4 * 2 - 2 * 2, 4 * 2 - 1 * 2);
                  reverseValue = reverseValue + value.substring(4 * 2 - 3 * 2, 4 * 2 - 2 * 2);
                  reverseValue = reverseValue + value.substring(4 * 2 - 4 * 2, 4 * 2 - 3 * 2);
                  var valDez = parseInt(reverseValue, 16);
                  var dummy = valDez.toString();
                  setState(state, dummy, true);
                  break;
              case "/api/rest/0100":                  // SW-Version Gerätesteuerung
                  // Byte Reihenfolge umkehren
                  var reverseValue = value.substring(3 * 2 - 1 * 2, 3 * 2 - 0 * 2);
                  var idummy = parseInt(reverseValue, 16);
                  var stringvalue = idummy.toString() + ".";
                  reverseValue = value.substring(3 * 2 - 2 * 2, 3 * 2 - 1 * 2);
                  var idummy = parseInt(reverseValue, 16)
                  var stringvalue = stringvalue + idummy.toString();
                  // nicht relevant
                  //reverseValue = reverseValue+value.substring(3*2-3*2,3*2-2*2);
                  setState(state, stringvalue, true);
                  break;
              case "/api/rest/0E00":                    // Inbetriebnahmedatum
                  var unixtimestamp = parseInt(value, 16)
                  var date = new Date(unixtimestamp * 1000);
                  setState(state, formatDate(date, "TT.MM.JJJJ"), true);
                  //console.log("Inbetriebnahmedatum: "+date.toString());
                  break;
              case "/api/rest/2500":                    // Betriebsstundenzähler
                  // Byte Reihenfolge umkehren
                  var tag2 = value.substring(4 * 2 - 1 * 2, 4 * 2 - 0 * 2);
                  var tag1 = value.substring(4 * 2 - 2 * 2, 4 * 2 - 1 * 2);
                  var std = value.substring(4 * 2 - 3 * 2, 4 * 2 - 2 * 2);
                  var min = value.substring(4 * 2 - 4 * 2, 4 * 2 - 3 * 2);
                  var Tage = 0
                  var tag2multiplikator = parseInt(tag2, 16);
                  if (tag2multiplikator > 0) {
                      Tage = parseInt(tag1, 16) + (255*tag2multiplikator);
                  } else {
                      Tage = parseInt(tag1, 16);
                  }
                  var Std = parseInt(std, 16);
                  var Min = parseInt(min, 16);
                  var betrieb = Tage.toString() + " Tage, " + Std.toString() + " Std., " + Min.toString() + " Min.";
                  setState(state, betrieb, true);
                  //console.log("value: "+value);
                  //console.log("Betriebsstundenzähler: "+betrieb);
                  break;
              // case "/api/rest/2800":                        // Gesamtwassermenge. // Wird von Softwell nicht unterstützt. Stattdessen über Weichwassermenge mit Formel berechnet.
              //   var reverseValue = value.substring(4*2-1*2,4*2-0*2);
              //   reverseValue = reverseValue+value.substring(4*2-2*2,4*2-1*2);
              //   reverseValue = reverseValue+value.substring(4*2-3*2,4*2-2*2);
              //   reverseValue = reverseValue+value.substring(4*2-4*2,4*2-3*2);
              //   //console.log(reverseValue);
              //   var idummy = parseInt(reverseValue, 16)/1000;
              //   //console.log("Gesamtwassermenge: "+dummy);
              //   setState(state, idummy, true);
              //   break;
              case "/api/rest/2900":                          // Weichwassermenge
                  var reverseValue = value.substring(4 * 2 - 1 * 2, 4 * 2 - 0 * 2);
                  reverseValue = reverseValue + value.substring(4 * 2 - 2 * 2, 4 * 2 - 1 * 2);
                  reverseValue = reverseValue + value.substring(4 * 2 - 3 * 2, 4 * 2 - 2 * 2);
                  reverseValue = reverseValue + value.substring(4 * 2 - 4 * 2, 4 * 2 - 3 * 2);
                  //console.log(reverseValue);
                  var idummy = parseInt(reverseValue, 16) / 1000;
                  //console.log("Weichwassermenge: "+dummy);
                  setState(state, idummy, true);
                  break;
              case "/api/rest/5100":                          // Wunschwasserhärte
                  var reverseValue2 = value.substring(2 * 2 - 1 * 2, 2 * 2 - 0 * 2);
                  var reverseValue1 = value.substring(2 * 2 - 2 * 2, 2 * 2 - 1 * 2);
                  var idummy = parseInt(reverseValue1, 16) + parseInt(reverseValue2, 16);
                  setState(state, idummy, true);
                  break;
              case "/api/rest/FB00":                          // Tagesstatistik
                  // Je 4 Byte sind 8 Zeichen
                  //console.log("/api/rest/FB00: " + value);
                  var idummy = parseInt(value.substring(1, 8), 16);
                  setState(state, idummy, true);
                  idummy = parseInt(value.substring(9, 16), 16);
                  setState(dpUserdata + myConfig.row[index + 1].dp, idummy, true);
                  idummy = parseInt(value.substring(17, 24), 16);
                  setState(dpUserdata + myConfig.row[index + 2].dp, idummy, true);
                  idummy = parseInt(value.substring(25, 32), 16);
                  setState(dpUserdata + myConfig.row[index + 3].dp, idummy, true);
                  idummy = parseInt(value.substring(33, 40), 16);
                  setState(dpUserdata + myConfig.row[index + 4].dp, idummy, true);
                  idummy = parseInt(value.substring(41, 48), 16);
                  setState(dpUserdata + myConfig.row[index + 5].dp, idummy, true);
                  idummy = parseInt(value.substring(49, 56), 16);
                  setState(dpUserdata + myConfig.row[index + 6].dp, idummy, true);
                  idummy = parseInt(value.substring(57, 64), 16);
                  setState(dpUserdata + myConfig.row[index + 7].dp, idummy, true);
                  break;
              case "/api/rest/FC00":                          // Wochenstatistik
                  // Je 4 Byte sind 8 Zeichen
                  //console.log("/api/rest/FC00: " + value);
                  var idummy = parseInt(value.substring(1, 8), 16);
                  setState(state, idummy, true);
                  idummy = parseInt(value.substring(9, 16), 16);
                  setState(dpUserdata + myConfig.row[index + 1].dp, idummy, true);
                  idummy = parseInt(value.substring(17, 24), 16);
                  setState(dpUserdata + myConfig.row[index + 2].dp, idummy, true);
                  idummy = parseInt(value.substring(25, 32), 16);
                  setState(dpUserdata + myConfig.row[index + 3].dp, idummy, true);
                  idummy = parseInt(value.substring(33, 40), 16);
                  setState(dpUserdata + myConfig.row[index + 4].dp, idummy, true);
                  idummy = parseInt(value.substring(41, 48), 16);
                  setState(dpUserdata + myConfig.row[index + 5].dp, idummy, true);
                  idummy = parseInt(value.substring(49, 56), 16);
                  setState(dpUserdata + myConfig.row[index + 6].dp, idummy, true);
                  break;
              case "/api/rest/FD00":                          // Monatsstatistik
                  // Je 4 Byte sind 8 Zeichen
                  //console.log("/api/rest/FD00: " + value);
                  var idummy = parseInt(value.substring(1, 8), 16);
                  setState(state, idummy, true);
                  idummy = parseInt(value.substring(9, 16), 16);
                  setState(dpUserdata + myConfig.row[index + 1].dp, idummy, true);
                  idummy = parseInt(value.substring(17, 24), 16);
                  setState(dpUserdata + myConfig.row[index + 2].dp, idummy, true);
                  idummy = parseInt(value.substring(25, 32), 16);
                  setState(dpUserdata + myConfig.row[index + 3].dp, idummy, true);
                  idummy = parseInt(value.substring(33, 40), 16);
                  setState(dpUserdata + myConfig.row[index + 4].dp, idummy, true);
                  idummy = parseInt(value.substring(41, 48), 16);
                  setState(dpUserdata + myConfig.row[index + 5].dp, idummy, true);
                  idummy = parseInt(value.substring(49, 56), 16);
                  setState(dpUserdata + myConfig.row[index + 6].dp, idummy, true);
                  idummy = parseInt(value.substring(57, 64), 16);
                  setState(dpUserdata + myConfig.row[index + 7].dp, idummy, true);
                  idummy = parseInt(value.substring(65, 72), 16);
                  setState(dpUserdata + myConfig.row[index + 8].dp, idummy, true);
                  idummy = parseInt(value.substring(73, 80), 16);
                  setState(dpUserdata + myConfig.row[index + 9].dp, idummy, true);
                  idummy = parseInt(value.substring(81, 88), 16);
                  setState(dpUserdata + myConfig.row[index + 10].dp, idummy, true);
                  idummy = parseInt(value.substring(89, 96), 16);
                  setState(dpUserdata + myConfig.row[index + 11].dp, idummy, true);
                  idummy = parseInt(value.substring(97, 104), 16);
                  setState(dpUserdata + myConfig.row[index + 12].dp, idummy, true);
                  idummy = parseInt(value.substring(105, 112), 16);
                  setState(dpUserdata + myConfig.row[index + 13].dp, idummy, true);
                  idummy = parseInt(value.substring(113, 120), 16);
                  setState(dpUserdata + myConfig.row[index + 14].dp, idummy, true);
                  idummy = parseInt(value.substring(121, 128), 16);
                  setState(dpUserdata + myConfig.row[index + 15].dp, idummy, true);
                  idummy = parseInt(value.substring(129, 136), 16);
                  setState(dpUserdata + myConfig.row[index + 16].dp, idummy, true);
                  idummy = parseInt(value.substring(137, 144), 16);
                  setState(dpUserdata + myConfig.row[index + 17].dp, idummy, true);
                  idummy = parseInt(value.substring(145, 152), 16);
                  setState(dpUserdata + myConfig.row[index + 18].dp, idummy, true);
                  idummy = parseInt(value.substring(153, 160), 16);
                  setState(dpUserdata + myConfig.row[index + 19].dp, idummy, true);
                  idummy = parseInt(value.substring(161, 168), 16);
                  setState(dpUserdata + myConfig.row[index + 20].dp, idummy, true);
                  idummy = parseInt(value.substring(169, 176), 16);
                  setState(dpUserdata + myConfig.row[index + 21].dp, idummy, true);
                  idummy = parseInt(value.substring(177, 184), 16);
                  setState(dpUserdata + myConfig.row[index + 22].dp, idummy, true);
                  idummy = parseInt(value.substring(185, 192), 16);
                  setState(dpUserdata + myConfig.row[index + 23].dp, idummy, true);
                  idummy = parseInt(value.substring(193, 200), 16);
                  setState(dpUserdata + myConfig.row[index + 24].dp, idummy, true);
                  idummy = parseInt(value.substring(201, 208), 16);
                  setState(dpUserdata + myConfig.row[index + 25].dp, idummy, true);
                  idummy = parseInt(value.substring(209, 216), 16);
                  setState(dpUserdata + myConfig.row[index + 26].dp, idummy, true);
                  idummy = parseInt(value.substring(217, 224), 16);
                  setState(dpUserdata + myConfig.row[index + 27].dp, idummy, true);
                  idummy = parseInt(value.substring(225, 232), 16);
                  setState(dpUserdata + myConfig.row[index + 28].dp, idummy, true);
                  idummy = parseInt(value.substring(233, 240), 16);
                  setState(dpUserdata + myConfig.row[index + 29].dp, idummy, true);
                  idummy = parseInt(value.substring(241, 248), 16);
                  setState(dpUserdata + myConfig.row[index + 30].dp, idummy, true);
                  break;
              case "/api/rest/FE00":                          // Wochenstatistik
                  // Je 4 Byte sind 8 Zeichen
                  //console.log("/api/rest/FE00: " + value);
                  var idummy = parseInt(value.substring(1, 8), 16);
                  setState(state, idummy, true);
                  idummy = parseInt(value.substring(9, 16), 16);
                  setState(dpUserdata + myConfig.row[index + 1].dp, idummy, true);
                  idummy = parseInt(value.substring(17, 24), 16);
                  setState(dpUserdata + myConfig.row[index + 2].dp, idummy, true);
                  idummy = parseInt(value.substring(25, 32), 16);
                  setState(dpUserdata + myConfig.row[index + 3].dp, idummy, true);
                  idummy = parseInt(value.substring(33, 40), 16);
                  setState(dpUserdata + myConfig.row[index + 4].dp, idummy, true);
                  idummy = parseInt(value.substring(41, 48), 16);
                  setState(dpUserdata + myConfig.row[index + 5].dp, idummy, true);
                  idummy = parseInt(value.substring(49, 56), 16);
                  setState(dpUserdata + myConfig.row[index + 6].dp, idummy, true);
                  idummy = parseInt(value.substring(57, 64), 16);
                  setState(dpUserdata + myConfig.row[index + 7].dp, idummy, true);
                  idummy = parseInt(value.substring(65, 72), 16);
                  setState(dpUserdata + myConfig.row[index + 8].dp, idummy, true);
                  idummy = parseInt(value.substring(73, 80), 16);
                  setState(dpUserdata + myConfig.row[index + 9].dp, idummy, true);
                  idummy = parseInt(value.substring(81, 88), 16);
                  setState(dpUserdata + myConfig.row[index + 10].dp, idummy, true);
                  idummy = parseInt(value.substring(89, 96), 16);
                  setState(dpUserdata + myConfig.row[index + 11].dp, idummy, true);
                  break;
          } // endSwitch
      }
      /**
       * Objekt erzeugen
       * @param {String} state Objektpfad
       * @param {String} name Name des Objektes
       * @param {String} desc Beschreibung des Objektes
       * @param {String} type Type des Objektes string,number
       * @param {Boolean} read Leserechte des Objektes
       * @param {Boolean} write Schreibrechte des Objektes
       * @param {String} role Rolle des Objektes button,...
       * @param {String} unit Rolle des Objektes button,...
       * @param {String} smartName Smartname für Alexa
       * @param {any} value Inhalt  
       */
      async function createMyState(state, name, desc, read, write, type, role, unit, smartName, value) {
          if (type == "number") {
              //value = Number(value);
              await createStateAsync(state, 0, {
                  name: name,
                  desc: desc,
                  read: read,
                  write: write,
                  type: type,
                  role: role,
                  unit: unit
              });
          } else {
              if (smartName == "") {
                  // ohne Smartnamen
                  await createStateAsync(state, value, {
                      name: name,
                      desc: desc,
                      read: read,
                      write: write,
                      type: type,
                      role: role,
                      unit: unit
                  });
              } else {
                  await createStateAsync(state, value, {
                      // mit Smartnamen
                      name: name,
                      desc: desc,
                      read: read,
                      write: write,
                      type: type,
                      role: role,
                      unit: unit,
                      smartName: {
                          de: smartName
                      }
                  });
              }
          }
      }
      

      Benutzung auf eigene Gefahr.
      Support kann ich nur eingeschränkt bieten.
      Über Feedback würde ich mich freuen.

      View
      Als kostenlose Zugabe eine View für die Vis 😊
      JUDO Wasserenthärtung Vis.gif
      Voraussetzung

      • Adapter Material Design Widgets
        Für mich das flexibelste und beste Material Widget.
      • Vis 1
        Leider findet sich niemand, der die Material Design Widgets in Vis 2 anpasst. Das ist sehr schade. Für mich ist das unverzichtbar, deshalb muss ich bei Vis 1 bleiben.

      Die einzelnen Views wurden gezipt. Views JUDO Wasserenthärtung.zip:
      View JUDO Wasserenthärtung.zip

      arteck 1 Reply Last reply Reply Quote 0
      • arteck
        arteck Developer Most Active @Bongo last edited by

        @bongo hast du nicht lust das in den adapter einzupflegen..

        https://github.com/arteck/ioBroker.judoisoft

        ich wollte mir die API mal rein tun aber die ist so grotten schlecht

        B 1 Reply Last reply Reply Quote 0
        • B
          Bongo @arteck last edited by

          @arteck Hm, der Adapter ist dem Namen nach für JUDO i-soft. Mein gerät ist ein JUDO SOFTwel. Da gibt es zwar Überschneidungen in der API aber vom Namen her würde es nicht passen, was für mich keine Rolle spielen würde.

          An Adapter Entwicklung habe ich mich bisher nicht ran gewagt, weil ich nicht den richtigen Einstieg gefunden habe.

          Grundsätzlich hätte ich Interesse, wenn ich einen Einstieg hätte um mich zu informieren und um den Zeitaufwand abschätzen zu können. Wo gibt es da Infos?

          arteck S 2 Replies Last reply Reply Quote 0
          • arteck
            arteck Developer Most Active @Bongo last edited by

            @bongo schaumal durch den code.. der ist recht einfach gestrikt..

            B 1 Reply Last reply Reply Quote 0
            • B
              Bongo @arteck last edited by

              @arteck Mir geht es da mehr um die Handhabung. Wie mache ich Änderungen? Ich kann ja nicht über die Admin-Oberfläche auf die Programmdateien zugreifen.

              arteck 1 Reply Last reply Reply Quote 0
              • arteck
                arteck Developer Most Active @Bongo last edited by arteck

                @bongo https://github.com/ioBroker/ioBroker.example

                hier ist noch was inoffizielles
                https://iobroker.readthedocs.io/de/latest/development/adapter.html

                1 Reply Last reply Reply Quote 0
                • S
                  SmartHomer 0 @Bongo last edited by SmartHomer 0

                  @bongo sagte in [Script] JUDO Wasserenthärtung - Connectivity-Modul API:

                  @arteck Hm, der Adapter ist dem Namen nach für JUDO i-soft. Mein gerät ist ein JUDO SOFTwel. Da gibt es zwar Überschneidungen in der API aber vom Namen her würde es nicht passen, was für mich keine Rolle spielen würde.

                  Hallo @Bongo,

                  ich habe die judo i-soft SAFE+ im Einsatz und nutze seit längerer Zeit den JUDO i-soft Adapter von @arteck. Der bietet mir eigentlich alles, was ich für SmartHome und Vis benötige.

                  Allerdings kommen damit folgende Themen auf:

                  1. Der Adapter läuft nur mit dem alten Connectivity-Modul von judo (das ohne WLAN und ohne API). JUDO hat mir freundlicherweise nach Veröffenlichung auch die neue Modul-Variante zukommen lassen (mit WLAN und API), damit spielt aber leider der Adapter von Arteck nicht mehr.
                  2. Der Adapter von Arteck läuft nur über Cloud/Portal von judo (kein lokaler Zugriff, keine Funktion mit der neuen API).
                    Leider hat aber das judo-Portal auffällig viele Ausfälle/Down-Zeiten.

                  Ich hatte Arteck mal angeschrieben, ob er nicht den Adapter auf das neue Modul und einen lokaöen Zugriff anpassen könnte (zumal judo sicher in letzter Zeit und künftig nur noch die neuen Connectivity-Module ausliefern wird).
                  Ich verstehe, dass er aber nicht mehr Zeit investieren kann/möchte (zumal er auch mir geschrieben hat, dass er keine Test-Umgebung hat und dass die API so "grottenschlecht" ist).

                  Als ich Dein Skript weiter oben gesehen habe, war ich begeistert:
                  Lokaler Zugriff auf die API des neuen connectivity-Moduls ohne das judo-Portal!

                  Ich hab's mal getestet: Tatsächlich funktionieren einige Datenpunkte für die i-soft SAFE+ schon direkt mit Deinem Script.
                  Idealerweise wollte ich dann Dein Script so anpassen, dass ich auch die anderen Werte, die die i-soft SAFE+ direkt bietet, auslesen kann (zB. Salz-Füllstand in kg und in %), "Reichweite Salz" etc., die API ist ja von JUDO veröffentlicht.
                  Musste aber schnell erkennen, dass meine Javascript-Kenntnisse dafür leider nicht ausreichen...

                  Insofern würde ich Dich gerne im Vorschlag von @arteck bekräftigen, entweder den Adapter anzupassen oder gerne auch eine angepasste Script-Version für die i-soft SAFE+ zu veröffentlichen.
                  Auslesen von Statistik-Daten etc. wären meines Erachtens nicht nötig, dass mache ich zB auch bisher schon mit SourceAnalytix etc.

                  Wenn ich das richtig verstehe, hast Du keine i-soft im Einsatz - Gerne kann ich als "Tester" der Script-Anpassungen unterstützen.

                  Schöne Grüße und schon heute "einen guten Rutsch".

                  1 Reply Last reply Reply Quote 0
                  • First post
                    Last post

                  Support us

                  ioBroker
                  Community Adapters
                  Donate

                  697
                  Online

                  31.6k
                  Users

                  79.5k
                  Topics

                  1.3m
                  Posts

                  javascript
                  3
                  7
                  388
                  Loading More Posts
                  • Oldest to Newest
                  • Newest to Oldest
                  • Most Votes
                  Reply
                  • Reply as topic
                  Log in to reply
                  Community
                  Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                  The ioBroker Community 2014-2023
                  logo