Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. chaozmc

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

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

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Profile
    • Following 0
    • Followers 1
    • Topics 2
    • Posts 5
    • Best 0
    • Groups 2

    chaozmc

    @chaozmc

    Developer

    0
    Reputation
    13
    Profile views
    5
    Posts
    1
    Followers
    0
    Following
    Joined Last Online
    Location localhost Age 38

    chaozmc Follow
    Developer Starter

    Latest posts made by chaozmc

    • RE: Test Adapter oekofen-json v0.2.x GitHub

      @wilbur ok gut zu wissen, dass das geht - also Branches installieren. Ich hab in dem Branch jedoch noch keine änderungen. Der einzige Branch der bis jetzt eine änderung und einen Commit hat ist der von dem Issue das ich dafür angelegt hab um das Thema zu tracken. Ich bin heut aber nicht dazu gekommen einen Testwebserver einzurichten um dein JSON damit zu delivern und zu schauen wie sich die Änderung des Codes verhält. Wenn ich recht habe mit meiner Idee, ist kein "Schalter" nötig sondern der gleiche Code ist für beide Varianten anwendbar. Mein Plan war den Workaround dann in dem v3-Branch den du Verlinkt hast zu mergen und den dann gegen V3.10d und weitere Versionen zu testen (sofern sich noch andere Testern hier melden) und wenn das funktioniert das in den Masterbranch einfach zu übernehmen.

      Auf die Art kann ich die das Parallel pflegen (da wir wissen, dass der Code im master bei 2 Leuten mit neueren Versionen stabil funktionieren dürfte).

      Ich hoffe ich komm morgen zwischendurch mal dazu den Code aus dem Issue-Branch gegen einen simplen webserver mit deinem JSON File zu testen. Du kannst natürlich den Code auch testen, jedoch sag ich gleich dazu, ich hab ihn noch nicht laufen lassen und weiß nicht ob er startet bzw Fehler produziert beim einlesen oder setzen der Werte.

      @wilbur sagte in Test Adapter oekofen-json v0.1.x GitHub:

      Ich habe das zurückschreiben mit heat_one über Postman getestet. Und siehe da: schreiben mit 1 und mit true wird angenommen und jeweils beides ignoriert.

      Das ist natürlich ganz doof, sie bieten den Datenpunkt an und nehmen dann kein Set mehr an. Auch eine Möglichkeit... 🤦‍♂️ 😆

      posted in Tester
      chaozmc
      chaozmc
    • RE: Test Adapter oekofen-json v0.2.x GitHub

      @wilbur sagte in Test Adapter oekofen-json v0.1.x GitHub:

      Für mich heißt es wohl, dass der Adapter (aktuell) nicht nutzbar ist. Ich musste sogar von der Version 4.x auf 3.x wieder runter gehen, weil die Heizung sich mit der 4.x mehrmals am Tag aufhängte.

      Vermutlich wirst du nicht der Einzige sein der noch eine ältere Version am Laufen hat...? Ich kann ja' probieren ob ich das in den bestehenden Code dazu packen kann in Form von extra Prüfungen und dann, beim Anlegen der Objekte bzw. beim Befüllen der Daten, jedes Mal einen cast auf number dazu packen. Dann wären zumindest die Objekte in ioBroker korrekt. Beim zurück-schreiben an den Ofen sollte der Datentyp zumindest egal sein, da es am Ende ein URL Aufruf wird und die URL in jedem Fall ein String ist. Lediglich bei true/false 0/1 frag ich mich ob die Steuerung dann wie im Format angegeben "0" oder "1" erwartet, oder doch wie im val ausgegeben "true" und "false". Auch wenn es hauptsächlich Read-Only Werte sind, zumindest der heat_once Datenpunkt bei ww1 wäre dann gesondert zu behandeln da ioBroker dann 0 oder 1 in den Objekten hätte, und das in "true" / "false" beim Aufruf übersetzt werden muss. Keinen Plan ob's dann noch irgendwelche Stolperfallen gibt die mir momentan nicht einfallen bzw. ob das zu neuen/anderen Problemen führt 🤔

      Weißt du, ob man in ioBroker gezielt einen Branch eines repo's auch installieren kann? Weil dann würde ich das in einem neuen Branch ausprobieren und bei Erfolg in den master übernehmen

      posted in Tester
      chaozmc
      chaozmc
    • RE: Test Adapter oekofen-json v0.2.x GitHub

      Hi @wilbur,

      danke für dein Input! Es sieht tatsächlich nach einem Thema in der älteren Software Version aus.

      Dass der Adapter bei dir überall Strings generiert dürfte daran liegen, dass in deinem all-JSON die Werte (auch wenn sie Zahlen sind) als Strings gesendet werden (erkennbar am " ")

      Hier zum Vergleich ein Ausschnitt aus meiner all-JSON:

      {
       "system":{
        "system_info":"system global variables",
        "L_ambient":{"val":313, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_errors":{"val":0, "factor":1, "min":-32768, "max":32767}, 
        "L_usb_stick":{"val":0, "format":"0:Aus|1:Ein"}, 
        "L_existing_boiler":{"val":0, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}
       }
      

      Im Falle der ENUM Felder sollte es eine Zahl mit states sein, hier ein Beispiel wie er die Datenpunkte bei mir anlegt wenn States definiert sind:

      {
        "type": "state",
        "common": {
          "name": "autocomfort",
          "type": "number",
          "role": "state",
          "read": true,
          "write": true,
          "states": {
            "0": "Aus",
            "1": "Ein",
            "2": "Morgens",
            "3": "Abends"
          }
        },
        "native": {},
        "from": "system.adapter.oekofen-json.0",
        "user": "system.user.admin",
        "ts": 1656180439445,
        "_id": "oekofen-json.0.hk1.autocomfort",
        "acl": {
          "object": 1636,
          "state": 1636,
          "owner": "system.user.admin",
          "ownerGroup": "system.group.administrator"
        }
      }
      

      ioBroker verlangt soweit ich es vom Datenmodell verstanden habe in diesem Fall ein Number Field und mittels states werden dann spezielle Werte (oder alle Werte) für die Anzeige aufgehübscht. Ein Replace wäre fatal, aber auch nicht notwendig wenn die Datenpunkte korrekt angelegt werden würden.

      Vermutlich müsste man für jedes Feld einen convert mit Number() durchführen und zusätzlich checken ob NaN rauskommt, damit man sicher weiß, dass es ein String ist der erzeugt werden soll. Derzeit habe ich mich darauf verlassen mit typeof zu arbeiten (siehe main.js, Zeile 189) da ich mich auf mein jsonfile gestützt habe, das hier die Datentypen korrekt sendet (Number/ String)

      Bei mir sendet er auch keine -1 Werte hab ich grade nachgesehen und die diskrepanz mit true/false 0/1 hab ich auch nicht.

      Gibt deine Steuerung wenn du die /all ohne ? aufrufst dann wenigstens konsistent auch Zahlen als String aus, oder schickt er dann dort doch wieder "echte" Zahlen ohne die anführungszeichen drumherum?

      Hier mal zum vergleich meine vollständige /all? Datei:

      {
       "system":{
        "system_info":"system global variables",
        "L_ambient":{"val":313, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_errors":{"val":0, "factor":1, "min":-32768, "max":32767}, 
        "L_usb_stick":{"val":0, "format":"0:Aus|1:Ein"}, 
        "L_existing_boiler":{"val":0, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}
       },
       "weather":{
        "weather_info":"current weather data",
        "L_temp":{"val":320, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_clouds":{"val":38, "unit":"%", "factor":1, "min":-32768, "max":32767}, 
        "L_forecast_temp":{"val":300, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_forecast_clouds":{"val":38, "unit":"%", "factor":1, "min":-32768, "max":32767}, 
        "L_forecast_today":{"val":1, "format":"0:Heute|1:Morgen"}, 
        "L_starttime":{"val":630, "factor":1, "min":-32768, "max":32767}, 
        "L_endtime":{"val":1810, "factor":1, "min":-32768, "max":32767}, 
        "L_source":{"val":"http://www.openweathermap.org", "length":20}, 
        "L_location":{"val":"Fallbach|AT|2779814", "length":20}, 
        "cloud_limit":{"val":35, "unit":"%", "factor":1, "min":0, "max":100}, 
        "hysteresys":{"val":-40, "unit":"K", "factor":0.1, "min":-200, "max":0}, 
        "offtemp":{"val":-300, "unit":"°C", "factor":0.1, "min":-300, "max":200}, 
        "lead":{"val":180, "unit":"min", "factor":1, "min":0, "max":600}, 
        "refresh":{"val":0}, 
        "oekomode":{"val":1, "format":"0:Aus|1:Ein"}
       },
       "forecast":{
        "forecast_info":"date|temp|cloud|speed|image|code|unit[|sunrise|sunset] code see https://openweathermap.org/weather-conditions",
        "L_w_0":{"val":"Mo, 27 Jun 15:52|32|38|21 km/h|03d|802|C|04:53|21:00", "length":20}, 
        "L_w_1":{"val":"Mo, 27 Jun 17:00|32|38|21 km/h|03d|802|C", "length":20}, 
        "L_w_2":{"val":"Mo, 27 Jun 20:00|28|38|11 km/h|03d|802|C", "length":20}, 
        "L_w_3":{"val":"Mo, 27 Jun 23:00|22|15|10 km/h|10n|500|C", "length":20}, 
        "L_w_4":{"val":"Di, 28 Jun 02:00|19|58|19 km/h|10n|500|C", "length":20}, 
        "L_w_5":{"val":"Di, 28 Jun 05:00|19|100|11 km/h|10d|500|C", "length":20}, 
        "L_w_6":{"val":"Di, 28 Jun 08:00|21|100|16 km/h|04d|804|C", "length":20}, 
        "L_w_7":{"val":"Di, 28 Jun 11:00|26|85|12 km/h|04d|804|C", "length":20}, 
        "L_w_8":{"val":"Di, 28 Jun 14:00|26|93|8 km/h|04d|804|C", "length":20}, 
        "L_w_9":{"val":"Di, 28 Jun 17:00|29|73|8 km/h|04d|803|C", "length":20}, 
        "L_w_10":{"val":"Di, 28 Jun 20:00|26|73|12 km/h|04d|803|C", "length":20}, 
        "L_w_11":{"val":"Di, 28 Jun 23:00|20|100|11 km/h|10n|500|C", "length":20}, 
        "L_w_12":{"val":"Mi, 29 Jun 02:00|19|97|7 km/h|10n|500|C", "length":20}, 
        "L_w_13":{"val":"Mi, 29 Jun 05:00|19|99|10 km/h|10d|500|C", "length":20}, 
        "L_w_14":{"val":"Mi, 29 Jun 08:00|22|99|13 km/h|10d|500|C", "length":20}, 
        "L_w_15":{"val":"Mi, 29 Jun 11:00|29|58|20 km/h|04d|803|C", "length":20}, 
        "L_w_16":{"val":"Mi, 29 Jun 14:00|34|51|23 km/h|04d|803|C", "length":20}, 
        "L_w_17":{"val":"Mi, 29 Jun 17:00|34|19|23 km/h|02d|801|C", "length":20}, 
        "L_w_18":{"val":"Mi, 29 Jun 20:00|30|12|16 km/h|02d|801|C", "length":20}, 
        "L_w_19":{"val":"Mi, 29 Jun 23:00|22|8|6 km/h|10n|500|C", "length":20}, 
        "L_w_20":{"val":"Do, 30 Jun 02:00|20|17|9 km/h|10n|500|C", "length":20}, 
        "L_w_21":{"val":"Do, 30 Jun 05:00|18|4|10 km/h|10d|500|C", "length":20}, 
        "L_w_22":{"val":"Do, 30 Jun 08:00|21|7|10 km/h|10d|500|C", "length":20}, 
        "L_w_23":{"val":"Do, 30 Jun 11:00|28|36|7 km/h|03d|802|C", "length":20}, 
        "L_w_24":{"val":"Do, 30 Jun 14:00|31|57|14 km/h|04d|803|C", "length":20}
       },
       "hk1":{
        "hk_info":"heating circuit data",
        "L_roomtemp_act":{"val":260, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_roomtemp_set":{"val":80, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_flowtemp_act":{"val":260, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_flowtemp_set":{"val":80, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_comfort":{"val":0, "unit":"K", "factor":0.1, "min":-32768, "max":32767}, 
        "L_state":{"val":1056, "factor":1}, 
        "L_statetext":"Heizbetrieb aktiv|Außentemp über Heizgrenze",
        "L_pump":{"val":0, "format":"0:Aus|1:Ein"}, 
        "remote_override":{"val":0, "unit":"K", "factor":0.1, "min":-32768, "max":32767}, 
        "mode_auto":{"val":1, "format":"0:Aus|1:Auto|2:Heizen|3:Absenken"}, 
        "time_prg":{"val":0, "format":"0:Zeit 1|1:Zeit 2"}, 
        "temp_setback":{"val":200, "unit":"°C", "factor":0.1, "min":100, "max":400}, 
        "temp_heat":{"val":200, "unit":"°C", "factor":0.1, "min":100, "max":400}, 
        "temp_vacation":{"val":150, "unit":"°C", "factor":0.1, "min":100, "max":400}, 
        "name":{"val":"", "length":20}, 
        "oekomode":{"val":0, "format":"0:Aus|1:Komfort|2:Minimum|3:Ökologisch"}, 
        "autocomfort":{"val":0, "format":"0:Aus|1:Ein|2:Morgens|3:Abends"}, 
        "autocomfort_sunset":{"val":0, "unit":"min", "factor":1, "min":-120, "max":120}, 
        "autocomfort_sunrise":{"val":0, "unit":"min", "factor":1, "min":-120, "max":120}
       },
       "ww1":{
        "ww_info":"domestic hot water data",
        "L_temp_set":{"val":500, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_ontemp_act":{"val":690, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_offtemp_act":{"val":690, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_pump":{"val":0, "format":"0:Aus|1:Ein"}, 
        "L_state":{"val":8208, "factor":1}, 
        "L_statetext":"Zeit innerhalb Zeitprogramm|Anforderung Aus",
        "time_prg":{"val":0, "format":"0:Zeit 1|1:Zeit 2"}, 
        "sensor_on":{"val":0, "format":"0:WW|1:TPO|2:TPM|3:SpUnten"}, 
        "sensor_off":{"val":0, "format":"0:WW|1:TPO|2:TPM|3:SpUnten"}, 
        "mode_auto":{"val":1, "format":"0:Aus|1:Auto|2:Ein"}, 
        "mode_dhw":{"val":1, "format":"0:Aus|1:Auto|2:Ein"}, 
        "heat_once":{"val":0, "format":"0:Aus|1:Ein"}, 
        "temp_min_set":{"val":80, "unit":"°C", "factor":0.1, "min":80, "max":800}, 
        "temp_max_set":{"val":600, "unit":"°C", "factor":0.1, "min":80, "max":800}, 
        "name":{"val":"", "length":20}, 
        "smartstart":{"val":90, "unit":"min", "factor":1, "min":0, "max":90}, 
        "use_boiler_heat":{"val":1, "format":"0:Aus|1:Ein"}, 
        "oekomode":{"val":3, "format":"0:Aus|1:Komfort|2:Minimum|3:Ökologisch"}
       },
       "pe1":{
        "pe_info":"pellematic data",
        "L_temp_act":{"val":229, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_temp_set":{"val":80, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_ext_temp":{"val":-32768, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_frt_temp_act":{"val":259, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_frt_temp_set":{"val":80, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_frt_temp_end":{"val":80, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_br":{"val":0, "format":"0:Aus|1:Ein"}, 
        "L_ak":{"val":0, "format":"0:Aus|1:Ein"}, 
        "L_not":{"val":1, "format":"0:Aus|1:Ein"}, 
        "L_stb":{"val":1, "format":"0:Aus|1:Ein"}, 
        "L_modulation":{"val":0, "unit":"%", "factor":1, "min":-32768, "max":32767}, 
        "L_runtimeburner":{"val":0, "unit":"zs", "factor":0.01}, 
        "L_resttimeburner":{"val":0, "unit":"zs", "factor":0.01}, 
        "L_currentairflow":{"val":0, "unit":"%", "factor":1, "min":-32768, "max":32767}, 
        "L_lowpressure":{"val":32766, "unit":"EH", "factor":0.1, "min":-32768, "max":32767}, 
        "L_lowpressure_set":{"val":800, "unit":"EH", "factor":0.1, "min":-32768, "max":32767}, 
        "L_fluegas":{"val":0, "unit":"%", "factor":1, "min":-32768, "max":32767}, 
        "L_uw_speed":{"val":10, "unit":"%", "factor":1, "min":-32768, "max":32767}, 
        "L_state":{"val":99, "format":"0:Dauerlauf|1:Start|2:Zuendung|3:Softstart|4:Leistungsbrand|5:Nachlauf|6:Aus|7:Saugen|8:! Asche !|9:! Pellets !|10:Pell Switch|11:Störung|12:Einmessen|13:1|14:1|15:1|16:1|17:1|18:1|19:1|20:1|21:1|22:1|23:1|24:1|25:1|26:1|27:1|28:1|29:1|30:1|31:1|32:1|33:1|34:1|35:1|36:1|37:1|38:1|39:1|40:1|41:1|42:1|43:1|44:1|45:1|46:1|47:1|48:1|49:1|50:1|51:1|52:1|53:1|54:1|55:1|56:1|57:1|58:1|59:1|60:1|61:1|62:1|63:1|64:1|65:1|66:1|67:1|68:1|69:1|70:1|71:1|72:1|73:1|74:1|75:1|76:1|77:1|78:1|79:1|80:1|81:1|82:1|83:1|84:1|85:1|86:1|87:1|88:1|89:1|90:1|91:1|92:1|93:1|94:1|95:1|96:1|97:Aus|98:Aus|99:Aus|100:Aus|101:Aus"}, 
        "L_statetext":"Aus",
        "L_type":{"val":1, "format":"0:PE|1:PES|2:PEK|3:PESK|4:SMART V1|5:SMART V2|6:CONDENS|7:SMART XS|8:SMART V3|9:COMPACT|10:AIR"}, 
        "L_starts":{"val":1151, "factor":1}, 
        "L_runtime":{"val":1768, "unit":"h", "factor":1}, 
        "L_avg_runtime":{"val":92, "unit":"min", "factor":1}, 
        "L_uw_release":{"val":600, "unit":"°C", "factor":0.1, "min":-32768, "max":32767}, 
        "L_uw":{"val":10, "unit":"%", "factor":1, "min":-32768, "max":32767}, 
        "L_storage_fill":{"val":0, "unit":"kg", "factor":1}, 
        "L_storage_min":{"val":400, "unit":"kg", "factor":1, "min":0, "max":4000}, 
        "L_storage_max":{"val":6000, "unit":"kg", "factor":1, "min":150, "max":30000}, 
        "L_storage_popper":{"val":0, "unit":"kg", "factor":1, "min":-32768, "max":32767}, 
        "storage_fill_today":{"val":0, "unit":"kg", "factor":1, "min":-32768, "max":32767}, 
        "storage_fill_yesterday":{"val":0, "unit":"kg", "factor":1, "min":-32768, "max":32767}, 
        "mode":{"val":1, "format":"0:Aus|1:Auto|2:Ein"}
       },
         "error":{
         }
      }
      

      Scheint so, als hätten die Entwickler der ÖkoFEN-Software erst mit der Zeit ein "echtes" JSON interface kreiert 😄

      posted in Tester
      chaozmc
      chaozmc
    • Test Adapter oekofen-json v0.2.x GitHub
      Aktuelle Test Version 0.1.0-beta.0 v0.2.0-beta.0
      Veröffentlichungsdatum 26.06.2022
      Github Link https://github.com/chaozmc/ioBroker.oekofen-json

      ACHTUNG
      Mit der Version v0.2.0-beta.0 wurde die mindestens benötigte Version des Admin-Adapters auf 5.2.0 gesetzt. Der Adapter verwendet jetzt die neue Variante der Admin-Config (jsonConfig.json)

      Adapter Beschreibung
      Der Adapter verbindet einen ÖkoFEN Pelletkessel (und dessen AddOns) mit ioBroker. Da die Steuerung ein generisches Interface mit Beschreibung zur Verfügung stellt, versucht der Adapter die Datenpunkte aufgrund der Werte, die von der Steuerung zur Verfügung gestellt werden (min, max, Einheit, Faktor), entsprechend anzulegen. Aufgrund eines Hinweises auf GitHub dürfte der Hersteller irgendwann das Encoding verändert haben, daher ist es auch möglich im Adapter-Admin zwischen latin1 und utf8 zu wählen.

      Leider gibt ÖkoFEN keinen Antwort-Header mit um das Encoding dynamisch festzustellen.

      Allem Anschein nach verwenden die neuen Software-Versionen latin1 weshalb das auch der Standard ist.

      Sollte beim Erstellen der Datenpunkte z.B. die Einheit der Temperatur-Datenpunkte mit ?-Zeichen statt ° gesetzt werden, reicht ein Stoppen des Adapters, löschen aller vom Adapter angelegten Datenpunkte, ändern des Encodings im Admin und Starten des Adapters. Der Adapter legt bei jedem Starten eventuell nicht vorhandene Datenpunkte anhand der Informationen vom Pelletkessel an.

      Touch V3.x Versionen
      Da die Steuerung in früheren Versionen in der JSON-Response alles als String gesendet hat, existiert ein Branch welcher das Problem versucht zu umgehen indem er die Werte explizit nochmal testet damit in ioBroker die Objekte richtig angelegt werden können. Das sollte keine Probleme mit neueren Versionen mit sich bringen welche im JSON den richtigen Datentyp eines Wertes verwenden. Ich teste selbst die Branch-Version mit meiner v4 Steuerung ohne Probleme. Wer interesse hat hier mit zu testen bitte diese Version statt der main installieren.

      Feedback
      Fehler & Feedback gerne hier im Forum und/oder auf GitHub in Form von Issues

      Changelog

      • 0.2.0-beta.0 (2022-07-03)
        • (chaozmc) update to admin v5 config and require min version of admin (>= 5.2.0)
      • 0.1.0-beta.0 (2022-06-26)
        • (chaozmc) selectable response encoding (utf8 & latin1) & bit of debug-logging added
      • 0.0.3
        • (chaozmc) code cleanup, trigger for update & rescan
      • 0.0.2
        • (chaozmc) first working release, fixed 0-value updates
      • 0.0.1
        • (chaozmc) initial build phase, much try and error
      posted in Tester
      chaozmc
      chaozmc
    • NodeRED ÖkoFEN Pelletronic Touch JSON

      Hallo zusammen,

      ich habe seit ein paar Wochen meinen Pelletkessel, aufgrund eines defektes der alten Steuerung, auf die neue Pelletronic Touch umbauen lassen und natürlich im Vorfeld recherchiert was meine Möglichkeiten der Anbindung an die Heimautomatisierung sind. Ich habe gelesen, dass es einerseits die Möglichkeit gibt das ganze über ModBUS TCP anzusprechen und in neueren Firmware-Versionen auch via JSON Interface. Laut Auskunft vom Techniker der den Umbau durchgeführt hat, führt die Verwendung von ModBUS jedoch zu einem schnelleren Verschleiß der Speichermodule des Bedienfeldes. Kann ich zwar nicht ganz nachvollziehen, jedoch kenne ich die genaue Programmierung der Firmware natürlich auch nicht.

      Ich dachte daher, ich sehe mir das JSON Interface genauer an und die Möglichkeiten die ich damit habe. Ursprünglich wollte ich dann einen "echten" Adapter bauen, damit komm ich aber nicht zurecht - sind zuviele neue technologien (NodeJS, devcontainer, ...) auf einmal.

      Stattdessen habe ich in NodeRED einen Flow zusammengebaut der im Großen und Ganzen das gleiche wie ein Adapter macht.

      Wichtig ist, dass man dem NodeRED Adapter in ioBroker das Recht "Erstellung von Fremd-Objekten zulassen" erteilt. Ansonsten müsste man die Nodes entsprechend anpassen und pelletronic.0 durch einen anderen Objektpfad ersetzen.

      Pelletronic-Flow.png

      Im Node "Set Pelletronic details" gibt man die IP, den Port und das sogenannte Passwort ein, das man direkt auf dem Touchdisplay des Kessels festlegen/ablesen kann wenn man JSON aktiviert. Ich habe bei mir übrigens die Option "Ein" gewählt (man kann zwischen Aus, Ein (kompatibel), Ein wählen). Dieser Node schreibt die Werte dann in den global Store.

      Der Node "Start Interface" baut dann die URL aus den Variablen zusammen und startet die Abfrage an die Steuerung und wird alle 30 Sekunden ausgeführt. Da der Webserver leider kein Encoding im Header zurückgibt führt das zu Problemen mit den °-Sonderzeichen, daher habe ich die Antwort nicht direkt als JSON weiterverarbeiten können und muss den Umweg über Binär und als latin1 encoden gehen.

      Der Flow ist so aufgebaut, dass die Objekte im ioBroker automatisch angelegt werden und auch die Werte für min/max/unit automatisch gesetzt werden. Zusätzlich speichert der Flow die JSON Antwort auch im Globalstore da manche Werte in der Pelletronic zusätzlich einen Umrechnungsfaktor benötigen (meistens 0.1 bei Temperaturwerten). Das wird in der JSON-Antwort aber mitgeliefert. Der Flow rechnet die Werte vom JSON entsprechend des Faktors um bevor er sie in ioBroker schreibt, bzw auch umgekehrt wenn die Werte in ioBroker geändert werden, bevor sie an die Pelletronic gesendet werden. Datenfelder welche ReadOnly sind, werden ebenfalls so in ioBroker angelegt (erkennbar am L_ Präfix). Der Flow berücksichtigt auch die min/max-Werte bevor sie an die Steuerung gesendet werden und bricht ab - die States in ioBroker bleiben dann auf unbestätigt. Wenn das Interface einen Fehler bei einer aktualisierung eines Wertes zurückgibt, bleibt der state ebenfalls unbestätigt.

      Ich kann natürlich nur die Funktionen die mein Ofen hat testen, sprich ich habe keine Solaranlage, keinen Pufferspeicher und nur einen Heizkreis. Da das JSON jedoch einem Schema folgt sollte es mit jeder Variante funktionieren denke ich.

      Vielleicht kann's jemand hier noch gebrauchen.

      [
          {
              "id": "227a035e.39564c",
              "type": "tab",
              "label": "OekoFEN JSON Interface",
              "disabled": false,
              "info": ""
          },
          {
              "id": "1d31f46f.b15f5c",
              "type": "http request",
              "z": "227a035e.39564c",
              "name": "request pelletronic data",
              "method": "use",
              "ret": "bin",
              "paytoqs": "query",
              "url": "",
              "tls": "",
              "persist": false,
              "proxy": "",
              "authType": "",
              "x": 330,
              "y": 160,
              "wires": [
                  [
                      "4c31bdd2.c3edf4"
                  ]
              ]
          },
          {
              "id": "56f4d2d4.277fac",
              "type": "inject",
              "z": "227a035e.39564c",
              "name": "Start interface",
              "props": [
                  {
                      "p": "url",
                      "v": "\"http://\" & $globalContext(\"settings.interface.ip\") & \":\" & $globalContext(\"settings.interface.port\") & \"/\" & $globalContext(\"settings.interface.password\") & \"/all?\"",
                      "vt": "jsonata"
                  },
                  {
                      "p": "method",
                      "v": "get",
                      "vt": "str"
                  }
              ],
              "repeat": "30",
              "crontab": "",
              "once": true,
              "onceDelay": "10",
              "topic": "",
              "x": 120,
              "y": 160,
              "wires": [
                  [
                      "1d31f46f.b15f5c"
                  ]
              ]
          },
          {
              "id": "1f1faf59.a89af1",
              "type": "split",
              "z": "227a035e.39564c",
              "name": "Split answer into subsystems (hk1, ww1, pe1, ...)",
              "splt": "\\n",
              "spltType": "str",
              "arraySplt": 1,
              "arraySpltType": "len",
              "stream": false,
              "addname": "",
              "x": 220,
              "y": 240,
              "wires": [
                  [
                      "266726d5.1fcb0a"
                  ]
              ]
          },
          {
              "id": "748f86c5.818278",
              "type": "json",
              "z": "227a035e.39564c",
              "name": "",
              "property": "payload",
              "action": "obj",
              "pretty": false,
              "x": 390,
              "y": 200,
              "wires": [
                  [
                      "1f1faf59.a89af1"
                  ]
              ]
          },
          {
              "id": "e15a1071.b68dd",
              "type": "split",
              "z": "227a035e.39564c",
              "name": "split values of subsystems (pe1, hk1, ...) into multiple messages",
              "splt": "\\n",
              "spltType": "str",
              "arraySplt": 1,
              "arraySpltType": "len",
              "stream": false,
              "addname": "",
              "x": 270,
              "y": 320,
              "wires": [
                  [
                      "1bff57ba.6805b8"
                  ]
              ]
          },
          {
              "id": "266726d5.1fcb0a",
              "type": "function",
              "z": "227a035e.39564c",
              "name": "delete unnecessary parts and set first part of topic",
              "func": "msg.topic = \"pelletronic.0.\" + msg.parts.key;\ndelete msg.parts;\ndelete msg.filename;\ndelete msg.method;\ndelete msg.statusCode;\ndelete msg.responseUrl;\ndelete msg.url;\ndelete msg.redirectList;\ndelete msg.headers;\nreturn msg;",
              "outputs": 1,
              "noerr": 0,
              "initialize": "",
              "finalize": "",
              "libs": [],
              "x": 230,
              "y": 280,
              "wires": [
                  [
                      "e15a1071.b68dd"
                  ]
              ]
          },
          {
              "id": "1bff57ba.6805b8",
              "type": "function",
              "z": "227a035e.39564c",
              "name": "set correct topic for the value and prepare for ioBroker",
              "func": "msg.topic = msg.topic + \".\" + msg.parts.key;\nif (msg.parts.key.startsWith(\"L_\")) {\n    \n    msg.stateReadonly = true;\n    \n} else {\n    \n    msg.stateReadonly = false;\n}\n\nmsg.stateName = msg.parts.key;\nvar originalPayload = RED.util.cloneMessage(msg.payload);\n\nif (typeof(msg.payload) === \"string\") {\n    msg.stateType = \"string\";\n    msg.payload = originalPayload;\n} else if (typeof(msg.payload.val) === \"string\") {\n    msg.stateType = \"string\";\n    msg.payload = originalPayload.val;\n} else {\n    if (originalPayload.unit !== undefined) {msg.stateUnit = originalPayload.unit;}\n    \n    if (originalPayload.min !== undefined) {\n        if (originalPayload.factor === undefined) {\n            msg.stateMin = originalPayload.min;\n        } else {\n            msg.stateMin = originalPayload.min * originalPayload.factor;\n        }\n    }\n    \n    if (originalPayload.max !== undefined) {\n        if (originalPayload.factor === undefined) {\n            msg.stateMax = originalPayload.max;\n        } else {\n            msg.stateMax = originalPayload.max * originalPayload.factor;\n        }\n    }\n    if (originalPayload.max === undefined && originalPayload.min === undefined && originalPayload.format !== undefined) {\n            let tempFormat = originalPayload.format.split(\"|\");\n            msg.stateMin = tempFormat[0].split(\":\")[0];\n            msg.stateMax = tempFormat[tempFormat.length -1].split(\":\")[0];\n            msg.stateName = msg.stateName + \"(\" + originalPayload.format + \")\";\n    }\n    \n\n    \n    if (originalPayload.factor === undefined) {\n        msg.payload = originalPayload.val;\n    } else {\n        msg.payload = originalPayload.val * originalPayload.factor;\n    }\n    msg.stateType = \"number\";\n    \n}\nlet globalPath = msg.topic.replace(\"pelletronic.0.\", \"\");\nglobal.set(globalPath, originalPayload);\nmsg.ack = true;\ndelete msg.parts;\nreturn msg;",
              "outputs": 1,
              "noerr": 0,
              "initialize": "",
              "finalize": "",
              "libs": [],
              "x": 240,
              "y": 360,
              "wires": [
                  [
                      "bec6b706.feea88"
                  ]
              ]
          },
          {
              "id": "bec6b706.feea88",
              "type": "ioBroker out",
              "z": "227a035e.39564c",
              "name": "",
              "topic": "",
              "ack": "true",
              "autoCreate": "true",
              "stateName": "",
              "role": "",
              "payloadType": "",
              "readonly": "",
              "stateUnit": "",
              "stateMin": "",
              "stateMax": "",
              "x": 620,
              "y": 360,
              "wires": []
          },
          {
              "id": "4c31bdd2.c3edf4",
              "type": "function",
              "z": "227a035e.39564c",
              "name": "encode answer with latin1",
              "func": "msg.payload = msg.payload.toString('latin1');\nreturn msg;",
              "outputs": 1,
              "noerr": 0,
              "initialize": "",
              "finalize": "",
              "libs": [],
              "x": 150,
              "y": 200,
              "wires": [
                  [
                      "748f86c5.818278"
                  ]
              ]
          },
          {
              "id": "cd22fc7f.ddfc8",
              "type": "ioBroker in",
              "z": "227a035e.39564c",
              "name": "",
              "topic": "pelletronic.0.*",
              "payloadType": "value",
              "onlyack": "",
              "func": "all",
              "gap": "",
              "fireOnStart": "false",
              "x": 110,
              "y": 520,
              "wires": [
                  [
                      "43732747.f8ed08"
                  ]
              ]
          },
          {
              "id": "43732747.f8ed08",
              "type": "function",
              "z": "227a035e.39564c",
              "name": "process the change from ioBroker",
              "func": "function replaceAll(str, find, replace) {\n  return str.replace(new RegExp(find, 'g'), replace);\n}\n\nfunction getFactor(strTopic) {\n    let gObject = global.get(strTopic.replace(\"pelletronic.0.\", \"\"));\n    if (gObject.factor !== undefined) {\n        return gObject.factor;\n    } else {\n        return 1;\n    }\n}\n\nfunction isValueValid(strTopic, newValue) {\n    let gObject = global.get(strTopic.replace(\"pelletronic.0.\", \"\"));\n    if (gObject.min !== undefined && gObject.max !== undefined) {\n        if (gObject.factor !== undefined) {\n            if (((newValue / gObject.factor) >= gObject.min) && ((newValue / gObject.factor) <= gObject.max)) {\n                return true;\n            }   \n        }\n        \n        if (newValue >= gObject.min && newValue <= gObject.max) {\n            return true;\n        }\n    }\n    \n    if (gObject.format !== undefined) {\n        let helper = gObject.format.split(\"|\");\n        for (var element of helper) {\n            if (element.startsWith(newValue.toString())) {\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nif (msg.acknowledged || msg.payload == \"\") {\n    return null;\n} else {\n    if (isValueValid(replaceAll(msg.topic, \"/\", \".\"), msg.payload)) {\n        var tempUrl = msg.topic.replace(\"pelletronic/0/\", \"\");\n        msg.topic = replaceAll(msg.topic, \"/\", \".\");\n        tempUrl = replaceAll(tempUrl, \"/\", \".\");\n        let oGlobSet = global.get(\"settings\");\n        tempUrl = \"http://\" + oGlobSet.interface.ip + \":\" + oGlobSet.interface.port + \"/\" + oGlobSet.interface.password + \"/\" + tempUrl + \"=\" + (msg.payload / getFactor(replaceAll(msg.topic, \"/\", \".\")));\n        msg.url = tempUrl;\n        msg.originalPayload = msg.payload;\n        delete msg.acknowledged;\n        return msg;\n    } else {\n        return null;\n    }\n}",
              "outputs": 1,
              "noerr": 0,
              "initialize": "",
              "finalize": "",
              "libs": [],
              "x": 340,
              "y": 520,
              "wires": [
                  [
                      "2c95cff0.32142"
                  ]
              ]
          },
          {
              "id": "9849d1ee.526ba",
              "type": "ioBroker out",
              "z": "227a035e.39564c",
              "name": "",
              "topic": "",
              "ack": "true",
              "autoCreate": "false",
              "stateName": "",
              "role": "",
              "payloadType": "",
              "readonly": "",
              "stateUnit": "",
              "stateMin": "",
              "stateMax": "",
              "x": 1140,
              "y": 540,
              "wires": []
          },
          {
              "id": "2c95cff0.32142",
              "type": "http request",
              "z": "227a035e.39564c",
              "name": "update pelletronic control",
              "method": "GET",
              "ret": "txt",
              "paytoqs": "ignore",
              "url": "",
              "tls": "",
              "persist": false,
              "proxy": "",
              "authType": "",
              "x": 610,
              "y": 520,
              "wires": [
                  [
                      "b8f1e197.87104"
                  ]
              ]
          },
          {
              "id": "f2851be8.7718e8",
              "type": "inject",
              "z": "227a035e.39564c",
              "name": "Set Pelletronic details",
              "props": [
                  {
                      "p": "interface.ip",
                      "v": "1.2.3.4",
                      "vt": "str"
                  },
                  {
                      "p": "interface.port",
                      "v": "8082",
                      "vt": "str"
                  },
                  {
                      "p": "interface.password",
                      "v": "abcDEFxyZ",
                      "vt": "str"
                  }
              ],
              "repeat": "",
              "crontab": "",
              "once": true,
              "onceDelay": "1",
              "topic": "",
              "payloadType": "str",
              "x": 140,
              "y": 40,
              "wires": [
                  [
                      "3931637.11f2d9c"
                  ]
              ]
          },
          {
              "id": "3931637.11f2d9c",
              "type": "function",
              "z": "227a035e.39564c",
              "name": "write settings to global store",
              "func": "global.set(\"settings\", msg);\nreturn msg;",
              "outputs": 1,
              "noerr": 0,
              "initialize": "",
              "finalize": "",
              "libs": [],
              "x": 380,
              "y": 40,
              "wires": [
                  []
              ]
          },
          {
              "id": "70c2cf04.38b1d",
              "type": "function",
              "z": "227a035e.39564c",
              "name": "write log that pelletronic set failed",
              "func": "node.warn(\"set of datapoint \" + msg.topic + \"failed\");\nreturn msg;",
              "outputs": 1,
              "noerr": 0,
              "initialize": "",
              "finalize": "",
              "libs": [],
              "x": 1020,
              "y": 500,
              "wires": [
                  []
              ]
          },
          {
              "id": "b8f1e197.87104",
              "type": "switch",
              "z": "227a035e.39564c",
              "name": "",
              "property": "payload",
              "propertyType": "msg",
              "rules": [
                  {
                      "t": "cont",
                      "v": "Failed",
                      "vt": "str"
                  },
                  {
                      "t": "else"
                  }
              ],
              "checkall": "true",
              "repair": false,
              "outputs": 2,
              "x": 790,
              "y": 520,
              "wires": [
                  [
                      "70c2cf04.38b1d"
                  ],
                  [
                      "4eef250e.69f02c"
                  ]
              ]
          },
          {
              "id": "4eef250e.69f02c",
              "type": "change",
              "z": "227a035e.39564c",
              "name": "",
              "rules": [
                  {
                      "t": "set",
                      "p": "payload",
                      "pt": "msg",
                      "to": "originalPayload",
                      "tot": "msg"
                  },
                  {
                      "t": "set",
                      "p": "ack",
                      "pt": "msg",
                      "to": "true",
                      "tot": "bool"
                  }
              ],
              "action": "",
              "property": "",
              "from": "",
              "to": "",
              "reg": false,
              "x": 960,
              "y": 540,
              "wires": [
                  [
                      "9849d1ee.526ba"
                  ]
              ]
          }
      ]
      
      posted in Praktische Anwendungen (Showcase)
      chaozmc
      chaozmc
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
    The ioBroker Community 2014-2023
    logo