Weiter zum Inhalt
  • Home
  • Aktuell
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Hell
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dunkel
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

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

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. Node-Red
  5. ich brauche etwas Nachhilfe mit Node Red und RS232

NEWS

  • Monatsrückblick Juli / August 2026 ist online!
    BluefoxB
    Bluefox
    10
    1
    1.0k

  • Der neue Monatsrückblick für Mai und Juni 2026 ist online!
    BluefoxB
    Bluefox
    8
    1
    1.4k

  • wichtiges UPDATE für controller 7.2.2 im stable
    HomoranH
    Homoran
    11
    1
    3.9k

ich brauche etwas Nachhilfe mit Node Red und RS232

Geplant Angeheftet Gesperrt Verschoben Node-Red
77 Beiträge 6 Kommentatoren 1.2k Aufrufe 4 Beobachtet
  • Ä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.
  • OliverIOO OliverIO

    @andibr

    Ich habe mir nochmal das Bild mit dem Node Flow und dem debug Screen rechts angeschaut.
    Da gibt die debug node undefined aus.
    Das ist natürlich kein String.
    Dann müsste an den Anfang der function node sowas rein

    if (msg.payload == undefined) return;
    

    Das sorgt dafür das keine neue msg generiert wird, wenn keine auswertbare Information kommt.
    Das filtert dann das aus.

    Kann das leider nicht testen, da aktuell kein Node red verfügbar

    mickymM Online
    mickymM Online
    mickym
    Most Active
    schrieb am zuletzt editiert von
    #49

    @OliverIO Wie meist, kann man das aber auch mit einer switch Node filtern und braucht dazu kein Javascript.

    a2e9a403-3763-473b-abfe-25e73ac31c57-image.jpeg

    Jeder Flow bzw. jedes Script, das ich hier poste implementiert jeder auf eigene Gefahr. Flows und Scripts können Fehler aufweisen und weder der Seitenbetreiber noch ich persönlich können hierfür haftbar gemacht werden. Das gleiche gilt für Empfehlungen aller Art.

    OliverIOO 1 Antwort Letzte Antwort
    0
    • mickymM mickym

      @OliverIO Wie meist, kann man das aber auch mit einer switch Node filtern und braucht dazu kein Javascript.

      a2e9a403-3763-473b-abfe-25e73ac31c57-image.jpeg

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

      @mickym

      Theoretisch schon
      Bin gerade nicht am Rechner
      Weiß nicht was man da auswählen kann
      Irgend was mit

      Ist
      Oder
      Ist nicht
      Oder
      Ist vom typ

      Und bei Typ
      Undefined

      Dann einen Ausgang entsprechend der Logik verdrahten so das die undefined Message ins Leere läuft

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

      mickymM 1 Antwort Letzte Antwort
      0
      • OliverIOO OliverIO

        @mickym

        Theoretisch schon
        Bin gerade nicht am Rechner
        Weiß nicht was man da auswählen kann
        Irgend was mit

        Ist
        Oder
        Ist nicht
        Oder
        Ist vom typ

        Und bei Typ
        Undefined

        Dann einen Ausgang entsprechend der Logik verdrahten so das die undefined Message ins Leere läuft

        mickymM Online
        mickymM Online
        mickym
        Most Active
        schrieb am zuletzt editiert von mickym
        #51

        @OliverIO Ich habe doch einen Screenshot gemacht. So kommen nur Strings durch. Kein undefined, Numbers etc., aber ich will mich da nicht in Eure Diskussion einmischen. Das ist ja nur ein Nebenschauplatz

        Jeder Flow bzw. jedes Script, das ich hier poste implementiert jeder auf eigene Gefahr. Flows und Scripts können Fehler aufweisen und weder der Seitenbetreiber noch ich persönlich können hierfür haftbar gemacht werden. Das gleiche gilt für Empfehlungen aller Art.

        OliverIOO 1 Antwort Letzte Antwort
        0
        • mickymM mickym

          @OliverIO Ich habe doch einen Screenshot gemacht. So kommen nur Strings durch. Kein undefined, Numbers etc., aber ich will mich da nicht in Eure Diskussion einmischen. Das ist ja nur ein Nebenschauplatz

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

          @mickym
          Wenn es String ist
          Könnte auch
          buffer
          Sein
          Kann mich nicht mehr erinnern

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

          mickymM 1 Antwort Letzte Antwort
          0
          • OliverIOO OliverIO

            @mickym
            Wenn es String ist
            Könnte auch
            buffer
            Sein
            Kann mich nicht mehr erinnern

            mickymM Online
            mickymM Online
            mickym
            Most Active
            schrieb am zuletzt editiert von
            #53

            @OliverIO Man kann auch undefined an Ausgang 1 schicken und ins Leere laufen lassen und den Rest weiterverarbeiten:

            ace69e52-9d5f-4f1c-8a52-7a7cf080908e-image.jpeg

            Jeder Flow bzw. jedes Script, das ich hier poste implementiert jeder auf eigene Gefahr. Flows und Scripts können Fehler aufweisen und weder der Seitenbetreiber noch ich persönlich können hierfür haftbar gemacht werden. Das gleiche gilt für Empfehlungen aller Art.

            1 Antwort Letzte Antwort
            0
            • P Offline
              P Offline
              peterfido
              schrieb am zuletzt editiert von
              #54

              So wie @mickym schreibt, ist es doch in meinem Beispiel-Code weiter oben.

              Gruß

              Peterfido

              A 1 Antwort Letzte Antwort
              0
              • P peterfido

                So wie @mickym schreibt, ist es doch in meinem Beispiel-Code weiter oben.

                A Offline
                A Offline
                andibr
                schrieb am zuletzt editiert von andibr
                #55

                Soweit ich das bis jetzt begriffen habe, gibt es mehrere Probleme mit meinem Flow:

                1. Das BMS sendet irgendwann plötzlich nicht mehr korrekte Daten.
                2. Der Flow verliert bei mir nach ca.36h Betrieb irgendwie die Synchronisation und blockiert bei mir irgendwie den ganzen Iobroker. Es entstehen hunderte Fehlermeldungen mit Bezug zum Node Red.
                3. Scheinbar gibt es da auch ein Problem beim so Datenschreiben in die Datenpunkte. Weil zu viele Daten angeblich im Node Red im Cash hängenbleiben und nicht gelöscht werden ( zumindest behauptet ein KI das).
                  Ich habe irgendwie kapituliert, weil ich nicht begreife wie das zu machen ist

                Ich habe mir auch überlegt, ob man allenfalls mit der msg.payload gleich eine Globale Variable schreiben könnte und danach diesen Inhalt im Node der die einzelne Listen Einträge erstellt, im Topic einsetzen. Konkret stelle ich mir das so vor: beim payload "bat 1" soll die Varaible auf den Wert "1" gesetzt. Und dann als Block 1 in die Topic eingesetzt werden. Bei "bat 2" dann eine "2" etc. Damit könnte man alle abfragen eben über den gleichen RS232 Node machen und hätte auch da nicht 8stk.

                1 Antwort Letzte Antwort
                0
                • P Offline
                  P Offline
                  peterfido
                  schrieb am zuletzt editiert von
                  #56

                  Hast du mein Beispiel ausprobiert? Evtl. Die kurzen Intervalle verlängern, wenn das tatsächlich zu schnell sein sollte. Und halt die Schnittstelle wieder anpassen.

                  Gruß

                  Peterfido

                  A 1 Antwort Letzte Antwort
                  0
                  • P peterfido

                    Hast du mein Beispiel ausprobiert? Evtl. Die kurzen Intervalle verlängern, wenn das tatsächlich zu schnell sein sollte. Und halt die Schnittstelle wieder anpassen.

                    A Offline
                    A Offline
                    andibr
                    schrieb am zuletzt editiert von
                    #57

                    @peterfido
                    Ja, habe ich, auch da verliert sich irgendwas mit der Laufzeit.

                    Ich habe auch festgestellt, dass genau der gleiche Fehler mit der synchronisation geschieht, wenn ich alle 15min einfach nur den "bat 1" sende. Die Laufzeit bis zum Fehler ist etwas länger aber, bei mir läuft er genau gleich rein, dass Node Red den erhaltenen String nicht mehr erkennen kann. Optisch sieht er identisch aus. Was ich mir überlegt habe, aber noch keine Beispiele gefunden habe, wenn man innerhalb von 24h den ganzen Flow automatisch deaktiviert und neu startet, sollte doch die synchronisation stabil bleiben? Das könnte man ja auch 2x am Tag machen.

                    P 1 Antwort Letzte Antwort
                    0
                    • A andibr

                      @peterfido
                      Ja, habe ich, auch da verliert sich irgendwas mit der Laufzeit.

                      Ich habe auch festgestellt, dass genau der gleiche Fehler mit der synchronisation geschieht, wenn ich alle 15min einfach nur den "bat 1" sende. Die Laufzeit bis zum Fehler ist etwas länger aber, bei mir läuft er genau gleich rein, dass Node Red den erhaltenen String nicht mehr erkennen kann. Optisch sieht er identisch aus. Was ich mir überlegt habe, aber noch keine Beispiele gefunden habe, wenn man innerhalb von 24h den ganzen Flow automatisch deaktiviert und neu startet, sollte doch die synchronisation stabil bleiben? Das könnte man ja auch 2x am Tag machen.

                      P Offline
                      P Offline
                      peterfido
                      schrieb am zuletzt editiert von
                      #58

                      @andibr sagte:

                      Optisch sieht er identisch aus

                      Evtl. nicht druckbare Sonderzeichen wie \n oder \r.

                      Die mal rausfiltern.

                      Gruß

                      Peterfido

                      A 1 Antwort Letzte Antwort
                      0
                      • P peterfido

                        @andibr sagte:

                        Optisch sieht er identisch aus

                        Evtl. nicht druckbare Sonderzeichen wie \n oder \r.

                        Die mal rausfiltern.

                        A Offline
                        A Offline
                        andibr
                        schrieb zuletzt editiert von
                        #59

                        @peterfido

                        node-red.0
                        	2026-09-05 11:08:03.860	warn	Node-RED: 5 Sep 11:08:03 - [warn] [function:convert to msgs] Zeile konnte nicht verarbeitet werden: 6 3355 28000 Charge Normal Normal
                        

                        So sieht die sporadische Fehlermeldung aus, wenn ich nun einfach den Node-Red Adapter neu restarte, läuft der Fehler weiter. Wenn ich aber stoppe und nach 5 min wieder starte läuft das ganze wieder korrekt an und besorgt mir völlig einwandfrei die Daten der einzelnen Zelle aus dem BMS. Irgendwann "stolpert" es dann wieder und erholt sich nicht mehr, bis ich wieder von Hand beende, warte und neu starte.

                        Da ich unterdessen auch verstanden habe wie das mit den Flow internen Variablen geht, habe ich mir auch den Flow noch etwas angepasst, dass er immer über den gleich Node mit dem BMS spricht:

                        Bildschirmfoto vom 2026-09-05 11-17-20.png

                        [
                            {
                                "id": "fd0e1b9d5e8f38e7",
                                "type": "tab",
                                "label": "Pytes_versuch",
                                "disabled": false,
                                "info": "",
                                "env": []
                            },
                            {
                                "id": "0725f77f48adb00d",
                                "type": "inject",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "Start Impuls",
                                "props": [
                                    {
                                        "p": "payload"
                                    }
                                ],
                                "repeat": "960",
                                "crontab": "",
                                "once": false,
                                "onceDelay": 0.1,
                                "topic": "",
                                "payload": "bat",
                                "payloadType": "str",
                                "x": 170,
                                "y": 60,
                                "wires": [
                                    [
                                        "965091ecae19a61f",
                                        "5af860489a0ca8d6",
                                        "aa0d423ef5fb8b59",
                                        "8b3a606685be0e29",
                                        "c3e1d9fe4343fb1c",
                                        "60d510edaebfaf58",
                                        "7493a195ec9b0478",
                                        "3136b0f19f41290c"
                                    ]
                                ]
                            },
                            {
                                "id": "d4771e7ca56cc341",
                                "type": "trigger",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 1",
                                "op1": "bat 1",
                                "op2": "",
                                "op1type": "str",
                                "op2type": "nul",
                                "duration": "250",
                                "extend": false,
                                "overrideDelay": false,
                                "units": "ms",
                                "reset": "",
                                "bytopic": "all",
                                "topic": "topic",
                                "outputs": 1,
                                "x": 850,
                                "y": 60,
                                "wires": [
                                    [
                                        "9b4a80b077795ae6"
                                    ]
                                ]
                            },
                            {
                                "id": "9b4a80b077795ae6",
                                "type": "serial request",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "BMSMaster",
                                "serial": "d031dd424e7b1ff2",
                                "x": 1150,
                                "y": 60,
                                "wires": [
                                    [
                                        "084e769979be04b4"
                                    ]
                                ]
                            },
                            {
                                "id": "084e769979be04b4",
                                "type": "function",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "convert to msgs",
                                "func": "const text = msg.payload;\n\nif (typeof text !== \"string\") {\n    node.error(\"msg.payload ist kein String\", msg);\n    return null;\n}\n\n// In einzelne Zeilen zerlegen\nconst lines = text\n    .split(/\\r?\\n/)\n    .map(line => line.trim())\n    .filter(line => line !== \"\");\n\n// Nur Zeilen berücksichtigen, die mit einer Batterienummer beginnen\nconst dataLines = lines.filter(line => /^\\d+\\s/.test(line));\n\nconst messages = [];\n\nfor (const line of dataLines) {\n\n    // Spalten sind durch mindestens 2 Leerzeichen getrennt\n    const columns = line.split(/\\s{2,}/);\n\n    if (columns.length < 9) {\n        node.warn(\"Zeile konnte nicht verarbeitet werden: \" + line);\n        continue;\n    }\n\n    const battery = {\n        battery: Number(columns[0]),\n        volt: Number(columns[1]),\n        tempr: Number(columns[2]),\n        baseState: columns[3],\n        voltState: columns[4],\n        currState: columns[5],\n        tempState: columns[6],\n        coulomb: Number(columns[7].replace(\"%\", \"\")),\n        capacity: Number(columns[8].replace(/[^\\d]/g, \"\"))\n    };\n\n    messages.push({\n        ...msg,\n        payload: battery\n    });\n}\n\n// Alle Nachrichten nacheinander über denselben Ausgang senden\nreturn [messages];",
                                "outputs": 1,
                                "timeout": 0,
                                "noerr": 0,
                                "initialize": "",
                                "finalize": "",
                                "libs": [],
                                "x": 1340,
                                "y": 60,
                                "wires": [
                                    [
                                        "63e1f64bbbcad67b"
                                    ]
                                ]
                            },
                            {
                                "id": "e493dc9ec265d760",
                                "type": "debug",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "debug 4",
                                "active": false,
                                "tosidebar": true,
                                "console": false,
                                "tostatus": false,
                                "complete": "true",
                                "targetType": "full",
                                "statusVal": "",
                                "statusType": "auto",
                                "x": 1760,
                                "y": 120,
                                "wires": []
                            },
                            {
                                "id": "bbb74bde5e74901e",
                                "type": "ioBroker out",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "",
                                "topic": "",
                                "ack": "true",
                                "autoCreate": "true",
                                "stateName": "",
                                "role": "",
                                "payloadType": "",
                                "readonly": "",
                                "stateUnit": "",
                                "stateMin": "",
                                "stateMax": "",
                                "x": 1780,
                                "y": 60,
                                "wires": []
                            },
                            {
                                "id": "63e1f64bbbcad67b",
                                "type": "function",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "Nachrichten erzeugen",
                                "func": "var f_battery = flow.get(\"f_battery\");\n\nconst battery = msg.payload;\n\nif (!battery || battery.battery === undefined) {\n    node.error(\"Ungültiges Battery-Objekt\", msg);\n    return null;\n}\n\nconst batteryId = battery.battery;\n\nconst states = [\n    {\n        id: \"voltage\",\n        value: battery.volt,\n        name: \"Voltage\",\n        role: \"value.voltage\",\n        type: \"number\",\n        readonly: true,\n        unit: \"mV\",\n        min: 0\n    },\n    {\n        id: \"temperature\",\n        value: battery.tempr / 1000,\n        name: \"Temperature\",\n        role: \"value.temperature\",\n        type: \"number\",\n        readonly: true,\n        unit: \"°C\"\n    },\n    {\n        id: \"baseState\",\n        value: battery.baseState,\n        name: \"Base State\",\n        role: \"text\",\n        type: \"string\",\n        readonly: true\n    },\n    {\n        id: \"voltageState\",\n        value: battery.voltState,\n        name: \"Voltage State\",\n        role: \"text\",\n        type: \"string\",\n        readonly: true\n    },\n    {\n        id: \"currentState\",\n        value: battery.currState,\n        name: \"Current State\",\n        role: \"text\",\n        type: \"string\",\n        readonly: true\n    },\n    {\n        id: \"temperatureState\",\n        value: battery.tempState,\n        name: \"Temperature State\",\n        role: \"text\",\n        type: \"string\",\n        readonly: true\n    },\n    {\n        id: \"charge\",\n        value: battery.coulomb,\n        name: \"Charge\",\n        role: \"value.battery\",\n        type: \"number\",\n        readonly: true,\n        unit: \"%\",\n        min: 0,\n        max: 100\n    },\n    {\n        id: \"capacity\",\n        value: battery.capacity,\n        name: \"Capacity\",\n        role: \"value\",\n        type: \"number\",\n        readonly: true,\n        unit: \"mAh\",\n        min: 0\n    }\n];\n\nconst messages = [];\n\nfor (const state of states) {\n    const out = {\n        topic: `0_userdata.0.pytes.${f_battery}.${batteryId}.${state.id}`,\n        payload: state.value,\n\n        stateName: state.name,\n        stateRole: state.role,\n        stateType: state.type,\n        stateReadonly: state.readonly\n    };\n\n    if (state.unit !== undefined) {\n        out.stateUnit = state.unit;\n    }\n\n    if (state.min !== undefined) {\n        out.stateMin = state.min;\n    }\n\n    if (state.max !== undefined) {\n        out.stateMax = state.max;\n    }\n\n    messages.push(out);\n}\n\nreturn [messages];",
                                "outputs": 1,
                                "timeout": 0,
                                "noerr": 0,
                                "initialize": "",
                                "finalize": "",
                                "libs": [],
                                "x": 1560,
                                "y": 60,
                                "wires": [
                                    [
                                        "bbb74bde5e74901e",
                                        "e493dc9ec265d760"
                                    ]
                                ]
                            },
                            {
                                "id": "965091ecae19a61f",
                                "type": "function",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 1",
                                "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 1;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                "outputs": 1,
                                "timeout": 0,
                                "noerr": 0,
                                "initialize": "",
                                "finalize": "",
                                "libs": [],
                                "x": 710,
                                "y": 60,
                                "wires": [
                                    [
                                        "d4771e7ca56cc341"
                                    ]
                                ]
                            },
                            {
                                "id": "5eb67c7159449f61",
                                "type": "trigger",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 2",
                                "op1": "bat 2",
                                "op2": "",
                                "op1type": "str",
                                "op2type": "nul",
                                "duration": "250",
                                "extend": false,
                                "overrideDelay": false,
                                "units": "ms",
                                "reset": "",
                                "bytopic": "all",
                                "topic": "topic",
                                "outputs": 1,
                                "x": 850,
                                "y": 120,
                                "wires": [
                                    [
                                        "9b4a80b077795ae6"
                                    ]
                                ]
                            },
                            {
                                "id": "d5963b13a796be5b",
                                "type": "function",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 2",
                                "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 2;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                "outputs": 1,
                                "timeout": 0,
                                "noerr": 0,
                                "initialize": "",
                                "finalize": "",
                                "libs": [],
                                "x": 710,
                                "y": 120,
                                "wires": [
                                    [
                                        "5eb67c7159449f61"
                                    ]
                                ]
                            },
                            {
                                "id": "5af860489a0ca8d6",
                                "type": "delay",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "",
                                "pauseType": "delay",
                                "timeout": "2",
                                "timeoutUnits": "minutes",
                                "rate": "1",
                                "nbRateUnits": "1",
                                "rateUnits": "second",
                                "randomFirst": "1",
                                "randomLast": "5",
                                "randomUnits": "seconds",
                                "drop": false,
                                "allowrate": false,
                                "outputs": 1,
                                "x": 540,
                                "y": 120,
                                "wires": [
                                    [
                                        "d5963b13a796be5b"
                                    ]
                                ]
                            },
                            {
                                "id": "525ce06e7c8d7f00",
                                "type": "trigger",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 3",
                                "op1": "bat 3",
                                "op2": "",
                                "op1type": "str",
                                "op2type": "nul",
                                "duration": "250",
                                "extend": false,
                                "overrideDelay": false,
                                "units": "ms",
                                "reset": "",
                                "bytopic": "all",
                                "topic": "topic",
                                "outputs": 1,
                                "x": 850,
                                "y": 180,
                                "wires": [
                                    [
                                        "9b4a80b077795ae6"
                                    ]
                                ]
                            },
                            {
                                "id": "2b362ada582e91a8",
                                "type": "function",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 3",
                                "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 3;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                "outputs": 1,
                                "timeout": 0,
                                "noerr": 0,
                                "initialize": "",
                                "finalize": "",
                                "libs": [],
                                "x": 710,
                                "y": 180,
                                "wires": [
                                    [
                                        "525ce06e7c8d7f00"
                                    ]
                                ]
                            },
                            {
                                "id": "aa0d423ef5fb8b59",
                                "type": "delay",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "",
                                "pauseType": "delay",
                                "timeout": "4",
                                "timeoutUnits": "minutes",
                                "rate": "1",
                                "nbRateUnits": "1",
                                "rateUnits": "second",
                                "randomFirst": "1",
                                "randomLast": "5",
                                "randomUnits": "seconds",
                                "drop": false,
                                "allowrate": false,
                                "outputs": 1,
                                "x": 540,
                                "y": 180,
                                "wires": [
                                    [
                                        "2b362ada582e91a8"
                                    ]
                                ]
                            },
                            {
                                "id": "bde0642d556936e1",
                                "type": "trigger",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 4",
                                "op1": "bat 4",
                                "op2": "",
                                "op1type": "str",
                                "op2type": "nul",
                                "duration": "250",
                                "extend": false,
                                "overrideDelay": false,
                                "units": "ms",
                                "reset": "",
                                "bytopic": "all",
                                "topic": "topic",
                                "outputs": 1,
                                "x": 850,
                                "y": 240,
                                "wires": [
                                    [
                                        "9b4a80b077795ae6"
                                    ]
                                ]
                            },
                            {
                                "id": "6f49131c2bfe6838",
                                "type": "function",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 4",
                                "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 4;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                "outputs": 1,
                                "timeout": 0,
                                "noerr": 0,
                                "initialize": "",
                                "finalize": "",
                                "libs": [],
                                "x": 710,
                                "y": 240,
                                "wires": [
                                    [
                                        "bde0642d556936e1"
                                    ]
                                ]
                            },
                            {
                                "id": "8b3a606685be0e29",
                                "type": "delay",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "",
                                "pauseType": "delay",
                                "timeout": "6",
                                "timeoutUnits": "minutes",
                                "rate": "1",
                                "nbRateUnits": "1",
                                "rateUnits": "second",
                                "randomFirst": "1",
                                "randomLast": "5",
                                "randomUnits": "seconds",
                                "drop": false,
                                "allowrate": false,
                                "outputs": 1,
                                "x": 540,
                                "y": 240,
                                "wires": [
                                    [
                                        "6f49131c2bfe6838"
                                    ]
                                ]
                            },
                            {
                                "id": "ab304046d710cbd9",
                                "type": "trigger",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 5",
                                "op1": "bat 5",
                                "op2": "",
                                "op1type": "str",
                                "op2type": "nul",
                                "duration": "250",
                                "extend": false,
                                "overrideDelay": false,
                                "units": "ms",
                                "reset": "",
                                "bytopic": "all",
                                "topic": "topic",
                                "outputs": 1,
                                "x": 850,
                                "y": 300,
                                "wires": [
                                    [
                                        "9b4a80b077795ae6"
                                    ]
                                ]
                            },
                            {
                                "id": "c34c33f5ab5129ae",
                                "type": "function",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 5",
                                "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 5;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                "outputs": 1,
                                "timeout": 0,
                                "noerr": 0,
                                "initialize": "",
                                "finalize": "",
                                "libs": [],
                                "x": 710,
                                "y": 300,
                                "wires": [
                                    [
                                        "ab304046d710cbd9"
                                    ]
                                ]
                            },
                            {
                                "id": "c3e1d9fe4343fb1c",
                                "type": "delay",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "",
                                "pauseType": "delay",
                                "timeout": "8",
                                "timeoutUnits": "minutes",
                                "rate": "1",
                                "nbRateUnits": "1",
                                "rateUnits": "second",
                                "randomFirst": "1",
                                "randomLast": "5",
                                "randomUnits": "seconds",
                                "drop": false,
                                "allowrate": false,
                                "outputs": 1,
                                "x": 540,
                                "y": 300,
                                "wires": [
                                    [
                                        "c34c33f5ab5129ae"
                                    ]
                                ]
                            },
                            {
                                "id": "3861e08a573a6b5e",
                                "type": "trigger",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 6",
                                "op1": "bat 6",
                                "op2": "",
                                "op1type": "str",
                                "op2type": "nul",
                                "duration": "250",
                                "extend": false,
                                "overrideDelay": false,
                                "units": "ms",
                                "reset": "",
                                "bytopic": "all",
                                "topic": "topic",
                                "outputs": 1,
                                "x": 850,
                                "y": 360,
                                "wires": [
                                    [
                                        "9b4a80b077795ae6"
                                    ]
                                ]
                            },
                            {
                                "id": "9ef24a26f9cff219",
                                "type": "function",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 6",
                                "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 6;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                "outputs": 1,
                                "timeout": 0,
                                "noerr": 0,
                                "initialize": "",
                                "finalize": "",
                                "libs": [],
                                "x": 710,
                                "y": 360,
                                "wires": [
                                    [
                                        "3861e08a573a6b5e"
                                    ]
                                ]
                            },
                            {
                                "id": "60d510edaebfaf58",
                                "type": "delay",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "",
                                "pauseType": "delay",
                                "timeout": "10",
                                "timeoutUnits": "minutes",
                                "rate": "1",
                                "nbRateUnits": "1",
                                "rateUnits": "second",
                                "randomFirst": "1",
                                "randomLast": "5",
                                "randomUnits": "seconds",
                                "drop": false,
                                "allowrate": false,
                                "outputs": 1,
                                "x": 550,
                                "y": 360,
                                "wires": [
                                    [
                                        "9ef24a26f9cff219"
                                    ]
                                ]
                            },
                            {
                                "id": "ae418dbd1af6f93d",
                                "type": "trigger",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 7",
                                "op1": "bat 7",
                                "op2": "",
                                "op1type": "str",
                                "op2type": "nul",
                                "duration": "250",
                                "extend": false,
                                "overrideDelay": false,
                                "units": "ms",
                                "reset": "",
                                "bytopic": "all",
                                "topic": "topic",
                                "outputs": 1,
                                "x": 850,
                                "y": 420,
                                "wires": [
                                    [
                                        "9b4a80b077795ae6"
                                    ]
                                ]
                            },
                            {
                                "id": "d12adb85188adfad",
                                "type": "function",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 7",
                                "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 7;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                "outputs": 1,
                                "timeout": 0,
                                "noerr": 0,
                                "initialize": "",
                                "finalize": "",
                                "libs": [],
                                "x": 710,
                                "y": 420,
                                "wires": [
                                    [
                                        "ae418dbd1af6f93d"
                                    ]
                                ]
                            },
                            {
                                "id": "7493a195ec9b0478",
                                "type": "delay",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "",
                                "pauseType": "delay",
                                "timeout": "12",
                                "timeoutUnits": "minutes",
                                "rate": "1",
                                "nbRateUnits": "1",
                                "rateUnits": "second",
                                "randomFirst": "1",
                                "randomLast": "5",
                                "randomUnits": "seconds",
                                "drop": false,
                                "allowrate": false,
                                "outputs": 1,
                                "x": 550,
                                "y": 420,
                                "wires": [
                                    [
                                        "d12adb85188adfad"
                                    ]
                                ]
                            },
                            {
                                "id": "95b46b37d98c2fe9",
                                "type": "trigger",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 8",
                                "op1": "bat 8",
                                "op2": "",
                                "op1type": "str",
                                "op2type": "nul",
                                "duration": "250",
                                "extend": false,
                                "overrideDelay": false,
                                "units": "ms",
                                "reset": "",
                                "bytopic": "all",
                                "topic": "topic",
                                "outputs": 1,
                                "x": 850,
                                "y": 480,
                                "wires": [
                                    [
                                        "9b4a80b077795ae6"
                                    ]
                                ]
                            },
                            {
                                "id": "fd827c1f7990d37f",
                                "type": "function",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "bat 8",
                                "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 8;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                "outputs": 1,
                                "timeout": 0,
                                "noerr": 0,
                                "initialize": "",
                                "finalize": "",
                                "libs": [],
                                "x": 710,
                                "y": 480,
                                "wires": [
                                    [
                                        "95b46b37d98c2fe9"
                                    ]
                                ]
                            },
                            {
                                "id": "3136b0f19f41290c",
                                "type": "delay",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "",
                                "pauseType": "delay",
                                "timeout": "14",
                                "timeoutUnits": "minutes",
                                "rate": "1",
                                "nbRateUnits": "1",
                                "rateUnits": "second",
                                "randomFirst": "1",
                                "randomLast": "5",
                                "randomUnits": "seconds",
                                "drop": false,
                                "allowrate": false,
                                "outputs": 1,
                                "x": 550,
                                "y": 480,
                                "wires": [
                                    [
                                        "fd827c1f7990d37f"
                                    ]
                                ]
                            },
                            {
                                "id": "7b063aef497a8a52",
                                "type": "catch",
                                "z": "fd0e1b9d5e8f38e7",
                                "name": "",
                                "scope": "group",
                                "uncaught": false,
                                "x": 210,
                                "y": 520,
                                "wires": [
                                    []
                                ]
                            },
                            {
                                "id": "d031dd424e7b1ff2",
                                "type": "serial-port",
                                "name": "Pytes",
                                "serialport": "/dev/serial/by-id/usb-FTDI_USB_Serial_Converter_FTFS8I5L-if00-port0",
                                "serialbaud": "115200",
                                "databits": 8,
                                "parity": "none",
                                "stopbits": 1,
                                "waitfor": "@",
                                "dtr": "none",
                                "rts": "none",
                                "cts": "none",
                                "dsr": "none",
                                "newline": "250",
                                "bin": "false",
                                "out": "time",
                                "addchar": "\\r\\n",
                                "responsetimeout": "250"
                            },
                            {
                                "id": "5395ceba9a814106",
                                "type": "global-config",
                                "env": [],
                                "modules": {
                                    "node-red-node-serialport": "2.0.3"
                                }
                            }
                        ]
                        

                        Ebenfalls habe ich eingerichtet das der Adapter immer um 03.00 automatisch neu gestartet wird, leider lösst das aber scheinbar das Problem nicht, weil die Schnittstelle nicht "geschlossen" wird.

                        Bis jetzt habe ich keinen Node oder Anleitung gefunden mit der ich die Schnittstelle echt schliessen könnte. Ich behaupt nach wie vor, das mit der Zeit die Synchronisierung der Datenübertragung verloren geht und dadurch plötzlich unerwartete Zeichen im String auftauchen. Leider nützt es auch nichts die "Delay-Zeiten" zu verlängern.

                        Der catch habe ich irgendwo gelesen, dass der die Fehleranfälligkeit vermindern soll, aber davon habe ich bis jetzt nicht viel bemerkt. Mit und ohne das gleiche Fehlerbild und die gleiche Regelmässigkeit, ich gehe davon aus, dass es nicht für diese Art der Anwendung gedacht ist.

                        OliverIOO 1 Antwort Letzte Antwort
                        0
                        • A andibr

                          @peterfido

                          node-red.0
                          	2026-09-05 11:08:03.860	warn	Node-RED: 5 Sep 11:08:03 - [warn] [function:convert to msgs] Zeile konnte nicht verarbeitet werden: 6 3355 28000 Charge Normal Normal
                          

                          So sieht die sporadische Fehlermeldung aus, wenn ich nun einfach den Node-Red Adapter neu restarte, läuft der Fehler weiter. Wenn ich aber stoppe und nach 5 min wieder starte läuft das ganze wieder korrekt an und besorgt mir völlig einwandfrei die Daten der einzelnen Zelle aus dem BMS. Irgendwann "stolpert" es dann wieder und erholt sich nicht mehr, bis ich wieder von Hand beende, warte und neu starte.

                          Da ich unterdessen auch verstanden habe wie das mit den Flow internen Variablen geht, habe ich mir auch den Flow noch etwas angepasst, dass er immer über den gleich Node mit dem BMS spricht:

                          Bildschirmfoto vom 2026-09-05 11-17-20.png

                          [
                              {
                                  "id": "fd0e1b9d5e8f38e7",
                                  "type": "tab",
                                  "label": "Pytes_versuch",
                                  "disabled": false,
                                  "info": "",
                                  "env": []
                              },
                              {
                                  "id": "0725f77f48adb00d",
                                  "type": "inject",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "Start Impuls",
                                  "props": [
                                      {
                                          "p": "payload"
                                      }
                                  ],
                                  "repeat": "960",
                                  "crontab": "",
                                  "once": false,
                                  "onceDelay": 0.1,
                                  "topic": "",
                                  "payload": "bat",
                                  "payloadType": "str",
                                  "x": 170,
                                  "y": 60,
                                  "wires": [
                                      [
                                          "965091ecae19a61f",
                                          "5af860489a0ca8d6",
                                          "aa0d423ef5fb8b59",
                                          "8b3a606685be0e29",
                                          "c3e1d9fe4343fb1c",
                                          "60d510edaebfaf58",
                                          "7493a195ec9b0478",
                                          "3136b0f19f41290c"
                                      ]
                                  ]
                              },
                              {
                                  "id": "d4771e7ca56cc341",
                                  "type": "trigger",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 1",
                                  "op1": "bat 1",
                                  "op2": "",
                                  "op1type": "str",
                                  "op2type": "nul",
                                  "duration": "250",
                                  "extend": false,
                                  "overrideDelay": false,
                                  "units": "ms",
                                  "reset": "",
                                  "bytopic": "all",
                                  "topic": "topic",
                                  "outputs": 1,
                                  "x": 850,
                                  "y": 60,
                                  "wires": [
                                      [
                                          "9b4a80b077795ae6"
                                      ]
                                  ]
                              },
                              {
                                  "id": "9b4a80b077795ae6",
                                  "type": "serial request",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "BMSMaster",
                                  "serial": "d031dd424e7b1ff2",
                                  "x": 1150,
                                  "y": 60,
                                  "wires": [
                                      [
                                          "084e769979be04b4"
                                      ]
                                  ]
                              },
                              {
                                  "id": "084e769979be04b4",
                                  "type": "function",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "convert to msgs",
                                  "func": "const text = msg.payload;\n\nif (typeof text !== \"string\") {\n    node.error(\"msg.payload ist kein String\", msg);\n    return null;\n}\n\n// In einzelne Zeilen zerlegen\nconst lines = text\n    .split(/\\r?\\n/)\n    .map(line => line.trim())\n    .filter(line => line !== \"\");\n\n// Nur Zeilen berücksichtigen, die mit einer Batterienummer beginnen\nconst dataLines = lines.filter(line => /^\\d+\\s/.test(line));\n\nconst messages = [];\n\nfor (const line of dataLines) {\n\n    // Spalten sind durch mindestens 2 Leerzeichen getrennt\n    const columns = line.split(/\\s{2,}/);\n\n    if (columns.length < 9) {\n        node.warn(\"Zeile konnte nicht verarbeitet werden: \" + line);\n        continue;\n    }\n\n    const battery = {\n        battery: Number(columns[0]),\n        volt: Number(columns[1]),\n        tempr: Number(columns[2]),\n        baseState: columns[3],\n        voltState: columns[4],\n        currState: columns[5],\n        tempState: columns[6],\n        coulomb: Number(columns[7].replace(\"%\", \"\")),\n        capacity: Number(columns[8].replace(/[^\\d]/g, \"\"))\n    };\n\n    messages.push({\n        ...msg,\n        payload: battery\n    });\n}\n\n// Alle Nachrichten nacheinander über denselben Ausgang senden\nreturn [messages];",
                                  "outputs": 1,
                                  "timeout": 0,
                                  "noerr": 0,
                                  "initialize": "",
                                  "finalize": "",
                                  "libs": [],
                                  "x": 1340,
                                  "y": 60,
                                  "wires": [
                                      [
                                          "63e1f64bbbcad67b"
                                      ]
                                  ]
                              },
                              {
                                  "id": "e493dc9ec265d760",
                                  "type": "debug",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "debug 4",
                                  "active": false,
                                  "tosidebar": true,
                                  "console": false,
                                  "tostatus": false,
                                  "complete": "true",
                                  "targetType": "full",
                                  "statusVal": "",
                                  "statusType": "auto",
                                  "x": 1760,
                                  "y": 120,
                                  "wires": []
                              },
                              {
                                  "id": "bbb74bde5e74901e",
                                  "type": "ioBroker out",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "",
                                  "topic": "",
                                  "ack": "true",
                                  "autoCreate": "true",
                                  "stateName": "",
                                  "role": "",
                                  "payloadType": "",
                                  "readonly": "",
                                  "stateUnit": "",
                                  "stateMin": "",
                                  "stateMax": "",
                                  "x": 1780,
                                  "y": 60,
                                  "wires": []
                              },
                              {
                                  "id": "63e1f64bbbcad67b",
                                  "type": "function",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "Nachrichten erzeugen",
                                  "func": "var f_battery = flow.get(\"f_battery\");\n\nconst battery = msg.payload;\n\nif (!battery || battery.battery === undefined) {\n    node.error(\"Ungültiges Battery-Objekt\", msg);\n    return null;\n}\n\nconst batteryId = battery.battery;\n\nconst states = [\n    {\n        id: \"voltage\",\n        value: battery.volt,\n        name: \"Voltage\",\n        role: \"value.voltage\",\n        type: \"number\",\n        readonly: true,\n        unit: \"mV\",\n        min: 0\n    },\n    {\n        id: \"temperature\",\n        value: battery.tempr / 1000,\n        name: \"Temperature\",\n        role: \"value.temperature\",\n        type: \"number\",\n        readonly: true,\n        unit: \"°C\"\n    },\n    {\n        id: \"baseState\",\n        value: battery.baseState,\n        name: \"Base State\",\n        role: \"text\",\n        type: \"string\",\n        readonly: true\n    },\n    {\n        id: \"voltageState\",\n        value: battery.voltState,\n        name: \"Voltage State\",\n        role: \"text\",\n        type: \"string\",\n        readonly: true\n    },\n    {\n        id: \"currentState\",\n        value: battery.currState,\n        name: \"Current State\",\n        role: \"text\",\n        type: \"string\",\n        readonly: true\n    },\n    {\n        id: \"temperatureState\",\n        value: battery.tempState,\n        name: \"Temperature State\",\n        role: \"text\",\n        type: \"string\",\n        readonly: true\n    },\n    {\n        id: \"charge\",\n        value: battery.coulomb,\n        name: \"Charge\",\n        role: \"value.battery\",\n        type: \"number\",\n        readonly: true,\n        unit: \"%\",\n        min: 0,\n        max: 100\n    },\n    {\n        id: \"capacity\",\n        value: battery.capacity,\n        name: \"Capacity\",\n        role: \"value\",\n        type: \"number\",\n        readonly: true,\n        unit: \"mAh\",\n        min: 0\n    }\n];\n\nconst messages = [];\n\nfor (const state of states) {\n    const out = {\n        topic: `0_userdata.0.pytes.${f_battery}.${batteryId}.${state.id}`,\n        payload: state.value,\n\n        stateName: state.name,\n        stateRole: state.role,\n        stateType: state.type,\n        stateReadonly: state.readonly\n    };\n\n    if (state.unit !== undefined) {\n        out.stateUnit = state.unit;\n    }\n\n    if (state.min !== undefined) {\n        out.stateMin = state.min;\n    }\n\n    if (state.max !== undefined) {\n        out.stateMax = state.max;\n    }\n\n    messages.push(out);\n}\n\nreturn [messages];",
                                  "outputs": 1,
                                  "timeout": 0,
                                  "noerr": 0,
                                  "initialize": "",
                                  "finalize": "",
                                  "libs": [],
                                  "x": 1560,
                                  "y": 60,
                                  "wires": [
                                      [
                                          "bbb74bde5e74901e",
                                          "e493dc9ec265d760"
                                      ]
                                  ]
                              },
                              {
                                  "id": "965091ecae19a61f",
                                  "type": "function",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 1",
                                  "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 1;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                  "outputs": 1,
                                  "timeout": 0,
                                  "noerr": 0,
                                  "initialize": "",
                                  "finalize": "",
                                  "libs": [],
                                  "x": 710,
                                  "y": 60,
                                  "wires": [
                                      [
                                          "d4771e7ca56cc341"
                                      ]
                                  ]
                              },
                              {
                                  "id": "5eb67c7159449f61",
                                  "type": "trigger",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 2",
                                  "op1": "bat 2",
                                  "op2": "",
                                  "op1type": "str",
                                  "op2type": "nul",
                                  "duration": "250",
                                  "extend": false,
                                  "overrideDelay": false,
                                  "units": "ms",
                                  "reset": "",
                                  "bytopic": "all",
                                  "topic": "topic",
                                  "outputs": 1,
                                  "x": 850,
                                  "y": 120,
                                  "wires": [
                                      [
                                          "9b4a80b077795ae6"
                                      ]
                                  ]
                              },
                              {
                                  "id": "d5963b13a796be5b",
                                  "type": "function",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 2",
                                  "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 2;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                  "outputs": 1,
                                  "timeout": 0,
                                  "noerr": 0,
                                  "initialize": "",
                                  "finalize": "",
                                  "libs": [],
                                  "x": 710,
                                  "y": 120,
                                  "wires": [
                                      [
                                          "5eb67c7159449f61"
                                      ]
                                  ]
                              },
                              {
                                  "id": "5af860489a0ca8d6",
                                  "type": "delay",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "",
                                  "pauseType": "delay",
                                  "timeout": "2",
                                  "timeoutUnits": "minutes",
                                  "rate": "1",
                                  "nbRateUnits": "1",
                                  "rateUnits": "second",
                                  "randomFirst": "1",
                                  "randomLast": "5",
                                  "randomUnits": "seconds",
                                  "drop": false,
                                  "allowrate": false,
                                  "outputs": 1,
                                  "x": 540,
                                  "y": 120,
                                  "wires": [
                                      [
                                          "d5963b13a796be5b"
                                      ]
                                  ]
                              },
                              {
                                  "id": "525ce06e7c8d7f00",
                                  "type": "trigger",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 3",
                                  "op1": "bat 3",
                                  "op2": "",
                                  "op1type": "str",
                                  "op2type": "nul",
                                  "duration": "250",
                                  "extend": false,
                                  "overrideDelay": false,
                                  "units": "ms",
                                  "reset": "",
                                  "bytopic": "all",
                                  "topic": "topic",
                                  "outputs": 1,
                                  "x": 850,
                                  "y": 180,
                                  "wires": [
                                      [
                                          "9b4a80b077795ae6"
                                      ]
                                  ]
                              },
                              {
                                  "id": "2b362ada582e91a8",
                                  "type": "function",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 3",
                                  "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 3;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                  "outputs": 1,
                                  "timeout": 0,
                                  "noerr": 0,
                                  "initialize": "",
                                  "finalize": "",
                                  "libs": [],
                                  "x": 710,
                                  "y": 180,
                                  "wires": [
                                      [
                                          "525ce06e7c8d7f00"
                                      ]
                                  ]
                              },
                              {
                                  "id": "aa0d423ef5fb8b59",
                                  "type": "delay",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "",
                                  "pauseType": "delay",
                                  "timeout": "4",
                                  "timeoutUnits": "minutes",
                                  "rate": "1",
                                  "nbRateUnits": "1",
                                  "rateUnits": "second",
                                  "randomFirst": "1",
                                  "randomLast": "5",
                                  "randomUnits": "seconds",
                                  "drop": false,
                                  "allowrate": false,
                                  "outputs": 1,
                                  "x": 540,
                                  "y": 180,
                                  "wires": [
                                      [
                                          "2b362ada582e91a8"
                                      ]
                                  ]
                              },
                              {
                                  "id": "bde0642d556936e1",
                                  "type": "trigger",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 4",
                                  "op1": "bat 4",
                                  "op2": "",
                                  "op1type": "str",
                                  "op2type": "nul",
                                  "duration": "250",
                                  "extend": false,
                                  "overrideDelay": false,
                                  "units": "ms",
                                  "reset": "",
                                  "bytopic": "all",
                                  "topic": "topic",
                                  "outputs": 1,
                                  "x": 850,
                                  "y": 240,
                                  "wires": [
                                      [
                                          "9b4a80b077795ae6"
                                      ]
                                  ]
                              },
                              {
                                  "id": "6f49131c2bfe6838",
                                  "type": "function",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 4",
                                  "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 4;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                  "outputs": 1,
                                  "timeout": 0,
                                  "noerr": 0,
                                  "initialize": "",
                                  "finalize": "",
                                  "libs": [],
                                  "x": 710,
                                  "y": 240,
                                  "wires": [
                                      [
                                          "bde0642d556936e1"
                                      ]
                                  ]
                              },
                              {
                                  "id": "8b3a606685be0e29",
                                  "type": "delay",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "",
                                  "pauseType": "delay",
                                  "timeout": "6",
                                  "timeoutUnits": "minutes",
                                  "rate": "1",
                                  "nbRateUnits": "1",
                                  "rateUnits": "second",
                                  "randomFirst": "1",
                                  "randomLast": "5",
                                  "randomUnits": "seconds",
                                  "drop": false,
                                  "allowrate": false,
                                  "outputs": 1,
                                  "x": 540,
                                  "y": 240,
                                  "wires": [
                                      [
                                          "6f49131c2bfe6838"
                                      ]
                                  ]
                              },
                              {
                                  "id": "ab304046d710cbd9",
                                  "type": "trigger",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 5",
                                  "op1": "bat 5",
                                  "op2": "",
                                  "op1type": "str",
                                  "op2type": "nul",
                                  "duration": "250",
                                  "extend": false,
                                  "overrideDelay": false,
                                  "units": "ms",
                                  "reset": "",
                                  "bytopic": "all",
                                  "topic": "topic",
                                  "outputs": 1,
                                  "x": 850,
                                  "y": 300,
                                  "wires": [
                                      [
                                          "9b4a80b077795ae6"
                                      ]
                                  ]
                              },
                              {
                                  "id": "c34c33f5ab5129ae",
                                  "type": "function",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 5",
                                  "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 5;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                  "outputs": 1,
                                  "timeout": 0,
                                  "noerr": 0,
                                  "initialize": "",
                                  "finalize": "",
                                  "libs": [],
                                  "x": 710,
                                  "y": 300,
                                  "wires": [
                                      [
                                          "ab304046d710cbd9"
                                      ]
                                  ]
                              },
                              {
                                  "id": "c3e1d9fe4343fb1c",
                                  "type": "delay",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "",
                                  "pauseType": "delay",
                                  "timeout": "8",
                                  "timeoutUnits": "minutes",
                                  "rate": "1",
                                  "nbRateUnits": "1",
                                  "rateUnits": "second",
                                  "randomFirst": "1",
                                  "randomLast": "5",
                                  "randomUnits": "seconds",
                                  "drop": false,
                                  "allowrate": false,
                                  "outputs": 1,
                                  "x": 540,
                                  "y": 300,
                                  "wires": [
                                      [
                                          "c34c33f5ab5129ae"
                                      ]
                                  ]
                              },
                              {
                                  "id": "3861e08a573a6b5e",
                                  "type": "trigger",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 6",
                                  "op1": "bat 6",
                                  "op2": "",
                                  "op1type": "str",
                                  "op2type": "nul",
                                  "duration": "250",
                                  "extend": false,
                                  "overrideDelay": false,
                                  "units": "ms",
                                  "reset": "",
                                  "bytopic": "all",
                                  "topic": "topic",
                                  "outputs": 1,
                                  "x": 850,
                                  "y": 360,
                                  "wires": [
                                      [
                                          "9b4a80b077795ae6"
                                      ]
                                  ]
                              },
                              {
                                  "id": "9ef24a26f9cff219",
                                  "type": "function",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 6",
                                  "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 6;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                  "outputs": 1,
                                  "timeout": 0,
                                  "noerr": 0,
                                  "initialize": "",
                                  "finalize": "",
                                  "libs": [],
                                  "x": 710,
                                  "y": 360,
                                  "wires": [
                                      [
                                          "3861e08a573a6b5e"
                                      ]
                                  ]
                              },
                              {
                                  "id": "60d510edaebfaf58",
                                  "type": "delay",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "",
                                  "pauseType": "delay",
                                  "timeout": "10",
                                  "timeoutUnits": "minutes",
                                  "rate": "1",
                                  "nbRateUnits": "1",
                                  "rateUnits": "second",
                                  "randomFirst": "1",
                                  "randomLast": "5",
                                  "randomUnits": "seconds",
                                  "drop": false,
                                  "allowrate": false,
                                  "outputs": 1,
                                  "x": 550,
                                  "y": 360,
                                  "wires": [
                                      [
                                          "9ef24a26f9cff219"
                                      ]
                                  ]
                              },
                              {
                                  "id": "ae418dbd1af6f93d",
                                  "type": "trigger",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 7",
                                  "op1": "bat 7",
                                  "op2": "",
                                  "op1type": "str",
                                  "op2type": "nul",
                                  "duration": "250",
                                  "extend": false,
                                  "overrideDelay": false,
                                  "units": "ms",
                                  "reset": "",
                                  "bytopic": "all",
                                  "topic": "topic",
                                  "outputs": 1,
                                  "x": 850,
                                  "y": 420,
                                  "wires": [
                                      [
                                          "9b4a80b077795ae6"
                                      ]
                                  ]
                              },
                              {
                                  "id": "d12adb85188adfad",
                                  "type": "function",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 7",
                                  "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 7;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                  "outputs": 1,
                                  "timeout": 0,
                                  "noerr": 0,
                                  "initialize": "",
                                  "finalize": "",
                                  "libs": [],
                                  "x": 710,
                                  "y": 420,
                                  "wires": [
                                      [
                                          "ae418dbd1af6f93d"
                                      ]
                                  ]
                              },
                              {
                                  "id": "7493a195ec9b0478",
                                  "type": "delay",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "",
                                  "pauseType": "delay",
                                  "timeout": "12",
                                  "timeoutUnits": "minutes",
                                  "rate": "1",
                                  "nbRateUnits": "1",
                                  "rateUnits": "second",
                                  "randomFirst": "1",
                                  "randomLast": "5",
                                  "randomUnits": "seconds",
                                  "drop": false,
                                  "allowrate": false,
                                  "outputs": 1,
                                  "x": 550,
                                  "y": 420,
                                  "wires": [
                                      [
                                          "d12adb85188adfad"
                                      ]
                                  ]
                              },
                              {
                                  "id": "95b46b37d98c2fe9",
                                  "type": "trigger",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 8",
                                  "op1": "bat 8",
                                  "op2": "",
                                  "op1type": "str",
                                  "op2type": "nul",
                                  "duration": "250",
                                  "extend": false,
                                  "overrideDelay": false,
                                  "units": "ms",
                                  "reset": "",
                                  "bytopic": "all",
                                  "topic": "topic",
                                  "outputs": 1,
                                  "x": 850,
                                  "y": 480,
                                  "wires": [
                                      [
                                          "9b4a80b077795ae6"
                                      ]
                                  ]
                              },
                              {
                                  "id": "fd827c1f7990d37f",
                                  "type": "function",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "bat 8",
                                  "func": "var f_battery = flow.get('f_battery') || 1;\nf_battery = 8;\nflow.set('f_battery', f_battery);\nmsg.payload=f_battery;\nreturn msg;",
                                  "outputs": 1,
                                  "timeout": 0,
                                  "noerr": 0,
                                  "initialize": "",
                                  "finalize": "",
                                  "libs": [],
                                  "x": 710,
                                  "y": 480,
                                  "wires": [
                                      [
                                          "95b46b37d98c2fe9"
                                      ]
                                  ]
                              },
                              {
                                  "id": "3136b0f19f41290c",
                                  "type": "delay",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "",
                                  "pauseType": "delay",
                                  "timeout": "14",
                                  "timeoutUnits": "minutes",
                                  "rate": "1",
                                  "nbRateUnits": "1",
                                  "rateUnits": "second",
                                  "randomFirst": "1",
                                  "randomLast": "5",
                                  "randomUnits": "seconds",
                                  "drop": false,
                                  "allowrate": false,
                                  "outputs": 1,
                                  "x": 550,
                                  "y": 480,
                                  "wires": [
                                      [
                                          "fd827c1f7990d37f"
                                      ]
                                  ]
                              },
                              {
                                  "id": "7b063aef497a8a52",
                                  "type": "catch",
                                  "z": "fd0e1b9d5e8f38e7",
                                  "name": "",
                                  "scope": "group",
                                  "uncaught": false,
                                  "x": 210,
                                  "y": 520,
                                  "wires": [
                                      []
                                  ]
                              },
                              {
                                  "id": "d031dd424e7b1ff2",
                                  "type": "serial-port",
                                  "name": "Pytes",
                                  "serialport": "/dev/serial/by-id/usb-FTDI_USB_Serial_Converter_FTFS8I5L-if00-port0",
                                  "serialbaud": "115200",
                                  "databits": 8,
                                  "parity": "none",
                                  "stopbits": 1,
                                  "waitfor": "@",
                                  "dtr": "none",
                                  "rts": "none",
                                  "cts": "none",
                                  "dsr": "none",
                                  "newline": "250",
                                  "bin": "false",
                                  "out": "time",
                                  "addchar": "\\r\\n",
                                  "responsetimeout": "250"
                              },
                              {
                                  "id": "5395ceba9a814106",
                                  "type": "global-config",
                                  "env": [],
                                  "modules": {
                                      "node-red-node-serialport": "2.0.3"
                                  }
                              }
                          ]
                          

                          Ebenfalls habe ich eingerichtet das der Adapter immer um 03.00 automatisch neu gestartet wird, leider lösst das aber scheinbar das Problem nicht, weil die Schnittstelle nicht "geschlossen" wird.

                          Bis jetzt habe ich keinen Node oder Anleitung gefunden mit der ich die Schnittstelle echt schliessen könnte. Ich behaupt nach wie vor, das mit der Zeit die Synchronisierung der Datenübertragung verloren geht und dadurch plötzlich unerwartete Zeichen im String auftauchen. Leider nützt es auch nichts die "Delay-Zeiten" zu verlängern.

                          Der catch habe ich irgendwo gelesen, dass der die Fehleranfälligkeit vermindern soll, aber davon habe ich bis jetzt nicht viel bemerkt. Mit und ohne das gleiche Fehlerbild und die gleiche Regelmässigkeit, ich gehe davon aus, dass es nicht für diese Art der Anwendung gedacht ist.

                          OliverIOO Offline
                          OliverIOO Offline
                          OliverIO
                          schrieb zuletzt editiert von
                          #60

                          @andibr

                          Woher kommt diese BMS Node?
                          Wie heißt das Paket?

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

                          A 1 Antwort Letzte Antwort
                          0
                          • OliverIOO OliverIO

                            @andibr

                            Woher kommt diese BMS Node?
                            Wie heißt das Paket?

                            A Offline
                            A Offline
                            andibr
                            schrieb zuletzt editiert von andibr
                            #61

                            @OliverIO
                            du meinst die eigentlich Schnittstelle?
                            Bildschirmfoto vom 2026-09-05 11-50-58.png

                            Bin mir nicht ganz sicher aber das kommt hier raus:
                            Bildschirmfoto vom 2026-09-05 11-52-58.png

                            Bin nur gerade am studieren ob ich da noch irgendwo Details finden kann?

                            Nachtrag:
                            Doch noch was gefunden:
                            https://flows.nodered.org/node/node-red-node-serialport

                            Habe aber auch überall gelesen, das man angeblich die Schnittstelle nicht zu schliessen braucht, dass kann ich irgendwie nicht mit meiner Erfahrung in EInklang bringen, aber vieleicht ist das heute wirklich so. Leider hat sich mein Raspberry verabschiedet (Hardwarefehler, bottet nicht mehr) und einen ganzen PC dort installieren ist dann doch etwas sehr aufwendig und mühevoll. Zumal es ja eigentlich geht und nur ziwischendurch sich sehr merkwürdig verhält.

                            Nachtrag 2
                            Soeben direkt aus dem Nod-Red den Fehler kopiert:

                            Zeile konnte nicht verarbeitet werden: 7        3385     27000    Charge
                            

                            Was auffällt: es beginnt meist mit einer neuen Zelle und nicht mitten drin.

                            OliverIOO 1 Antwort Letzte Antwort
                            0
                            • A andibr

                              @OliverIO
                              du meinst die eigentlich Schnittstelle?
                              Bildschirmfoto vom 2026-09-05 11-50-58.png

                              Bin mir nicht ganz sicher aber das kommt hier raus:
                              Bildschirmfoto vom 2026-09-05 11-52-58.png

                              Bin nur gerade am studieren ob ich da noch irgendwo Details finden kann?

                              Nachtrag:
                              Doch noch was gefunden:
                              https://flows.nodered.org/node/node-red-node-serialport

                              Habe aber auch überall gelesen, das man angeblich die Schnittstelle nicht zu schliessen braucht, dass kann ich irgendwie nicht mit meiner Erfahrung in EInklang bringen, aber vieleicht ist das heute wirklich so. Leider hat sich mein Raspberry verabschiedet (Hardwarefehler, bottet nicht mehr) und einen ganzen PC dort installieren ist dann doch etwas sehr aufwendig und mühevoll. Zumal es ja eigentlich geht und nur ziwischendurch sich sehr merkwürdig verhält.

                              Nachtrag 2
                              Soeben direkt aus dem Nod-Red den Fehler kopiert:

                              Zeile konnte nicht verarbeitet werden: 7        3385     27000    Charge
                              

                              Was auffällt: es beginnt meist mit einer neuen Zelle und nicht mitten drin.

                              OliverIOO Offline
                              OliverIOO Offline
                              OliverIO
                              schrieb zuletzt editiert von
                              #62

                              @andibr

                              Eventuell ist in der Übertragung immer noch etwas dabei, was durch die nodes Code nicht richtig interpretiert wird
                              Das bringt dann den Flow durcheinander.
                              Kannst du mal noch irgendwas einbauen, bei dem jeglicher Input in lesbarer Form der Reihe nach runter geschrieben wird?
                              Dann könnte man erkennen, was in den Daten vor dieser Fehlermeldung drin steht.

                              Hier habe ich ein Programm gefunden, dass ebenfalls per RS 232 mit deinem Gerät kommuniziert.
                              Da finde ich noch etwas von End Markers
                              https://github.com/chinezbrun/pytes_esp/blob/e93aa9d1d5b52c390bae7b207f8eae43ff56e132/esp32/main.py#L47
                              Das ist wohl was, was dein Gerät am Schluss noch sendet, um zu signalisieren, dass diese Nachricht erst einmal beendet ist.

                              Eventuell ist es das, was da rein pfuschelt
                              Ich denke aber nicht, dass es ein Problem mit der Kommunikation an sich ist. Nur in der richtigen Interpretation der Daten und bis wann alle Fälle abgedeckt hat.

                              Ich werde nachher mal noch deinen Flow importieren und mal noch mal durchschauen

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

                              A 1 Antwort Letzte Antwort
                              1
                              • OliverIOO OliverIO

                                @andibr

                                Eventuell ist in der Übertragung immer noch etwas dabei, was durch die nodes Code nicht richtig interpretiert wird
                                Das bringt dann den Flow durcheinander.
                                Kannst du mal noch irgendwas einbauen, bei dem jeglicher Input in lesbarer Form der Reihe nach runter geschrieben wird?
                                Dann könnte man erkennen, was in den Daten vor dieser Fehlermeldung drin steht.

                                Hier habe ich ein Programm gefunden, dass ebenfalls per RS 232 mit deinem Gerät kommuniziert.
                                Da finde ich noch etwas von End Markers
                                https://github.com/chinezbrun/pytes_esp/blob/e93aa9d1d5b52c390bae7b207f8eae43ff56e132/esp32/main.py#L47
                                Das ist wohl was, was dein Gerät am Schluss noch sendet, um zu signalisieren, dass diese Nachricht erst einmal beendet ist.

                                Eventuell ist es das, was da rein pfuschelt
                                Ich denke aber nicht, dass es ein Problem mit der Kommunikation an sich ist. Nur in der richtigen Interpretation der Daten und bis wann alle Fälle abgedeckt hat.

                                Ich werde nachher mal noch deinen Flow importieren und mal noch mal durchschauen

                                A Offline
                                A Offline
                                andibr
                                schrieb zuletzt editiert von andibr
                                #63

                                @OliverIO
                                Ich fürchte es ist alles viel einfacher als das wir alle denken. Mit dieser Ergänzung:
                                Bildschirmfoto vom 2026-09-05 14-26-15.png

                                habe ich jetzt nämlich ein File bekommen, dass mitte im String einfach aufhört.
                                meinfile.txt

                                ganz am Schluss hat es einen Antwortblock, der einfach mittendrin abbricht. Damit ist es natürlich logisch, das die erzeugung der Daten für die weiterverarbeitung nicht funktioniert.

                                Aus meiner Sicht müsste man in dem Fall zusätzlich zuerst noch überprüfen ob der "Datensatz" quasi auch vollständig ist und sonst den ganzen verwerfen. Nur was geschieht wenn er plötzlich alle verwirft und die Daten nicht mehr aktualisiert werden und keiner das bemerkt? Da müsste man ja noch irgend eine Fehlebehandlung reinbauen?

                                Ich frage mich aber immer noch woran es liegt, das er plötzlich abbricht, kann es sein, dass da irgend ein Interrupt im Prozessor die Komunikation unterbricht? Das wäre ja auch etwas doof, schliesslich ist das ja die Konfigurationsschnittstelle.

                                Nachtrag

                                Kann man da eine Abfrage machen ob am Schluss der Text "Comman completed successfully" steht und erst dann die Daten aufbereiten?

                                OliverIOO 1 Antwort Letzte Antwort
                                0
                                • A andibr

                                  @OliverIO
                                  Ich fürchte es ist alles viel einfacher als das wir alle denken. Mit dieser Ergänzung:
                                  Bildschirmfoto vom 2026-09-05 14-26-15.png

                                  habe ich jetzt nämlich ein File bekommen, dass mitte im String einfach aufhört.
                                  meinfile.txt

                                  ganz am Schluss hat es einen Antwortblock, der einfach mittendrin abbricht. Damit ist es natürlich logisch, das die erzeugung der Daten für die weiterverarbeitung nicht funktioniert.

                                  Aus meiner Sicht müsste man in dem Fall zusätzlich zuerst noch überprüfen ob der "Datensatz" quasi auch vollständig ist und sonst den ganzen verwerfen. Nur was geschieht wenn er plötzlich alle verwirft und die Daten nicht mehr aktualisiert werden und keiner das bemerkt? Da müsste man ja noch irgend eine Fehlebehandlung reinbauen?

                                  Ich frage mich aber immer noch woran es liegt, das er plötzlich abbricht, kann es sein, dass da irgend ein Interrupt im Prozessor die Komunikation unterbricht? Das wäre ja auch etwas doof, schliesslich ist das ja die Konfigurationsschnittstelle.

                                  Nachtrag

                                  Kann man da eine Abfrage machen ob am Schluss der Text "Comman completed successfully" steht und erst dann die Daten aufbereiten?

                                  OliverIOO Offline
                                  OliverIOO Offline
                                  OliverIO
                                  schrieb zuletzt editiert von
                                  #64

                                  @andibr

                                  Das Geheimnis liegt bei

                                  Command completed successfully

                                  Erst wenn das kommt, hast du alle Daten erhalten.
                                  Eine andere Alternative wäre, jede Zeile hat eine definierte Länge.
                                  Wenn eine Zeile mal nicht die exakte Länge hat, dann wird diese Zeile verworfen.
                                  Interessant wäre jetzt, gibt es immer wieder mal Kommunikationsunterbrechungen und wird beim nächsten anfordern normal fortgesetzt? Oder bricht der Flow dann komplett ab?
                                  Wenn die serielle Schnittstelle immer wieder mal was verschluckt, aber beim nächsten Mal normal weitermacht, könnte man das glaube ich für verschmerzen.
                                  Alternativ könnte man, wenn man so etwas erkennt, die Daten sofort erneut anfordern, muss man aber aufpassen, dass man nicht in einen unendlich Zyklus, der sich aufschaukelt gerät.

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

                                  1 Antwort Letzte Antwort
                                  0
                                  • A Offline
                                    A Offline
                                    andibr
                                    schrieb zuletzt editiert von andibr
                                    #65

                                    Genau das habe ich auch gerade entdeckt.
                                    Jetzt müsste man eigentlich doch im ersten Function Node in Zeile 7 ein Filter einbauen der im String die Anwesenheit vom "Command....." überwacht?
                                    Nur da bin ich jetzt überfordert.

                                    Wie geschrieben habe ich das Gefühl, das geschieht nicht wilkürlich, sondern das BMS bricht den Stream ab, weil etwas anderes wichtigeres gemacht werden muss. Denn der Datenverlust ist an verschiedenen Stellen im ganzen String zu finden.

                                    Nachtrag
                                    Mit hilfe von irgend einer KI habe ich nun ein Filter gebastelt:

                                    // Prüft, ob der Suchbegriff in der msg.payload existiert
                                    if (msg.payload.includes("completed")) {
                                        msg.found = true;
                                        msg.payload = "Text wurde gefunden!";
                                    } else {
                                        msg.found = false;
                                        return null;
                                    }
                                    

                                    Nur zweifle ich stark, das der funktioniert, denn eigentlich dürfte jetzt doch keine Zelldaten mehr rauskommen, der derpyload sollte doch jetzt "Text wurde gefunden sein"?
                                    Es kommen aber nach wievor die einzelnen Zelldaten hinten raus.

                                    OliverIOO 3 Antworten Letzte Antwort
                                    0
                                    • A andibr

                                      Genau das habe ich auch gerade entdeckt.
                                      Jetzt müsste man eigentlich doch im ersten Function Node in Zeile 7 ein Filter einbauen der im String die Anwesenheit vom "Command....." überwacht?
                                      Nur da bin ich jetzt überfordert.

                                      Wie geschrieben habe ich das Gefühl, das geschieht nicht wilkürlich, sondern das BMS bricht den Stream ab, weil etwas anderes wichtigeres gemacht werden muss. Denn der Datenverlust ist an verschiedenen Stellen im ganzen String zu finden.

                                      Nachtrag
                                      Mit hilfe von irgend einer KI habe ich nun ein Filter gebastelt:

                                      // Prüft, ob der Suchbegriff in der msg.payload existiert
                                      if (msg.payload.includes("completed")) {
                                          msg.found = true;
                                          msg.payload = "Text wurde gefunden!";
                                      } else {
                                          msg.found = false;
                                          return null;
                                      }
                                      

                                      Nur zweifle ich stark, das der funktioniert, denn eigentlich dürfte jetzt doch keine Zelldaten mehr rauskommen, der derpyload sollte doch jetzt "Text wurde gefunden sein"?
                                      Es kommen aber nach wievor die einzelnen Zelldaten hinten raus.

                                      OliverIOO Offline
                                      OliverIOO Offline
                                      OliverIO
                                      schrieb zuletzt editiert von
                                      #66

                                      @andibr

                                      dann hast du die KI falsch angewendet.
                                      Bei KI immer lösungsoffen formulieren, sonst interpretiert sie eine gewisse Vorgabe als Regel und hält sich daran.

                                      Hier mal mein Prompt

                                      ich habe eine function node in node red diese erhält input der serial node aus einer rs232 kommunikation leider bricht die kommunikation immer wieder mal ab, so das einzelne zeilen aus dem input nicht korrekt verarbeitet werden können. das ist die function node

                                      const text = msg.payload;
                                      
                                      if (typeof text !== "string") {
                                          node.error("msg.payload ist kein String", msg);
                                          return null;
                                      }
                                      
                                      // In einzelne Zeilen zerlegen
                                      const lines = text
                                          .split(/\r?\n/)
                                          .map(line => line.trim())
                                          .filter(line => line !== "");
                                      
                                      // Nur Zeilen berücksichtigen, die mit einer Batterienummer beginnen
                                      const dataLines = lines.filter(line => /^\d+\s/.test(line));
                                      
                                      const messages = [];
                                      
                                      for (const line of dataLines) {
                                      
                                          // Spalten sind durch mindestens 2 Leerzeichen getrennt
                                          const columns = line.split(/\s{2,}/);
                                      
                                          if (columns.length < 9) {
                                              node.warn("Zeile konnte nicht verarbeitet werden: " + line);
                                              continue;
                                          }
                                      
                                          const battery = {
                                              battery: Number(columns[0]),
                                              volt: Number(columns[1]),
                                              tempr: Number(columns[2]),
                                              baseState: columns[3],
                                              voltState: columns[4],
                                              currState: columns[5],
                                              tempState: columns[6],
                                              coulomb: Number(columns[7].replace("%", "")),
                                              capacity: Number(columns[8].replace(/[^\d]/g, ""))
                                          };
                                      
                                          messages.push({
                                              ...msg,
                                              payload: battery
                                          });
                                      }
                                      
                                      // Alle Nachrichten nacheinander über denselben Ausgang senden
                                      return [messages];
                                      

                                      das ist der message input.

                                      <<hier habe ich die komplette datei eingefügt.>>

                                      leider weiß ich nicht, ob durch die serial node noch transformationen durchgeführt wurden. kannst du mir die function node so erweitern, das prüfungen der datenqualität vorgenommen werden, das nachrichtenende ordentlich erkannt wird. ggfs unvollständige daten ausgefiltert werden. fehler und warnungen dazu als nachrichten ausgegeben werden, so das man bei weiteren problemen diese dann besser analysiert werden können. passe nur die function node an. keine weiteren nodes einführen. bzw. als hinweis für den anwender mitgeben.

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

                                      1 Antwort Letzte Antwort
                                      0
                                      • A andibr

                                        Genau das habe ich auch gerade entdeckt.
                                        Jetzt müsste man eigentlich doch im ersten Function Node in Zeile 7 ein Filter einbauen der im String die Anwesenheit vom "Command....." überwacht?
                                        Nur da bin ich jetzt überfordert.

                                        Wie geschrieben habe ich das Gefühl, das geschieht nicht wilkürlich, sondern das BMS bricht den Stream ab, weil etwas anderes wichtigeres gemacht werden muss. Denn der Datenverlust ist an verschiedenen Stellen im ganzen String zu finden.

                                        Nachtrag
                                        Mit hilfe von irgend einer KI habe ich nun ein Filter gebastelt:

                                        // Prüft, ob der Suchbegriff in der msg.payload existiert
                                        if (msg.payload.includes("completed")) {
                                            msg.found = true;
                                            msg.payload = "Text wurde gefunden!";
                                        } else {
                                            msg.found = false;
                                            return null;
                                        }
                                        

                                        Nur zweifle ich stark, das der funktioniert, denn eigentlich dürfte jetzt doch keine Zelldaten mehr rauskommen, der derpyload sollte doch jetzt "Text wurde gefunden sein"?
                                        Es kommen aber nach wievor die einzelnen Zelldaten hinten raus.

                                        OliverIOO Offline
                                        OliverIOO Offline
                                        OliverIO
                                        schrieb zuletzt editiert von
                                        #67

                                        @andibr

                                        hier die Antowrt der KI

                                        Ja. Im Mitschnitt ist das Muster ziemlich eindeutig: Ein sauberer Block beginnt mit der Kopfzeile Battery Volt Tempr ..., enthält Batterien 0 bis 15 und endet mit Command completed successfully. Später sieht man tatsächlich einen Abbruch mitten in Batterie 12, worauf direkt ein neuer Header folgt. Genau so einen Block sollte man komplett verwerfen statt teilweise weiterzuverarbeiten.

                                        Ich würde außerdem nicht mehr davon ausgehen, dass ein msg.payload exakt einen vollständigen Datensatz enthält. Die Function puffert deshalb Fragmente über mehrere Serial-Nachrichten hinweg und gibt Batteriedaten erst nach einem sauber erkannten Blockende und vollständiger Prüfung aller 16 Batterien aus.

                                        /*
                                         * Robuster Parser für RS232-Batteriedaten
                                         *
                                         * Eigenschaften:
                                         * - verarbeitet fragmentierte Serial-Daten über mehrere msg.payload hinweg
                                         * - erkennt Beginn eines Datensatzes anhand der Headerzeile
                                         * - erkennt Ende anhand "Command completed successfully"
                                         * - erwartet Batterien 0..15 genau einmal
                                         * - verwirft unvollständige Datensätze komplett
                                         * - prüft Zahlen, Prozentwert, Capacity und grobe Wertebereiche
                                         * - erzeugt Diagnosemeldungen für Warnungen/Fehler
                                         * - schreibt Warnungen zusätzlich in die Node-RED Debug-/Log-Ausgabe
                                         *
                                         * EIN Ausgang:
                                         *   msg.messageType === "data"     -> gültige Batteriedaten
                                         *   msg.messageType === "warning"  -> Diagnose/Warnung
                                         *   msg.messageType === "error"    -> Diagnose/Fehler
                                         */
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Konfiguration
                                        // ------------------------------------------------------------
                                        
                                        const EXPECTED_BATTERIES = 16;
                                        
                                        // Maximale Zeit, die ein begonnener Datensatz offen bleiben darf.
                                        // Die Prüfung erfolgt beim nächsten eintreffenden msg.
                                        const BLOCK_TIMEOUT_MS = 30000;
                                        
                                        // Schutz gegen unbegrenzt anwachsende Fragmentpuffer
                                        const MAX_FRAGMENT_LENGTH = 4096;
                                        
                                        // Schutz gegen völlig entartete Datensätze
                                        const MAX_BLOCK_LINES = 100;
                                        
                                        // Sehr großzügige Plausibilitätsgrenzen.
                                        // Diese können später an die tatsächliche Anlage angepasst werden.
                                        const LIMITS = {
                                            voltMin: 0,
                                            voltMax: 10000,
                                        
                                            temprMin: -100000,
                                            temprMax: 200000,
                                        
                                            coulombMin: 0,
                                            coulombMax: 100,
                                        
                                            capacityMin: 0,
                                            capacityMax: 1000000
                                        };
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Eingang prüfen
                                        // ------------------------------------------------------------
                                        
                                        const text = msg.payload;
                                        
                                        if (typeof text !== "string") {
                                        
                                            const diagnostic = createDiagnostic(
                                                "error",
                                                "INVALID_PAYLOAD_TYPE",
                                                "msg.payload ist kein String",
                                                {
                                                    receivedType: typeof text
                                                }
                                            );
                                        
                                            node.error(diagnostic, msg);
                                        
                                            return [[diagnostic]];
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Zustand aus Node-Context holen
                                        // ------------------------------------------------------------
                                        
                                        let fragment = context.get("serialFragment") || "";
                                        let block = context.get("batteryBlock") || null;
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Ausgaben dieser Function-Ausführung
                                        // ------------------------------------------------------------
                                        
                                        const output = [];
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Diagnosefunktion
                                        // ------------------------------------------------------------
                                        
                                        function createDiagnostic(severity, code, message, details) {
                                        
                                            return {
                                                ...msg,
                                        
                                                messageType: severity,
                                        
                                                payload: {
                                                    severity: severity,
                                                    code: code,
                                                    message: message,
                                                    timestamp: new Date().toISOString(),
                                                    details: details || {}
                                                }
                                            };
                                        }
                                        
                                        
                                        function diagnostic(severity, code, message, details) {
                                        
                                            const diag = createDiagnostic(
                                                severity,
                                                code,
                                                message,
                                                details
                                            );
                                        
                                            output.push(diag);
                                        
                                            // Zusätzlich in Node-RED sichtbar machen
                                            if (severity === "error") {
                                                node.error(
                                                    code + ": " + message +
                                                    (details ? " | " + JSON.stringify(details) : "")
                                                );
                                            } else {
                                                node.warn(
                                                    code + ": " + message +
                                                    (details ? " | " + JSON.stringify(details) : "")
                                                );
                                            }
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Hilfsfunktionen
                                        // ------------------------------------------------------------
                                        
                                        function isHeader(line) {
                                        
                                            return /^Battery\s+Volt\s+Tempr\s+Base\s+State/i.test(line);
                                        }
                                        
                                        
                                        function isEndMarker(line) {
                                        
                                            return /^Command completed successfully\s*$/i.test(line);
                                        }
                                        
                                        
                                        function isPromptOrNoise(line) {
                                        
                                            return (
                                                line === "" ||
                                                line === "$$" ||
                                                line === "@" ||
                                                /^PYTES>/i.test(line)
                                            );
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Batteriezeile parsen
                                        // ------------------------------------------------------------
                                        
                                        function parseBatteryLine(line) {
                                        
                                            /*
                                             * Beispiel:
                                             *
                                             * 0        3462     28000    Charge       Normal
                                             * Normal   Normal   97%      95980 mAH
                                             *
                                             * Absichtlich nicht nur split(/\s{2,}/), damit kleinere
                                             * Änderungen der Abstände nicht sofort zum Fehler führen.
                                             */
                                        
                                            const match = line.match(
                                                /^(\d+)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\d+(?:\.\d+)?)%\s+(\d+)\s*mAH\s*$/i
                                            );
                                        
                                            if (!match) {
                                                return {
                                                    valid: false,
                                                    reason: "FORMAT_ERROR"
                                                };
                                            }
                                        
                                            const battery = {
                                                battery: Number(match[1]),
                                                volt: Number(match[2]),
                                                tempr: Number(match[3]),
                                                baseState: match[4],
                                                voltState: match[5],
                                                currState: match[6],
                                                tempState: match[7],
                                                coulomb: Number(match[8]),
                                                capacity: Number(match[9])
                                            };
                                        
                                        
                                            // --------------------------------------------------------
                                            // Datentypen prüfen
                                            // --------------------------------------------------------
                                        
                                            const numericValues = [
                                                battery.battery,
                                                battery.volt,
                                                battery.tempr,
                                                battery.coulomb,
                                                battery.capacity
                                            ];
                                        
                                            if (numericValues.some(v => !Number.isFinite(v))) {
                                        
                                                return {
                                                    valid: false,
                                                    reason: "INVALID_NUMBER",
                                                    battery: battery
                                                };
                                            }
                                        
                                        
                                            // --------------------------------------------------------
                                            // Harte Plausibilitätsprüfungen
                                            // --------------------------------------------------------
                                        
                                            if (
                                                battery.battery < 0 ||
                                                battery.battery >= EXPECTED_BATTERIES
                                            ) {
                                                return {
                                                    valid: false,
                                                    reason: "INVALID_BATTERY_NUMBER",
                                                    battery: battery
                                                };
                                            }
                                        
                                        
                                            if (
                                                battery.coulomb < LIMITS.coulombMin ||
                                                battery.coulomb > LIMITS.coulombMax
                                            ) {
                                                return {
                                                    valid: false,
                                                    reason: "INVALID_COULOMB_VALUE",
                                                    battery: battery
                                                };
                                            }
                                        
                                        
                                            if (
                                                battery.capacity < LIMITS.capacityMin ||
                                                battery.capacity > LIMITS.capacityMax
                                            ) {
                                                return {
                                                    valid: false,
                                                    reason: "INVALID_CAPACITY_VALUE",
                                                    battery: battery
                                                };
                                            }
                                        
                                        
                                            if (
                                                battery.volt < LIMITS.voltMin ||
                                                battery.volt > LIMITS.voltMax
                                            ) {
                                                return {
                                                    valid: false,
                                                    reason: "INVALID_VOLTAGE_VALUE",
                                                    battery: battery
                                                };
                                            }
                                        
                                        
                                            if (
                                                battery.tempr < LIMITS.temprMin ||
                                                battery.tempr > LIMITS.temprMax
                                            ) {
                                                return {
                                                    valid: false,
                                                    reason: "INVALID_TEMPERATURE_VALUE",
                                                    battery: battery
                                                };
                                            }
                                        
                                        
                                            return {
                                                valid: true,
                                                battery: battery
                                            };
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Angefangenen Block verwerfen
                                        // ------------------------------------------------------------
                                        
                                        function discardBlock(reason, additionalDetails) {
                                        
                                            if (!block) {
                                                return;
                                            }
                                        
                                            const receivedBatteries = Object.keys(block.batteries)
                                                .map(Number)
                                                .sort((a, b) => a - b);
                                        
                                            diagnostic(
                                                "warning",
                                                "BLOCK_DISCARDED",
                                                "Unvollständiger oder beschädigter Batteriedatensatz wurde verworfen.",
                                                {
                                                    reason: reason,
                                                    receivedBatteryCount: receivedBatteries.length,
                                                    receivedBatteries: receivedBatteries,
                                                    invalidLines: block.invalidLines,
                                                    startedAt: new Date(block.startedAt).toISOString(),
                                                    ...additionalDetails
                                                }
                                            );
                                        
                                            block = null;
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Fertigen Block validieren
                                        // ------------------------------------------------------------
                                        
                                        function finishBlock() {
                                        
                                            if (!block) {
                                        
                                                diagnostic(
                                                    "warning",
                                                    "END_WITHOUT_HEADER",
                                                    "Blockende erkannt, obwohl kein aktiver Datensatz vorhanden war."
                                                );
                                        
                                                return;
                                            }
                                        
                                        
                                            const batteryNumbers = Object.keys(block.batteries)
                                                .map(Number)
                                                .sort((a, b) => a - b);
                                        
                                        
                                            // Erwartete Batterien erzeugen
                                            const expected = [];
                                        
                                            for (let i = 0; i < EXPECTED_BATTERIES; i++) {
                                                expected.push(i);
                                            }
                                        
                                        
                                            const missing = expected.filter(
                                                batteryNumber => !batteryNumbers.includes(batteryNumber)
                                            );
                                        
                                        
                                            // --------------------------------------------------------
                                            // Datensatz unvollständig
                                            // --------------------------------------------------------
                                        
                                            if (
                                                batteryNumbers.length !== EXPECTED_BATTERIES ||
                                                missing.length > 0 ||
                                                block.invalidLines.length > 0
                                            ) {
                                        
                                                diagnostic(
                                                    "warning",
                                                    "INCOMPLETE_DATASET",
                                                    "Datensatz wurde vollständig empfangen beendet, enthält aber nicht alle erwarteten gültigen Batteriedaten.",
                                                    {
                                                        expectedBatteryCount: EXPECTED_BATTERIES,
                                                        receivedBatteryCount: batteryNumbers.length,
                                                        receivedBatteries: batteryNumbers,
                                                        missingBatteries: missing,
                                                        invalidLines: block.invalidLines,
                                                        startedAt: new Date(block.startedAt).toISOString(),
                                                        durationMs: Date.now() - block.startedAt
                                                    }
                                                );
                                        
                                                block = null;
                                        
                                                return;
                                            }
                                        
                                        
                                            // --------------------------------------------------------
                                            // Vollständigen Datensatz ausgeben
                                            // --------------------------------------------------------
                                        
                                            const batchId =
                                                Date.now().toString(36) +
                                                "-" +
                                                Math.random().toString(36).substring(2, 8);
                                        
                                        
                                            for (let i = 0; i < EXPECTED_BATTERIES; i++) {
                                        
                                                output.push({
                                                    ...msg,
                                        
                                                    messageType: "data",
                                        
                                                    batchId: batchId,
                                        
                                                    dataQuality: {
                                                        valid: true,
                                                        completeDataset: true,
                                                        batteryCount: EXPECTED_BATTERIES
                                                    },
                                        
                                                    payload: block.batteries[i]
                                                });
                                            }
                                        
                                        
                                            // optional im Node-Status sichtbar
                                            node.status({
                                                fill: "green",
                                                shape: "dot",
                                                text: "16 Batterien OK"
                                            });
                                        
                                        
                                            block = null;
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Einzelne komplette Textzeile verarbeiten
                                        // ------------------------------------------------------------
                                        
                                        function processLine(rawLine) {
                                        
                                            const line = rawLine.trim();
                                        
                                        
                                            // --------------------------------------------------------
                                            // Header
                                            // --------------------------------------------------------
                                        
                                            if (isHeader(line)) {
                                        
                                                // Es läuft bereits ein Block:
                                                // der vorherige wurde offensichtlich nicht sauber beendet.
                                                if (block) {
                                        
                                                    discardBlock(
                                                        "NEW_HEADER_BEFORE_END",
                                                        {
                                                            newHeader: line
                                                        }
                                                    );
                                                }
                                        
                                        
                                                block = {
                                                    startedAt: Date.now(),
                                                    batteries: {},
                                                    invalidLines: [],
                                                    lineCount: 0
                                                };
                                        
                                        
                                                node.status({
                                                    fill: "yellow",
                                                    shape: "ring",
                                                    text: "Datensatz empfangen..."
                                                });
                                        
                                                return;
                                            }
                                        
                                        
                                            // --------------------------------------------------------
                                            // Blockende
                                            // --------------------------------------------------------
                                        
                                            if (isEndMarker(line)) {
                                        
                                                finishBlock();
                                        
                                                return;
                                            }
                                        
                                        
                                            // --------------------------------------------------------
                                            // bekannte Prompt-/Steuerzeilen ignorieren
                                            // --------------------------------------------------------
                                        
                                            if (isPromptOrNoise(line)) {
                                                return;
                                            }
                                        
                                        
                                            // --------------------------------------------------------
                                            // Außerhalb eines Blocks
                                            // --------------------------------------------------------
                                        
                                            if (!block) {
                                        
                                                // Batteriezeile außerhalb eines Headers ist verdächtig
                                                if (/^\d+\s/.test(line)) {
                                        
                                                    diagnostic(
                                                        "warning",
                                                        "DATA_OUTSIDE_BLOCK",
                                                        "Batteriezeile außerhalb eines gültigen Datensatzes erkannt und verworfen.",
                                                        {
                                                            rawLine: line
                                                        }
                                                    );
                                                }
                                        
                                                return;
                                            }
                                        
                                        
                                            block.lineCount++;
                                        
                                        
                                            // --------------------------------------------------------
                                            // Sicherheitslimit
                                            // --------------------------------------------------------
                                        
                                            if (block.lineCount > MAX_BLOCK_LINES) {
                                        
                                                discardBlock(
                                                    "TOO_MANY_LINES",
                                                    {
                                                        lineCount: block.lineCount
                                                    }
                                                );
                                        
                                                return;
                                            }
                                        
                                        
                                            // --------------------------------------------------------
                                            // Nur Zeilen, die mit Batterie-ID anfangen, interessieren
                                            // --------------------------------------------------------
                                        
                                            if (!/^\d+\s/.test(line)) {
                                        
                                                diagnostic(
                                                    "warning",
                                                    "UNEXPECTED_LINE",
                                                    "Unerwartete Zeile innerhalb eines Batteriedatensatzes.",
                                                    {
                                                        rawLine: line
                                                    }
                                                );
                                        
                                                return;
                                            }
                                        
                                        
                                            // --------------------------------------------------------
                                            // Batteriezeile parsen
                                            // --------------------------------------------------------
                                        
                                            const parsed = parseBatteryLine(line);
                                        
                                        
                                            if (!parsed.valid) {
                                        
                                                block.invalidLines.push({
                                                    line: line,
                                                    reason: parsed.reason
                                                });
                                        
                                        
                                                diagnostic(
                                                    "warning",
                                                    "INVALID_BATTERY_LINE",
                                                    "Batteriezeile konnte nicht sicher verarbeitet werden.",
                                                    {
                                                        reason: parsed.reason,
                                                        rawLine: line,
                                                        parsedData: parsed.battery || null
                                                    }
                                                );
                                        
                                                return;
                                            }
                                        
                                        
                                            const batteryNumber = parsed.battery.battery;
                                        
                                        
                                            // --------------------------------------------------------
                                            // Doppelte Batterie-ID
                                            // --------------------------------------------------------
                                        
                                            if (block.batteries[batteryNumber] !== undefined) {
                                        
                                                block.invalidLines.push({
                                                    line: line,
                                                    reason: "DUPLICATE_BATTERY"
                                                });
                                        
                                        
                                                diagnostic(
                                                    "warning",
                                                    "DUPLICATE_BATTERY",
                                                    "Batterienummer wurde innerhalb desselben Datensatzes mehrfach empfangen.",
                                                    {
                                                        battery: batteryNumber,
                                                        rawLine: line
                                                    }
                                                );
                                        
                                                return;
                                            }
                                        
                                        
                                            block.batteries[batteryNumber] = parsed.battery;
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Timeout des vorherigen Blocks prüfen
                                        // ------------------------------------------------------------
                                        
                                        if (
                                            block &&
                                            Date.now() - block.startedAt > BLOCK_TIMEOUT_MS
                                        ) {
                                        
                                            discardBlock(
                                                "BLOCK_TIMEOUT",
                                                {
                                                    timeoutMs: BLOCK_TIMEOUT_MS
                                                }
                                            );
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Fragmentierung der seriellen Schnittstelle behandeln
                                        // ------------------------------------------------------------
                                        
                                        fragment += text;
                                        
                                        
                                        // Schutz gegen kaputte / niemals abgeschlossene Eingabe
                                        if (fragment.length > MAX_FRAGMENT_LENGTH) {
                                        
                                            diagnostic(
                                                "error",
                                                "SERIAL_FRAGMENT_OVERFLOW",
                                                "Der serielle Fragmentpuffer wurde zu groß und wurde zurückgesetzt.",
                                                {
                                                    fragmentLength: fragment.length,
                                                    maxFragmentLength: MAX_FRAGMENT_LENGTH,
                                                    fragmentPreview: fragment.substring(0, 500)
                                                }
                                            );
                                        
                                            fragment = "";
                                        
                                            discardBlock(
                                                "SERIAL_FRAGMENT_OVERFLOW"
                                            );
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Zeilenenden erkennen
                                        //
                                        // Unterstützt:
                                        //   \r\n
                                        //   \n
                                        //   \r
                                        // ------------------------------------------------------------
                                        
                                        const parts = fragment.split(/\r\n|\n|\r/);
                                        
                                        
                                        // Das letzte Element könnte eine noch unvollständige Zeile sein
                                        fragment = parts.pop() || "";
                                        
                                        
                                        // Alle sicher abgeschlossenen Zeilen verarbeiten
                                        for (const line of parts) {
                                            processLine(line);
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Sonderfall:
                                        // Serial-Node liefert möglicherweise bereits jeweils EINE komplette
                                        // Zeile, entfernt aber selbst das Zeilenende.
                                        //
                                        // Wenn das aktuelle Fragment eindeutig wie eine vollständige
                                        // relevante Zeile aussieht, kann es sofort verarbeitet werden.
                                        // ------------------------------------------------------------
                                        
                                        const trimmedFragment = fragment.trim();
                                        
                                        if (trimmedFragment !== "") {
                                        
                                            const completeBatteryLine =
                                                parseBatteryLine(trimmedFragment).valid;
                                        
                                            const obviousCompleteLine =
                                                isHeader(trimmedFragment) ||
                                                isEndMarker(trimmedFragment) ||
                                                isPromptOrNoise(trimmedFragment) ||
                                                completeBatteryLine;
                                        
                                            if (obviousCompleteLine) {
                                        
                                                processLine(trimmedFragment);
                                        
                                                fragment = "";
                                            }
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Zustand speichern
                                        // ------------------------------------------------------------
                                        
                                        context.set("serialFragment", fragment);
                                        context.set("batteryBlock", block);
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Node-Status bei Fehlern/Warnungen
                                        // ------------------------------------------------------------
                                        
                                        if (output.some(m => m.messageType === "error")) {
                                        
                                            node.status({
                                                fill: "red",
                                                shape: "dot",
                                                text: "RS232 Fehler"
                                            });
                                        
                                        } else if (output.some(m => m.messageType === "warning")) {
                                        
                                            node.status({
                                                fill: "yellow",
                                                shape: "dot",
                                                text: "RS232 Warnung"
                                            });
                                        }
                                        
                                        
                                        // ------------------------------------------------------------
                                        // Alle Nachrichten nacheinander über denselben Ausgang senden
                                        // ------------------------------------------------------------
                                        
                                        return [output];
                                        

                                        Was sich gegenüber deiner bisherigen Function ändert

                                        Der wichtigste Unterschied ist, dass die Function nicht mehr jede zufällig empfangene Batteriezeile sofort weitergibt. Sie wartet auf einen kompletten Datensatz:

                                        Battery ... → Batterie 0 → 1 → … → 15 → Command completed successfully

                                        Erst wenn dieses Muster vollständig und plausibel ist, werden die 16 Nachrichten ausgegeben. Im Mitschnitt ist beispielsweise ein Block bei Batterie 12 mitten in der Zeile abgebrochen. Mit deiner bisherigen Function könnten die davor stehenden Batterien 0–11 bereits als scheinbar gültige Messwerte verarbeitet werden. Mit der neuen Version wird der gesamte Block verworfen.

                                        Die Function erkennt außerdem einen besonders wichtigen Fehlerfall: Kommt ein neuer Battery ...-Header, während der vorherige Datensatz noch nicht durch Command completed successfully beendet wurde, wird eine Warnung BLOCK_DISCARDED / NEW_HEADER_BEFORE_END erzeugt. Das dürfte genau der typische Fehler bei deinen Kommunikationsabbrüchen sein.

                                        Bei einem gültigen Block sehen die normalen Nachrichten weiterhin fast genauso aus wie bisher:

                                        msg.messageType = "data";
                                        
                                        msg.payload = {
                                            battery: 0,
                                            volt: 3462,
                                            tempr: 28000,
                                            baseState: "Charge",
                                            voltState: "Normal",
                                            currState: "Normal",
                                            tempState: "Normal",
                                            coulomb: 97,
                                            capacity: 95980
                                        };
                                        

                                        Zusätzlich bekommen alle 16 Nachrichten eines Blocks dieselbe batchId. Damit kannst du später erkennen, welche Messwerte garantiert aus derselben RS232-Abfrage stammen.

                                        Eine Diagnosemeldung sieht beispielsweise so aus:

                                        msg.messageType = "warning";
                                        
                                        msg.payload = {
                                            severity: "warning",
                                            code: "INCOMPLETE_DATASET",
                                            message: "Datensatz wurde vollständig empfangen beendet, enthält aber nicht alle erwarteten gültigen Batteriedaten.",
                                            timestamp: "...",
                                            details: {
                                                expectedBatteryCount: 16,
                                                receivedBatteryCount: 12,
                                                receivedBatteries: [0,1,2,3,4,5,6,7,8,9,10,11],
                                                missingBatteries: [12,13,14,15]
                                            }
                                        };
                                        

                                        Damit sind unter anderem NEW_HEADER_BEFORE_END, BLOCK_TIMEOUT, INVALID_BATTERY_LINE, DUPLICATE_BATTERY, DATA_OUTSIDE_BLOCK und SERIAL_FRAGMENT_OVERFLOW unterscheidbar. Gleichzeitig werden diese Informationen über node.warn() beziehungsweise node.error() im Node-RED-Debug/Log sichtbar.

                                        Ein Punkt ist für dein bestehendes Flow wichtig: Weil du ausdrücklich nur diese eine Function Node ändern möchtest, laufen Daten und Diagnosen über denselben Ausgang. Nachgelagerte Verarbeitung, die blind davon ausgeht, dass jede Nachricht eine Batterie enthält, sollte deshalb msg.messageType === "data" beachten. Falls du deinen bestehenden Flow überhaupt nicht anfassen möchtest, kann ich die Variante auch so ändern, dass nur gültige Batteriedaten am Ausgang erscheinen und sämtliche Diagnoseinformationen ausschließlich über node.warn()/node.error() protokolliert werden. Das wäre für einen bestehenden Produktiv-Flow wahrscheinlich die kompatibelste Variante.

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

                                        1 Antwort Letzte Antwort
                                        0
                                        • A andibr

                                          Genau das habe ich auch gerade entdeckt.
                                          Jetzt müsste man eigentlich doch im ersten Function Node in Zeile 7 ein Filter einbauen der im String die Anwesenheit vom "Command....." überwacht?
                                          Nur da bin ich jetzt überfordert.

                                          Wie geschrieben habe ich das Gefühl, das geschieht nicht wilkürlich, sondern das BMS bricht den Stream ab, weil etwas anderes wichtigeres gemacht werden muss. Denn der Datenverlust ist an verschiedenen Stellen im ganzen String zu finden.

                                          Nachtrag
                                          Mit hilfe von irgend einer KI habe ich nun ein Filter gebastelt:

                                          // Prüft, ob der Suchbegriff in der msg.payload existiert
                                          if (msg.payload.includes("completed")) {
                                              msg.found = true;
                                              msg.payload = "Text wurde gefunden!";
                                          } else {
                                              msg.found = false;
                                              return null;
                                          }
                                          

                                          Nur zweifle ich stark, das der funktioniert, denn eigentlich dürfte jetzt doch keine Zelldaten mehr rauskommen, der derpyload sollte doch jetzt "Text wurde gefunden sein"?
                                          Es kommen aber nach wievor die einzelnen Zelldaten hinten raus.

                                          OliverIOO Offline
                                          OliverIOO Offline
                                          OliverIO
                                          schrieb zuletzt editiert von OliverIO
                                          #68

                                          @andibr

                                          In der Nachfolge node "Nachrichten erzeugen"

                                          solltest du noch

                                          if (msg.messageType !== "data") {
                                              return null;
                                          } 
                                          

                                          am Anfang einfügen.
                                          f6ade35b-d8c7-43da-b197-f61115dbb10e-image.jpeg

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

                                          A 1 Antwort Letzte Antwort
                                          0

                                          Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.

                                          Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.

                                          Mit deinem Input könnte dieser Beitrag noch besser werden 💗

                                          Registrieren Anmelden
                                          Antworten
                                          • In einem neuen Thema antworten
                                          Anmelden zum Antworten
                                          • Älteste zuerst
                                          • Neuste zuerst
                                          • Meiste Stimmen


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          209

                                          Online

                                          33.1k

                                          Benutzende

                                          83.7k

                                          Themen

                                          1.3m

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

                                          • Du hast noch kein Konto? Registrieren

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