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

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo
  1. ioBroker Community Home
  2. Deutsch
  3. Einsteigerfragen
  4. Einbindung von Geräten
  5. Adapter für Ecoflow Einbindung

NEWS

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    8.1k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    1.9k

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    15
    1
    2.1k

Adapter für Ecoflow Einbindung

Geplant Angeheftet Gesperrt Verschoben Einbindung von Geräten
212 Beiträge 42 Kommentatoren 61.3k Aufrufe 41 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • W Waly_de

    @applepro Es sieht ganz gut aus 🙂 Dank xNodKane's Arbeit hab ich es inzwischen geschafft sowohl einige der Statusmeldungen (PV1 und PV2 Watt sowie Leistung zum Haus) auszulesen, als auch den Wert für "Leistungsbedarf am AC..." zu schreiben.
    Allerdings gibt es noch einige Probleme.

    Das wichtigste ist, die entsprechenden Felder im MQTT auf den Typ "file" zu stellen und dann den Adapter neu zu starten...

    Danach könnt ihr mit diesem Script den Inhalt auslesen und mit https://protobuf-decoder.netlify.app/ entschlüsseln.

    getBinaryState('mqtt.<Instanznummer>.app.<USER_ID>.<SERIENNUMMER>.thing.property.set', function (err, data) {
      log("frisch ausgelesen:"+ data.toString("hex"))
    });
    

    Senden geht dann so:

    sendTo('mqtt.<Instanznummer>', 'sendMessage2Client', {topic: '/app/.<USER_ID>/<SERIENNUMMER>/thing/property/set', message:<buffer>});
    

    die Daten müssen als Buffer object übergeben werden.

    Viel Erfolg 🙂

    Ein Problem, wofür vielleicht einer von Euch eine Lösung weiß:
    Wenn ich den STATE im MQTT auf 'file' umstelle, kann ich keine Änderungen mehr Monitoren.

    on({id: /mqtt.2.app.device.property.HWXXXXXXXXXXXX/, change: 'any'}, function (obj) {
        log("EVENT!")
    });
    

    ...da kommt nach der Umstellung nichts mehr. Hat jemand eine Idee?

    VG
    Markus

    A Offline
    A Offline
    applepro
    schrieb am zuletzt editiert von
    #142

    @waly_de Ich habe folgenden Code benutzt:

    on({id: 'mqtt.<Instanznummer>.app.<USER_ID>.<SERIENNUMMER>.thing.property.set', change: 'any'}, async function (obj) {
        log("EVENT!")
    });
    

    Damit läuft das Monitoring!

    VG
    Jannick

    W 1 Antwort Letzte Antwort
    0
    • A applepro

      @waly_de Ich habe folgenden Code benutzt:

      on({id: 'mqtt.<Instanznummer>.app.<USER_ID>.<SERIENNUMMER>.thing.property.set', change: 'any'}, async function (obj) {
          log("EVENT!")
      });
      

      Damit läuft das Monitoring!

      VG
      Jannick

      W Offline
      W Offline
      Waly_de
      schrieb am zuletzt editiert von
      #143

      @applepro hmm bei mir leider nicht ... welche Version vom js-controller und welche node.js nutzt Du?

      A 1 Antwort Letzte Antwort
      0
      • xNodKaneX xNodKane

        @waly_de @applepro
        Habe gerade noch mal etwas probiert:
        Wenn man auf folgendes Topic hört bekommt man alle Powerstream Daten (in .proto format).

        /app/device/property/{serialNumber}
        

        Dann das Proto PowerMessage benutzen und dann kommt im Feld 38 der Wert für PV Sum (muss man durch 10 teilen um den Wert in W zu erhalten).
        Für alle SmartPlug user, diese können über PlugPower Feld 10 die Leistungsaufnahme messen. Auch hier wieder durch 10 teilen.

        syntax = "proto3";
        message PowerMessage {
          PowerItem item = 1;
        }
        message PowerItem {
          optional Meta meta = 1;
          string serialNumber = 25;
        }
        message Meta {
          int32 value = 1;
          int32 pvPowerSum = 38;
          int32 plugPower = 10;
        }
        

        Da jedoch noch viele weitere verschiedene Daten hier in das Topic kommen, weiß ich noch nicht nach was ich filtern muss.
        Vielleicht weiß da jemand schon mehr.

        W Offline
        W Offline
        Waly_de
        schrieb am zuletzt editiert von
        #144

        @xnodkane sehr gut ... hab auch ein wenig geforscht. Meinst du nicht das 38 der wert für "Andere Verbraucher" ist?
        Und kann man nicht eine .proto für alles machen. Die anderen Felder scheint es da ja auch zu geben.
        Ich hatte das hier erstellt. Spricht da etwas gegen?

        syntax = "proto3";
        
        message PowerItem {
          optional Meta meta = 1;
          uint32 src = 2;
          uint32 dest = 3;
          uint32 cmdFunc = 8;
          CmdFunction cmdId = 9;
          uint32 unknown = 10;
          uint32 needAck = 11;
          uint64 timestamp = 14;
          string serialNumber = 25;
        }
        
        message PowerMessage {
          PowerItem item = 1;
        }
        
        message Meta {
          optional int32 value = 1;
          optional int32 PV1_Watt = 19;
          optional int32 PV2_Watt = 24;
          optional int32 ToHome_Watt = 38;
        }
        
        enum CmdFunction {
            Unknown = 0;
            PermanentWattsPack = 129;
            SupplyPriorityPack = 130;
        }
        
        xNodKaneX 1 Antwort Letzte Antwort
        1
        • W Waly_de

          @applepro hmm bei mir leider nicht ... welche Version vom js-controller und welche node.js nutzt Du?

          A Offline
          A Offline
          applepro
          schrieb am zuletzt editiert von
          #145

          @waly_de js-controller: 4.0.24 und node.js: v16.17.1, hier werde ich gleich mal updaten

          1 Antwort Letzte Antwort
          0
          • A Offline
            A Offline
            applepro
            schrieb am zuletzt editiert von applepro
            #146

            auch nach update auf v16.20.1 läuft es weiterhin, es funktioniert nur dann nicht mehr, wenn man auf file umstellt, so wie du beschrieben hast, man sollte vlt richtig lesen....

            W 1 Antwort Letzte Antwort
            0
            • A applepro

              auch nach update auf v16.20.1 läuft es weiterhin, es funktioniert nur dann nicht mehr, wenn man auf file umstellt, so wie du beschrieben hast, man sollte vlt richtig lesen....

              W Offline
              W Offline
              Waly_de
              schrieb am zuletzt editiert von Waly_de
              #147

              @applepro Das ist seltsam. Bist Du sicher das du das Feld auf "File" umgestellt hast? Hab einen Bug dazu gemeldet und es wurde bestätigt das das so ist, und uns leider auch noch ziemlich lange erhalten bleibt...

              https://github.com/ioBroker/ioBroker.mqtt/issues/369

              haus-automatisierungH 1 Antwort Letzte Antwort
              1
              • W Waly_de

                @applepro Das ist seltsam. Bist Du sicher das du das Feld auf "File" umgestellt hast? Hab einen Bug dazu gemeldet und es wurde bestätigt das das so ist, und uns leider auch noch ziemlich lange erhalten bleibt...

                https://github.com/ioBroker/ioBroker.mqtt/issues/369

                haus-automatisierungH Offline
                haus-automatisierungH Offline
                haus-automatisierung
                Developer Most Active
                schrieb am zuletzt editiert von haus-automatisierung
                #148

                @waly_de sagte in Adapter für Ecoflow Einbindung:

                Bist Du sicher das du das Feld auf "File" umgestellt hast?

                File / Binary states sind doch eh deprecated (und müssen auch ganz anders geschrieben werden als normale states). Das wird niemand mehr implementieren, da es gerade aus allen Adaptern rausfliegt.

                Eine Lösung wäre ja, dass der Wert als base64 oder hex geschrieben wird, falls Binärdaten kommen.

                🧑‍🎓 Autor des beliebten ioBroker-Master-Kurses
                🎥 Tutorials rund um das Thema DIY-Smart-Home: https://haus-automatisierung.com/
                📚 Meine inoffizielle ioBroker Dokumentation

                W 1 Antwort Letzte Antwort
                0
                • haus-automatisierungH haus-automatisierung

                  @waly_de sagte in Adapter für Ecoflow Einbindung:

                  Bist Du sicher das du das Feld auf "File" umgestellt hast?

                  File / Binary states sind doch eh deprecated (und müssen auch ganz anders geschrieben werden als normale states). Das wird niemand mehr implementieren, da es gerade aus allen Adaptern rausfliegt.

                  Eine Lösung wäre ja, dass der Wert als base64 oder hex geschrieben wird, falls Binärdaten kommen.

                  W Offline
                  W Offline
                  Waly_de
                  schrieb am zuletzt editiert von
                  #149

                  @haus-automatisierung sagte in Adapter für Ecoflow Einbindung:

                  Eine Lösung wäre ja, dass der Wert als base64 oder hex geschrieben wird, falls Binärdaten kommen.

                  Gute Idee... müsste dann in den MQTT implementiert werden... magst Du einen Request stellen, oder gibt es den schon?

                  @haus-automatisierung sagte in Adapter für Ecoflow Einbindung:

                  File / Binary states sind doch eh deprecated (und müssen auch ganz anders geschrieben werden als normale states). Das wird niemand mehr implementieren, da es gerade aus allen Adaptern rausfliegt.

                  Es gibt aber auch noch keine funktionierende Alternative, oder? File wird ja implementiert, aber das Handling ist noch nicht eingebaut. Soweit ich weiss braucht es dazu js-controller 5.0.x

                  haus-automatisierungH 1 Antwort Letzte Antwort
                  0
                  • W Waly_de

                    @haus-automatisierung sagte in Adapter für Ecoflow Einbindung:

                    Eine Lösung wäre ja, dass der Wert als base64 oder hex geschrieben wird, falls Binärdaten kommen.

                    Gute Idee... müsste dann in den MQTT implementiert werden... magst Du einen Request stellen, oder gibt es den schon?

                    @haus-automatisierung sagte in Adapter für Ecoflow Einbindung:

                    File / Binary states sind doch eh deprecated (und müssen auch ganz anders geschrieben werden als normale states). Das wird niemand mehr implementieren, da es gerade aus allen Adaptern rausfliegt.

                    Es gibt aber auch noch keine funktionierende Alternative, oder? File wird ja implementiert, aber das Handling ist noch nicht eingebaut. Soweit ich weiss braucht es dazu js-controller 5.0.x

                    haus-automatisierungH Offline
                    haus-automatisierungH Offline
                    haus-automatisierung
                    Developer Most Active
                    schrieb am zuletzt editiert von
                    #150

                    @waly_de sagte in Adapter für Ecoflow Einbindung:

                    File wird ja implementiert, aber das Handling ist noch nicht eingebaut. Soweit ich weiss braucht es dazu js-controller 5.0.x

                    Doch, das ist alles in den Adaptern soweit vorbereitet. Im JavaScript-Adapter gibt es schon "onFile" usw. Das funktioniert aber nur mit der js-controller 5.x beta. Die gibts ja schon.

                    🧑‍🎓 Autor des beliebten ioBroker-Master-Kurses
                    🎥 Tutorials rund um das Thema DIY-Smart-Home: https://haus-automatisierung.com/
                    📚 Meine inoffizielle ioBroker Dokumentation

                    1 Antwort Letzte Antwort
                    0
                    • W Waly_de

                      @xnodkane sehr gut ... hab auch ein wenig geforscht. Meinst du nicht das 38 der wert für "Andere Verbraucher" ist?
                      Und kann man nicht eine .proto für alles machen. Die anderen Felder scheint es da ja auch zu geben.
                      Ich hatte das hier erstellt. Spricht da etwas gegen?

                      syntax = "proto3";
                      
                      message PowerItem {
                        optional Meta meta = 1;
                        uint32 src = 2;
                        uint32 dest = 3;
                        uint32 cmdFunc = 8;
                        CmdFunction cmdId = 9;
                        uint32 unknown = 10;
                        uint32 needAck = 11;
                        uint64 timestamp = 14;
                        string serialNumber = 25;
                      }
                      
                      message PowerMessage {
                        PowerItem item = 1;
                      }
                      
                      message Meta {
                        optional int32 value = 1;
                        optional int32 PV1_Watt = 19;
                        optional int32 PV2_Watt = 24;
                        optional int32 ToHome_Watt = 38;
                      }
                      
                      enum CmdFunction {
                          Unknown = 0;
                          PermanentWattsPack = 129;
                          SupplyPriorityPack = 130;
                      }
                      
                      xNodKaneX Offline
                      xNodKaneX Offline
                      xNodKane
                      schrieb am zuletzt editiert von
                      #151

                      @waly_de sagte in Adapter für Ecoflow Einbindung:

                      Ich hatte das hier erstellt. Spricht da etwas gegen?

                      Ich habe gerade noch mal bei mir auf das Dashboard geschaut im Reiter "Bereich" und dann nochmal auf das Powerstream system drücken (Die große Ansicht).
                      Würde jedenfalls hier noch die SmartPlug Daten ergänzen 😉

                      syntax = "proto3";
                      
                      message PowerItem {
                        optional Meta meta = 1;
                        uint32 src = 2;
                        uint32 dest = 3;
                        uint32 cmdFunc = 8;
                        CmdFunction cmdId = 9;
                        uint32 unknown = 10;
                        uint32 needAck = 11;
                        uint64 timestamp = 14;
                        string serialNumber = 25;
                      }
                      
                      message PowerMessage {
                        PowerItem item = 1;
                      }
                      
                      message Meta {
                        optional int32 value = 1;
                        optional int32 plugPower = 10;   // power/10=W
                        optional int32 pv1_Power = 19;   // power/10=W
                        optional int32 pv2_Power = 24;   // power/10=W
                        optional int32 toHomePower = 38; // power/10=W
                      }
                      
                      enum CmdFunction {
                          Unknown = 0;
                          PermanentWattsPack = 129;
                          SupplyPriorityPack = 130;
                      }
                      
                      W 1 Antwort Letzte Antwort
                      1
                      • xNodKaneX xNodKane

                        @waly_de sagte in Adapter für Ecoflow Einbindung:

                        Ich hatte das hier erstellt. Spricht da etwas gegen?

                        Ich habe gerade noch mal bei mir auf das Dashboard geschaut im Reiter "Bereich" und dann nochmal auf das Powerstream system drücken (Die große Ansicht).
                        Würde jedenfalls hier noch die SmartPlug Daten ergänzen 😉

                        syntax = "proto3";
                        
                        message PowerItem {
                          optional Meta meta = 1;
                          uint32 src = 2;
                          uint32 dest = 3;
                          uint32 cmdFunc = 8;
                          CmdFunction cmdId = 9;
                          uint32 unknown = 10;
                          uint32 needAck = 11;
                          uint64 timestamp = 14;
                          string serialNumber = 25;
                        }
                        
                        message PowerMessage {
                          PowerItem item = 1;
                        }
                        
                        message Meta {
                          optional int32 value = 1;
                          optional int32 plugPower = 10;   // power/10=W
                          optional int32 pv1_Power = 19;   // power/10=W
                          optional int32 pv2_Power = 24;   // power/10=W
                          optional int32 toHomePower = 38; // power/10=W
                        }
                        
                        enum CmdFunction {
                            Unknown = 0;
                            PermanentWattsPack = 129;
                            SupplyPriorityPack = 130;
                        }
                        
                        W Offline
                        W Offline
                        Waly_de
                        schrieb am zuletzt editiert von Waly_de
                        #152

                        @xnodkane
                        gut .. hab nämlich keine Smartplugs...

                        Hab heute auch getüftelt...
                        Hier mal meine Version ... Hab auch alles eingefügt was ich gesehen habe aber nicht zuordnen kann.

                        syntax = "proto3";
                        
                        message PowerItem {
                          optional Meta meta = 1;
                          optional uint32 src = 2;
                          optional uint32 dest = 3;
                          optional uint32 unknown1 = 4;
                          optional uint32 unknown2 = 5;
                          optional uint32 unknown3 = 6;
                          optional uint32 unknown4 = 7;
                          optional uint32 cmdFunc = 8;
                          optional CmdFunction cmdId = 9;
                          optional uint32 unknown5 = 10;
                          optional uint32 needAck = 11;
                          uint64 timestamp = 14;
                          optional uint32 unknown6 = 16; //3 Byte?
                          optional uint32 unknown7 = 17; //3 Byte?
                          optional string OS = 23;
                          optional string serialNumber = 25;
                        }
                        
                        message PowerMessage {
                          PowerItem item = 1;
                        }
                        
                        message Meta {
                        
                          optional int32 value = 1;
                          optional int32 plugPower = 10; 
                          optional int32 M_Unknown7 = 14; // bei Prio-änderung gesehen
                          optional int32 M_Unknown8 = 15; //bei Prio-änderung gesehen
                          
                          optional int32 PV1_Power = 19;
                          optional int32 M_Unknown1 = 21;
                          optional int32 PV2_Power = 24;
                          optional int32 From_Bat_Power = 29;
                          optional int32 Batt_Poz = 31;
                          optional int32 M_Unknown2 = 33;
                          optional int32 M_Unknown3 = 35;
                          optional int32 M_Unknown6 = 37;
                          optional int32 ToHome_Power = 38;
                          optional int32 M_Unknown9 = 43; //prio Power von summe PVx_Power abziehen ?
                          optional int32 Needed_Power = 48;
                          optional int32 M_Unknown4 = 59;
                          optional int32 M_Unknown5 = 60;
                        }
                        
                        enum CmdFunction {
                            Unknown = 0;
                            PermanentWattsPack = 129;
                            SupplyPriorityPack = 130;
                        }
                        
                        1 Antwort Letzte Antwort
                        2
                        • W Waly_de

                          @applepro Es sieht ganz gut aus 🙂 Dank xNodKane's Arbeit hab ich es inzwischen geschafft sowohl einige der Statusmeldungen (PV1 und PV2 Watt sowie Leistung zum Haus) auszulesen, als auch den Wert für "Leistungsbedarf am AC..." zu schreiben.
                          Allerdings gibt es noch einige Probleme.

                          Das wichtigste ist, die entsprechenden Felder im MQTT auf den Typ "file" zu stellen und dann den Adapter neu zu starten...

                          Danach könnt ihr mit diesem Script den Inhalt auslesen und mit https://protobuf-decoder.netlify.app/ entschlüsseln.

                          getBinaryState('mqtt.<Instanznummer>.app.<USER_ID>.<SERIENNUMMER>.thing.property.set', function (err, data) {
                            log("frisch ausgelesen:"+ data.toString("hex"))
                          });
                          

                          Senden geht dann so:

                          sendTo('mqtt.<Instanznummer>', 'sendMessage2Client', {topic: '/app/.<USER_ID>/<SERIENNUMMER>/thing/property/set', message:<buffer>});
                          

                          die Daten müssen als Buffer object übergeben werden.

                          Viel Erfolg 🙂

                          Ein Problem, wofür vielleicht einer von Euch eine Lösung weiß:
                          Wenn ich den STATE im MQTT auf 'file' umstelle, kann ich keine Änderungen mehr Monitoren.

                          on({id: /mqtt.2.app.device.property.HWXXXXXXXXXXXX/, change: 'any'}, function (obj) {
                              log("EVENT!")
                          });
                          

                          ...da kommt nach der Umstellung nichts mehr. Hat jemand eine Idee?

                          VG
                          Markus

                          A Offline
                          A Offline
                          applepro
                          schrieb am zuletzt editiert von
                          #153

                          @waly_de Hey, das einzige was ich noch nicht hinbekommen habe ist das Schriebn von Daten per Buffer, wie hast du das genau angestellt, ich kann zwar Daten senden, aber es tut sich nichts...

                          Gruß
                          Jannick

                          W 1 Antwort Letzte Antwort
                          0
                          • A applepro

                            @waly_de Hey, das einzige was ich noch nicht hinbekommen habe ist das Schriebn von Daten per Buffer, wie hast du das genau angestellt, ich kann zwar Daten senden, aber es tut sich nichts...

                            Gruß
                            Jannick

                            W Offline
                            W Offline
                            Waly_de
                            schrieb am zuletzt editiert von
                            #154

                            @applepro
                            genau so wie oben geschrieben... wenn du die Daten in einem hexString hast, dann kannst du damit daraus einen Buffer machen:

                            const buffer = Buffer.from(hexString, "hex");
                            

                            und dann einfach

                            sendTo('mqtt.<Instanznummer>', 'sendMessage2Client', {topic: '/app/<USER_ID>/<SERIENNUMMER>/thing/property/set', message: buffer});
                            
                            A 1 Antwort Letzte Antwort
                            0
                            • W Waly_de

                              @applepro
                              genau so wie oben geschrieben... wenn du die Daten in einem hexString hast, dann kannst du damit daraus einen Buffer machen:

                              const buffer = Buffer.from(hexString, "hex");
                              

                              und dann einfach

                              sendTo('mqtt.<Instanznummer>', 'sendMessage2Client', {topic: '/app/<USER_ID>/<SERIENNUMMER>/thing/property/set', message: buffer});
                              
                              A Offline
                              A Offline
                              applepro
                              schrieb am zuletzt editiert von applepro
                              #155

                              @waly_de mhh komisch, genau so hatte ich es eigentlich gemacht. Edit: Gerade nochmal alles sauber aufgesetzt, jetzt läuft es.

                              VespaGamingV 1 Antwort Letzte Antwort
                              0
                              • A applepro

                                @waly_de mhh komisch, genau so hatte ich es eigentlich gemacht. Edit: Gerade nochmal alles sauber aufgesetzt, jetzt läuft es.

                                VespaGamingV Offline
                                VespaGamingV Offline
                                VespaGaming
                                schrieb am zuletzt editiert von
                                #156

                                @applepro @waly_de
                                Ihr habt mich mit meinem Laienwissen deutlich abehängt.
                                Wie könnte so ein Javascript mit .proto decodierung sowie senden aussehen?
                                Daten bekomme ich ausgelesen und nach hex convertiert

                                1 Antwort Letzte Antwort
                                0
                                • T Offline
                                  T Offline
                                  TDahinten
                                  schrieb am zuletzt editiert von TDahinten
                                  #157

                                  Wäre dankbar, wenn hier die notwendigen Schritte evtl. nochmal einfacher erklärt werden würden.
                                  Bislang habe ich es nur geschafft, den HEX Wert darzustellen und mit https://protobuf-decoder.netlify.app/ zu entschlüsseln.
                                  Allerdings haben meine Versuche mit dem Senden noch nicht funktioniert.
                                  Der "Leistungsverbrauch von anderen Verbrauchern" hat sich leider nicht verändert, nach dem Senden.
                                  Vielleicht baut ja sogar jemand ein fertiges Script 😉

                                  Wäre wirklich prima, wenn ich den Leistungsverbrauch dynamisch anpassen könnte. Weitere Werte bräuchte ich
                                  eigentlich nicht für meinen Zweck.

                                  W 1 Antwort Letzte Antwort
                                  0
                                  • T TDahinten

                                    Wäre dankbar, wenn hier die notwendigen Schritte evtl. nochmal einfacher erklärt werden würden.
                                    Bislang habe ich es nur geschafft, den HEX Wert darzustellen und mit https://protobuf-decoder.netlify.app/ zu entschlüsseln.
                                    Allerdings haben meine Versuche mit dem Senden noch nicht funktioniert.
                                    Der "Leistungsverbrauch von anderen Verbrauchern" hat sich leider nicht verändert, nach dem Senden.
                                    Vielleicht baut ja sogar jemand ein fertiges Script 😉

                                    Wäre wirklich prima, wenn ich den Leistungsverbrauch dynamisch anpassen könnte. Weitere Werte bräuchte ich
                                    eigentlich nicht für meinen Zweck.

                                    W Offline
                                    W Offline
                                    Waly_de
                                    schrieb am zuletzt editiert von Waly_de
                                    #158

                                    @tdahinten

                                    Ok... Zufällig hab ich heute ein Script fertig gestellt, das vermutlich den meisten helfen wird.

                                    Man muss lediglich die App-Zugangsdaten und Seriennummern eingeben, den Rest macht das Teil hoffentlich von alleine. Ich hab auf den Mqtt-Adapter verzichtet und lieber einen eigenen Client genutzt. Damit gibt es keine "Binary/File Probleme" mehr.
                                    RAW Daten werden sowohl als HEX also auch dekodiert in States gespeichert. Alle einzelnen bekannten Daten werden automatisch als States angelegt.
                                    Bisher lässt sich nur ein State, nämlich die Einspeiseleistung schreiben ("...thing_property_set.setAC")

                                    Dann viel Spaß damit... bin sehr gespannt ob es bei Euch funktioniert!

                                    Benutzen auf eigene Gefahr !! 😉

                                    /**
                                     * ecoflow-iobroker-connector.js
                                     * Version:      0.2    
                                     * Release date: 28.06.2023
                                     * Autor:        Waly_de 
                                     * Forum:        https://forum.iobroker.net/topic/54929/adapter-für-ecoflow-einbindung/155
                                     * 
                                     *
                                     * This JavaScript file establishes a simple connection between IOBroker and EcoFlow. 
                                     * It automatically creates known states under 0_userdata.
                                     * 
                                     * Please note that adjustments in the ConfigData section are required. Here, you need to enter your access credentials 
                                     * used for the EcoFlow app, as well as the serial numbers of your devices.
                                     * 
                                     * Important: The second serial number entry should always correspond to the Powerstream as it is associated with control functions.
                                     * 
                                     * If you have a state that displays the current power consumption (SmartmeterID), please provide it as well. 
                                     * Configure a history for this state so that the script can determine the lowest power consumption in the last 10 minutes (configurable). 
                                     * This value will be used to dynamically adjust the Powerstream's feed-in power.
                                     * 
                                     * You can adust Powerstream's feed-in power by your self. Just write to the State "...thing_property_set.setAC" (Watt * 10)
                                     * 
                                     * Not all parameters of the Powerstream data are known yet. All known parameters will be automatically created as states.
                                     * By modifying the "protoSource" constant, newly discovered data will also be automatically created.
                                     * 
                                     * The raw data of the interface is logged as a HEX string.
                                     * 
                                     * Please exercise caution as this is the initial version of the script. Use it at your own risk!
                                     *
                                     * Requirements:
                                     * - Install protobuf using the command "npm install protobufjs" from the terminal console.
                                     * - The "Paho MQTT Client" is also required. If not already installed, use the command "npm install mqtt".
                                     *
                                     * Note: It is encouraged to discover and publish missing data definitions to improve the script.
                                     * Suggestions, optimizations, and extensions are welcome at any time.
                                     *
                                     * Special thanks to all contributors for their valuable input and support.
                                     */
                                    
                                    /*******  YOUR DATA HERE  ****************/
                                    var ConfigData = {
                                        email: "your@mail.com",
                                        passwort: "yourAppPasswort!",
                                        seriennummern: [
                                            { seriennummer: "XXXXXXXXXXXXX", name: "PowerStream" }, //1. has to be your PowerStream, you can add more devices...
                                            { seriennummer: "XXXXXXXXXXXXX", name: "DELTA Max" }
                                        ],
                                        SmartmeterID: "sonoff.0.Stromzaehler1.MT175_P",
                                        BasePowerOffset: 50,
                                        MaxPower: 600,
                                        MinValueMin: 10,
                                        statesPrefix: "0_userdata.0.ecoflow",
                                        Debug: false
                                    };
                                    //***************************************/
                                    
                                    
                                    const protoSource = `
                                    syntax = "proto3";
                                    message PowerItem {
                                      optional Meta meta = 1;
                                      optional uint32 src = 2;
                                      optional uint32 dest = 3;
                                      optional uint32 unknown1 = 4;
                                      optional uint32 unknown2 = 5;
                                      optional uint32 unknown3 = 6;
                                      optional uint32 unknown4 = 7;
                                      optional uint32 cmdFunc = 8;
                                      optional CmdFunction cmdId = 9;
                                      optional uint32 unknown5 = 10;
                                      optional uint32 needAck = 11;
                                      uint64 timestamp = 14;
                                      optional uint32 unknown6 = 16; //3 Byte?
                                      optional uint32 unknown7 = 17; //3 Byte?
                                      optional string OS = 23;
                                      optional string serialNumber = 25;
                                    }
                                    message PowerMessage {
                                      PowerItem item = 1;
                                    }
                                    message Meta {
                                      optional int32 value = 1;
                                      optional int32 plugPower = 10; 
                                      optional int32 M_Unknown7 = 14; // bei Prio-änderung gesehen
                                      optional int32 M_Unknown8 = 15; //bei Prio-änderung gesehen
                                      optional int32 PV1_Power = 19;
                                      optional int32 M_Unknown1 = 21;
                                      optional int32 PV2_Power = 24;
                                      optional int32 From_Bat_Power = 29;
                                      optional int32 Batt_Poz = 31;
                                      optional int32 M_Unknown2 = 33;
                                      optional int32 M_Unknown3 = 35;
                                      optional int32 M_Unknown6 = 37;
                                      optional int32 ToHome_Power = 38;
                                      optional int32 M_Unknown9 = 43; //prio Power von summe PVx_Power abziehen ?
                                      optional int32 Needed_Power = 48;
                                      optional int32 M_Unknown4 = 59;
                                      optional int32 Bat_Minutes = 60;
                                    }
                                    enum CmdFunction {
                                        Unknown = 0;
                                        PermanentWattsPack = 129;
                                        SupplyPriorityPack = 130;
                                    }
                                    `;
                                    
                                    
                                    const mqtt = require('mqtt');
                                    const https = require('https');
                                    const protobuf = require("protobufjs");
                                    
                                    const mqttDaten = {
                                        UserID: '',
                                        User: '',
                                        Passwort: '',
                                        URL: '',
                                        Port: '',
                                        protocol: '',
                                        clientID: ''
                                    }
                                    
                                    /*=======================================================
                                      =========             Timer               ============
                                      =======================================================*/
                                    //alle 5 minuten
                                    schedule('*/1 * * * *', function () {
                                        SetBasePower();
                                    });
                                    
                                    
                                    
                                    await getEcoFlowMqttData(ConfigData.email, ConfigData.passwort)
                                    async function getEcoFlowMqttData(email, password) {
                                        const options = {
                                            hostname: 'api.ecoflow.com',
                                            path: '/auth/login',
                                            method: 'POST',
                                            headers: {
                                                'Host': 'api.ecoflow.com',
                                                'lang': 'de-de',
                                                'platform': 'android',
                                                'sysversion': '11',
                                                'version': '4.1.2.02',
                                                'phonemodel': 'SM-X200',
                                                'content-type': 'application/json',
                                                'user-agent': 'okhttp/3.14.9'
                                            }
                                        };
                                    
                                        const data = {
                                            appVersion: "4.1.2.02",
                                            email: email,
                                            os: "android",
                                            osVersion: "30",
                                            password: Buffer.from(password).toString('base64'),
                                            scene: "IOT_APP",
                                            userType: "ECOFLOW"
                                        };
                                    
                                        function httpsRequest(options, data) {
                                            return new Promise((resolve, reject) => {
                                                const req = https.request(options, res => {
                                                    let data = '';
                                                    res.on('data', chunk => {
                                                        data += chunk;
                                                    });
                                                    res.on('end', () => {
                                                        resolve(data);
                                                    });
                                                });
                                    
                                                req.on('error', error => {
                                                    reject(error);
                                                });
                                    
                                                if (data) {
                                                    req.write(JSON.stringify(data));
                                                }
                                    
                                                req.end();
                                            });
                                        }
                                    
                                        function uuidv4() {
                                            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                                                var r = Math.random() * 16 | 0,
                                                    v = c === 'x' ? r : (r & 0x3 | 0x8);
                                                return v.toString(16);
                                            });
                                        }
                                    
                                        let response = await httpsRequest(options, data);
                                        try {
                                            let token = JSON.parse(response).data.token;
                                            let userid = JSON.parse(response).data.user.userId;
                                        } catch (error) {
                                            log(response)
                                            throw new Error("Ein Fehler bei der Ermittlung der Zugangsdaten ist aufgetreten. Bitte prüfe die Zugangsdaten.");
                                        }
                                    
                                        let token = JSON.parse(response).data.token;
                                        let userid = JSON.parse(response).data.user.userId;
                                    
                                        options.path = `/iot-auth/app/certification?userId=${userid}`;
                                        options.method = 'GET';
                                        options.headers.authorization = `Bearer ${token}`;
                                        response = await httpsRequest(options);
                                        try {
                                            mqttDaten.Passwort = JSON.parse(response).data.certificatePassword
                                            mqttDaten.Port = JSON.parse(response).data.port
                                            mqttDaten.UserID = userid
                                            mqttDaten.User = JSON.parse(response).data.certificateAccount
                                            mqttDaten.URL = JSON.parse(response).data.url
                                            mqttDaten.protocol = JSON.parse(response).data.protocol
                                            mqttDaten.clientID = "ANDROID_" + uuidv4() + "_" + userid
                                        } catch (error) {
                                            log(response)
                                            throw new Error("Ein Fehler bei der Ermittlung der Zugangsdaten ist aufgetreten. Bitte prüfe die Zugangsdaten.");
                                        }
                                        /*    
                                            console.log("UserID: " + userid);
                                            console.log("User: " + JSON.parse(response).data.certificateAccount);
                                            console.log("Passwort: " + JSON.parse(response).data.certificatePassword);
                                            console.log("URL: " + JSON.parse(response).data.url);
                                            console.log("Port: " + JSON.parse(response).data.port);
                                            console.log("protocol: " + JSON.parse(response).data.protocol);
                                            console.log("clientID: ANDROID_" + uuidv4() + "_" + userid);
                                        */
                                    
                                    }
                                    
                                    //################ MQTT Verbindung ##################
                                    
                                    // Verbindung herstellen
                                    const options = {
                                        port: mqttDaten.Port,
                                        clientId: mqttDaten.clientID,
                                        username: mqttDaten.User,
                                        password: mqttDaten.Passwort,
                                        protocol: mqttDaten.protocol
                                    };
                                    
                                    
                                    const client = mqtt.connect("mqtt://" + mqttDaten.URL, options);
                                    
                                    // Auf Verbindung hergestellt Ereignis reagieren
                                    client.on('connect', function () {
                                        console.log('Verbunden mit dem MQTT-Broker');
                                    
                                        ConfigData.seriennummern.forEach(item => {
                                            client.subscribe('/app/' + mqttDaten.UserID + '/' + item.seriennummer + '/thing/property/set');
                                            client.subscribe('/app/' + mqttDaten.UserID + '/' + item.seriennummer + '/thing/property/get');
                                            client.subscribe('/app/device/property/' + item.seriennummer);
                                        });
                                    });
                                    
                                    // Auf Nachricht empfangen Ereignis reagieren
                                    client.on('message', async function (topic, message) {
                                        var jsonMessage = ""
                                        const mqState = topic.replace(/^\//, '').replace(/\//g, '_')
                                        await createMyState(mqState + ".RAW")
                                        try {
                                            jsonMessage = JSON.parse(message);
                                            if (ConfigData.Debug) log('JSON-Nachricht empfangen:' + topic + ':' + JSON.stringify(jsonMessage));
                                            setState(ConfigData.statesPrefix + '.' + mqState + ".RAW", JSON.stringify(jsonMessage))
                                            generateAndSyncSub("data", jsonMessage, false, ConfigData.statesPrefix + '.' + mqState)
                                        } catch (error) {
                                            if (ConfigData.Debug) log('Binäre Nachricht empfangen:' + topic + ':' + message.toString('hex'));
                                            await createMyState(mqState + ".RAW_HEX")
                                            setState(ConfigData.statesPrefix + '.' + mqState + ".RAW_HEX", message.toString('hex'))
                                            //log('Decodierte Nachricht:' + decodeAndPrint(message.toString('hex')))
                                            const messagedecoded = decodeAndPrint(message.toString('hex'))
                                            setState(ConfigData.statesPrefix + '.' + mqState + ".RAW", messagedecoded)
                                            generateAndSyncSub("data", JSON.parse(messagedecoded), false, ConfigData.statesPrefix + '.' + mqState)
                                        }
                                    });
                                    // Callback für Fehler
                                    client.on('error', function (error) {
                                        log('Fehler bei der MQTT-Verbindung:' + error, error);
                                    });
                                    
                                    // close connection if script stopped
                                    onStop(function (callback) {
                                        if (client) {
                                            // close connection
                                            client.end();
                                            log("MQTT-Client beendet")
                                        }
                                        callback();
                                    }, 2000);
                                    //*/
                                    
                                    
                                    
                                    async function createMyState(name) {
                                        if (!(await existsObjectAsync(ConfigData.statesPrefix + '.' + name))) {
                                            await createStateAsync(ConfigData.statesPrefix + '.' + name, {
                                                name: name.split('.').pop(),
                                                role: 'state',
                                                type: 'string',
                                                read: true,
                                                write: true
                                            });
                                        }
                                    }
                                    
                                    function decodeAndPrint(hexString) {
                                        const root = protobuf.parse(protoSource).root;
                                        const PowerMessage = root.lookupType("PowerMessage");
                                        const message = PowerMessage.decode(Buffer.from(hexString, "hex"));
                                        const object = PowerMessage.toObject(message, { defaults: false });
                                        return JSON.stringify(object);
                                    }
                                    
                                    function SendProto(protomsg, topic) {
                                        const root = protobuf.parse(protoSource).root;
                                        const PowerMessage = root.lookupType("PowerMessage");
                                        const message = PowerMessage.create(JSON.parse(protomsg));
                                        const messageBuffer = PowerMessage.encode(message).finish();
                                        //log("Modifizierter Hex-String:" +  Buffer.from(messageBuffer).toString("hex"));
                                        //log("topic:" +  topic);
                                        client.publish(topic, messageBuffer, { qos: 1 }, function (error) {
                                            if (error) {
                                                console.error('Fehler beim Veröffentlichen der MQTT-Nachricht:', error);
                                            } else {
                                                if (ConfigData.Debug) log('Die MQTT-Nachricht wurde erfolgreich veröffentlicht.');
                                            }
                                        });
                                    }
                                    
                                    //############ Funktionen zum setzen von Werten
                                    
                                    const musterSetAC = `
                                    {
                                      "item": {
                                        "meta": {
                                          "value": 1300
                                        },
                                        "src": 32,
                                        "dest": 53,
                                        "unknown1": 1,
                                        "unknown2": 1,
                                        "unknown4": 3,
                                        "cmdFunc": 20,
                                        "cmdId": 129,
                                        "unknown5": 3,
                                        "needAck": 1,
                                        "timestamp": {
                                          "low": 35061401,
                                          "high": 0,
                                          "unsigned": true
                                        },
                                        "unknown6": 19,
                                        "unknown7": 1,
                                        "OS": "ios",
                                        "serialNumber": "ABCxxxxxxx123"
                                      }
                                    }
                                    `
                                    await createMyState('app_' + mqttDaten.UserID + '_' + ConfigData.seriennummern[0].seriennummer + '_thing_property_set.setAC')
                                    on({ id: ConfigData.statesPrefix + '.app_' + mqttDaten.UserID + '_' + ConfigData.seriennummern[0].seriennummer + '_thing_property_set.setAC', change: "any", ack: false }, function (obj) {
                                        setAC(Number(obj.state.val))
                                        setState(obj.id, obj.state.val, true);
                                    });
                                    
                                    function setAC(Value = 1000) {
                                        const updatedMusterSetAC = JSON.parse(musterSetAC);
                                        updatedMusterSetAC.item.timestamp.low = Date.now().toString();
                                        updatedMusterSetAC.item.meta.value = Value
                                        updatedMusterSetAC.item.serialNumber = ConfigData.seriennummern[0].seriennummer
                                        SendProto(JSON.stringify(updatedMusterSetAC), '/app/' + mqttDaten.UserID + '/' + ConfigData.seriennummern[0].seriennummer + '/thing/property/set');
                                    }
                                    
                                    function generateAndSyncSub(id, JElements, sub = false, preset = "0_userdata.0.test") {
                                        if (!JElements || typeof JElements !== 'object') {
                                            log('Ungültige JElements übergeben!');
                                            return;
                                        }
                                        for (var JElement in JElements) {
                                            var AktVal;
                                            if (typeof JElements[JElement] === "object") {
                                                generateAndSyncSub(id + "." + JElement, JElements[JElement], true, preset);
                                            } else {
                                                try {
                                                    if (isState2(preset + "." + id + "." + JElement)) AktVal = getState(preset + "." + id + "." + JElement).val;
                                                } catch (e) {
                                                    log("Fehler: " + e);
                                                }
                                                if (AktVal == null) {
                                                    createState(preset + "." + id + "." + JElement, JElements[JElement], false);
                                                    AktVal = JElements[JElement];
                                                }
                                                if (AktVal != JElements[JElement]) {
                                                    if (isState2(preset + "." + id + "." + JElement)) setState(preset + "." + id + "." + JElement, JElements[JElement]);
                                                }
                                            }
                                        }
                                    }
                                    
                                    
                                    /**
                                     * Checks if a a given state or part of state is existing.
                                     * This is a workaround, as getObject() or getState() throw warnings in the log.
                                     * Set strict to true if the state shall match exactly. If it is false, it will add a wildcard * to the end.
                                     * See: https://forum.iobroker.net/topic/11354/
                                     * @param {string}    strStatePath     Input string of state, like 'javascript.0.switches.Osram.Bedroom'
                                     * @param {boolean}   [strict=false]   Optional: if true, it will work strict, if false, it will add a wildcard * to the end of the string
                                     * @return {boolean}                   true if state exists, false if not
                                     */
                                    function isState2(strStatePath, strict = true) {
                                        let mSelector;
                                        if (strict) {
                                            mSelector = $(strStatePath);
                                        } else {
                                            mSelector = $(strStatePath + "*");
                                        }
                                        if (mSelector.length > 0) {
                                            return true;
                                        } else {
                                            return false;
                                        }
                                    }
                                    
                                    
                                    // ########### Grundbedarf steuern
                                    // Es müssen Historydaten für den Wert des Smartmeters vorhanden sein, damit der niedrigeste wert der letzten x Minuten ermittelt werden kann
                                    
                                    function getLowestValue(id, minuten = 120) {
                                        return new Promise((resolve, reject) => {
                                            const now = new Date().getTime();
                                            const range = minuten * 60 * 1000;
                                            var myresult = 0;
                                            getHistory(0, {
                                                id: id,
                                                start: now - range,
                                                end: now,
                                                aggregate: 'minmax'
                                            }, function (err, result) {
                                                if (err) {
                                                    reject(err);
                                                } else if (result.length) {
                                                    let lowestValue = result[0].val;
                                                    for (let i = 1; i < result.length; i++) {
                                                        if (result[i].val < lowestValue) {
                                                            lowestValue = result[i].val;
                                                        }
                                                    }
                                                    myresult = Number(lowestValue);
                                                    resolve(myresult);
                                                } else {
                                                    reject(new Error('No data'));
                                                }
                                            });
                                        });
                                    }
                                    
                                    function SetBasePower() {
                                        if (isState2(ConfigData.SmartmeterID)) {
                                            getLowestValue(ConfigData.SmartmeterID, ConfigData.MinValueMin)
                                                .then(lowestValue => {
                                                    if (lowestValue > 0) {
                                                        if (ConfigData.Debug) log("Tiefster Wert der letzten " + ConfigData.MinValueMin + " Minuten: " + lowestValue);
                                                        var AndereVerbraucher = 0
                                                        const ToHomeId = ConfigData.statesPrefix + ".app_device_property_" + ConfigData.seriennummern[0].seriennummer + ".data.item.meta.ToHome_Power"
                                                        if (isState2(ToHomeId)) {
                                                            AndereVerbraucher = Number(getState(ToHomeId).val) / 10
                                                            var NewValue = lowestValue + AndereVerbraucher - ConfigData.BasePowerOffset
                                                            if (NewValue > ConfigData.MaxPower) NewValue = ConfigData.MaxPower
                                                            if (ConfigData.Debug) {
                                                                log("AndereVerbraucher: " + AndereVerbraucher)
                                                                log("Macht : " + (lowestValue + AndereVerbraucher) + "W Grundbedarf")
                                                                log("- Offset von: " + ConfigData.BasePowerOffset + " W = " + (NewValue) + " W Grundbedarf")
                                                            }
                                                            setAC(NewValue * 10);
                                    
                                                        }
                                                    }
                                                })
                                                .catch(error => {
                                                    log("Fehler beim Abrufen des niedrigsten Werts: " + error);
                                                });
                                        }
                                    }
                                    
                                    
                                    T A 2 Antworten Letzte Antwort
                                    1
                                    • W Waly_de

                                      @tdahinten

                                      Ok... Zufällig hab ich heute ein Script fertig gestellt, das vermutlich den meisten helfen wird.

                                      Man muss lediglich die App-Zugangsdaten und Seriennummern eingeben, den Rest macht das Teil hoffentlich von alleine. Ich hab auf den Mqtt-Adapter verzichtet und lieber einen eigenen Client genutzt. Damit gibt es keine "Binary/File Probleme" mehr.
                                      RAW Daten werden sowohl als HEX also auch dekodiert in States gespeichert. Alle einzelnen bekannten Daten werden automatisch als States angelegt.
                                      Bisher lässt sich nur ein State, nämlich die Einspeiseleistung schreiben ("...thing_property_set.setAC")

                                      Dann viel Spaß damit... bin sehr gespannt ob es bei Euch funktioniert!

                                      Benutzen auf eigene Gefahr !! 😉

                                      /**
                                       * ecoflow-iobroker-connector.js
                                       * Version:      0.2    
                                       * Release date: 28.06.2023
                                       * Autor:        Waly_de 
                                       * Forum:        https://forum.iobroker.net/topic/54929/adapter-für-ecoflow-einbindung/155
                                       * 
                                       *
                                       * This JavaScript file establishes a simple connection between IOBroker and EcoFlow. 
                                       * It automatically creates known states under 0_userdata.
                                       * 
                                       * Please note that adjustments in the ConfigData section are required. Here, you need to enter your access credentials 
                                       * used for the EcoFlow app, as well as the serial numbers of your devices.
                                       * 
                                       * Important: The second serial number entry should always correspond to the Powerstream as it is associated with control functions.
                                       * 
                                       * If you have a state that displays the current power consumption (SmartmeterID), please provide it as well. 
                                       * Configure a history for this state so that the script can determine the lowest power consumption in the last 10 minutes (configurable). 
                                       * This value will be used to dynamically adjust the Powerstream's feed-in power.
                                       * 
                                       * You can adust Powerstream's feed-in power by your self. Just write to the State "...thing_property_set.setAC" (Watt * 10)
                                       * 
                                       * Not all parameters of the Powerstream data are known yet. All known parameters will be automatically created as states.
                                       * By modifying the "protoSource" constant, newly discovered data will also be automatically created.
                                       * 
                                       * The raw data of the interface is logged as a HEX string.
                                       * 
                                       * Please exercise caution as this is the initial version of the script. Use it at your own risk!
                                       *
                                       * Requirements:
                                       * - Install protobuf using the command "npm install protobufjs" from the terminal console.
                                       * - The "Paho MQTT Client" is also required. If not already installed, use the command "npm install mqtt".
                                       *
                                       * Note: It is encouraged to discover and publish missing data definitions to improve the script.
                                       * Suggestions, optimizations, and extensions are welcome at any time.
                                       *
                                       * Special thanks to all contributors for their valuable input and support.
                                       */
                                      
                                      /*******  YOUR DATA HERE  ****************/
                                      var ConfigData = {
                                          email: "your@mail.com",
                                          passwort: "yourAppPasswort!",
                                          seriennummern: [
                                              { seriennummer: "XXXXXXXXXXXXX", name: "PowerStream" }, //1. has to be your PowerStream, you can add more devices...
                                              { seriennummer: "XXXXXXXXXXXXX", name: "DELTA Max" }
                                          ],
                                          SmartmeterID: "sonoff.0.Stromzaehler1.MT175_P",
                                          BasePowerOffset: 50,
                                          MaxPower: 600,
                                          MinValueMin: 10,
                                          statesPrefix: "0_userdata.0.ecoflow",
                                          Debug: false
                                      };
                                      //***************************************/
                                      
                                      
                                      const protoSource = `
                                      syntax = "proto3";
                                      message PowerItem {
                                        optional Meta meta = 1;
                                        optional uint32 src = 2;
                                        optional uint32 dest = 3;
                                        optional uint32 unknown1 = 4;
                                        optional uint32 unknown2 = 5;
                                        optional uint32 unknown3 = 6;
                                        optional uint32 unknown4 = 7;
                                        optional uint32 cmdFunc = 8;
                                        optional CmdFunction cmdId = 9;
                                        optional uint32 unknown5 = 10;
                                        optional uint32 needAck = 11;
                                        uint64 timestamp = 14;
                                        optional uint32 unknown6 = 16; //3 Byte?
                                        optional uint32 unknown7 = 17; //3 Byte?
                                        optional string OS = 23;
                                        optional string serialNumber = 25;
                                      }
                                      message PowerMessage {
                                        PowerItem item = 1;
                                      }
                                      message Meta {
                                        optional int32 value = 1;
                                        optional int32 plugPower = 10; 
                                        optional int32 M_Unknown7 = 14; // bei Prio-änderung gesehen
                                        optional int32 M_Unknown8 = 15; //bei Prio-änderung gesehen
                                        optional int32 PV1_Power = 19;
                                        optional int32 M_Unknown1 = 21;
                                        optional int32 PV2_Power = 24;
                                        optional int32 From_Bat_Power = 29;
                                        optional int32 Batt_Poz = 31;
                                        optional int32 M_Unknown2 = 33;
                                        optional int32 M_Unknown3 = 35;
                                        optional int32 M_Unknown6 = 37;
                                        optional int32 ToHome_Power = 38;
                                        optional int32 M_Unknown9 = 43; //prio Power von summe PVx_Power abziehen ?
                                        optional int32 Needed_Power = 48;
                                        optional int32 M_Unknown4 = 59;
                                        optional int32 Bat_Minutes = 60;
                                      }
                                      enum CmdFunction {
                                          Unknown = 0;
                                          PermanentWattsPack = 129;
                                          SupplyPriorityPack = 130;
                                      }
                                      `;
                                      
                                      
                                      const mqtt = require('mqtt');
                                      const https = require('https');
                                      const protobuf = require("protobufjs");
                                      
                                      const mqttDaten = {
                                          UserID: '',
                                          User: '',
                                          Passwort: '',
                                          URL: '',
                                          Port: '',
                                          protocol: '',
                                          clientID: ''
                                      }
                                      
                                      /*=======================================================
                                        =========             Timer               ============
                                        =======================================================*/
                                      //alle 5 minuten
                                      schedule('*/1 * * * *', function () {
                                          SetBasePower();
                                      });
                                      
                                      
                                      
                                      await getEcoFlowMqttData(ConfigData.email, ConfigData.passwort)
                                      async function getEcoFlowMqttData(email, password) {
                                          const options = {
                                              hostname: 'api.ecoflow.com',
                                              path: '/auth/login',
                                              method: 'POST',
                                              headers: {
                                                  'Host': 'api.ecoflow.com',
                                                  'lang': 'de-de',
                                                  'platform': 'android',
                                                  'sysversion': '11',
                                                  'version': '4.1.2.02',
                                                  'phonemodel': 'SM-X200',
                                                  'content-type': 'application/json',
                                                  'user-agent': 'okhttp/3.14.9'
                                              }
                                          };
                                      
                                          const data = {
                                              appVersion: "4.1.2.02",
                                              email: email,
                                              os: "android",
                                              osVersion: "30",
                                              password: Buffer.from(password).toString('base64'),
                                              scene: "IOT_APP",
                                              userType: "ECOFLOW"
                                          };
                                      
                                          function httpsRequest(options, data) {
                                              return new Promise((resolve, reject) => {
                                                  const req = https.request(options, res => {
                                                      let data = '';
                                                      res.on('data', chunk => {
                                                          data += chunk;
                                                      });
                                                      res.on('end', () => {
                                                          resolve(data);
                                                      });
                                                  });
                                      
                                                  req.on('error', error => {
                                                      reject(error);
                                                  });
                                      
                                                  if (data) {
                                                      req.write(JSON.stringify(data));
                                                  }
                                      
                                                  req.end();
                                              });
                                          }
                                      
                                          function uuidv4() {
                                              return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                                                  var r = Math.random() * 16 | 0,
                                                      v = c === 'x' ? r : (r & 0x3 | 0x8);
                                                  return v.toString(16);
                                              });
                                          }
                                      
                                          let response = await httpsRequest(options, data);
                                          try {
                                              let token = JSON.parse(response).data.token;
                                              let userid = JSON.parse(response).data.user.userId;
                                          } catch (error) {
                                              log(response)
                                              throw new Error("Ein Fehler bei der Ermittlung der Zugangsdaten ist aufgetreten. Bitte prüfe die Zugangsdaten.");
                                          }
                                      
                                          let token = JSON.parse(response).data.token;
                                          let userid = JSON.parse(response).data.user.userId;
                                      
                                          options.path = `/iot-auth/app/certification?userId=${userid}`;
                                          options.method = 'GET';
                                          options.headers.authorization = `Bearer ${token}`;
                                          response = await httpsRequest(options);
                                          try {
                                              mqttDaten.Passwort = JSON.parse(response).data.certificatePassword
                                              mqttDaten.Port = JSON.parse(response).data.port
                                              mqttDaten.UserID = userid
                                              mqttDaten.User = JSON.parse(response).data.certificateAccount
                                              mqttDaten.URL = JSON.parse(response).data.url
                                              mqttDaten.protocol = JSON.parse(response).data.protocol
                                              mqttDaten.clientID = "ANDROID_" + uuidv4() + "_" + userid
                                          } catch (error) {
                                              log(response)
                                              throw new Error("Ein Fehler bei der Ermittlung der Zugangsdaten ist aufgetreten. Bitte prüfe die Zugangsdaten.");
                                          }
                                          /*    
                                              console.log("UserID: " + userid);
                                              console.log("User: " + JSON.parse(response).data.certificateAccount);
                                              console.log("Passwort: " + JSON.parse(response).data.certificatePassword);
                                              console.log("URL: " + JSON.parse(response).data.url);
                                              console.log("Port: " + JSON.parse(response).data.port);
                                              console.log("protocol: " + JSON.parse(response).data.protocol);
                                              console.log("clientID: ANDROID_" + uuidv4() + "_" + userid);
                                          */
                                      
                                      }
                                      
                                      //################ MQTT Verbindung ##################
                                      
                                      // Verbindung herstellen
                                      const options = {
                                          port: mqttDaten.Port,
                                          clientId: mqttDaten.clientID,
                                          username: mqttDaten.User,
                                          password: mqttDaten.Passwort,
                                          protocol: mqttDaten.protocol
                                      };
                                      
                                      
                                      const client = mqtt.connect("mqtt://" + mqttDaten.URL, options);
                                      
                                      // Auf Verbindung hergestellt Ereignis reagieren
                                      client.on('connect', function () {
                                          console.log('Verbunden mit dem MQTT-Broker');
                                      
                                          ConfigData.seriennummern.forEach(item => {
                                              client.subscribe('/app/' + mqttDaten.UserID + '/' + item.seriennummer + '/thing/property/set');
                                              client.subscribe('/app/' + mqttDaten.UserID + '/' + item.seriennummer + '/thing/property/get');
                                              client.subscribe('/app/device/property/' + item.seriennummer);
                                          });
                                      });
                                      
                                      // Auf Nachricht empfangen Ereignis reagieren
                                      client.on('message', async function (topic, message) {
                                          var jsonMessage = ""
                                          const mqState = topic.replace(/^\//, '').replace(/\//g, '_')
                                          await createMyState(mqState + ".RAW")
                                          try {
                                              jsonMessage = JSON.parse(message);
                                              if (ConfigData.Debug) log('JSON-Nachricht empfangen:' + topic + ':' + JSON.stringify(jsonMessage));
                                              setState(ConfigData.statesPrefix + '.' + mqState + ".RAW", JSON.stringify(jsonMessage))
                                              generateAndSyncSub("data", jsonMessage, false, ConfigData.statesPrefix + '.' + mqState)
                                          } catch (error) {
                                              if (ConfigData.Debug) log('Binäre Nachricht empfangen:' + topic + ':' + message.toString('hex'));
                                              await createMyState(mqState + ".RAW_HEX")
                                              setState(ConfigData.statesPrefix + '.' + mqState + ".RAW_HEX", message.toString('hex'))
                                              //log('Decodierte Nachricht:' + decodeAndPrint(message.toString('hex')))
                                              const messagedecoded = decodeAndPrint(message.toString('hex'))
                                              setState(ConfigData.statesPrefix + '.' + mqState + ".RAW", messagedecoded)
                                              generateAndSyncSub("data", JSON.parse(messagedecoded), false, ConfigData.statesPrefix + '.' + mqState)
                                          }
                                      });
                                      // Callback für Fehler
                                      client.on('error', function (error) {
                                          log('Fehler bei der MQTT-Verbindung:' + error, error);
                                      });
                                      
                                      // close connection if script stopped
                                      onStop(function (callback) {
                                          if (client) {
                                              // close connection
                                              client.end();
                                              log("MQTT-Client beendet")
                                          }
                                          callback();
                                      }, 2000);
                                      //*/
                                      
                                      
                                      
                                      async function createMyState(name) {
                                          if (!(await existsObjectAsync(ConfigData.statesPrefix + '.' + name))) {
                                              await createStateAsync(ConfigData.statesPrefix + '.' + name, {
                                                  name: name.split('.').pop(),
                                                  role: 'state',
                                                  type: 'string',
                                                  read: true,
                                                  write: true
                                              });
                                          }
                                      }
                                      
                                      function decodeAndPrint(hexString) {
                                          const root = protobuf.parse(protoSource).root;
                                          const PowerMessage = root.lookupType("PowerMessage");
                                          const message = PowerMessage.decode(Buffer.from(hexString, "hex"));
                                          const object = PowerMessage.toObject(message, { defaults: false });
                                          return JSON.stringify(object);
                                      }
                                      
                                      function SendProto(protomsg, topic) {
                                          const root = protobuf.parse(protoSource).root;
                                          const PowerMessage = root.lookupType("PowerMessage");
                                          const message = PowerMessage.create(JSON.parse(protomsg));
                                          const messageBuffer = PowerMessage.encode(message).finish();
                                          //log("Modifizierter Hex-String:" +  Buffer.from(messageBuffer).toString("hex"));
                                          //log("topic:" +  topic);
                                          client.publish(topic, messageBuffer, { qos: 1 }, function (error) {
                                              if (error) {
                                                  console.error('Fehler beim Veröffentlichen der MQTT-Nachricht:', error);
                                              } else {
                                                  if (ConfigData.Debug) log('Die MQTT-Nachricht wurde erfolgreich veröffentlicht.');
                                              }
                                          });
                                      }
                                      
                                      //############ Funktionen zum setzen von Werten
                                      
                                      const musterSetAC = `
                                      {
                                        "item": {
                                          "meta": {
                                            "value": 1300
                                          },
                                          "src": 32,
                                          "dest": 53,
                                          "unknown1": 1,
                                          "unknown2": 1,
                                          "unknown4": 3,
                                          "cmdFunc": 20,
                                          "cmdId": 129,
                                          "unknown5": 3,
                                          "needAck": 1,
                                          "timestamp": {
                                            "low": 35061401,
                                            "high": 0,
                                            "unsigned": true
                                          },
                                          "unknown6": 19,
                                          "unknown7": 1,
                                          "OS": "ios",
                                          "serialNumber": "ABCxxxxxxx123"
                                        }
                                      }
                                      `
                                      await createMyState('app_' + mqttDaten.UserID + '_' + ConfigData.seriennummern[0].seriennummer + '_thing_property_set.setAC')
                                      on({ id: ConfigData.statesPrefix + '.app_' + mqttDaten.UserID + '_' + ConfigData.seriennummern[0].seriennummer + '_thing_property_set.setAC', change: "any", ack: false }, function (obj) {
                                          setAC(Number(obj.state.val))
                                          setState(obj.id, obj.state.val, true);
                                      });
                                      
                                      function setAC(Value = 1000) {
                                          const updatedMusterSetAC = JSON.parse(musterSetAC);
                                          updatedMusterSetAC.item.timestamp.low = Date.now().toString();
                                          updatedMusterSetAC.item.meta.value = Value
                                          updatedMusterSetAC.item.serialNumber = ConfigData.seriennummern[0].seriennummer
                                          SendProto(JSON.stringify(updatedMusterSetAC), '/app/' + mqttDaten.UserID + '/' + ConfigData.seriennummern[0].seriennummer + '/thing/property/set');
                                      }
                                      
                                      function generateAndSyncSub(id, JElements, sub = false, preset = "0_userdata.0.test") {
                                          if (!JElements || typeof JElements !== 'object') {
                                              log('Ungültige JElements übergeben!');
                                              return;
                                          }
                                          for (var JElement in JElements) {
                                              var AktVal;
                                              if (typeof JElements[JElement] === "object") {
                                                  generateAndSyncSub(id + "." + JElement, JElements[JElement], true, preset);
                                              } else {
                                                  try {
                                                      if (isState2(preset + "." + id + "." + JElement)) AktVal = getState(preset + "." + id + "." + JElement).val;
                                                  } catch (e) {
                                                      log("Fehler: " + e);
                                                  }
                                                  if (AktVal == null) {
                                                      createState(preset + "." + id + "." + JElement, JElements[JElement], false);
                                                      AktVal = JElements[JElement];
                                                  }
                                                  if (AktVal != JElements[JElement]) {
                                                      if (isState2(preset + "." + id + "." + JElement)) setState(preset + "." + id + "." + JElement, JElements[JElement]);
                                                  }
                                              }
                                          }
                                      }
                                      
                                      
                                      /**
                                       * Checks if a a given state or part of state is existing.
                                       * This is a workaround, as getObject() or getState() throw warnings in the log.
                                       * Set strict to true if the state shall match exactly. If it is false, it will add a wildcard * to the end.
                                       * See: https://forum.iobroker.net/topic/11354/
                                       * @param {string}    strStatePath     Input string of state, like 'javascript.0.switches.Osram.Bedroom'
                                       * @param {boolean}   [strict=false]   Optional: if true, it will work strict, if false, it will add a wildcard * to the end of the string
                                       * @return {boolean}                   true if state exists, false if not
                                       */
                                      function isState2(strStatePath, strict = true) {
                                          let mSelector;
                                          if (strict) {
                                              mSelector = $(strStatePath);
                                          } else {
                                              mSelector = $(strStatePath + "*");
                                          }
                                          if (mSelector.length > 0) {
                                              return true;
                                          } else {
                                              return false;
                                          }
                                      }
                                      
                                      
                                      // ########### Grundbedarf steuern
                                      // Es müssen Historydaten für den Wert des Smartmeters vorhanden sein, damit der niedrigeste wert der letzten x Minuten ermittelt werden kann
                                      
                                      function getLowestValue(id, minuten = 120) {
                                          return new Promise((resolve, reject) => {
                                              const now = new Date().getTime();
                                              const range = minuten * 60 * 1000;
                                              var myresult = 0;
                                              getHistory(0, {
                                                  id: id,
                                                  start: now - range,
                                                  end: now,
                                                  aggregate: 'minmax'
                                              }, function (err, result) {
                                                  if (err) {
                                                      reject(err);
                                                  } else if (result.length) {
                                                      let lowestValue = result[0].val;
                                                      for (let i = 1; i < result.length; i++) {
                                                          if (result[i].val < lowestValue) {
                                                              lowestValue = result[i].val;
                                                          }
                                                      }
                                                      myresult = Number(lowestValue);
                                                      resolve(myresult);
                                                  } else {
                                                      reject(new Error('No data'));
                                                  }
                                              });
                                          });
                                      }
                                      
                                      function SetBasePower() {
                                          if (isState2(ConfigData.SmartmeterID)) {
                                              getLowestValue(ConfigData.SmartmeterID, ConfigData.MinValueMin)
                                                  .then(lowestValue => {
                                                      if (lowestValue > 0) {
                                                          if (ConfigData.Debug) log("Tiefster Wert der letzten " + ConfigData.MinValueMin + " Minuten: " + lowestValue);
                                                          var AndereVerbraucher = 0
                                                          const ToHomeId = ConfigData.statesPrefix + ".app_device_property_" + ConfigData.seriennummern[0].seriennummer + ".data.item.meta.ToHome_Power"
                                                          if (isState2(ToHomeId)) {
                                                              AndereVerbraucher = Number(getState(ToHomeId).val) / 10
                                                              var NewValue = lowestValue + AndereVerbraucher - ConfigData.BasePowerOffset
                                                              if (NewValue > ConfigData.MaxPower) NewValue = ConfigData.MaxPower
                                                              if (ConfigData.Debug) {
                                                                  log("AndereVerbraucher: " + AndereVerbraucher)
                                                                  log("Macht : " + (lowestValue + AndereVerbraucher) + "W Grundbedarf")
                                                                  log("- Offset von: " + ConfigData.BasePowerOffset + " W = " + (NewValue) + " W Grundbedarf")
                                                              }
                                                              setAC(NewValue * 10);
                                      
                                                          }
                                                      }
                                                  })
                                                  .catch(error => {
                                                      log("Fehler beim Abrufen des niedrigsten Werts: " + error);
                                                  });
                                          }
                                      }
                                      
                                      
                                      T Offline
                                      T Offline
                                      TDahinten
                                      schrieb am zuletzt editiert von TDahinten
                                      #159

                                      @waly_de said in Adapter für Ecoflow Einbindung:

                                      Also erstmal vielen Dank, für die schnelle Unterstützung. 👍

                                      Habe soweit alles im Script befüllt. Ebenfalls die mqttDaten.
                                      Die notwendigen Installationen wurden durchgeführt.

                                      Folgende Fehler werden im Log gemeldet::

                                      error javascript.0 (1474) script.js.common.PowerStream_Script: Error: illegal token '{' (line 5)
                                      error javascript.0 (1474) at decodeAndPrint (script.js.common.PowerStream_Script:629:27)
                                      error javascript.0 (1474) at MqttClient.<anonymous> (script.js.common.PowerStream_Script:557:32)

                                      W 1 Antwort Letzte Antwort
                                      0
                                      • T TDahinten

                                        @waly_de said in Adapter für Ecoflow Einbindung:

                                        Also erstmal vielen Dank, für die schnelle Unterstützung. 👍

                                        Habe soweit alles im Script befüllt. Ebenfalls die mqttDaten.
                                        Die notwendigen Installationen wurden durchgeführt.

                                        Folgende Fehler werden im Log gemeldet::

                                        error javascript.0 (1474) script.js.common.PowerStream_Script: Error: illegal token '{' (line 5)
                                        error javascript.0 (1474) at decodeAndPrint (script.js.common.PowerStream_Script:629:27)
                                        error javascript.0 (1474) at MqttClient.<anonymous> (script.js.common.PowerStream_Script:557:32)

                                        W Offline
                                        W Offline
                                        Waly_de
                                        schrieb am zuletzt editiert von
                                        #160

                                        @tdahinten hmm ... guck mal bitte ob du ein Komma zu viel oder zu wenig im Bereich der Seriennummern hast. die {} müssen ein Komma getrennt sein:

                                        seriennummern: [
                                                { seriennummer: "XXXXXXXXXXXXX", name: "PowerStream" },
                                                { seriennummer: "XXXXXXXXXXXXX", name: "DELTA Max" }
                                            ],
                                        
                                        1 Antwort Letzte Antwort
                                        0
                                        • W Waly_de

                                          @tdahinten

                                          Ok... Zufällig hab ich heute ein Script fertig gestellt, das vermutlich den meisten helfen wird.

                                          Man muss lediglich die App-Zugangsdaten und Seriennummern eingeben, den Rest macht das Teil hoffentlich von alleine. Ich hab auf den Mqtt-Adapter verzichtet und lieber einen eigenen Client genutzt. Damit gibt es keine "Binary/File Probleme" mehr.
                                          RAW Daten werden sowohl als HEX also auch dekodiert in States gespeichert. Alle einzelnen bekannten Daten werden automatisch als States angelegt.
                                          Bisher lässt sich nur ein State, nämlich die Einspeiseleistung schreiben ("...thing_property_set.setAC")

                                          Dann viel Spaß damit... bin sehr gespannt ob es bei Euch funktioniert!

                                          Benutzen auf eigene Gefahr !! 😉

                                          /**
                                           * ecoflow-iobroker-connector.js
                                           * Version:      0.2    
                                           * Release date: 28.06.2023
                                           * Autor:        Waly_de 
                                           * Forum:        https://forum.iobroker.net/topic/54929/adapter-für-ecoflow-einbindung/155
                                           * 
                                           *
                                           * This JavaScript file establishes a simple connection between IOBroker and EcoFlow. 
                                           * It automatically creates known states under 0_userdata.
                                           * 
                                           * Please note that adjustments in the ConfigData section are required. Here, you need to enter your access credentials 
                                           * used for the EcoFlow app, as well as the serial numbers of your devices.
                                           * 
                                           * Important: The second serial number entry should always correspond to the Powerstream as it is associated with control functions.
                                           * 
                                           * If you have a state that displays the current power consumption (SmartmeterID), please provide it as well. 
                                           * Configure a history for this state so that the script can determine the lowest power consumption in the last 10 minutes (configurable). 
                                           * This value will be used to dynamically adjust the Powerstream's feed-in power.
                                           * 
                                           * You can adust Powerstream's feed-in power by your self. Just write to the State "...thing_property_set.setAC" (Watt * 10)
                                           * 
                                           * Not all parameters of the Powerstream data are known yet. All known parameters will be automatically created as states.
                                           * By modifying the "protoSource" constant, newly discovered data will also be automatically created.
                                           * 
                                           * The raw data of the interface is logged as a HEX string.
                                           * 
                                           * Please exercise caution as this is the initial version of the script. Use it at your own risk!
                                           *
                                           * Requirements:
                                           * - Install protobuf using the command "npm install protobufjs" from the terminal console.
                                           * - The "Paho MQTT Client" is also required. If not already installed, use the command "npm install mqtt".
                                           *
                                           * Note: It is encouraged to discover and publish missing data definitions to improve the script.
                                           * Suggestions, optimizations, and extensions are welcome at any time.
                                           *
                                           * Special thanks to all contributors for their valuable input and support.
                                           */
                                          
                                          /*******  YOUR DATA HERE  ****************/
                                          var ConfigData = {
                                              email: "your@mail.com",
                                              passwort: "yourAppPasswort!",
                                              seriennummern: [
                                                  { seriennummer: "XXXXXXXXXXXXX", name: "PowerStream" }, //1. has to be your PowerStream, you can add more devices...
                                                  { seriennummer: "XXXXXXXXXXXXX", name: "DELTA Max" }
                                              ],
                                              SmartmeterID: "sonoff.0.Stromzaehler1.MT175_P",
                                              BasePowerOffset: 50,
                                              MaxPower: 600,
                                              MinValueMin: 10,
                                              statesPrefix: "0_userdata.0.ecoflow",
                                              Debug: false
                                          };
                                          //***************************************/
                                          
                                          
                                          const protoSource = `
                                          syntax = "proto3";
                                          message PowerItem {
                                            optional Meta meta = 1;
                                            optional uint32 src = 2;
                                            optional uint32 dest = 3;
                                            optional uint32 unknown1 = 4;
                                            optional uint32 unknown2 = 5;
                                            optional uint32 unknown3 = 6;
                                            optional uint32 unknown4 = 7;
                                            optional uint32 cmdFunc = 8;
                                            optional CmdFunction cmdId = 9;
                                            optional uint32 unknown5 = 10;
                                            optional uint32 needAck = 11;
                                            uint64 timestamp = 14;
                                            optional uint32 unknown6 = 16; //3 Byte?
                                            optional uint32 unknown7 = 17; //3 Byte?
                                            optional string OS = 23;
                                            optional string serialNumber = 25;
                                          }
                                          message PowerMessage {
                                            PowerItem item = 1;
                                          }
                                          message Meta {
                                            optional int32 value = 1;
                                            optional int32 plugPower = 10; 
                                            optional int32 M_Unknown7 = 14; // bei Prio-änderung gesehen
                                            optional int32 M_Unknown8 = 15; //bei Prio-änderung gesehen
                                            optional int32 PV1_Power = 19;
                                            optional int32 M_Unknown1 = 21;
                                            optional int32 PV2_Power = 24;
                                            optional int32 From_Bat_Power = 29;
                                            optional int32 Batt_Poz = 31;
                                            optional int32 M_Unknown2 = 33;
                                            optional int32 M_Unknown3 = 35;
                                            optional int32 M_Unknown6 = 37;
                                            optional int32 ToHome_Power = 38;
                                            optional int32 M_Unknown9 = 43; //prio Power von summe PVx_Power abziehen ?
                                            optional int32 Needed_Power = 48;
                                            optional int32 M_Unknown4 = 59;
                                            optional int32 Bat_Minutes = 60;
                                          }
                                          enum CmdFunction {
                                              Unknown = 0;
                                              PermanentWattsPack = 129;
                                              SupplyPriorityPack = 130;
                                          }
                                          `;
                                          
                                          
                                          const mqtt = require('mqtt');
                                          const https = require('https');
                                          const protobuf = require("protobufjs");
                                          
                                          const mqttDaten = {
                                              UserID: '',
                                              User: '',
                                              Passwort: '',
                                              URL: '',
                                              Port: '',
                                              protocol: '',
                                              clientID: ''
                                          }
                                          
                                          /*=======================================================
                                            =========             Timer               ============
                                            =======================================================*/
                                          //alle 5 minuten
                                          schedule('*/1 * * * *', function () {
                                              SetBasePower();
                                          });
                                          
                                          
                                          
                                          await getEcoFlowMqttData(ConfigData.email, ConfigData.passwort)
                                          async function getEcoFlowMqttData(email, password) {
                                              const options = {
                                                  hostname: 'api.ecoflow.com',
                                                  path: '/auth/login',
                                                  method: 'POST',
                                                  headers: {
                                                      'Host': 'api.ecoflow.com',
                                                      'lang': 'de-de',
                                                      'platform': 'android',
                                                      'sysversion': '11',
                                                      'version': '4.1.2.02',
                                                      'phonemodel': 'SM-X200',
                                                      'content-type': 'application/json',
                                                      'user-agent': 'okhttp/3.14.9'
                                                  }
                                              };
                                          
                                              const data = {
                                                  appVersion: "4.1.2.02",
                                                  email: email,
                                                  os: "android",
                                                  osVersion: "30",
                                                  password: Buffer.from(password).toString('base64'),
                                                  scene: "IOT_APP",
                                                  userType: "ECOFLOW"
                                              };
                                          
                                              function httpsRequest(options, data) {
                                                  return new Promise((resolve, reject) => {
                                                      const req = https.request(options, res => {
                                                          let data = '';
                                                          res.on('data', chunk => {
                                                              data += chunk;
                                                          });
                                                          res.on('end', () => {
                                                              resolve(data);
                                                          });
                                                      });
                                          
                                                      req.on('error', error => {
                                                          reject(error);
                                                      });
                                          
                                                      if (data) {
                                                          req.write(JSON.stringify(data));
                                                      }
                                          
                                                      req.end();
                                                  });
                                              }
                                          
                                              function uuidv4() {
                                                  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                                                      var r = Math.random() * 16 | 0,
                                                          v = c === 'x' ? r : (r & 0x3 | 0x8);
                                                      return v.toString(16);
                                                  });
                                              }
                                          
                                              let response = await httpsRequest(options, data);
                                              try {
                                                  let token = JSON.parse(response).data.token;
                                                  let userid = JSON.parse(response).data.user.userId;
                                              } catch (error) {
                                                  log(response)
                                                  throw new Error("Ein Fehler bei der Ermittlung der Zugangsdaten ist aufgetreten. Bitte prüfe die Zugangsdaten.");
                                              }
                                          
                                              let token = JSON.parse(response).data.token;
                                              let userid = JSON.parse(response).data.user.userId;
                                          
                                              options.path = `/iot-auth/app/certification?userId=${userid}`;
                                              options.method = 'GET';
                                              options.headers.authorization = `Bearer ${token}`;
                                              response = await httpsRequest(options);
                                              try {
                                                  mqttDaten.Passwort = JSON.parse(response).data.certificatePassword
                                                  mqttDaten.Port = JSON.parse(response).data.port
                                                  mqttDaten.UserID = userid
                                                  mqttDaten.User = JSON.parse(response).data.certificateAccount
                                                  mqttDaten.URL = JSON.parse(response).data.url
                                                  mqttDaten.protocol = JSON.parse(response).data.protocol
                                                  mqttDaten.clientID = "ANDROID_" + uuidv4() + "_" + userid
                                              } catch (error) {
                                                  log(response)
                                                  throw new Error("Ein Fehler bei der Ermittlung der Zugangsdaten ist aufgetreten. Bitte prüfe die Zugangsdaten.");
                                              }
                                              /*    
                                                  console.log("UserID: " + userid);
                                                  console.log("User: " + JSON.parse(response).data.certificateAccount);
                                                  console.log("Passwort: " + JSON.parse(response).data.certificatePassword);
                                                  console.log("URL: " + JSON.parse(response).data.url);
                                                  console.log("Port: " + JSON.parse(response).data.port);
                                                  console.log("protocol: " + JSON.parse(response).data.protocol);
                                                  console.log("clientID: ANDROID_" + uuidv4() + "_" + userid);
                                              */
                                          
                                          }
                                          
                                          //################ MQTT Verbindung ##################
                                          
                                          // Verbindung herstellen
                                          const options = {
                                              port: mqttDaten.Port,
                                              clientId: mqttDaten.clientID,
                                              username: mqttDaten.User,
                                              password: mqttDaten.Passwort,
                                              protocol: mqttDaten.protocol
                                          };
                                          
                                          
                                          const client = mqtt.connect("mqtt://" + mqttDaten.URL, options);
                                          
                                          // Auf Verbindung hergestellt Ereignis reagieren
                                          client.on('connect', function () {
                                              console.log('Verbunden mit dem MQTT-Broker');
                                          
                                              ConfigData.seriennummern.forEach(item => {
                                                  client.subscribe('/app/' + mqttDaten.UserID + '/' + item.seriennummer + '/thing/property/set');
                                                  client.subscribe('/app/' + mqttDaten.UserID + '/' + item.seriennummer + '/thing/property/get');
                                                  client.subscribe('/app/device/property/' + item.seriennummer);
                                              });
                                          });
                                          
                                          // Auf Nachricht empfangen Ereignis reagieren
                                          client.on('message', async function (topic, message) {
                                              var jsonMessage = ""
                                              const mqState = topic.replace(/^\//, '').replace(/\//g, '_')
                                              await createMyState(mqState + ".RAW")
                                              try {
                                                  jsonMessage = JSON.parse(message);
                                                  if (ConfigData.Debug) log('JSON-Nachricht empfangen:' + topic + ':' + JSON.stringify(jsonMessage));
                                                  setState(ConfigData.statesPrefix + '.' + mqState + ".RAW", JSON.stringify(jsonMessage))
                                                  generateAndSyncSub("data", jsonMessage, false, ConfigData.statesPrefix + '.' + mqState)
                                              } catch (error) {
                                                  if (ConfigData.Debug) log('Binäre Nachricht empfangen:' + topic + ':' + message.toString('hex'));
                                                  await createMyState(mqState + ".RAW_HEX")
                                                  setState(ConfigData.statesPrefix + '.' + mqState + ".RAW_HEX", message.toString('hex'))
                                                  //log('Decodierte Nachricht:' + decodeAndPrint(message.toString('hex')))
                                                  const messagedecoded = decodeAndPrint(message.toString('hex'))
                                                  setState(ConfigData.statesPrefix + '.' + mqState + ".RAW", messagedecoded)
                                                  generateAndSyncSub("data", JSON.parse(messagedecoded), false, ConfigData.statesPrefix + '.' + mqState)
                                              }
                                          });
                                          // Callback für Fehler
                                          client.on('error', function (error) {
                                              log('Fehler bei der MQTT-Verbindung:' + error, error);
                                          });
                                          
                                          // close connection if script stopped
                                          onStop(function (callback) {
                                              if (client) {
                                                  // close connection
                                                  client.end();
                                                  log("MQTT-Client beendet")
                                              }
                                              callback();
                                          }, 2000);
                                          //*/
                                          
                                          
                                          
                                          async function createMyState(name) {
                                              if (!(await existsObjectAsync(ConfigData.statesPrefix + '.' + name))) {
                                                  await createStateAsync(ConfigData.statesPrefix + '.' + name, {
                                                      name: name.split('.').pop(),
                                                      role: 'state',
                                                      type: 'string',
                                                      read: true,
                                                      write: true
                                                  });
                                              }
                                          }
                                          
                                          function decodeAndPrint(hexString) {
                                              const root = protobuf.parse(protoSource).root;
                                              const PowerMessage = root.lookupType("PowerMessage");
                                              const message = PowerMessage.decode(Buffer.from(hexString, "hex"));
                                              const object = PowerMessage.toObject(message, { defaults: false });
                                              return JSON.stringify(object);
                                          }
                                          
                                          function SendProto(protomsg, topic) {
                                              const root = protobuf.parse(protoSource).root;
                                              const PowerMessage = root.lookupType("PowerMessage");
                                              const message = PowerMessage.create(JSON.parse(protomsg));
                                              const messageBuffer = PowerMessage.encode(message).finish();
                                              //log("Modifizierter Hex-String:" +  Buffer.from(messageBuffer).toString("hex"));
                                              //log("topic:" +  topic);
                                              client.publish(topic, messageBuffer, { qos: 1 }, function (error) {
                                                  if (error) {
                                                      console.error('Fehler beim Veröffentlichen der MQTT-Nachricht:', error);
                                                  } else {
                                                      if (ConfigData.Debug) log('Die MQTT-Nachricht wurde erfolgreich veröffentlicht.');
                                                  }
                                              });
                                          }
                                          
                                          //############ Funktionen zum setzen von Werten
                                          
                                          const musterSetAC = `
                                          {
                                            "item": {
                                              "meta": {
                                                "value": 1300
                                              },
                                              "src": 32,
                                              "dest": 53,
                                              "unknown1": 1,
                                              "unknown2": 1,
                                              "unknown4": 3,
                                              "cmdFunc": 20,
                                              "cmdId": 129,
                                              "unknown5": 3,
                                              "needAck": 1,
                                              "timestamp": {
                                                "low": 35061401,
                                                "high": 0,
                                                "unsigned": true
                                              },
                                              "unknown6": 19,
                                              "unknown7": 1,
                                              "OS": "ios",
                                              "serialNumber": "ABCxxxxxxx123"
                                            }
                                          }
                                          `
                                          await createMyState('app_' + mqttDaten.UserID + '_' + ConfigData.seriennummern[0].seriennummer + '_thing_property_set.setAC')
                                          on({ id: ConfigData.statesPrefix + '.app_' + mqttDaten.UserID + '_' + ConfigData.seriennummern[0].seriennummer + '_thing_property_set.setAC', change: "any", ack: false }, function (obj) {
                                              setAC(Number(obj.state.val))
                                              setState(obj.id, obj.state.val, true);
                                          });
                                          
                                          function setAC(Value = 1000) {
                                              const updatedMusterSetAC = JSON.parse(musterSetAC);
                                              updatedMusterSetAC.item.timestamp.low = Date.now().toString();
                                              updatedMusterSetAC.item.meta.value = Value
                                              updatedMusterSetAC.item.serialNumber = ConfigData.seriennummern[0].seriennummer
                                              SendProto(JSON.stringify(updatedMusterSetAC), '/app/' + mqttDaten.UserID + '/' + ConfigData.seriennummern[0].seriennummer + '/thing/property/set');
                                          }
                                          
                                          function generateAndSyncSub(id, JElements, sub = false, preset = "0_userdata.0.test") {
                                              if (!JElements || typeof JElements !== 'object') {
                                                  log('Ungültige JElements übergeben!');
                                                  return;
                                              }
                                              for (var JElement in JElements) {
                                                  var AktVal;
                                                  if (typeof JElements[JElement] === "object") {
                                                      generateAndSyncSub(id + "." + JElement, JElements[JElement], true, preset);
                                                  } else {
                                                      try {
                                                          if (isState2(preset + "." + id + "." + JElement)) AktVal = getState(preset + "." + id + "." + JElement).val;
                                                      } catch (e) {
                                                          log("Fehler: " + e);
                                                      }
                                                      if (AktVal == null) {
                                                          createState(preset + "." + id + "." + JElement, JElements[JElement], false);
                                                          AktVal = JElements[JElement];
                                                      }
                                                      if (AktVal != JElements[JElement]) {
                                                          if (isState2(preset + "." + id + "." + JElement)) setState(preset + "." + id + "." + JElement, JElements[JElement]);
                                                      }
                                                  }
                                              }
                                          }
                                          
                                          
                                          /**
                                           * Checks if a a given state or part of state is existing.
                                           * This is a workaround, as getObject() or getState() throw warnings in the log.
                                           * Set strict to true if the state shall match exactly. If it is false, it will add a wildcard * to the end.
                                           * See: https://forum.iobroker.net/topic/11354/
                                           * @param {string}    strStatePath     Input string of state, like 'javascript.0.switches.Osram.Bedroom'
                                           * @param {boolean}   [strict=false]   Optional: if true, it will work strict, if false, it will add a wildcard * to the end of the string
                                           * @return {boolean}                   true if state exists, false if not
                                           */
                                          function isState2(strStatePath, strict = true) {
                                              let mSelector;
                                              if (strict) {
                                                  mSelector = $(strStatePath);
                                              } else {
                                                  mSelector = $(strStatePath + "*");
                                              }
                                              if (mSelector.length > 0) {
                                                  return true;
                                              } else {
                                                  return false;
                                              }
                                          }
                                          
                                          
                                          // ########### Grundbedarf steuern
                                          // Es müssen Historydaten für den Wert des Smartmeters vorhanden sein, damit der niedrigeste wert der letzten x Minuten ermittelt werden kann
                                          
                                          function getLowestValue(id, minuten = 120) {
                                              return new Promise((resolve, reject) => {
                                                  const now = new Date().getTime();
                                                  const range = minuten * 60 * 1000;
                                                  var myresult = 0;
                                                  getHistory(0, {
                                                      id: id,
                                                      start: now - range,
                                                      end: now,
                                                      aggregate: 'minmax'
                                                  }, function (err, result) {
                                                      if (err) {
                                                          reject(err);
                                                      } else if (result.length) {
                                                          let lowestValue = result[0].val;
                                                          for (let i = 1; i < result.length; i++) {
                                                              if (result[i].val < lowestValue) {
                                                                  lowestValue = result[i].val;
                                                              }
                                                          }
                                                          myresult = Number(lowestValue);
                                                          resolve(myresult);
                                                      } else {
                                                          reject(new Error('No data'));
                                                      }
                                                  });
                                              });
                                          }
                                          
                                          function SetBasePower() {
                                              if (isState2(ConfigData.SmartmeterID)) {
                                                  getLowestValue(ConfigData.SmartmeterID, ConfigData.MinValueMin)
                                                      .then(lowestValue => {
                                                          if (lowestValue > 0) {
                                                              if (ConfigData.Debug) log("Tiefster Wert der letzten " + ConfigData.MinValueMin + " Minuten: " + lowestValue);
                                                              var AndereVerbraucher = 0
                                                              const ToHomeId = ConfigData.statesPrefix + ".app_device_property_" + ConfigData.seriennummern[0].seriennummer + ".data.item.meta.ToHome_Power"
                                                              if (isState2(ToHomeId)) {
                                                                  AndereVerbraucher = Number(getState(ToHomeId).val) / 10
                                                                  var NewValue = lowestValue + AndereVerbraucher - ConfigData.BasePowerOffset
                                                                  if (NewValue > ConfigData.MaxPower) NewValue = ConfigData.MaxPower
                                                                  if (ConfigData.Debug) {
                                                                      log("AndereVerbraucher: " + AndereVerbraucher)
                                                                      log("Macht : " + (lowestValue + AndereVerbraucher) + "W Grundbedarf")
                                                                      log("- Offset von: " + ConfigData.BasePowerOffset + " W = " + (NewValue) + " W Grundbedarf")
                                                                  }
                                                                  setAC(NewValue * 10);
                                          
                                                              }
                                                          }
                                                      })
                                                      .catch(error => {
                                                          log("Fehler beim Abrufen des niedrigsten Werts: " + error);
                                                      });
                                              }
                                          }
                                          
                                          
                                          A Offline
                                          A Offline
                                          applepro
                                          schrieb am zuletzt editiert von
                                          #161

                                          @waly_de Wow!!! Besten Dank von meiner Seite, ich wollte Ihn gerade testen, jedoch bekomme ich auch eine ähnliche Fehlermedlung:

                                          08:59:38.144	error	javascript.0 (444) script.js.Solar.Abfrage_MQTT: Error: illegal token '{' (line 3)
                                          08:59:38.145	error	javascript.0 (444) at decodeAndPrint (script.js.Solar.Abfrage_MQTT:314:27)
                                          08:59:38.145	error	javascript.0 (444) at MqttClient.<anonymous> (script.js.Solar.Abfrage_MQTT:278:32)
                                          

                                          Vielen Dank schon einmal für deine Hilfe 🙂

                                          Ich hatte mir in der Zwischenzeit alle States als HEX ausgelesen und mir so behelfsweise eine kurzes Skript geschrieben, welches mit Hilfe meines Powerfox Meters den jeweiligen Buffer sendet und so die Leistung anpasst, leider musste ich immer den aktuellen Einspeisewert fortschreiben, da ich diese ja nicht auslesen konnte.

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


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          403

                                          Online

                                          32.4k

                                          Benutzer

                                          81.4k

                                          Themen

                                          1.3m

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

                                          • Du hast noch kein Konto? Registrieren

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