Navigation

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

    NEWS

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

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    • Profile
    • Following 0
    • Followers 29
    • Topics 54
    • Posts 16088
    • Best 1417
    • Groups 2

    mickym

    @mickym

    Most Active

    1586
    Reputation
    730
    Profile views
    16088
    Posts
    29
    Followers
    0
    Following
    Joined Last Online

    mickym Follow
    Pro Most Active

    Best posts made by mickym

    • Zigbee/Conbee2 funktioniert nach Update nicht mehr (udev)

      Beitrag am 07.05.2023 überarbeitet:

      Ich habe leider keine Informationen im Netz gefunden und kenne die Ursache nicht. Jedenfalls zerschiesst Euch ggf. (zumindest ist es bei mir so) - die ein Update des Debian / Raspberry Eure Zigbee2mqtt Installation. Ich finde leider nichts im Netz.

      Der Service startet normal - aber man kann die Geräte weder via mqtt ansteuern noch funktioniert die Weboberfläche.

      Vielleicht findet einer von Euch irgendwelche Hintergründe - ansonsten möchte ich nur vor dem Update warnen. Zum Glück habe ich eine Imagesicherung vor dem Update gemacht, um wieder auf eine funktionierende Installation zurückgreifen zu können.

      Nach dem neuesten Update starten ggf. Zigbee Geräte nicht mehr die über einen USB-Koordinator betrieben werden. Ich kann es hier nur von dem conbee2 berichten, vielleicht betrifft es aber andere Geräte zumindest, wenn diese über serial/by-id eingebunden sind.

      Testen kann das jeder mit:

      ls -l /dev/serial/by-id/
      

      sollte dann kommen, dass kein Zugriff möglich ist, da Datei oder Verzeichnis nicht gefunden wurde, ist man von dem Bug betroffen.

      Ursache ist ein fehlerhaftes udev Paket genauer udev/stable 247.3-7+deb11u2 mit 2 dazugehörenden Bibliotheken.

      Nun gibt es 2 Möglichkeiten:

      ===================================================================================

      1. Hat man noch kein Update durchgeführt, dann kann man das Update des udev-Paketes verhindern in dem man es auf "on-hold" markiert.
      sudo apt-mark hold udev
      

      überprüfen kann man das ganze dann mit

      sudo apt-mark showhold
      

      Nun kann man wieder getrost das System aktualisieren. Es werden bei

      sudo apt update
      

      immer diese 3 Pakete zur Aktualisierung angezeigt, jedoch bei anschließenden

      sudo apt upgrade
      

      nicht installiert. (full-upgrade oder dist-upgrade verhalten sich ebenso).

      ===================================================================================

      1. Ist das Update bereits durchgelaufen und diese Version installiert, kann man sich nun mit einem Paket aus Backports-Repository behelfen.

      EDIT 29.5.2023: Gemäß dem Post (https://forum.iobroker.net/post/997296) von @Thomas-Braun beachten - habe ich die Beschreibung entsprechend geändert.

      Um jedoch zu überprüfen ob man betroffen ist, gibt man ein

      apt policy udev
      

      Sollte man dann folgende Ausgabe bekommen:

      udev:
        Installed: 247.3-7+deb11u2
        Candidate: 247.3-7+deb11u2
        Version table:
       *** 247.3-7+deb11u2 500
              500 http://deb.debian.org/debian bullseye/main arm64 Packages
              100 /var/lib/dpkg/status
      

      dann hat man das fehlerhafte Paket bereits installiert und sollte eine höhere Version aus dem Backports Repository installieren.

      Wechsle in das Verzeichnis:

      cd  /etc/apt/sources.list.d
      

      erstelle dort eine Datei: bullseye-proposed-updates.list
      also:

      sudo nano bullseye-proposed-updates.list
      

      In diese Datei kopierst Du diese beiden Zeilen:

      # bullseye-proposed-updates
      deb http://deb.debian.org/debian bullseye-proposed-updates main
      

      Dann führst Du das aus:

      sudo apt update
      sudo apt -t bullseye-proposed-updates install udev
      

      anschließend ein Reboot und es sollte alles wieder funktionieren. Prüfen ob das Update geklappt hat, kann man mit

      apt policy udev
      

      dann sollte die Ausgabe wie folgt aussehen:

      apt policy udev
      udev:
        Installiert:           247.3-7+deb11u4
        Installationskandidat: 247.3-7+deb11u4
        Versionstabelle:
       *** 247.3-7+deb11u4 500
              500 http://deb.debian.org/debian bullseye-proposed-updates/main amd64 Packages
              100 /var/lib/dpkg/status
           247.3-7+deb11u2 500
              500 http://deb.debian.org/debian bullseye/main amd64 Packages
      

      Für alle die, die Möglichkeit 1 genutzt haben und auf die neuere Version umsteigen wollen, müssen diese das "on-hold" wieder entfernen.

      sudo apt-mark unhold udev
      

      Damit glaube ich ist das Problem soweit erst mal im Griff und nochmals Danke an alle Beteiligten für die Hilfe.

      ===================================================================================
      Edit: 10.05.2023

      Ein großes Dankeschön von meiner Seite auch an Matthias, der extra zu diesem Problem ein Video gedreht hat:
      https://www.youtube.com/watch?v=2Jsedi4IueE

      ===================================================================================

      EDIT 09.06.2023
      Wenn beim Udate festgestellt wird, dass keys - Schlüssel fehlen, dann bitte folgende Befehle eingeben:

      sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138
      sudo apt update 
      
      

      ===================================================================================

      EDIT 10.06.2023

      Falls jemand trotz allem auf dem Raspberry (vermutlich 32 bit OS) immer noch Probleme hat - beim mir hat alles gemäß Anleitung auf einem 64-bit OS auf dem Raspberry funktioniert - der kann noch folgendes versuchen:

      sudo apt install udev=247.3-7+deb11u4 libudev1=247.3-7+deb11u4
      

      und anschliessend mit

      sudo apt-mark hold udev
      

      auf hold setzen.

      posted in Einbindung von Geräten
      mickym
      mickym
    • RE: Admin 6.0 - neu als Beta

      Na ich hatte gehofft - das größte Manko dieser Admin 5 Oberfläche - sprich die Mausbedienung der Spaltenbreiten wieder in einem Majorrelease wieder da ist, davon scheint allerdings nicht die Rede zu sein. Ansonsten lass ich mich überraschen. Vielleicht sollte man dann halt Browserversionen für Tablets und Desktops machen. Ich behaupte aber mal, dass die Mehrzahl den Admin nicht auf dem Tablet bedienen. Solange die Mausbedienung nicht wieder zurück ist, finde ich es schon schade, dass man die Unterstützung der genialen Admin4 Oberfläche einstellt. 😉 Aber ich bin hier halt in der Minderheit und man gewöhnt sich ja an vieles. Zudem inzwischen manche Dinge schon postiv nachgearbeitet wurden (z. Bsp. Kopieren des Namens und nicht nur des Pfades aus den Objekten etc.) Da hat sich schon auch was positiv verändert.

      posted in ioBroker Allgemein
      mickym
      mickym
    • Neuer Node-Red Adapter 3.x in Latest - Repository

      Nachdem ich im Node-RED Bereich des ioBroker-Forums relativ aktiv bin und auch bei den Tests zu dem neuen Major-Release des Node-Red Adapters in der Version 3.0.0 mithelfen durfte, habe ich mich in Abstimmung mit @apollon77 dazu bereit erklärt ein paar Highlights und Fehlerbehebungen des neuen Major-Releases hier vorzustellen bzw. zu dokumentieren. Teilweise werde ich hier auch ein paar persönliche Schwerpunkte setzen - es aber auch nicht schaffen, alles in einem Posting festzuhalten.

      Ich möchte mich persönlich auf diesem Weg nochmals bei allen Entwicklern (@apollon77, @Bluefox und @jwiesel), die an der Entwicklung und bei der Bereitstellung dieses Node-Red Adapters beteiligt waren, persönlich bedanken!
      Es ist nicht nur ein Meilenstein, weil nun offiziell Node-Red in der Version 2.2.2 enthalten ist und diese ebenfalls ein paar wirkliche Neuerungen und Erleichterungen mit sich bringen, sondern weil in meinen Augen auch die meisten Fehlerbehebungen und Verbesserungen des Node-Red Adapters im Zusammenspiel mit dem iobroker enthalten.

      Da die Sprünge bei den Node-Red Versionen nun doch erheblich waren, hier ein paar Quellen und ein paar Highlights, die inzwischen implementiert wurden.

      Neues Major Release Node-Red Version 2

      In der Version 2.0 sind erst mal die wirklich weit reichensten Änderungen erhalten, die einem das Leben wesentlich erleichtern.

      Einen Überblick vom Node-Red Guru mit einem Video auf Englisch gibt es hier: https://nodered.org/blog/2021/07/20/version-2-0-released

      Ein paar Einstellungen muss man immer noch die settings.js anpassen. Grundsätzlich ist diese Datei vollkommen neu strukturiert und nun wesentlich übersichtlicher aufgebaut.
      Für bestimmte Einstellungen muss man diese immer noch an den bekannten Stellen editieren.

      Wenn man also den "neuen" Monaco Editor im Programmierfenster der function Nodes nutzen möchte, um kontextbezogene Hilfe bzw. Vorschläge zu bekommen, dann muss man das manuell weiterhin in der settings.js machen. Der bisheriger Editor ist "ace", der neue "monaco". Ich bevorzuge eigentlich weiter den bisherigen Editor - aber ist Gewöhnungssache.

      1c1099bd-ca4c-466e-9099-a10aa1f9ea04-image.png

      Eines der gewaltigsten Vorteile der NR Version 2 ist die Installation und das Nutzen externer NodeJS Module in Function Nodes ohne diese installieren zu müssen!!!
      Die Module müssen also nicht in der settings.js bekannt gemacht werden und werden automatisch im
      /opt/iobroker/iobroker-data/node-red/node_modules Verzeichnis installiert. Es ist KEINE Installation über Adaptereinstellungen oder über die Kommandozeile erforderlich.
      Die Module können einfach in den function Nodes über den Setup-Tab bekannt gemacht werden:

      16316e33-96d0-4109-b071-bac6108e053c-image.png

      Beispiele für die Verwendung von NodeJS Bibliotheken in function Nodes gibts in diesem Thread.

      Ansonsten heißen die ehemaligen RBE Nodes nun Filter Nodes:

      f1725060-85cf-4507-9b99-62f8a2425010-image.png

      Wenn es Probleme mit dieser Node gibt - müsst ihr ggf. die rbe Nodes manuell deinstallieren. Im Palettenmanager tauchen die rbe/filter Nodes unter den Core Nodes auf und dürfen nicht mehr als eigenständige Nodes zu sehen sein.

      Die tail Node ist im Gegenzug nicht mehr Bestandteil der Core-Nodes. Wer diese also braucht oder im Einsatz hat muss diese neu installieren: https://flows.nodered.org/node/node-red-node-tail

      Ab der Version 2.1.
      gibt es als Highlight erst mal eine Guided Tour, die alle Neuerungen vorstellt. Allerdings kann man nicht die Vorgängerversionen anschauen - da die aktuelle Version bereits 2.2.2 ist - findet man nun die Guided Tour nur für diese Version, aber eben keine anderen.

      Die aktuelle Guided Tour findet man unter dem Change Log - das sich öffnet sobald man im Hauptmenü auf die aktuelle Versionsnummer klickt. Dort findet man dann ganz oben die Guided Tour.

      9a3e3557-dc9d-4bd9-8ffd-7653d22cb9af-image.png 3e1a5225-4350-4925-9bdb-8fa8a183dd66-image.png

      Die Details vom NR-Guru in Englisch findet man hier - zusammen mit einem Video: https://nodered.org/blog/2021/10/21/version-2-1-released

      Dieses Release vor allem verbessert die Übersichtlichkeit und das Anordnen der Nodes. Man markiert die gewünschten Nodes und kann diese dann über das Menü anordnen:

      fd523360-9619-42ba-8ac8-760cb77d5757-image.png

      Wer schon mal mit Visio oder ähnlichen Tools gearbeitet hat oder Visual Basic um eine GUI zu entwerfen, dem wird das sicher bekannt vorkommen. 😉

      Das wichtigste Menü - um die bessere Übersichtlichkeit zu nutzen - ist im Flows Menü:

      67634f91-3efe-44df-9d9f-bd82158cb2bf-image.png

      Damit kann mal alle Flows, die man gerade nicht braucht verstecken und über den Dialog wieder sichtbar machen oder man klickt in der Flow übersicht auf den Flow und toggelt zwischen versteckt (durchgestrichenes Auge) und sichtbar:

      d9c71a89-66b7-4417-9ad7-13a44890f331-image.png

      Ein weitere Möglichkeit einen Flow zu verstecken ist einfach in dem Tab auf das Auge zu klicken:
      18984b4c-2546-437c-8c94-bdb7b66406d8-image.png

      Eine weitere meines Erachtens sehr erwähnenswerte Neuerung ist, dass man nicht nur für Subflows, sondern auch für Flows Umgebungsvariablen nutzen zu können, um ggf. die Flows zu initialisieren. Dazu braucht man also nicht mehr unbedingt einen Datenpunkt im iobroker zu definieren.

      Bei Subflows sind diese Umgebungsvariablen schon eine gute Erfindung, da man so jede Instanz der Node bzw. des Subflows unterschiedlich initialisieren kann.

      Hier mal ein Beispiel für die Initialisierung eines Flows.
      In den Eigenschaften eines Flows gibt es rechts einen neuen Button, in dem man Umgebungsvariablen definieren kann.

      62165503-91fd-48fb-90b8-2e242c21c8b1-image.png

      In dem Flow kann man dann auf diese Umgebungsvariable zugreifen.

      f32e9b5e-369c-4577-80d2-b369903b8f02-image.png

      Ein weiteres Highlight dieser Version ist für mqtt-Benutzer.
      Man kann die MQTT Nodes nun dynamisch konfigurieren. In der Beschreibung zum mqtt-Broker kann man nun das automatische Verbinden unterbinden - das sehe ich aber nicht als den Hauptvorteil.

      Der Vorteil dieser MQTT Nodes dynamisch zu konfigurieren ist, dass man so ein topic getriggert auslesen kann, was man im iobroker Umfeld mit einer iobroker-get Node macht.
      Allerdings ist das nicht gut dokumentiert in der Hilfe:

      Wenn man die mqtt-In Node dynamisch konfiguriert - bekommt diese einen Eingang und kann dann über msg.topic getriggert das topic auslesen:

      6cab157b-d79b-47ea-9ca4-d78172a94ba2-image.png

      Damit das Ganze aber funktioniert muss man eine action subscribe mitgeben - und wie gesagt das ist alles nicht dokumentiert:

      79c934ee-4437-411d-9e42-15304638897f-image.png

      Ein paar Beispiele für valide actions - gerade auch zum manuelle Aufbau zu einem mqtt Broker gibts hier in dem folgenden Flow:

      [
         {
             "id": "52942541834747c1",
             "type": "mqtt out",
             "z": "54b226bc.0793e8",
             "name": "",
             "topic": "",
             "qos": "",
             "retain": "",
             "respTopic": "",
             "contentType": "",
             "userProps": "",
             "correl": "",
             "expiry": "",
             "broker": "8a6b74c0.3c461",
             "x": 390,
             "y": 3200,
             "wires": []
         },
         {
             "id": "e2f0aae314b88447",
             "type": "inject",
             "z": "54b226bc.0793e8",
             "name": "connect port 1883",
             "props": [
                 {
                     "p": "action",
                     "v": "connect",
                     "vt": "str"
                 },
                 {
                     "p": "broker",
                     "v": "{\"broker\":\"192.168.1.51\",\"port\":1883}",
                     "vt": "json"
                 }
             ],
             "repeat": "",
             "crontab": "",
             "once": false,
             "onceDelay": 0.1,
             "topic": "",
             "x": 190,
             "y": 3200,
             "wires": [
                 [
                     "52942541834747c1",
                     "c1cfb193f31c86a7"
                 ]
             ]
         },
         {
             "id": "f5ed93bae65b0374",
             "type": "inject",
             "z": "54b226bc.0793e8",
             "name": "connect 1884",
             "props": [
                 {
                     "p": "action",
                     "v": "connect",
                     "vt": "str"
                 },
                 {
                     "p": "broker",
                     "v": "{\"broker\":\"192.168.1.51\",\"port\":1884}",
                     "vt": "json"
                 }
             ],
             "repeat": "",
             "crontab": "",
             "once": false,
             "onceDelay": 0.1,
             "topic": "",
             "payloadType": "str",
             "x": 170,
             "y": 3280,
             "wires": [
                 [
                     "52942541834747c1"
                 ]
             ]
         },
         {
             "id": "c1cfb193f31c86a7",
             "type": "debug",
             "z": "54b226bc.0793e8",
             "name": "",
             "active": true,
             "tosidebar": true,
             "console": false,
             "tostatus": false,
             "complete": "true",
             "targetType": "full",
             "statusVal": "",
             "statusType": "auto",
             "x": 440,
             "y": 3120,
             "wires": []
         },
         {
             "id": "1342c8cb6c7d1396",
             "type": "inject",
             "z": "54b226bc.0793e8",
             "name": "disconnect",
             "props": [
                 {
                     "p": "action",
                     "v": "disconnect",
                     "vt": "str"
                 }
             ],
             "repeat": "",
             "crontab": "",
             "once": false,
             "onceDelay": 0.1,
             "topic": "",
             "x": 180,
             "y": 3420,
             "wires": [
                 [
                     "52942541834747c1"
                 ]
             ]
         },
         {
             "id": "a945fa7b989d68d6",
             "type": "mqtt in",
             "z": "54b226bc.0793e8",
             "name": "",
             "topic": "",
             "qos": "2",
             "datatype": "auto",
             "broker": "8a6b74c0.3c461",
             "nl": false,
             "rap": true,
             "rh": 0,
             "inputs": 1,
             "x": 390,
             "y": 3540,
             "wires": [
                 []
             ]
         },
         {
             "id": "a853a0255681f2c0",
             "type": "inject",
             "z": "54b226bc.0793e8",
             "name": "connect",
             "props": [
                 {
                     "p": "action",
                     "v": "connect",
                     "vt": "str"
                 },
                 {
                     "p": "topic",
                     "vt": "str"
                 }
             ],
             "repeat": "",
             "crontab": "",
             "once": false,
             "onceDelay": 0.1,
             "topic": "",
             "x": 200,
             "y": 3120,
             "wires": [
                 [
                     "52942541834747c1"
                 ]
             ]
         },
         {
             "id": "388b902f250d4ab1",
             "type": "inject",
             "z": "54b226bc.0793e8",
             "name": "force  connect 1884",
             "props": [
                 {
                     "p": "action",
                     "v": "connect",
                     "vt": "str"
                 },
                 {
                     "p": "broker",
                     "v": "{\"broker\":\"192.168.1.51\",\"port\":1884,\"force\":true}",
                     "vt": "json"
                 }
             ],
             "repeat": "",
             "crontab": "",
             "once": false,
             "onceDelay": 0.1,
             "topic": "",
             "x": 190,
             "y": 3340,
             "wires": [
                 [
                     "52942541834747c1"
                 ]
             ]
         },
         {
             "id": "6128f1909cbf8ea4",
             "type": "inject",
             "z": "54b226bc.0793e8",
             "name": "subscribe topic test",
             "props": [
                 {
                     "p": "action",
                     "v": "subscribe",
                     "vt": "str"
                 },
                 {
                     "p": "topic",
                     "vt": "str"
                 }
             ],
             "repeat": "",
             "crontab": "",
             "once": false,
             "onceDelay": 0.1,
             "topic": "test",
             "x": 180,
             "y": 3540,
             "wires": [
                 [
                     "a945fa7b989d68d6"
                 ]
             ]
         },
         {
             "id": "4c7b8677c28b28d6",
             "type": "inject",
             "z": "54b226bc.0793e8",
             "name": "Unsubscribe topic test",
             "props": [
                 {
                     "p": "action",
                     "v": "unsubscribe",
                     "vt": "str"
                 },
                 {
                     "p": "topic",
                     "vt": "str"
                 }
             ],
             "repeat": "",
             "crontab": "",
             "once": false,
             "onceDelay": 0.1,
             "topic": "test",
             "x": 209,
             "y": 3606,
             "wires": [
                 [
                     "a945fa7b989d68d6"
                 ]
             ]
         },
         {
             "id": "8a6b74c0.3c461",
             "type": "mqtt-broker",
             "name": "localhost:1883",
             "broker": "192.168.1.51",
             "port": "1883",
             "clientid": "",
             "autoConnect": false,
             "usetls": false,
             "protocolVersion": "5",
             "keepalive": "60",
             "cleansession": true,
             "birthTopic": "",
             "birthQos": "0",
             "birthRetain": "false",
             "birthPayload": "",
             "birthMsg": {},
             "closeTopic": "",
             "closePayload": "",
             "closeMsg": {},
             "willTopic": "",
             "willQos": "0",
             "willRetain": "false",
             "willPayload": "",
             "willMsg": {},
             "sessionExpiry": ""
         }
      ]
      

      Ansonsten kann man im Debug Fenster nun auch die Debug Nodes filtern, die man sehen will, ohne diese im Flow deaktivieren bzw. aktivieren zu müssen. Hab ich aber auch noch nicht benutzt.

      Auf die Highlights der Version 2.2 gehe ich hier erst mal nicht ein - hier verweise ich auf die aktuelle Guided Tour.

      ==============================================================================

      Ich halte mich mal an die Liste - und werde diese ggf. mit eine paar Beispielen aufzeigen:

      3.0.0 (2022-03-11)

      IMPORTANT: Node-RED is now v2. Please check your nodes for compatibility! See also https://nodered.org/blog/2021/07/20/version-2-0-released and https://nodered.org/blog/2021/10/21/version-2-1-released

      • (jwiesel) Node-RED updated to 2.2.2

      Nun erst nochmals vielen Dank! - Wie gesagt an dem vorangegangen Post sieht man, dass doch erhebliche Erweiterungen und Verbesserungen mit den neuen Verbesserungen einhergegangen sind.

      • (jwiesel) "Tail" node has been removed from the default palette in Node-RED 2.0. You can reinstall it from node-red-node-tail.

      wurde bereits erwähnt

      • (Apollon77) Automatically create missing folders when node-red creates objects in javascript., node-red. and 0_userdata.0.*

      Hier steckte ein größerer Aufwand dahinter ist nun aber wieder kompatibel mit dem neuen Admin 5 und erstellt nun automatisch Folder Objekte für alle Hierarchieebenen. Ich persönlich habe mich ja sehr darüber mokiert, dass das nun so unflexibel war und bin hier sehr dankbar, dass dieses Problem gelöst ist und man unter 0_userdata.0.* wieder volle Flexibilität hat. Auch Folder Objekte in der Hierarchie können im Nachhinein wieder zu States umgewandelt werden. Als Beispiel werde ich mal meinen Subflow verwenden, um zu demonstrieren, dass die Objekte nun automatisch von der iobroker-out Node angelegt werden.

      Ich hab einfach mal aus den JSONATA Beispielen mal einen JSON String als Beispiel genommen und in eine INJECT-Node gepackt:

      a1267a73-3522-4646-b11e-f42593e2d219-image.png
      Über eine Subflow Variable legt man fest unter welchem Datenpunkt die Struktur angelegt werden soll.

      Das Ergebnis kann sich nun sehen lassen:

      712528bf-8408-43ed-9a19-d3a16136ca7f-image.png

      Man sieht der ganze JSON String wird als Datenstruktur mit den erforderlichen Folder-Objekten von der iobroker-out Node angelegt. Herzlichen Dank nochmals an @apollon77

      • (jwiesel) Added NodeRed parameter httpStatic to instance settings

      Auch das habe ich angeregt, da ich bei jedem Update die settings.js immer anpassen musste und das in meinen Augen ein wichtiger Parameter ist, den man nun in der Adapterkonfiguration festlegen kann.

      76c54ba5-ea69-4dfd-bac8-1af434031a5a-image.png

      Dieses Verzeichnis ist das Basisverzeichnis, um im Dashboard auf eigene Resourcen zugreifen zu können. Das können JS-Programme sein (s. Steelseries Thread) oder bei mir liegen Bilder und Wettericons in diesem Pfad.

      Im Flow ist das dann das Root Verzeichnis:

      Hier zeige ich zum Beispiel ein bestimmtes Icon für das Wetter an:

      619c1387-4ddf-4a0e-a949-c52e6876381a-image.png
      Basis ist also : /images/WetterIcons/ zusammen mit dem http-Static Path - liegt das Verzeichnis auf der Maschine also im Verzeichnis:
      /data/node-red/images/WetterIcons/

      40fe5ce5-5d44-4979-981c-82b74ead5c5b-image.png

      • (bluefox) Added the reading of objects from admin for SelectID dialog

      Das ist meines Erachtens noch offen und funktioniert immer noch nicht.
      Also den Pfad weiterhin manuell rauskopieren oder den Adapter neu starten.

      • (bluefox) Added debug output: Cannot set state of non-existing object

      Das ist meines Erachtens auch eine riesige Verbesserung. Hier gab es in der Vorgängerversion folgenden Eintrag im Log:

      Automatic objects creation is not enabled. You can enable it in the node configuration
      

      Da kommt man auch nicht gleich drauf, dass diese Meldung erzeugt wird, weil eine iobroker-IN oder iobroker-GET Node einen Datenpunkt im iobroker lesen möchte, den es gar nicht gibt.

      Hier mal eine ioBroker IN Node, die auf einen Datenpunkt verweist - der nicht existiert.

      Nun war man in der Vergangenheit mit obiger Meldung aufgeschmissen, weil man

      1. nicht wusste welcher Datenpunkt nicht existiert
        und
      2. man nicht wusste welche Node auf diesen Datenpunkt verweist.

      ac7a449e-5760-4e00-9860-79083761ee34-image.png

      Nun löst der neue Log-Eintrag beide Probleme:

      5727f4605ec73bac: "ioBroker in" Cannot set state of non-existing object "0_userdata.0.testType5".
      

      zum einen weiß man nun welcher Datenpunkt nicht existiert und bekommt auch noch gleich die Node-ID mitgeliefert mit der man die Node in seinen Flows identifizieren kann. Also die ID aus dem LOG kopieren und dann in das Suchfenster der Flows eingeben.
      Mit der Suche wird einem nicht nur die Node angezeigt:

      3e6d891e-c8e6-4bab-99fd-096287a71c7b-image.png

      Durch einen Doppelklick auf die Lupe wird sowohl auf den Flow mit der betroffenen Node gewechselt, diese markiert (oranger Rahmen) und die Definition aufgemacht.
      527d91ef-a74a-4beb-80e5-2eac84c40722-image.png

      Also in meinen Augen ein toller Komfortgewinn.

      • (bluefox) Allow setting of regular expression in the list node in message

      Hier hat nach meinen Tests, sowohl der reguläre Ausdruck nicht richtig funktioniert und zukünftig ist dieser reguläre Ausdruck auch noch dynamisch konfigurierbar.

      Hier wieder ein Anwendungsbeispiel:

      Die folgende iobroker-List Node - kann alle Objekte eines bestimmten Typs mit einem bestimmten Pfad selektieren.
      Hier mal meine Struktur unter 0_userdata.0

      d3884432-46f6-463a-861f-4a7f3486ac2a-image.png

      Über einen regulären Ausdruck möchte ich nun nur die Datenpunkte

      0_userdata.0.testType2
      0_userdata.0.testType3
      0_userdata.0.testType4
      

      herausfiltern.

      Die Definition der List Node sieht also wie folgt aus:

      e05708f5-1c02-4221-8eb7-c58cbc268647-image.png

      Das Topic selektiert alle Objekte unter 0_userdata.0.* (grün markiert) und filtert dann mit dem regulären Ausdruck (gelb markiert) die 3 gewünschten Objekte heraus .

      Die Anforderung war nun auch den Filter dynamisch konfigurieren zu können.

      Nun kann sowohl das Topic (grün), als auch der reguläre Ausdruck (gelb) über msg.regex dynamisch konfiguriert werden!

      90deb17a-a679-4cfa-b69c-ca12b4729537-image.png

      • (bluefox) Allow the filtering of ack=false messages for IN node

      Auch dies macht nun den NR-Fans das Leben viel leichter - hier hatten die Blockly Fans immer einen Vorteil. Wir konnten nie auf ACK=false überprüfen, sondern nur auf true oder egal. Gut es ging umständlich, indem wir das gesamte Objekt auslasen und dann über eine Switch Node filterten.

      Nun kann man auch ACK= false filtern und quasi wie ein HW Adapter agieren:

      2e7b43e8-fa70-40e5-840f-dc013b18da0a-image.png

      Beispiel in Zusammenspiel mit dem YAHKA Adapter, um Endlosschleifen zu vermeiden.
      Man erstellt zum Beispiel einen eigenen Datenpunkt unter 0_userdata.0. Wenn man dann in der HomeApp das Gerät schaltet, wird dieser Datenpunkt mit ACK=false gesetzt. Der Flow filtert dann über ACK=false und der iobroker-In Node den Trigger heraus und schaltet die eigentliche Hardware. Als Rückmeldung setzt der Flow den Datenpunkt mit ACK=true und verhindert so, dass die HW erneut geschaltet wird.

      • (Apollon77) Enhance GetNode rbe/deadband functions to optionally ignore initial value (wurde in Version 3.1.x geändert - und am Ende ergänzt)

      • (Apollon77) Return undefined for GetNode if the state currently has no value set (e.g. because expired or never set)

      Das bisherige Verhalten - hatte einen nicht vorhandenen State einfach ignoriert. Damit konnte man im Flow nicht auf diesen Fall reagieren und ggf. einen State erstellen. Nun hat man folgende Möglichkeiten:

      768b1683-168e-4790-bc2e-8a2f974daf05-image.png

      1. Return nothing
        Das entspricht dem bisherigen Verhalten und nicht vorhandene States werden ignoriert. Eine info wird im iobroker Log geloggt.

      2. Return state value as undefined
        Es wird ein undefined zurückgegeben, egal ob ein Wert nicht existiert oder nicht initialisiert ist. Man muss also in der Folge selbst entscheiden, ob man auf beide Situationen unterschiedlich reagieren will.

      3. Return error
        Ein uninitialisierter Wert wird weiterhin undefined weitergeben, bei einem nicht vorhandenen Wert wird ein Fehler erzeugt. Wird dieser nicht behandelt gibt es nur eine Fehlereintrag im LOG mit dem entsprechenden Datenpunkt, der nicht vorhanden ist.
        In Kombination mit einer Catch-Node kann man diesen Fehler abfangen und den Datenpunkt/State über eine iobroker-out Nodes anlegen.

      • (Apollon77) Allow for GetNode to return an error if a state-id is used for which no object exists, else also return undefined

      Wurde wie vorher besprochen.

      • (Apollon77) Also allow to access system.* states directly

      Das war leider seit der Version 2.x des iobroker NodeRed-Adapters nicht mehr möglich. In der Version 1 ging das. Somit musste man einen Alias bemühen, um den Zustand von beispielsweise Adapter zu überprüfen.

      Nun kann man die Objekte unter system wieder abfragen:

      4de0c45b-f846-447a-94c5-8e453c59e117-image.png

      Damit ist es ohne Umwege wieder möglich - den Zustand von Adapter zu analysieren und ggf. eigene Maßnahmen einzuleiten.

      Vielen Dank auch hierfür.

      • (Apollon77) When RBE function is used on InNode and not value is sent on start still initialize current value internally

      wurde bereits besprochen

      • (Apollon77) Add node-ID in front of all log lines logged by node logic

      Der Komfortgewinn wurde in Zusammenhang bei der Suche von iobroker-IN Nodes, die auf nicht vorhandene Datenpunkte verweisen erläutert.

      • (jwiesel) Changed default setting to "convert data from ioBroker nodes into Strings" to false. Setting will not be changed automatically in instances already existing

      Dies ist wohl eine der wichtigsten Verbesserungen für Anfänger. Wie oft muss man fragen, ob hier der Haken rausgenommen wurde. Nun ist der Standardwert, dass aus dem iobroker gelesene Werte ihren Typ behalten und nicht in Strings umgewandelt werden!

      ==============================================================================

      Also nochmals vielen Dank - an alle die an den Verbesserungen mitgewirkt haben und falls es noch Fragen zu meinen Erläuterungen gibt, nutzt den Thread und ich denke neben mir werden auch alle anderen versuchen, hier zu helfen!!!

      Ach ja - noch was Wichtiges: Dieser Node-Red Adapter ist nun mit dem JS 4.0.x Adapter kompatibel!!! - Somit können auch NR-Fans nun wieder das System auf den akuellen Stand bringen!

      ==============================================================================
      Änderungen in Version 3.2.0

      • ListenpunktEnhance GetNode rbe/deadband functions to optionally ignore initial value

      Das ignorieren des Initialwertes entspricht nun dem Verhalten der Filter Node und bedeutet, dass dieser Initialwert nicht gesendet wird, sondern nur zum Initialisieren der Node genutzt wird, um Änderungen zu erkennen.

      Die Beschreibung wurde von Ignore auf Initialize geändert:

      3cab447c-e3a7-467c-b7a1-f461ba4e03a1-image.png

      Will man also den Anfangswert nach Adapterstart oder Neustart der Flows unterdrücken will, nutzt man die Initialisierungsoption - anderenfalls wird dieser Wert - falls Nachrichten bei Start auslesen gewählt ist - gesendet.

      Hier das Bild direkt nach Adapterstart - wenn send msg at start definiert wurde:

      f75c3999-d239-436a-bfcb-84c339ee73f4-image.png

      Falls no msg at start ausgewählt wurde findet die Initialisierung nach dem ersten Update statt.

      Ansonsten stehen wie beim Filter diese Optionen zur Verfügung:

      1. Wert hat sich geändert.
      2. Wert hat sich um einen definierten Wert geändert (also um eine Zahl)
      3. Wert hat sich um einen Prozentsatz geändert.

      In den Fällen 2 und 3 wird größer gleich als Vergleich angewandt.

      Das ganze funktioniert nicht über Wildcards.

      Für alle komplexeren Fälle empfieht es sich die Filter-Node in Kombination zu nutzen.
      In diesem Fall sollte man die iobroker-In Node, wie folgt konfigurieren:

      1. send msg at start
      2. send all events

      Die Filterung konfiguriert man dann über die Filter Node. Da stehen weitere Optionen zur Verfügung. Nutzt man Wildcards in der iobroker-IN Node, und konfiguriert, dass der Filter auf topic Basis arbeitet:

      ddcf1313-5065-47b1-994b-1685794a6585-image.png

      • (Bannsaenger) Added option for in Node to choose topic format (MQTT with / or ioBroker with .). Default: MQTT

      Nach dem Bilder in meinen Augen mehr als 1000 Worte sagen. Das bisherige Verhalten die Hierarchien der Topics mit / zu trennen, wie es unter MQTT üblich ist (grün), kann man sich das topic auch als iobroker Pfade mit einem Punkt zur Trennung der Hierarchieebenen ausgeben lassen (gelb).

      941e64f1-944b-47d0-88be-1f0f0137cfde-image.png

      Zu den letzten beiden Punkten kann ich nicht viel sagen, da ich weder Authentisierung, noch das Ändern der Pfade für den Webzugang genutzt habe.

      • Added new parameter "httpNodeRoot" as httpRoot has been replaced by httpAdminRoot in version 3.0.0.

      • Added extended authentication to instance settings and config
        Hier hat man in der NodeRed Adapter Konfiguration einen eigenen Tab, mit folgenden Optionen:

      1. Keine Authentifizierung
      2. Einfache Authentifizierung - mit Benutzer und Passwort (wobei ich nicht weiß, ob das wirklich noch funktioniert)
      3. Erweiterte Authentifizierung - hier kann man dann verschiedene Benutzer mit einer differenzierten Rechtevergabe definieren.

      5a60bb09-ded0-415a-aa24-dcaa2fa9c8fe-image.png

      Aber wie gesagt - hier muss man selbst Nachlesen welche Rechte es gibt.

      26ce2512-2b1b-4d23-b0d2-5ec9a11cb104-image.png

      Viel habe ich zu Benutzerberechtigungen nicht gefunden: Entweder "read" oder "*" für Vollzugriff. Welche Objekte es gibt, muss man eher ausprobieren. HIer mal die Seite zu BEnutzerberechtigungen: https://nodered.org/docs/user-guide/runtime/securing-node-red#user-permissions

      posted in Node-Red
      mickym
      mickym
    • Internet-Speedtest als Adapterersatz via NodeRed

      Da ich keinen vernünftigen Adapter im stable gefunden habe und ich ja auch bereits in einem eigenen Thread gezeigt habe, wie einfach es mit NodeRed in der jetzigen Version ist, externe NodeJS Module zu nutzen, habe ich einen super simplen Flow erstellt, der einen Speedtest durchführt und alles in Datenpunkte schreibt. (Also als Adapterersatz quasi quick & dirty)

      Da die Node in NodeRed auch schon in die Jahre gekommen ist, habe ich es über die automatische Installation einfach gehabt.

      Ich habe aber bewußt nichts konfiguriert, man muss also mit dem Ergebnis so leben, wie es ist. 😉 Das Tool bzw. die Bibliothek mit der der Speedtest arbeitet ist diese: https://github.com/ddsol/speedtest.net#readme

      Hier mal das Ergebnis - etwaige Umrechnungen müsst ihr selbst vornehmen:

      10740c03-1f22-4516-9384-72a54881e793-image.png

      Der Flow ist super simple und nutzt natürlich meinen Subflow zur automatischen Erstellung von Datenpunkten aus komplexen Datenstrukturen:

      357106df-6aca-46c6-86d3-276d7d00eab6-image.png

      Wenn ihr den Flow importiert müsst ihr ein paar Minuten warten, bis NodeRed im Hintergrund die Bibliothek installiert hat.

      Wer ungeduldig ist bekommt den Fehler: Node ist nicht vorhanden. Also so ca. 5 Minuten warten bevor ihr den Flow triggert.
      66c14325-7d60-4257-9405-08253828f154-image.png

      Und natürlich wieder die Erstellung von Fremdobjekten im NodeRed Adapter zulassen:

      [
          {
              "id": "6e802f1553b18149",
              "type": "subflow",
              "name": "JSON or Obj to IOBroker",
              "info": "# Creates an IOBroker tree\n\nThis node creates an IOBroker tree out of an Java-Object or JSON String.\n\nThe object tree will be created under 0_userdata.0\nIn addition to the JSON-String or Java Object as `msg.payload` it is necessary to specify a `msg.top` properity in addition to the msg-Object.\n\nThe object tree will be created under 0_userdata.0\n\nExisting `msg.topic` entries will be deleted.\nAn iobroker-out node has to be appended to this subflow node. It is not part of the subflow itself. No topic should be specified in the iobroker out node.\n\nIs `msg.top` property isn't defined, the top-value of the node (environment variable top) is used. \n\n**Attention:**\nIf msg.top and top is empty, all msg.topics (msg.topic) will be directly prefixed with 0_userdata.0. . \n\n# Erstellt einen Objektbaum im ioBroker\n\nDiese Node erstellt einen Objektbaum im ioBroker aus einem JAVA Objekt bzw. einem JSON String. \n\nDer Baum wird in jedem Fall unter 0_userdata.0 erstellt und zwar unter dem Topic der in` msg.top` mitgegeben wurde. In der `msg.payload` befindet sich dann der JSON String oder das entsprechende Objekt.\n\nExistierende `msg.topic `Einträge werden gelöscht.\nEin entsprechende iobroker-out Node muss an den Flow angehängt werden. Sie ist nicht Bestandteil des Subflows. In dieser iobroker-out Node darf kein Topic angegeben werden. \n\nFalls msg.top nicht definiert wurde, wird der top-Wert (Umgebungsvariable top) der Node verwendet. <br>\n\n**Achtung:**\nWenn top und msg.top leer ist, werden alle msg.topics (msg.topic) direkt unter dem Präfix 0_userdata.0., angelegt bzw. ausgegeben. ",
              "category": "",
              "in": [
                  {
                      "x": 60,
                      "y": 160,
                      "wires": [
                          {
                              "id": "e023fe88445ce43e"
                          }
                      ]
                  }
              ],
              "out": [
                  {
                      "x": 2120,
                      "y": 280,
                      "wires": [
                          {
                              "id": "f5d52c6a57d08904",
                              "port": 0
                          },
                          {
                              "id": "74c895ce724750de",
                              "port": 0
                          }
                      ]
                  }
              ],
              "env": [
                  {
                      "name": "top",
                      "type": "str",
                      "value": "objRoot"
                  }
              ],
              "meta": {},
              "color": "#E2D96E",
              "icon": "node-red/batch.svg"
          },
          {
              "id": "3e11e8338f694832",
              "type": "split",
              "z": "6e802f1553b18149",
              "name": "split object",
              "splt": "\\n",
              "spltType": "str",
              "arraySplt": 1,
              "arraySpltType": "len",
              "stream": false,
              "addname": "key",
              "x": 1170,
              "y": 160,
              "wires": [
                  [
                      "0562a4249c8b856b"
                  ]
              ]
          },
          {
              "id": "0562a4249c8b856b",
              "type": "change",
              "z": "6e802f1553b18149",
              "name": "add key to topic",
              "rules": [
                  {
                      "t": "set",
                      "p": "stateName",
                      "pt": "msg",
                      "to": "key",
                      "tot": "msg"
                  },
                  {
                      "t": "set",
                      "p": "topic",
                      "pt": "msg",
                      "to": "topic  & '.' & key",
                      "tot": "jsonata"
                  },
                  {
                      "t": "change",
                      "p": "topic",
                      "pt": "msg",
                      "from": " ",
                      "fromt": "str",
                      "to": "_",
                      "tot": "str"
                  }
              ],
              "action": "",
              "property": "",
              "from": "",
              "to": "",
              "reg": false,
              "x": 1360,
              "y": 160,
              "wires": [
                  [
                      "ddc90985bef0fafa"
                  ]
              ]
          },
          {
              "id": "ddc90985bef0fafa",
              "type": "switch",
              "z": "6e802f1553b18149",
              "name": "is type?",
              "property": "payload",
              "propertyType": "msg",
              "rules": [
                  {
                      "t": "istype",
                      "v": "array",
                      "vt": "array"
                  },
                  {
                      "t": "istype",
                      "v": "object",
                      "vt": "object"
                  },
                  {
                      "t": "else"
                  }
              ],
              "checkall": "true",
              "repair": false,
              "outputs": 3,
              "x": 1540,
              "y": 160,
              "wires": [
                  [
                      "bfce19b206660fbe"
                  ],
                  [
                      "3e11e8338f694832"
                  ],
                  [
                      "1a8c03d866b85b12"
                  ]
              ]
          },
          {
              "id": "bfce19b206660fbe",
              "type": "split",
              "z": "6e802f1553b18149",
              "name": "split array",
              "splt": "\\n",
              "spltType": "str",
              "arraySplt": 1,
              "arraySpltType": "len",
              "stream": false,
              "addname": "",
              "x": 580,
              "y": 280,
              "wires": [
                  [
                      "e89927810c6d75ec"
                  ]
              ]
          },
          {
              "id": "e89927810c6d75ec",
              "type": "change",
              "z": "6e802f1553b18149",
              "name": "add index to topic",
              "rules": [
                  {
                      "t": "set",
                      "p": "topic",
                      "pt": "msg",
                      "to": "topic  & '.' & parts.index",
                      "tot": "jsonata"
                  }
              ],
              "action": "",
              "property": "",
              "from": "",
              "to": "",
              "reg": false,
              "x": 770,
              "y": 280,
              "wires": [
                  [
                      "a4d1a5d04564dc77"
                  ]
              ]
          },
          {
              "id": "f5d52c6a57d08904",
              "type": "change",
              "z": "6e802f1553b18149",
              "name": "finalize msg.topic",
              "rules": [
                  {
                      "t": "set",
                      "p": "top",
                      "pt": "msg",
                      "to": "'0_userdata.0.' & top",
                      "tot": "jsonata"
                  },
                  {
                      "t": "set",
                      "p": "topic",
                      "pt": "msg",
                      "to": "top & topic",
                      "tot": "jsonata"
                  },
                  {
                      "t": "change",
                      "p": "topic",
                      "pt": "msg",
                      "from": "..",
                      "fromt": "str",
                      "to": ".",
                      "tot": "str"
                  }
              ],
              "action": "",
              "property": "",
              "from": "",
              "to": "",
              "reg": false,
              "x": 1970,
              "y": 240,
              "wires": [
                  []
              ]
          },
          {
              "id": "c863dd7d651b2272",
              "type": "switch",
              "z": "6e802f1553b18149",
              "name": "is type?",
              "property": "payload",
              "propertyType": "msg",
              "rules": [
                  {
                      "t": "istype",
                      "v": "json",
                      "vt": "json"
                  },
                  {
                      "t": "istype",
                      "v": "object",
                      "vt": "object"
                  },
                  {
                      "t": "istype",
                      "v": "array",
                      "vt": "array"
                  },
                  {
                      "t": "else"
                  }
              ],
              "checkall": "true",
              "repair": false,
              "outputs": 4,
              "x": 400,
              "y": 160,
              "wires": [
                  [
                      "158930afddd0780b"
                  ],
                  [
                      "3e11e8338f694832"
                  ],
                  [
                      "bfce19b206660fbe"
                  ],
                  [
                      "a4d1a5d04564dc77"
                  ]
              ]
          },
          {
              "id": "158930afddd0780b",
              "type": "json",
              "z": "6e802f1553b18149",
              "name": "",
              "property": "payload",
              "action": "",
              "pretty": false,
              "x": 570,
              "y": 120,
              "wires": [
                  [
                      "3649300b4c233b10"
                  ]
              ]
          },
          {
              "id": "1a8c03d866b85b12",
              "type": "switch",
              "z": "6e802f1553b18149",
              "name": "is msg.top != null",
              "property": "top",
              "propertyType": "msg",
              "rules": [
                  {
                      "t": "nnull"
                  },
                  {
                      "t": "null"
                  }
              ],
              "checkall": "true",
              "repair": false,
              "outputs": 2,
              "x": 1750,
              "y": 280,
              "wires": [
                  [
                      "f5d52c6a57d08904"
                  ],
                  [
                      "74c895ce724750de"
                  ]
              ]
          },
          {
              "id": "e023fe88445ce43e",
              "type": "change",
              "z": "6e802f1553b18149",
              "name": "",
              "rules": [
                  {
                      "t": "delete",
                      "p": "topic",
                      "pt": "msg"
                  }
              ],
              "action": "",
              "property": "",
              "from": "",
              "to": "",
              "reg": false,
              "x": 210,
              "y": 160,
              "wires": [
                  [
                      "c863dd7d651b2272"
                  ]
              ]
          },
          {
              "id": "3649300b4c233b10",
              "type": "switch",
              "z": "6e802f1553b18149",
              "name": "is array?",
              "property": "payload",
              "propertyType": "msg",
              "rules": [
                  {
                      "t": "istype",
                      "v": "array",
                      "vt": "array"
                  },
                  {
                      "t": "else"
                  }
              ],
              "checkall": "true",
              "repair": false,
              "outputs": 2,
              "x": 700,
              "y": 120,
              "wires": [
                  [
                      "bfce19b206660fbe"
                  ],
                  [
                      "3e11e8338f694832"
                  ]
              ]
          },
          {
              "id": "1b8480cd2df7ba3f",
              "type": "comment",
              "z": "6e802f1553b18149",
              "name": "Array",
              "info": "",
              "x": 400,
              "y": 280,
              "wires": []
          },
          {
              "id": "b3541807672be040",
              "type": "comment",
              "z": "6e802f1553b18149",
              "name": "object",
              "info": "",
              "x": 1140,
              "y": 100,
              "wires": []
          },
          {
              "id": "a4d1a5d04564dc77",
              "type": "switch",
              "z": "6e802f1553b18149",
              "name": "is type?",
              "property": "payload",
              "propertyType": "msg",
              "rules": [
                  {
                      "t": "istype",
                      "v": "object",
                      "vt": "object"
                  },
                  {
                      "t": "istype",
                      "v": "array",
                      "vt": "array"
                  },
                  {
                      "t": "else"
                  }
              ],
              "checkall": "true",
              "repair": false,
              "outputs": 3,
              "x": 960,
              "y": 280,
              "wires": [
                  [
                      "3e11e8338f694832"
                  ],
                  [
                      "bfce19b206660fbe"
                  ],
                  [
                      "1a8c03d866b85b12"
                  ]
              ]
          },
          {
              "id": "74c895ce724750de",
              "type": "change",
              "z": "6e802f1553b18149",
              "name": "finalize msg.topic",
              "rules": [
                  {
                      "t": "set",
                      "p": "top",
                      "pt": "msg",
                      "to": "top",
                      "tot": "env"
                  },
                  {
                      "t": "set",
                      "p": "top",
                      "pt": "msg",
                      "to": "'0_userdata.0.' & top",
                      "tot": "jsonata"
                  },
                  {
                      "t": "set",
                      "p": "topic",
                      "pt": "msg",
                      "to": "top & topic",
                      "tot": "jsonata"
                  },
                  {
                      "t": "change",
                      "p": "topic",
                      "pt": "msg",
                      "from": "..",
                      "fromt": "str",
                      "to": ".",
                      "tot": "str"
                  }
              ],
              "action": "",
              "property": "",
              "from": "",
              "to": "",
              "reg": false,
              "x": 1970,
              "y": 320,
              "wires": [
                  []
              ]
          },
          {
              "id": "c9b74b75fb88fae5",
              "type": "comment",
              "z": "2140b385.78fb7c",
              "name": "Speedtest Internet",
              "info": "",
              "x": 190,
              "y": 3600,
              "wires": []
          },
          {
              "id": "ca0931a9b59c5c60",
              "type": "function",
              "z": "2140b385.78fb7c",
              "name": "Speedtest",
              "func": "msg = {};\n\n(async () => {\n  try {\n    await speedTest({acceptLicense: true, acceptGdpr: true}).then(output => {\n    msg.payload = output;\n//    clearTimeout(myTimeout);\n    node.send(msg);\n    node.done();\n    }).catch(err => {\n    // An error has been returned by the Promise.\n    // Do something with it...\n    msg.error = {name: err.name, \n            message:err.message};\n    node.error(\"Error in try\",msg);\n    node.done();\n});\n  } catch (err) {\n    node.error(\"Error in async\",{error: {name: err.name,  message:err.message}});\n  } \n})();\n",
              "outputs": 1,
              "noerr": 0,
              "initialize": "",
              "finalize": "",
              "libs": [
                  {
                      "var": "speedTest",
                      "module": "speedtest-net"
                  }
              ],
              "x": 320,
              "y": 3720,
              "wires": [
                  [
                      "c05dc2ab8d6c3bf2"
                  ]
              ]
          },
          {
              "id": "96b2931dd2362824",
              "type": "inject",
              "z": "2140b385.78fb7c",
              "name": "",
              "props": [
                  {
                      "p": "payload"
                  }
              ],
              "repeat": "",
              "crontab": "",
              "once": false,
              "onceDelay": 0.1,
              "topic": "",
              "payload": "true",
              "payloadType": "bool",
              "x": 170,
              "y": 3720,
              "wires": [
                  [
                      "ca0931a9b59c5c60"
                  ]
              ]
          },
          {
              "id": "c05dc2ab8d6c3bf2",
              "type": "change",
              "z": "2140b385.78fb7c",
              "name": "",
              "rules": [
                  {
                      "t": "set",
                      "p": "payload.timestamp",
                      "pt": "msg",
                      "to": "$moment(payload.timestamp).format('DD.MM.YYYY HH:mm:ss')\t",
                      "tot": "jsonata"
                  }
              ],
              "action": "",
              "property": "",
              "from": "",
              "to": "",
              "reg": false,
              "x": 550,
              "y": 3720,
              "wires": [
                  [
                      "fcf68520386d279a"
                  ]
              ]
          },
          {
              "id": "fcf68520386d279a",
              "type": "subflow:6e802f1553b18149",
              "z": "2140b385.78fb7c",
              "name": "",
              "env": [
                  {
                      "name": "top",
                      "value": "speedTest",
                      "type": "str"
                  }
              ],
              "x": 830,
              "y": 3720,
              "wires": [
                  [
                      "5df05b2321564d35"
                  ]
              ]
          },
          {
              "id": "5df05b2321564d35",
              "type": "ioBroker out",
              "z": "2140b385.78fb7c",
              "name": "",
              "topic": "",
              "ack": "true",
              "autoCreate": "true",
              "stateName": "",
              "role": "",
              "payloadType": "",
              "readonly": "true",
              "stateUnit": "",
              "stateMin": "",
              "stateMax": "",
              "x": 1060,
              "y": 3720,
              "wires": []
          },
          {
              "id": "194a0d9b8bff3a64",
              "type": "catch",
              "z": "2140b385.78fb7c",
              "name": "",
              "scope": [
                  "ca0931a9b59c5c60"
              ],
              "uncaught": false,
              "x": 270,
              "y": 3800,
              "wires": [
                  [
                      "5f88c6f34f800ee0"
                  ]
              ]
          },
          {
              "id": "5f88c6f34f800ee0",
              "type": "debug",
              "z": "2140b385.78fb7c",
              "name": "",
              "active": true,
              "tosidebar": true,
              "console": false,
              "tostatus": false,
              "complete": "true",
              "targetType": "full",
              "statusVal": "",
              "statusType": "auto",
              "x": 430,
              "y": 3800,
              "wires": []
          }
      ]
      

      Achso und wer den ganzen Datenschutzeinstellungen nicht zustimmt, der muss bitte in der Funktion Node die Parameter auf false setzen (Zeile 5):

      {acceptLicense: true, acceptGdpr: true}
      

      Fehler - also bei nicht akzeptieren Datenschutz oder Lizenzbestimmungen werden dann über die Catch Node abgefangen und ausgegeben. Wer quasi aber schon mal zugestimmt hat, dann wird das anscheinend gecacht.

      Achso für alle die nicht so bewandert mit den Möglichkeiten sind:

      1. In der Inject Node kann man ein Wiederholungsintervall definieren, um den Speedtest zyklisch auszuführen.
        6f94c784-e24a-41c9-9dff-5f9e3c98fe64-image.png

      oder man

      1. erstellt einen weiteren Datenpunkt und hängt vorne noch eine iobrokerIN Node dran. Dann kann man über seine VIS oder was auch immer für eine Visualisierung den Speedtest bei Bedarf trigggern.

      Viel Spaß damit. 😁

      posted in Node-Red
      mickym
      mickym
    • Laufschrift in einem NodeRed Flow erzeugen

      Da ich von einem User hier an Board gefragt worden bin, ob man in NodeRed eine Laufschrift erzeugen kann und ich vergeblich nach einer bereits fertigen Node gesucht habe, habe ich dieses Mal selbst ein function Node geschrieben. 😉

      Hintergrund ist wohl, dass man bei den KNX-Tastern auf 14 Zeichen zur Anzeige von Text. Gibt auch bereits einen Flow zu dem Thema: https://knx-user-forum.de/forum/supportforen/proserv/1470641-14-byte-text-von-node-red-auf-den-bus
      Das kam mir aber sehr komplex vor.

      Für die Möglichkeiten des Scroll-Textes habe ich mich wie in diesem Video beschrieben an diese Gira Blöcke angelehnt.

      Hier dann als Demo im NodeRed Dashboard da ich ja keinen KNX Taster habe:

      Mode Zirkulierend:

      Dabei konnte ich mal wieder meine Javascript Skills testen - aber die sind natürlich laienhaft im Vergleich zu den Profis hier.

      Interessant ist, wie man in function Nodes (ich fand das nicht dokumentiert) einen Timer erstellen kann, der auch bei erneutem Aufruf der Node ansprechbar bleibt. Das geht anscheinend in dem man die Variable nicht normal im Kontext abspeichert sondern quasi als Eigenschaft des Kontextes. Das wusste ich noch nicht. Man erstellt deshalb auch keine Variable sondern erstellt es quasi implizit im Kontext:

      context.timer; /* undokumentiert - setze Variable im Node Kontext um 
                          auf Timerinstanz zu zugreifen */
      

      Hier nun die Funktionsweise dieser Node:

      Laufschrift erzeugen

      Diese Node erzeugt in konfigurierbaren Textteile, um so eine Laufschrift zu erzeugen.

      Grundsätzlich startet eine msg.payload automatisch die Node mit Standardvorgaben.
      Ein erneutes Senden einer msg.payload stoppt bzw. inaktiviert die Node wieder.

      Konfiguration

      Eine Nachricht, die keine msg.payload enthält (z. Bsp. nur eine msg.config) oder eine leere msg.payload stoppt die Node.
      Die Konfigurationsparameter können über eine msg.config erstellt werden. Dabei muss das Konfigurations-Objekt vollständig übergeben werden.

      Das Konfiguationsobjekt ist direkt im Code wie folgt beschrieben:

      {"offset": 1,        // scrollen um x Zeichen
      "textwindow": 14,   // Fenster wie groß der Text sein darf
      "interval": 1000,   // ms mit der sich der Text bewegt bzw. ausgegeben wird
      "mode": 0,          // 0 = Zirkulierend; 1 = Anfang - Ende; 2 = Hin und Her
      "separator": " * "  // Trennungsstring am Ende des Textes}
      

      Die passenden Scrollparameter muss man halt selbst herausfinden. Ausserdem belasten natürlich zu kurze Intervalle das System. Voreingestellt sind 1000 ms - was ein Laufschrift sehr ruckelig macht, aber dafür kann man die payload besser debuggen, falls erforderlich.

      Den gleichen Text findet man auch in der Beschreibung zu der function Node:

      Ansonsten habe ich alles in den Hilfetext der function Node geschrieben mit einem Beispielflow:

      17d0ecb5-fb40-4d6d-8cba-1db3f53c0868-image.png

      Demo:

      Lauftext.gif

      Und natürlich zum Schluss der Beispielflow mit der function Node für den Lauftext:

      EDIT: 5.2.2023
      Enthält nun Version 0.3 - wenn die Textlänge der payload unter oder gleich dem textwindow ist, wird der Text unverändert als einfacher String weitergegeben.

      EDIT 11.2.2023
      Enthält nun Version 0.4 - Lauftext wird nur noch gestoppt mit leerer payload oder Länge kleiner textwindow. Ansonsten kann nun Text und Konfiguration dynamisch geändert werden.

      EDIT 17.2.2023
      Timer nicht mehr direkt im Kontext gespeichert und leere msg.config ohne payload startet keinen neuen Timer mehr. Version 0.5.1

      [
          {
              "id": "03201976729fd712",
              "type": "inject",
              "z": "5289f6ad4bf32e52",
              "name": "Beispiel",
              "props": [
                  {
                      "p": "payload"
                  }
              ],
              "repeat": "",
              "crontab": "",
              "once": false,
              "onceDelay": 0.1,
              "topic": "",
              "payload": "Dies ist ein sehr, sehr langer Text",
              "payloadType": "str",
              "x": 210,
              "y": 220,
              "wires": [
                  [
                      "ed7d5b75938de5ff"
                  ]
              ]
          },
          {
              "id": "f03c5796d29ad693",
              "type": "inject",
              "z": "5289f6ad4bf32e52",
              "name": "",
              "props": [
                  {
                      "p": "payload"
                  }
              ],
              "repeat": "",
              "crontab": "",
              "once": false,
              "onceDelay": 0.1,
              "topic": "",
              "payload": "Hallo",
              "payloadType": "str",
              "x": 210,
              "y": 320,
              "wires": [
                  [
                      "ed7d5b75938de5ff"
                  ]
              ]
          },
          {
              "id": "4cd600bbf5582f51",
              "type": "inject",
              "z": "5289f6ad4bf32e52",
              "name": "stop",
              "props": [
                  {
                      "p": "payload"
                  }
              ],
              "repeat": "",
              "crontab": "",
              "once": false,
              "onceDelay": 0.1,
              "topic": "",
              "payload": "",
              "payloadType": "str",
              "x": 210,
              "y": 360,
              "wires": [
                  [
                      "ed7d5b75938de5ff"
                  ]
              ]
          },
          {
              "id": "8cfd9b55e5251123",
              "type": "inject",
              "z": "5289f6ad4bf32e52",
              "name": "config fast",
              "props": [
                  {
                      "p": "config",
                      "v": "{\"offset\":2,\"textwindow\":14,\"interval\":200,\"mode\":0,\"separator\":\" * \"}",
                      "vt": "json"
                  }
              ],
              "repeat": "",
              "crontab": "",
              "once": false,
              "onceDelay": 0.1,
              "topic": "",
              "x": 200,
              "y": 120,
              "wires": [
                  [
                      "4c274b6ade59ef73"
                  ]
              ]
          },
          {
              "id": "fda69c0a0c8d05bc",
              "type": "catch",
              "z": "5289f6ad4bf32e52",
              "name": "",
              "scope": [
                  "9bf7625128ecafdc"
              ],
              "uncaught": false,
              "x": 230,
              "y": 540,
              "wires": [
                  [
                      "05275e48396c5862"
                  ]
              ]
          },
          {
              "id": "05275e48396c5862",
              "type": "debug",
              "z": "5289f6ad4bf32e52",
              "name": "ErrObjekt",
              "active": true,
              "tosidebar": true,
              "console": false,
              "tostatus": false,
              "complete": "true",
              "targetType": "full",
              "statusVal": "",
              "statusType": "auto",
              "x": 400,
              "y": 540,
              "wires": []
          },
          {
              "id": "10903a351cc8f674",
              "type": "change",
              "z": "5289f6ad4bf32e52",
              "name": "Modus",
              "rules": [
                  {
                      "t": "set",
                      "p": "modes",
                      "pt": "msg",
                      "to": "[{\"id\":0,\"Beschreibung\":\"0 - Zirkulierend\"},{\"id\":1,\"Beschreibung\":\"1 - Anfang bis Ende\"},{\"id\":2,\"Beschreibung\":\"2 - Hin und Her\"}]",
                      "tot": "json"
                  },
                  {
                      "t": "set",
                      "p": "payload",
                      "pt": "msg",
                      "to": "modes[id=$$.config.mode].Beschreibung",
                      "tot": "jsonata"
                  }
              ],
              "action": "",
              "property": "",
              "from": "",
              "to": "",
              "reg": false,
              "x": 410,
              "y": 120,
              "wires": [
                  [
                      "a9fff8ec4b1f4231"
                  ]
              ]
          },
          {
              "id": "a9fff8ec4b1f4231",
              "type": "ui_text",
              "z": "5289f6ad4bf32e52",
              "group": "57f13d6f733e5c9d",
              "order": 5,
              "width": 0,
              "height": 0,
              "name": "Modus",
              "label": "Modus",
              "format": "{{msg.payload}}",
              "layout": "row-spread",
              "className": "",
              "x": 690,
              "y": 120,
              "wires": []
          },
          {
              "id": "23af56526b7b3c88",
              "type": "inject",
              "z": "5289f6ad4bf32e52",
              "name": "Beispiel 2",
              "props": [
                  {
                      "p": "payload"
                  }
              ],
              "repeat": "",
              "crontab": "",
              "once": false,
              "onceDelay": 0.1,
              "topic": "",
              "payload": "Neuer Beispieltext 2!",
              "payloadType": "str",
              "x": 200,
              "y": 260,
              "wires": [
                  [
                      "ed7d5b75938de5ff"
                  ]
              ]
          },
          {
              "id": "a07f352124bb3886",
              "type": "inject",
              "z": "5289f6ad4bf32e52",
              "name": "config slow",
              "props": [
                  {
                      "p": "config",
                      "v": "{\"offset\":2,\"textwindow\":14,\"interval\":1000,\"mode\":0,\"separator\":\" * \"}",
                      "vt": "json"
                  }
              ],
              "repeat": "",
              "crontab": "",
              "once": false,
              "onceDelay": 0.1,
              "topic": "",
              "x": 200,
              "y": 160,
              "wires": [
                  [
                      "4c274b6ade59ef73"
                  ]
              ]
          },
          {
              "id": "a4bc525066ffdd78",
              "type": "inject",
              "z": "5289f6ad4bf32e52",
              "name": "Beispiel immer schnell",
              "props": [
                  {
                      "p": "payload"
                  },
                  {
                      "p": "config",
                      "v": "{     \"offset\": 2,     \"textwindow\": 14,     \"interval\": 200,     \"mode\": 0,     \"separator\": \" * \" }",
                      "vt": "json"
                  }
              ],
              "repeat": "",
              "crontab": "",
              "once": false,
              "onceDelay": 0.1,
              "topic": "",
              "payload": "Dies ist ein sehr, sehr langer Text",
              "payloadType": "str",
              "x": 160,
              "y": 420,
              "wires": [
                  [
                      "ed7d5b75938de5ff"
                  ]
              ]
          },
          {
              "id": "daf6067dc52d7873",
              "type": "inject",
              "z": "5289f6ad4bf32e52",
              "name": "Beispiel 2 immer langsam",
              "props": [
                  {
                      "p": "payload"
                  },
                  {
                      "p": "config",
                      "v": "{\"offset\":2,\"textwindow\":14,\"interval\":1000,\"mode\":0,\"separator\":\" * \"}",
                      "vt": "json"
                  }
              ],
              "repeat": "",
              "crontab": "",
              "once": false,
              "onceDelay": 0.1,
              "topic": "",
              "payload": "Neuer Beispieltext 2!",
              "payloadType": "str",
              "x": 150,
              "y": 460,
              "wires": [
                  [
                      "ed7d5b75938de5ff"
                  ]
              ]
          },
          {
              "id": "5f2b32e2189a673e",
              "type": "function",
              "z": "5289f6ad4bf32e52",
              "name": "Laufschrift v0.5.1",
              "func": "/**\n* Zweck:      Erzeugt eine Laufschrift als payload\n* Datum:      17.02.2023\n* Version:    v 0.5.1\n* Autor:      @mickym\n*/\n\n\ncontext.timer; /* undokumentiert - setze Variable im Node Kontext um \n                    auf Timerinstanz zu zugreifen */\nclearInterval(context.timer);\n\nvar active = context.get(\"active\") || false;\n\n\nvar config = context.get(\"config\") || {\n    \"offset\": 1,        // scrollen um x Zeichen\n    \"textwindow\": 14,   // Fenster wie groß der Text sein darf\n    \"interval\": 1000,   // ms mit der sich der Text bewegt bzw. ausgegeben wird\n    \"mode\": 0,          // 0 = Zirkulierend; 1 = Anfang - Ende; 2 = Hin und Her\n    \"separator\": \" * \"  // Trennungsstring am Ende des Textes\n}\n\n\nif (msg.config) {\n    config = msg.config;\n    context.set(\"config\", config);\n    if (!msg.payload) {\n        msg.payload = context.get(\"text\");\n    }\n}\n\nif (msg.payload) {\n    if (msg.payload.length <= config.textwindow) {\n        active = false;\n        node.send(msg);\n        node.done;\n    } else {\n        active = true;\n        context.set(\"text\",msg.payload);\n        context.timer = setInterval(laufschrift, config.interval);\n    }\n} else active = false;\n\n\nvar text = msg.payload + config.separator;\nvar i = 0; //Positionszähler\nvar d; // für mode 2\n\nnode.status(\n    {\n        fill: \"blue\",\n        shape: active ? \"dot\" : \"ring\",\n        text: active ? \"aktiv\" : \"inaktiv\"\n    }\n);\n\ncontext.set(\"active\",active);\n\nfunction laufschrift(){\n   // var len = text.length;\n    var output; \n\n\n\n    switch (config.mode) {\n        case 0:\n            // code block\n            output = text.substr(i, config.textwindow);\n            text = text.substr(config.offset) + text.substr(0, config.offset);\n            break;\n        case 1:\n            // code block\n            output = text.slice(i, config.textwindow + i).padEnd(config.textwindow,\" \");\n            i < text.length ? i+=config.offset : i=0;\n            break;\n        case 2:\n            // code block\n            output = text.slice(i, config.textwindow + i).padEnd(config.textwindow, \" \");\n\n            if (i <= 0) d = true;\n            if (i >= text.length) d = false;\n            d ? i += config.offset : i -= config.offset;\n            if (i < 0) i = 0;\n            if (i > text.length) i = text.length;\n            break;\n        default:\n        // code block\n        error(\"invalid mode in config\");\n    }\n\n    /* msg = {  //nur für debug Zwecke\n        \"config\": config,\n        \"payload\": output,\n        \"Textlänge\": output.length,\n        \"Zähler\": i\n    } */\n\n    msg.payload = output;\n    node.send(msg);\n    node.done;\n}\n\n/**\n* @param {string} text\n*/\nfunction error(text){\n    node.status(\n        {\n            fill: \"red\",\n            shape: \"dot\",\n            text: \"Error: \" + text\n        }\n    );\n    clearInterval(context.timer);\n    \n    node.error(text, msg);\n}",
              "outputs": 1,
              "noerr": 0,
              "initialize": "",
              "finalize": "",
              "libs": [],
              "x": 510,
              "y": 320,
              "wires": [
                  [
                      "69b97a0af5eb83ad",
                      "3b908b1849af30ba"
                  ]
              ],
              "info": "# Laufschrift erzeugen \r\n\r\nDiese Node erzeugt in konfigurierbaren Textteile, um so eine Laufschrift zu erzeugen.\r\n\r\nGrundsätzlich startet eine `msg.payload` automatisch die Node mit Standardvorgaben. \r\nGestoppt wird er Lauftext durch eine leere oder eine `msg.payload` deren Text kürzer, als `textwindow`ist.\r\n\r\n## Konfiguration\r\nDie Konfigurationsparameter können über eine `msg.config` erstellt werden. Dabei muss das Konfigurations-Objekt vollständig übergeben werden. \r\nDie Konfiguration wird sofort auf den Lauftext angewandt. \r\nDas Konfiguationsobjekt ist direkt im Code wie folgt beschrieben: \r\n\r\n    \r\n    {\"offset\": 1,        // scrollen um x Zeichen\r\n    \"textwindow\": 14,   // Fenster wie groß der Text sein darf\r\n    \"interval\": 1000,   // ms mit der sich der Text bewegt bzw. ausgegeben wird\r\n    \"mode\": 0,          // 0 = Zirkulierend; 1 = Anfang - Ende; 2 = Hin und Her\r\n    \"separator\": \" * \"  // Trennungsstring am Ende des Textes}\r\n\r\nDie passenden Scrollparameter muss man halt selbst herausfinden. Ausserdem belasten natürlich zu kurze Intervalle das System. Voreingestellt sind 1000 ms - was ein Laufschrift sehr ruckelig macht, aber dafür kann man die payload besser debuggen, falls erforderlich."
          },
          {
              "id": "69b97a0af5eb83ad",
              "type": "ui_text",
              "z": "5289f6ad4bf32e52",
              "group": "57f13d6f733e5c9d",
              "order": 6,
              "width": 0,
              "height": 0,
              "name": "",
              "label": "",
              "format": "{{msg.payload}}",
              "layout": "col-center",
              "className": "",
              "x": 710,
              "y": 320,
              "wires": []
          },
          {
              "id": "3b908b1849af30ba",
              "type": "debug",
              "z": "5289f6ad4bf32e52",
              "name": "Node 1",
              "active": true,
              "tosidebar": true,
              "console": false,
              "tostatus": false,
              "complete": "payload",
              "targetType": "msg",
              "statusVal": "",
              "statusType": "auto",
              "x": 720,
              "y": 280,
              "wires": []
          },
          {
              "id": "4c274b6ade59ef73",
              "type": "junction",
              "z": "5289f6ad4bf32e52",
              "x": 300,
              "y": 140,
              "wires": [
                  [
                      "10903a351cc8f674",
                      "ed7d5b75938de5ff"
                  ]
              ]
          },
          {
              "id": "ed7d5b75938de5ff",
              "type": "junction",
              "z": "5289f6ad4bf32e52",
              "x": 380,
              "y": 320,
              "wires": [
                  [
                      "5f2b32e2189a673e"
                  ]
              ]
          },
          {
              "id": "57f13d6f733e5c9d",
              "type": "ui_group",
              "name": "Test",
              "tab": "20b3095113f94d70",
              "order": 1,
              "disp": true,
              "width": "6",
              "collapse": false,
              "className": ""
          },
          {
              "id": "20b3095113f94d70",
              "type": "ui_tab",
              "name": "Home",
              "icon": "dashboard",
              "order": 1,
              "disabled": false,
              "hidden": false
          }
      ]
      

      EDIT 21.2.2023
      Neue Version: 0.6.
      Ab hier wird nur noch der Code der einzelnen Node gepostet:

      [
         {
             "id": "5f2b32e2189a673e",
             "type": "function",
             "z": "5289f6ad4bf32e52",
             "name": "Laufschrift v0.6",
             "func": "/**\n* Zweck:      Erzeugt eine Laufschrift als payload\n* Datum:      21.02.2023\n* Version:    v 0.6\n* Autor:      @mickym\n*/\n\n\ncontext.timer; /* undokumentiert - setze Variable im Node Kontext um \n                    auf Timerinstanz zu zugreifen */\nclearInterval(context.timer);\n\nvar active = context.get(\"active\") || false;\n\n\nvar config = context.get(\"config\") || {\n    \"offset\": 1,        // scrollen um x Zeichen\n    \"textwindow\": 14,   // Fenster wie groß der Text sein darf\n    \"interval\": 1000,   // ms mit der sich der Text bewegt bzw. ausgegeben wird\n    \"mode\": 0,          // 0 = Zirkulierend; 1 = Anfang - Ende; 2 = Hin und Her\n    \"separator\": \" * \"  // Trennungsstring am Ende des Textes\n}\n\n\nif (msg.config) {\n    config = msg.config;\n    context.set(\"config\", config);\n    if (!msg.payload) {\n        msg.payload = context.get(\"text\");\n    }\n}\n\nvar description = config.mode ? (config.mode === 1) ? \"Anfang - Ende\" : \"Hin und Her\" : \"Zirkulierend\";\ndescription = \"Modus: \" + description + \"; Offset: \" + config.offset + \"; Intervall: \" + config.interval + \" ms; Textfenster: \" + config.textwindow;\n\n\nif (msg.payload) {\n    if (msg.payload.length <= config.textwindow) {\n        active = false;\n        node.send(msg);\n        node.done;\n    } else {\n        active = true;\n        context.set(\"text\",msg.payload);\n        context.timer = setInterval(laufschrift, config.interval);\n    }\n} else active = false;\n\n\nvar text = msg.payload + config.separator;\nvar i = 0; //Positionszähler\nvar d; // für mode 2  (true = vorwärts, false = rückwärts)\n\nnode.status(\n    {\n        fill: \"blue\",\n        shape: active ? \"dot\" : \"ring\",\n        text: active ? description : \"inaktiv\"\n    }\n);\n\ncontext.set(\"active\",active);\n\nfunction laufschrift(){\n   // var len = text.length;\n    var output; \n\n\n\n    switch (config.mode) {\n        case 0:\n            // code block\n            output = text.substr(i, config.textwindow);\n            text = text.substr(config.offset) + text.substr(0, config.offset);\n            break;\n        case 1:\n            // code block\n            // output = text.slice(i, config.textwindow + i).padEnd(config.textwindow,\" \");\n            output = text.slice(i, config.textwindow + i);\n            i < text.length ? i+=config.offset : i=0;\n            break;\n        case 2:\n            // code block\n            // output = text.slice(i, config.textwindow + i).padEnd(config.textwindow, \" \");\n            output = text.slice(i, config.textwindow + i);\n            if (i <= 0) d = true;\n            if (i >= text.length) d = false;\n            d ? i += config.offset : i -= config.offset;\n            if (i < 0) i = 0;\n            if (i > text.length) i = text.length;\n            break;\n        default:\n        // code block\n        error(\"invalid mode in config\");\n    }\n\n    /* msg = {  //nur für debug Zwecke\n        \"config\": config,\n        \"payload\": output,\n        \"Textlänge\": output.length,\n        \"Zähler\": i\n    } */\n\n    msg.payload = output;\n    if (msg.payload) node.send(msg);\n    node.done;\n}\n\n/**\n* @param {string} text\n*/\nfunction error(text){\n    node.status(\n        {\n            fill: \"red\",\n            shape: \"dot\",\n            text: \"Error: \" + text\n        }\n    );\n    clearInterval(context.timer);\n    \n    node.error(text, msg);\n}",
             "outputs": 1,
             "noerr": 0,
             "initialize": "",
             "finalize": "",
             "libs": [],
             "x": 500,
             "y": 320,
             "wires": [
                 [
                     "69b97a0af5eb83ad",
                     "3b908b1849af30ba"
                 ]
             ],
             "info": "# Laufschrift erzeugen \r\n\r\nDiese Node erzeugt in konfigurierbaren Textteile, um so eine Laufschrift zu erzeugen.\r\n\r\nGrundsätzlich startet eine `msg.payload` automatisch die Node mit Standardvorgaben. \r\nGestoppt wird er Lauftext durch eine leere oder eine `msg.payload` deren Text kürzer, als `textwindow`ist.\r\n\r\n## Konfiguration\r\nDie Konfigurationsparameter können über eine `msg.config` erstellt werden. Dabei muss das Konfigurations-Objekt vollständig übergeben werden. \r\nDie Konfiguration wird sofort auf den Lauftext angewandt. \r\nDas Konfiguationsobjekt ist direkt im Code wie folgt beschrieben: \r\n\r\n    \r\n    {\"offset\": 1,        // scrollen um x Zeichen\r\n    \"textwindow\": 14,   // Fenster wie groß der Text sein darf\r\n    \"interval\": 1000,   // ms mit der sich der Text bewegt bzw. ausgegeben wird\r\n    \"mode\": 0,          // 0 = Zirkulierend; 1 = Anfang - Ende; 2 = Hin und Her\r\n    \"separator\": \" * \"  // Trennungsstring am Ende des Textes}\r\n\r\nDie passenden Scrollparameter muss man halt selbst herausfinden. Ausserdem belasten natürlich zu kurze Intervalle das System. Voreingestellt sind 1000 ms - was ein Laufschrift sehr ruckelig macht, aber dafür kann man die payload besser debuggen, falls erforderlich."
         }
      ]
      

      Die Beschreibung zu Version 0.6 ist hier: https://forum.iobroker.net/post/951154

      posted in Node-Red
      mickym
      mickym
    • RE: Your system is booting into "graphical.target"

      @codierknecht sagte in Your system is booting into "graphical.target":

      Ein Desktop hat auf 'nem Serversystem schließlich nix zu suchen.

      Ich kann diese Sätze nicht mehr hören. Es gibt auch Leute, die nutzen einen Monitor mit einem Dashboard an einem Server. Man kann das durchaus differenzieren. Nachdem ich das aber schon 100 mal hier diskutiert habe, wäre es nur mal ganz schön, wenn man nicht immer mit dieser absoluten - ich habe die Wahrheit gepachtet - Dogmen in die Welt posaunt..

      posted in ioBroker Allgemein
      mickym
      mickym
    • Datum und Zeitverarbeitung mit NodeRed

      Da ich mich nun mal 1-2 Tage intensiv mit der "eingebauten" Datums- und Uhrzeitverarbeitung in NodeRed beschäftigt habe, würde ich meine Erkenntnisse gerne teilen und vielleicht springt ja für den einen oder anderen was nützliches heraus.

      Es geht in diesem Thread nicht um die Installation von zusätzlichen Nodes, die noch weitere Steuerungsmöglichkeiten bieten, sondern das was im Grundbaukasten bereits vorhanden ist.

      Als wer noch mehr zu den Themen - scheduling oder Zeit filtern sucht - der soll sich mal folgende Nodes anschauen:

      1. cronplus: https://flows.nodered.org/node/node-red-contrib-cron-plus - alles und noch mehr was iobroker mit dem cron als Scheduler bietet.
      2. lightscheduler: https://flows.nodered.org/node/node-red-contrib-light-scheduler triggert - aber vor allem filtert nach Zeitereignissen
      3. bigtimer - wobei ich zwar am Anfang begeistert war, aber ich inzwischen den Nutzen nicht mehr sehr hoch einschätze:
        https://flows.nodered.org/node/node-red-contrib-bigtimer

      Doch mir geht es ja nicht darum, mit welchen zusätzlichen Nodes man noch was machen kann, so wie man mit dem Grundbaukasten Zeit- und Datumsereignisse verarbeitet. Zum Schluss stelle ich dann noch einen kleinen Flow vor, den man als Timer nutzen kann. 😉 - und zwar flexibler als bei den fertigen Nodes. 😉

      Die Javascript Bibliothek, die in Node Red für die Datums- und Uhrzeit verarbeitung verfügbar ist, ist wohl die moment.js - und die Funktionen dieser Bibliothek werden ich nun im Verlauf weiter vorstellen - allerdings nicht über Javascript, sondern im Prinzip kann man diese ganze Bibliothek über JSONATA nutzen. Erst seit dem ich mich damit nun etwas näher beschäftigt habe, ergeben sich neuen Möglichkeiten, wobei ich auch noch hin und wieder ??? habe und deswegen vielleicht manches hier umständlich aussieht.

      Dennoch kommt bei diesem Thread quasi kein natives Javascript zur Anwendung (also keine Function Nodes). 😉 😉

      Ich denke, das im Blockly wohl auch die moment.js eingebunden ist - insofern kann man das vergleichen und gegenüberstellen.

      Was im Standard nicht verfügbar ist, sind die Astrozeiten - dafür bieten sich aber alle 3 oben genannten Nodes an - die hier eine Vielzahl an Funktionen bieten - wer da mehr wissen will, meldet sich einfach.

      Wie gesagt - sowohl im Blockly als auch in Node Red wurde für die Datums und Uhrzeitverarbeitung die moment.js Bibliothek verfügbar gemacht. Dabei geht in NodeRed in meinen Augen die Möglichkeiten der Nutzung über das hinaus, was üblicherweise in den Puzzleteilchen angeboten wird. 😉

      Die volle Funktionalität der moment.js Bibliothek sollte man sich als Nachschlagewerk als Seite abspeichern:
      https://momentjs.com/docs/#/parsing/

      Anscheinend wird die Bibliothek nicht mehr weiter entwickelt - wird aber noch gewartet.

      Nodes die vollkommen überflüssig sind, sind die moment.js Nodes - zumindest seitdem die moment.js Bibliothek unter NodeRed im JSONATA verfügbar gemacht wurde. Diese Nodes : https://flows.nodered.org/node/node-red-contrib-moment können also komplett ersetzt werden. Ich hatte die anfangs auch, werden nun aber rausgeschmissen.

      Dreh- und Angelpunkte bei der Nutzung der moment.js Bibliothek sind natürlich die moment-Objekte. Diese sind keine date-Objekte von Javascript. Wer also die moment.js Bibliothek im Javascript nutzen will, muss sie nach Installation halt wie üblich mit require in den Code einbinden.

      https://momentjs.com/docs/#/use-it/

      var moment = require('moment'); // require
      moment().format()
      

      In NodeRed ist es wie gesagt nicht erforderlich und man benötigt weder eine moment.js Insallation noch muss man Bibliohteken global verfügbar machen - außer man wollte die moment.js in function Nodes nutzen, was hier aber nicht der Fall ist und deswegen auch nicht weiter beschrieben wird. Hier geht es deshalb ausschließlich um die moment.js Funktionen, die JSONATA in NodeRed zur Verfügung stellt und die deshalb in verschiedenen Nodes wie der Change-Node, der Inject-Node, der Switch-Node, Join-Node etc. zur Verfügung steht und angewandt wird.

      Im folgenden werde ich mich etwas an Blockly orientieren - da in meinen Augen die gleiche Bibliothek dahinter liegt und erklären, wie man das im JSONATA und in NodeRed umsetzt.

      posted in Node-Red
      mickym
      mickym
    • RE: MQTT-Instanz sendet Daten und werden als NaN empfangen

      @iojoe22 Ich habe auch ein Problem mit dem Adapter als Broker (retain Nachrichten etc). Ich würde Dir empfehlen mosquitto als mqtt Broker zu nehmen und den mqtt Adapter als Client zu verwenden. So mache ich das seit Jahren und kann das nur weiter empfehlen.

      posted in Skripten / Logik
      mickym
      mickym
    • RE: Nach Nodejs Update kein Adapter mehr updatebar

      @tilly sagte in Nach Nodejs Update kein Adapter mehr updatebar:

      @mickym

      wie würde ich da vorgehen?

      also in das /opt/iobroker Verzeichnis wechseln.
      IOB stoppen natürlich:

      iob stop
      
      cd /opt/iobroker
      

      komplettes node_modules Verzeichnis löschen oder das Verzeichnis umbenennen

      sudo rm -rf node_modules
      

      bzw.

      sudo mv node_modules node_modules.bak
      

      etwaige package-lock.json löschen

      sudo rm package-lock.json
      

      Den cache sicherheitshalber noch leeren:

      npm cache clean --force
      

      Dann das node_modules neu aufbauen lassen:

      npm install
      

      Die ganzen Informationen über die Adapter und deren Abhängigkeiten stehen in der package.json.

      Eine datensicherung oder ein Image würde ich aber in jedem Fall machen, falls was nicht geht. Ist aber noch schneller, als das ganze System neu aufzubauen.

      zum Schluss in dem Verzeichnis /opt/iobroker noch den Befehl

      npm list
      

      und schauen, ob Du einen sauberen Baum hast. npm cache hast ja soweit ich sehe schon gelöscht.

      posted in Error/Bug
      mickym
      mickym
    • Neuaufbau - Kein Recovery (NodeRed) mit BackitUp möglich

      Ich habe die letzten beiden Tage mein System neu von "Scratch" neu aufgebaut - bei mir war das wie zu Erwarten kein Tasks von wenigen Stunden, das hat aber mit dem iobroker nur zur Hälfte was zu tun. Allerdings bin ich froh, dass ich immer noch ein laufendes System hatte, um fehlende Dateien zu kopieren, da leider mit BackItUp - mein System unwiederbringlich kaputt gewesen wäre, da leider überhaupt keine Datei meiner Hauptinstanz von NodeRed gesichert wurden. Doch alles der Reihe nach - ich schreib das jetzt als Erfahrungsbericht, bevor alles verloren geht. Ich habe mein System wiederhergestellt und hab deswegen einigen Verbesserungsvorschläge für den backitup Adapter und werde dann auch ggf. entsprechende Issues aufmachen. Erschreckend, um es vorwegzunehmen war jedoch, dass ich alle meine Flows verloren hätte, wenn ich mich nur auf den BackitUP Adapter verlassen hätte. Genaueres im Verlauf dieses Posts.

      Wer mich hier im Forum kennt, weiß ja, dass ich einen Neuaufbau des Systems gescheut habe, wie die Pest, deshalb stellt sich vielleicht der eine oder andere die Frage, warum ich das gemacht habe. Andererseits ist man wesentlich entspannter ein System neu aufzubauen, wenn man weiß, dass man ein funktionierendes System in der Hinterhand hat.

      Hauptgrund war, dass es seit Februar 2022 auch offiziell ab dem Raspberry 3 und 4 eine 64-bit Version des Betriebssystems gibt und ich zum einen denke, dass dies auf lange Sicht dann eh irgendwann mal eine Umstellung bedarf und angeblich die 64bit-Version schneller laufen soll.
      Neben der Möglichkeit 64bit Programme laufen zu lassen, soll der Geschwindigkeitsvorteil bis zu 48% betragen:
      https://buyzero.de/blogs/news/antworten-auf-eure-fragen-zum-raspberry-pi-os-64-bit

      Um es vorwegzunehmen - vom Speicherbedarf merke ich keinen Unterschied. Bei der Geschwindigkeit habe ich manchmal den Eindruck, es würde ein bisschen flüssiger laufen, aber kann auch Einbildung sein. Jedenfalls ist der Unterschied nicht so gravierend, wie 48% vermuten lassen.

      Doch bevor ich hier über meine Erfahrungen berichte und vielleicht ein paar Tipps geben kann, muss ich ja erst mal vorstellen, was auf meinem Raspberry Pi4 mit 4 GB läuft. Ich habe nicht soviele Adapter, aber doch einige Dienste. Das Swappen ist grundsätzlich bei mir ausgeschaltet, um die SD Karte nicht unnötig zu belasten.

      Der Hauptspeicher ist mit gut 80% gut ausgelastet, muss man sich anschauen, ob man das Swappen wieder aktiviert.

      a83d0d3b-d0b7-47c8-9019-3c3a2c768def-image.png

      Bevor ich anfange - hier mal eine Beschreibung, was auf das System drauf musste, was angepasst werden musste und meine einzelnen Schritte.

      Auch wenn es hier verpönt wird, weil man ja einen Headless Server in der Regel betreibt, hängt bei mir ein Bildschirm am Raspberry, der mir den Status des Systems anzeigt und deshalb einen Browser und Desktop benötigt. Der Bildschirm ist aber im Stand-By (dunkel) und wird über einen Bewegungsmelder gesteuert, so dass dieser nur an ist, wenn sich jemand in dem Zimmer bewegt.
      Ich will auch keine Diskussion darüber führen, ob das nun sinnvoll ist oder nicht.

      So was musste also wieder auf das System drauf:

      1. Desktop OS Raspbian mit xrdp
      2. Zugriff auf Windows Systeme zur Sicherung von einzelnen Dateien und ggf. Datenaustausch vom Raspberry aus,
      3. MySQL Installation mit Konfiguration, dass Datenbanken auf externem USB-Stick gespeichert werden und nicht auf der SD-Karte
      4. mqtt-Broker mit mosquitto und verschlüsselter Verbindung zu einer externen mqtt-Bridge für owntracks Kommunikation
      5. FHEM Installation zur Ansteuerung der MAX-Cubes (Hauptgrund), aber auch als Systemmonitor (SYSMON) für beide Raspberries. ssh Remote für Zugriff auf entfernten Raspberry
      6. iobroker Installation und Recovery mit BackitUp und Remote ssh für Zugriff auf entfernten Raspberry
      7. Zigbee2Mqtt Installation
      8. Firefox Installation als präferierter Browser für das NodeRed Dashboard.
      9. Abschließende Arbeiten

      So nun zu den einzelnen Phasen und ein paar Dinge, die ich gemacht habe, weil ich sie als nützlich empfunden habe. Auch wenn ich mit den nächsten Aussagen hier wieder anderer Meinung als so mancher hier an Board bin, ist es praktisch die /root Partition klein zu halten. Bei mir sind es nur 16 GB SD Karten, die aber auch nur zur Hälfte gefüllt sind. Es war goldwert nach diesen Phasen immer wieder mit einem Image abzusichern. Ich hatte 11 Images und schon ist man so bei ca. 160 GB, das man zur Verfügung haben sollte. Mit dem Win32 Disk Imager, war so ein Image auf meinem Hochleistungslaptop jeweils in gut 3 Minuten fertig. 😉 Grundsätzlich sogut der apt Paketmanager zwar funktioniert, löscht man aber ein Verzeichnis, bekommt man fehlerhaft installierte Pakete nicht mehr aus dem System. Wenn man ca. 15 Minuten probiert hat, ist es effizienter wieder auf das letzte Image zurückzuladen und neu anzufangen. Ich habs jedenfalls mehrfach nicht geschafft, sowas wieder aus dem System zu bringen - da bin ich zu sehr Linux Laie, obwohl ich ja schon immer besser werde. 😉

      So nun zu den einzelnen Phasen und was dort alles gemacht wurde:

      1. Desktop OS Raspbian mit xrdp

      Im Gegensatz zu dem oben verlinkten Bericht, ist die 64 Bit Version vom Raspbian keine Betaversion, sondern wird offiziell unterstützt und angeboten. Wie immer nicht von irgendwelchen dubiosen Links oder Videos runterladen, sondern immer das Original: https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-64-bit

      Das Archiv wird gepackt heruntergeladen und ist ca. 800 MB groß. Daraus einfach das Image rauskopieren, ist dann ca. 4,5 GB groß.

      Kann man dann auch mit dem Win32Disk Imager auf die SD Karte schreiben. Leeres ssh File drauf machen und booten.
      Nach dem Einstellen der persönlichen Bedürfnisse und Länder- und Spracheinstellungen habe ich noch folgendes gemacht:

      • als erstes Hostname ändern (damit dieser nicht in irgendwelchen Konfigurationsdateien verewigt wird und man dann einen hohen Aufwand hat, alle möglichen Dateien zu editieren.
      • bei den neuen Installationen muss mit orca -s auch noch die Ansagen ausschalten. War total ungewohnt, dass nach der Installation jemand alles auf dem Bildschirm vorliest. 😉
      • nachdem sich die Installation einfach den restlichen Speicherplatz krallt, habe ich anschließend über einen Paritition Manager die Partitionen wieder so verkleinert, dass ca. 500 MB nicht genutzt werden, so dass die Images auch auf verschiedene Marken von SD Karten passt.
        623c378e-0acd-4574-ad72-777fa285416b-image.png
      • das Swappen wird wie gesagt abgeschaltet und geht ziemlich einfach in dem man den Service stoppt und disabled:
        deinstalliert wurde nichts, so dass man bei Bedarf das auch wieder leicht aktivieren kann.
      sudo systemctl stop dphys-swapfile
      sudo systemctl disable dphys-swapfile
      
      • anschließend wurde wie gesagt xrdp installiert und ein user angelegt, den man für die RDP Kommunikation nutzt. Habe ich ja schon mal geschrieben, dass das nun erforderlich ist. Was mich etwas Zeit gekostet hatte, dass ich den User am Anfang ohne Home-Directory erstellt hatte, das ist aber erforderlich, damit sich der Desktop aufbauen kann. Eigene Blödheit, aber ich habs ja nun aufgeschrieben. 😉
      1. Zugriff auf Windows Systeme zur Sicherung von einzelnen Dateien und ggf. Datenaustausch vom Raspberry aus,
      • der Zugriff auf die übrigen Resource ist relativ einfach gewesen, indem man einfach die entsprechenden Einträge aus einer bestehen fstab kopiert und ggf. die Windows Credentials in einer eigenen Datei abgespeichert sind.
      • USB Stick permanent als Datenträger für Daten eingebunden
      1. MySQL Installation mit Konfiguration, dass Datenbanken auf externem USB-Stick gespeichert werden und nicht auf der SD-Karte
      • Installiert wird das einfach mit
      sudo apt install mariadb-server
      
      • das Umbiegen auf einen externen Datenträger ist etwas mehr tricky. (musste ich auch 2 mal machen 😉 ) Nach der Installation das /var/lib/mysql in das neue Verzeichnis kopieren. Dann kann man auch direkt die alten Datenbanken in das Verzeichnis kopieren. Ich habe bewusst 2 Verzeichnisse auf dem USB Stick gehabt, sodass man beiden Installationen (32bit und 64 bit) auf unterschiedliche Verzeichnisse zugreift und sich nichts zerschiesst.
        In dem Verzeichnis: /etc/mysql/mariadb.conf.d dann einfach die 50-server.cnf bearbeiten und dort das data-dir umbiegen und die lokale Bindung auskommentieren, wenn man von anderen Maschinen auf die Datenbank zugreifen will. - Damit war das auch erledigt.
      1. mqtt-Broker mit mosquitto und verschlüsselter Verbindung zu einer externen mqtt-Bridge für owntracks Kommunikation
      • das klappte auch gut: Mit sudo apt mosquitto installieren und dann einfach alle Konfigurationsdateien auf /etc/mosquitto mit den Unterverzeichnissen kopieren. Dort sind auch die Verschlüsselungszertifikate für die Kommunikation mit der Bridge enthalten.
      1. FHEM Installation
      • das hat mich auch mindestens 3 Anläufe gekostet, da ich mir immer den Paketmanager kaputt gemacht habe und ich dann die Verweise auf kaputte Pakete nicht mehr entfernt bekam.
      • großes Problem, dass ich FHEM nicht mehr so wie vor 3 Jahren installieren konnte, war dass apt-key nicht mehr unterstützt wurde bzw. mir dann wieder eine Anleitung gefehlt hat, die die entsprechenden Schlüssel zur Verfügung stellte. Anleitungen mit dkpg kann man auch vergessen, da fehlen dann wieder Bibliotheken, die vorher installiert sein müssen usw. - alles Murks. 😞
      • Für die es interessiert hier eine Anleitung mit der es gut funktioniert hat:
      apt update
      apt install gpg
      wget -O- https://debian.fhem.de/archive.key | gpg --dearmor > /usr/share/keyrings/debianfhemde-archive-keyring.gpg
      echo "deb [signed-by=/usr/share/keyrings/debianfhemde-archive-keyring.gpg] https://debian.fhem.de/nightly/ /" >> /etc/apt/sources.list
      apt update
      apt install fhem
      
      • Danach sind der User fhem angelegt und die Services definiert - sodass man nichts mehr machen muss. Alle anderen Installationsmethoden waren für mich nicht brauchbar. Und wie gesagt das apt-key was man in älteren Anleitungen findet, funktioniert nicht mehr.
      • Dann wollte ich die rsa key für die remote ssh Kommandos generieren. Habe ich als user fhem gemacht, wurde im Homeverzeichnis von fhem gemacht (das ist das /opt/fhem) Verzeichnis, usw. . Es funktionierte einfach nicht. ssh Schlüssel nicht gefunden. Dann wirklich das .ssh Verzeichnis kopiert und in händisch in das /opt/fhem Verzeichnis kopiert. Dann muss man aber wieder die Rechte anpassen. Die id_rsa (also der private Schlüssel) darf nur für den user zugreifbar sein. Also sudo chmod 600 id_rsa im /opt/fhem/.ssh Verzeichnis. - Man könnte das Backup zwar anpassen, aber generell wird halt nicht das ganze fhem Bezeichnis gesichert.
      • Ansonsten einfach mit dem tar Befehl das ganze /opt/fhem Verzeichnis überschreiben. Es sind alle Geräte und Parameter wieder vorhanden. Ist ja zum größten Teil eh in der fhem.cfg

      =================================================================================

      1. iobroker Installation und Recovery mit BackitUp und Remote ssh für Zugriff auf entfernten Raspberry

      So das ist sicher der interessanteste Teil.

      • Die Installation mit dem Einzeiler hat wirklich gut funktioniert und auch nodejs, npm wurde in den empfohlenen Versionen herunter geladen:
      curl -sLf https://iobroker.net/install.sh | bash -
      
      • Was ich nicht mehr in Erinnerung hatte, war dieser Assistent beim ersten Start vom iobroker und wofür man ein Administratorpasswort eingeben musste, auch wenn ich keine Authentisierung verwende.
      • Dann noch den Discovery Adapter deinstalliert und den Restore angestossen via BackitUp Adapter.
      • Ich habe nun nicht viele Adapter installiert, sodass es wohl mit steigender Anzahl ggf. auch mehr Probleme zu erwarten sind:
      iobroker update
      Used repository: Stable (default)
      Adapter    "admin"        : 5.3.8    , installed 5.4.9
      Adapter    "backitup"     : 2.4.10   , installed 2.4.10
      Adapter    "dwd"          : 2.8.3    , installed 2.8.3
      Adapter    "flot"         : 1.11.0   , installed 1.11.0
      Adapter    "info"         : 1.9.19   , installed 1.9.19
      Adapter    "javascript"   : 5.7.0    , installed 5.7.0
      Controller "js-controller": 4.0.23   , installed 4.0.23
      Adapter    "linux-control": 1.1.3    , installed 1.1.3
      Adapter    "mercedesme"   : 0.0.56   , installed 0.0.56
      Adapter    "mqtt"         : 3.0.6    , installed 4.0.7
      Adapter    "node-red"     : 3.3.1    , installed 3.3.1
      Adapter    "pi-hole"      : 1.3.4    , installed 1.3.4
      Adapter    "ping"         : 1.5.3    , installed 1.5.3
      Adapter    "simple-api"   : 2.7.0    , installed 2.7.0
      Adapter    "socketio"     : 4.2.0    , installed 4.2.0
      Adapter    "sql"          : 2.1.7    , installed 2.1.7
      Adapter    "tr-064"       : 4.2.16   , installed 4.2.16
      Adapter    "vis"          : 1.4.15   , installed 1.4.15
      Adapter    "vis-hqwidgets": 1.2.0    , installed 1.2.0
      Adapter    "web"          : 4.3.0    , installed 4.3.0
      Adapter    "ws"           : 1.3.0    , installed 1.3.0
      Adapter    "yahka"        : 0.13.1   , installed 0.13.1
      
      • Etwas gewöhnungsbedürftig ist, dass nachdem der Restore als complete angezeigt wird, die eigentliche Adapterinstallation beginnt. Ich hatte mit 3-4 Adaptern bzw. dem Restore Probleme, wobei der Restore mit NodeRed schon am gravierensten war.

      • Das erste Problem ist, dass der Adapter der Probleme macht, gar nicht in der Liste ist, da er nur auf dem Beta-Repository verfügbar ist. Es handelt sich um den sourceanalytics - Adapter. Ehrlich gesagt verstehe ich sowas nicht ganz. Im Prinzip müsste eigentlich das BackitUp sowohl das stable, als auch das beta Repository durchsuchen. Durch die Version ist ja festgelegt, was zu installieren ist. Jedenfalls muss man das Beta-Repository anhaken, aber auch dann funktioniert die Installtion nicht. Man muss eine neue Instanz von dem Adapter nach Installation erstellen. Anschließend kann die Instanz wieder gelöscht werden und der Adapter funktioniert wie er soll.

      • Der zweite Problemfall war der vis Adapter, der sich einfach nicht installieren ließ - zumindest nicht in der aktuellen Version 1.4.15. Vielleicht sollte man ein Restore mit dem BackitUp mal ins Testprogramm aufnehmen, bevor die Version in das stable Repository wandert. Im Prinzip ist es nicht ganz so schlimm, weil man wirklich auf Kommandozeile eine vorhergehende Version installieren muss - wie hier empfohlen. Die Version 1.4.0 des vis-Adapters funktioniert und lässt sich dann auch problemlos updaten. Mit einer zukünftigen Version, wird dieses Problem wahrscheinlich verschwinden.

      • Ein weiterer Kritikpunkt ist, dass im iobroker Home-Verzeichnis auch Dateien gesichert werden sollten. Zum Beispiel wenn ein .ssh Verzeichnis vorhanden ist. Ansonsten hat eben linux-control - Adapter ein Problem, wenn ein ssh Remote Zugriff definiert wurde. So war es am besten das .ssh Verzeichnis wieder händisch in das /home/iobroker Verzeichnis zu kopieren und wieder - analog wie zum FHEM Problem - mit sudo chmod 600 id_rsa im /home/iobroker/.ssh Verzeichnis die Rechte anzupassen.

      • Der nächste Problemfall war der vis-materialdesign - Adapter. Diesen Adapter gibt es schlicht und ergreifend nicht mehr und ließ sich nicht mehr wiederherstellen. Ich denke, dass es dafür einen Nachfolger mit anderem Namen gibt, aber ist halt vielleicht doch dumm, wenn man auf den Adapter angewiesen ist. da ich kaum was mit vis mache, habe ich den Adapter halt gelöscht.

      • So nun zum Node-Red Adapter. Seit der Version 3.3.1 kann man Node-Red ja auch in mehreren Instanzen installieren, was sehr praktisch ist. So habe ich eine Instanz als Testinstanz, die ich im Gegensatz zur Projektfunktion ja nun parallel betreiben kann. Die Testinstanz von Node-Red hat nicht mit der Projektfunktion gearbeitet, die Hauptinstanz hatte die Node-Red Projektfunktion aktiviert. So um es gleich vorweg zunehmen: Diejenigen, die die Node-Red Instanz ohne Projektfunktion betreiben, haben kein großes Problem. Die Flows wurden wiederhergestellt, allerdings könnte man das nun doch anwenderfreundlicher machen.

      fd0d03d0-6dc3-4f42-981d-1efb06c7ee6b-image.png

      Diesen Zwang sich zwischen dem Pallettenmanager oder die module in die Adapterkonfiguration einzutragen zu entscheiden, verstehe ich ehrlich gesagt nicht. Ich verstehe zwar, dass man die nodejs module nicht zum Bestandteil des Backups macht, allerdings könnte man die package.json sichern und anschließend ein npm install anschliessen. Jedenfalls habe ich das gemacht und die fehlenden Nodes wurden automatisch installiert. Ich verstehe es nicht, warum die package.json NICHT Bestandteil des Backups sind.

      Das wie ursprünglich behauptet, das ganze iobroker-data Verzeichnis gesichert wird, ist jedenfalls NICHT der Fall.

      So und nun leider zum traurigsten Fall: Leute, die die Projektfunktion in NodeRed aktiviert haben

      b2666ac7-932a-4617-9e3e-e32d32e7363e-image.png

      SCHAUEN LEIDER komplett in die Röhre! 😞 - Es wurde nichts gesichert.

      f6c5c739-d1bc-4658-aa89-042bf5e225f7-image.png

      Das projects Verzeichnis, dass alle Flows enthielt war leer.
      Das lib Verzeichnis, dass die eigene Flow Bibliothek enthält war leer.
      Einige Nodes legen in entsprechenden Verzeichnissen Konfigurationsdaten ab - waren nicht vorhanden oder leer.
      Das Projects Verzeichnis enthält zudem quasi ein lokales git Reprository indem die Verlaufsstände zur Wiederherstellung gespeichert sind - wird alles nicht gesichert.

      726705f3-186f-4087-8596-e6f38cd5ea78-image.png

      Das geht alles verloren! In meinen Augen muss ALLES gesichert werden, ausser dem node_modules Verzeichnis. Und auch hier gilt wie oben. Wenn man die package.json mit sicher kann ein anschliessendes npm install in dem Verzeichnis alles wiederherstellen auch die fehlen Nodes:

      npm ls
      node-red-project@0.0.1 /opt/iobroker/iobroker-data/node-red
      ├── @mdi/font@5.9.55
      ├── node-red-contrib-bigtimer@2.8.2
      ├── node-red-contrib-buffer-parser@3.2.2
      ├── node-red-contrib-cron-plus@1.5.7
      ├── node-red-contrib-crypto-js@0.1.1
      ├── node-red-contrib-fs-ops@1.6.0
      ├── node-red-contrib-harmony-websocket@2.2.6
      ├── node-red-contrib-light-scheduler@0.0.18
      ├── node-red-contrib-tail-file@1.2.6
      ├── node-red-contrib-ui-contextmenu@2.0.1
      ├── node-red-contrib-ui-time-scheduler@1.17.1
      ├── node-red-contrib-web-worldmap@2.28.3
      ├── node-red-contrib-whin@0.1.15
      ├── node-red-dashboard@3.1.7
      ├── node-red-node-email@1.17.0
      ├── node-red-node-feedparser@0.3.0
      ├── node-red-node-mysql@1.0.3
      ├── node-red-node-ping@0.3.1
      ├── node-red-node-snmp@1.0.2
      ├── node-red-node-tail@0.3.2
      ├── node-red-node-ui-table@0.3.12
      └── speedtest-net@2.2.0
      

      Ausserdem ist die Datei .gitconfig aus dem /home/iobroker Verzeichnis zu sichern. Ich musste die Daten zwar nochmal eingeben, konnte dann aber in die Projekte wechseln.

      So nun kommt etwas wichtiges, was kein Problem des BackitUp Adapters ist, aber das wenige auf dem Schirm haben - zumindest seit der Version 2 werden die credentials zusätzlich verschlüsselt. Wenn man also das Verschlüsselungspasswort nicht weiß, müssen alle Credentials neu angegeben werden.

      In Projekten ist also das flows_cred.json nochmals verschlüsselt.

      715bb52b-d4a0-41f0-a426-a0fe9e381c99-image.png

      Wenn man den Schlüssel nicht mehr weiß - und ein neues Passwort vergibt sind alle Credentials weg. Was bedeutet das:

      In jeder Node - die Anmeldedaten enthält in dem Flow müssen ALLE Credentials neu eingeben werden.
      Dazu gehören:
      alle Email Nodes
      alle HTTP Request Nodes, die Basisauthentifizierung nutzen
      alle Mqtt Nodes bzw. deren Konfiguration zum mqtt-Broker
      alle SQL Nodes

      usw.

      Hat mich mindestens eine weitere Stunde gekostet, bis das wieder in Ordnung war.

      So, dass ist leider das traurige an dem Zwischenfazit: Meine GANZE Logik für die Hausautomation in NodeRed abgebildet, wäre verloren, wenn ich mich nur auf den BackitUp Adapter verlassen hätte. Ich werde ggf. noch ein Issue auf gitHub aufmachen, wobei ich sicher nicht nochmal Stunden opfern würde. Im Prinzip muss einfach bis auf die Module alles gesichert werden.

      =================================================================================

      1. Zigbee2Mqtt Installation

      Am Besten hin und wieder ein backup des Datenverzeichnis machen. Das geht auch easy über die GUI.

      8e5a0dda-c259-410e-8ffe-6e7255d5fb9e-image.png

      Ansonsten wie bei der Neuinstallation alle Schritte durchführen: https://www.zigbee2mqtt.io/guide/installation/01_linux.html#installing

      Bevor man den Service startet einfach alle Dateien aus der Datensicherung (wie eben beschrieben) in das /opt/zigbee2mqtt/data Verzeichnis kopieren und anschließend den Service starten.

      1. Firefox Installation

      Das macht man auch am Besten über eine Paket-Installation:

      sudo apt install firefox-esr-l10n-de
      

      für die Installation des Firefox Browsers mit deutschem Sprachpaket.

      Andere Sprachpakete siehe hier: https://packages.debian.org/search?keywords=firefox-esr-l10n

      1. Abschließende Arbeiten

      Ein iobroker fix erstellt eine iobroker Datei unter /etc/sudoers.d

      Damit der iobroker user andere Services (im NodeRed Flow) managen kann, muss ggf. die iobroker Datei unter /etc/sudoers.d ändern.

      Auch wenn die Meldung von dem BackitUp Adapter, dass Backups auf dem gleichen Datenträger keinen Sinn machen, prinzipiell richtig sind, sollte man die Abstellen können. Der Adapter bekommt bei mir gar nicht mit, dass er auf einem anderen device sichert, da ich einen symbolischen Link auf ein Verzeichnis auf dem USB Stick eingerichtet habe.

      Dazu sich zum Benutzer iobroker wechseln und den symbolischen Link erstellen:

      sudo -su iobroker
      cd /opt/iobroker
      mv backups backups.org
      ln -s /data/backup/iobroker backups
      

      erzeugt dann so eine Struktur

       ls -la
      insgesamt 972
      drwxrwxr-x+   6 iobroker iobroker   4096  9. Aug 23:47 .
      drwxr-xr-x    6 root     root       4096  9. Aug 15:01 ..
      lrwxrwxrwx    1 iobroker iobroker     21  9. Aug 23:47 backups -> /data/backup/iobroker
      drwxrwxr-x+   2 iobroker iobroker   4096  9. Aug 09:59 backups.org
      -rwxrwxrwx+   1 iobroker iobroker    237  9. Aug 20:54 INSTALLER_INFO.txt
      lrwxrwxrwx    1 iobroker iobroker     22  9. Aug 20:54 iob -> /opt/iobroker/iobroker
      -rwxr-xr-x+   1 iobroker iobroker    309  9. Aug 20:54 iobroker
      drwxrwxr-x+  10 iobroker iobroker   4096  9. Aug 23:50 iobroker-data
      drwxrwxr-x+   2 iobroker iobroker   4096 10. Aug 02:45 log
      drwxrwxr-x+ 749 iobroker iobroker  24576  9. Aug 11:16 node_modules
      -rw-rwxr--+   1 iobroker iobroker    155  9. Aug 20:54 .npmrc
      -rw-rwxr--+   1 iobroker iobroker    746  9. Aug 11:16 package.json
      -rw-rwxr--+   1 iobroker iobroker 927906  9. Aug 11:16 package-lock.json
      

      =================================================================================
      FAZIT:

      So ich bin am Ende mit meiner 2 tägigen Arbeit. Ich weiß, die meisten von euch bauen Ihr System in 1 Stunde wieder auf und haben auch keine GUI auf ihren Servern.

      Ich kann aber - im Nachhinein - auch wenn ich mich immer gewehrt habe, trotzdem jedem raten, mal sein System von Grund auf neu aufzubauen und das zu protokollieren . Ich muss das alles noch zusammenschreiben. 😉 Und ich bin noch nicht mal sicher, ob nicht die eine oder andere Überraschung noch auf mich wartet.

      Jedenfalls ist es besser, das zu machen, wenn man noch ein funktionierendes System in der Hinterhand hat, als ggf. im Streß eines aktuellen Problemfalls.

      Die 64bit Variante des OS ist bisher noch nicht so richtig spürbar. Ich hoffe jedenfalls, dass für den EINEN oder ANDEREN eine interessante Information dabei war.

      posted in ioBroker Allgemein
      mickym
      mickym

    Latest posts made by mickym

    • RE: ESPHome MQTT error

      Dieses Löschen von Nachrichten - nach x retries hatte ich schon vor 5 Jahren. Deshalb betreibe ich den mqtt adapter als Client und nicht als Server. Deshalb meine Empfehlung - mosquitto als mqtt Broker nutzen und den Adapter als Client.

      posted in Error/Bug
      mickym
      mickym
    • RE: Einzelwerte aus Objekt selektieren

      @frankthegreat Warum nimmst Du nicht einfach den Subflow?
      https://forum.iobroker.net/topic/43856/json-oder-javascript-objekt-in-iobroker-datenpunkte-zerlegen

      posted in Node-Red
      mickym
      mickym
    • RE: [gelöst] node.status Weitergabe aus Subflow

      @mage Im Subflow - gibts kein node.status wie für die function Node.

      5e4d8ff8-a3cc-40bd-9c6c-b84f66926a2a-image.png

      Du musst die node.status infos als eigene payload in die status Node des subflows schicken:

      042c449a-e30d-4d55-a435-9b540631d31c-image.png

      69053197-c85f-4cee-b011-e5cc053a4272-image.png

      Also im Prinzip würde ich als eigene Eigenschaft - den node.status in msg.status weitergeben und diese msg.status dann in die payload für die status Node verwenden.

      Trotzdem will nicht in mein Kopf - was ein Subflow mit EINER function Node für einen Sinn macht. Wenn Du anstelle der function Node einen Flow daraus machen würdest, würde ich es ja verstehen - aber so macht das ja kaum Sinn.

      posted in Node-Red
      mickym
      mickym
    • RE: Fehler Meldung als "WARN"

      @totocotonio Na ich keine Deinen Flow nicht, aber indem Du halt verhinderst, dass diese Node, die den Fehler verursacht, getriggert wird, wenn das Display aktiv ist. Sprich du setzt irgendwo eine Variable, der den Zustand des Displays enthält und blockierst den Flow, solange die Variable bzw. das Display aktiv ist.

      posted in Node-Red
      mickym
      mickym
    • RE: Fehler Meldung als "WARN"

      @totocotonio sagte in Fehler Meldung als "WARN":

      b22d9ab5.1a84c8:3ae677fd.42e558

      Na bin zwar nicht sicher - aber ich würde mal eine von den 4 Nummern in die Suchmaske eingeben und dann findest Du die Node, die den Ärger macht. Wahrscheinlich kommen diese Fehler seit dem der Kontext automatisch auf persistent umgestellt wurde.

      4833539c-0f46-492f-b6ec-3e46cb5f5bab-image.png

      So ein Bezug mündet quasi in einer Endlosschleife - also ggf. den Kontext in einer anderen Variablen speichern.

      posted in Node-Red
      mickym
      mickym
    • RE: Node-Red Warnungen im Protokoll

      @leon Nun wenn du das Device oder den Flow gefunden hast, dann wäre mein Vorgehen - erst mal den Flow, die Node oder was auch immer zu deaktivieren und schauen, ob die Meldungen aufhören.
      Ich habe keine Alexa und kann Dir nicht helfen, aber ggf. hilft Dir hier jemand, wenn du den Flow bzw. die Nodes, die die Meldung verursachen hier vorstellst. Aber den ersten Schritt hast du ja gemacht, in dem Du den Flow oder die Stelle gefunden hast.
      Wie gesagt, wenn Du die Stelle gefunden hast, dann musst Du halt den Teil hier veröffentlichen, wenn Dir jemand weiterhelfen soll. Ich werde es wahrscheinlich nicht können, aber vielleicht gibt es ja noch andere Leute, die noch NodeRed mit Alexa nutzen.

      posted in Node-Red
      mickym
      mickym
    • RE: Node-Red Warnungen im Protokoll

      @leon indem du suchst und in das Feld mit der Lupe im infotab, der alle Nodes enthält nach dem String suchst

      posted in Node-Red
      mickym
      mickym
    • RE: Node red Wert regelmäßig senden

      @felli Na schaut schön übersichtlich aus. 👍 😄 - jedenfalls sollte man gerade, wenn man Anfänger Tipps gibt - diesen das Codeschreiben nicht unbedingt angewöhnen und ja ich weiß, dass wenn man im Netz nach Beispielen sucht, die meisten codieren und ChatGPT codiert sowieso am liebsten, da es die Node nicht wirklich malen kann. 😉

      Aber gut - ich denke es wurde genügend Argumente ausgetauscht und am Ende zählt das Ergebnis. Nur wie gesagt, man sollte halt das Debuggen und das Verstehen bei der Fehlersuche immer mitbedenken, da dies in meinen Augen halt ein fundamental und wesentlicher Vorteil dieser grafischen Programmierung ist.

      posted in Node-Red
      mickym
      mickym
    • RE: Node red Wert regelmäßig senden

      @felli Ein Function Node ist halt auch wesentlich schwieriger zu debuggen - Du musst mit node.warn arbeiten etc., wenn Deine Logik in der function Node nicht funktioniert.
      In einem Flow kannst Du einfach das Kabel trennen oder irgendwo eine Debug Node hinmachen.
      Function Nodes nutze ich wirklich nur, wenn ich einen Nodekontext benötige, ggf. andere NodeJS Funktionen nutze möchte. Je länger ich mit NodeRed arbeite, desto mehr habe ich function Nodes ersetzt.

      Wenn ich mehr als einen Wert in der Logik habe die am Ende entscheiden ob true oder false z.B. nehme ich gerne function nodes,

      Gerade hier ist das grafische Arbeiten von Vorteil, in dem man die Bedingungen als switches implementiert. Ordnet man diese nun parallel oder seriell an, hat man sofort den Überblick ob man mit UND oder ODER verknüpft hat und diese Bedingungen sind leichter zu durchschauen oder zu debuggen.

      posted in Node-Red
      mickym
      mickym
    • RE: Node red Wert regelmäßig senden

      @felli Man kann auch komplexere Flows mit Nodes realisieren und das muss nicht unübersichtlich sein - man kann auch Subflows verwenden.
      f625f58a-5392-4e30-b875-c65e065e5dd2-image.png

      Du kannst auch jeden Flow in einer function Node realisieren - nur das hat halt nichts mehr mit den Vorteilen einer wartungsfreundlichen grafischen Programmierung zu tun.

      posted in Node-Red
      mickym
      mickym
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
    The ioBroker Community 2014-2023
    logo