Geräte ersetzen in HG's

Es ist mal wieder soweit für ein neues Projekt.
Leider ist ja vermehr wieder zu lesen das Geräte neu angelernt werden müssen.
Das ist bei vielen mit einer HG Schlacht verbunden und mit viel Zeit.

Daher habe ich mir mein Node Red vorgenommen und eine Funktion geschrieben die bei den HG’s die ID’s tauscht.

Dazu muss Node Red installiert sein ( system ist egal es geht auch nen Windows Rechner ) sowie das homee Node von @stfnhmplr.

Das tote Gerät darf noch nicht gelöscht sein und das neue muss angelernt sein.
Das homee Node (API) muss mit dem homee verbunden sein und das Speichern im Kontext muss aktiviert sein.

[
    {
        "id": "76e0d02a.6b828",
        "type": "inject",
        "z": "2fafa37e.5aa2cc",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "get:homeegrams",
        "payloadType": "str",
        "x": 180,
        "y": 860,
        "wires": [
            [
                "ac5cba84.d15698"
            ]
        ]
    },
    {
        "id": "9492b4bb.9b0458",
        "type": "function",
        "z": "2fafa37e.5aa2cc",
        "name": "Attribute und Node ID ersetzen bei Trigger , Conditions und Actions ",
        "func": "var nodeold = 0;\nvar nodenew = 0;\nvar attribute = global.get(\"homee.attributes\");\nvar nodes = global.get(\"homee.nodes\");\n\nif (Object.keys(msg.payload)[0] === \"homeegrams\"){\nvar hg = msg.payload.homeegrams;\nhg.forEach(function(hgs){\n    hgs.triggers.attribute_triggers.forEach(function(trigger){\n        if (trigger.node_id == nodeold){\n            var typeold = attribute.find(attri => attri.id === trigger.attribute_id );\n            var typenew = nodes.find(node => node.id === nodenew );\n            typenew.attributes.forEach(function(attritype){\n                if (attritype.type == typeold.type && attritype.instance == typeold.instance){\n        node.send({payload: \"PUT:homeegrams/\"+trigger.homeegram_id+\"/triggers/\"+trigger.id+\"?attribute_id=\"+attritype.id});\n        node.send({payload: \"PUT:homeegrams/\"+trigger.homeegram_id+\"/triggers/\"+trigger.id+\"?node_id=\"+nodenew})}\n            })\n        }\n    })\n\n    hgs.actions.attribute_actions.forEach(function(action){\n        if (action.node_id == nodeold){\n            var typeold = attribute.find(attri => attri.id === action.attribute_id );\n            var typenew = nodes.find(node => node.id === nodenew );\n            typenew.attributes.forEach(function(attritype){\n                if (attritype.type == typeold.type && attritype.instance == typeold.instance){\n        node.send({payload: \"PUT:homeegrams/\"+action.homeegram_id+\"/actions/\"+action.id+\"?node_id=\"+nodenew+\"&attribute_id=\"+attritype.id})}\n            })\n        }\n    })\n    \n    hgs.conditions.attribute_conditions.forEach(function(conditions){\n        if (conditions.node_id == nodeold ){\n            var typeold = attribute.find(attri => attri.id === conditions.attribute_id );\n            var typenew = nodes.find(node => node.id === nodenew );\n            typenew.attributes.forEach(function(attritype){\n                if (attritype.type == typeold.type && attritype.instance == typeold.instance){\n        node.send({payload: \"PUT:homeegrams/\"+conditions.homeegram_id+\"/conditions/\"+conditions.id+\"?node_id=\"+nodenew+\"&attribute_id=\"+attritype.id})}\n            })\n        }\n    })\n    \n})\n}\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 340,
        "y": 1000,
        "wires": [
            [
                "ac5cba84.d15698"
            ]
        ]
    },
    {
        "id": "ac5cba84.d15698",
        "type": "homeeApi",
        "z": "2fafa37e.5aa2cc",
        "homee": "",
        "name": "homeeApi",
        "messageTypeFilter": [],
        "nodeFilter": null,
        "attributeFilter": null,
        "x": 420,
        "y": 860,
        "wires": [
            [
                "9492b4bb.9b0458"
            ]
        ]
    }
]

Dann diesen Flow importieren und in der Funktion die alte Node ID und die neue Node ID eingeben. ( Diese findet Ihr in der Browser Eingabezeile )

Dann den Inject Button drücken und in wenigen Sekunden ist alles erledigt und Ihr könnt das alte Gerät löschen und das neue ist Betriebsbereit.

Die Funktion berücksichtigt hier alle Attributtypen und deren Instancen.

Viel Spaß beim testen und beim Zeitsparen.

VG Micha

39 Like

Vielen Dank @Micha :+1:

1 Like

Als Nächstes müsste man noch an die relationships ran um die Zugehörigkeit in den Gruppen zu ändern.
Das werde ich mir bei Bedarf mal anschauen.
VG

3 Like

Das wäre natürlich noch das hohe C. Dies wird aber eigentlich beim einlernen festgelegt und sollte erledigt sein.

Grüße

1 Like

Die Gruppenzugehörigkeit wird nicht automatisch gemacht :crazy_face:

Ja. Ich meine wenn ich ein Gerät einlerne, lege ich ja zum Schluss den Namen und die Gruppen fest.

1 Like

Danke @Micha!!! :+1: :+1: Das ist ein wahnsinniger Mehrwert für die Würfel.
Hat Dich CA eigentlich schon direkt angefragt?

:rofl: :rofl:

3 Like

Meine Qualifikation liegt mehr in einem anderen Sektor und nicht beim Programmieren.

1 Like

Tja, scheinbar braucht es deine Qualifikationen :wink:

3 Like

Hallo @Micha ,
ich hätte noch eine Frage:
Das Geräte ersetzen funktioniert wahrscheinlich nur, wenn ich genau das gleiche Gerät mit einem Gerät mit den gleichen Messwerten ersetze?
Falls ich ein Nachfolgegerät mit anderen Eigenschaften erwische, funktioniert wahrscheinlich nur das HG nicht mehr richtig, aber das System überlebt es?

Warum ich Frage; homee hat leider bei ähnlichen Geräten verschiedene Messwert-Eigenschaften (z.B. bei Fenstersnsoren, die heißen manchmal „Tür-/Fensterzustand“ oder nur „Zustand“) und die lassen sich auch nicht in Gruppen verwenden :roll_eyes:
Weil es könnte ja jemand auf die Idee komm, Gerät Typ A tut es nicht richtig, ich ersetze es durch Typ B (besser, anders, neuer).
Nicht das man dadurch das System zerstört?

Wenn jetzt ein node eine Eigenschaft hat die das neue Geräte nicht hat dann wird hier auch nichts ersetzt. Ich schau mir das gerne an und baue da einen fallback ein.
Das maximale was passieren kann ist, das dein HG nicht funktioniert.
Dein System wird da aber nicht weiter beeinflusst.

Laut dem Code wird dieses Attribut nicht ersetzt wenn dazu kein passender Type gefunden wird.
Es wird nur der Type 1:1 ersetzt und nicht Type 1 mit 2.
Wenn also dein alter Sensor nen Temperatur Attribut hat und der neue nicht, dann wird da nichts geändert.

Die Funktion sucht hier explizit nach dem alten Type und wenn dieser gefunden wird dann wird noch die instance kontrolliert bzw. rausgesucht.

Sollte also passen ansonsten einfach die Funktion trocken durchlaufen lassen und die Ausgabe im Debug kontrollieren und dann erstes an die homee api senden.

3 Like

Hier ein passendes Video dazu.

[
    {
        "id": "9492b4bb.9b0458",
        "type": "function",
        "z": "e435a8ce.c0d9c8",
        "name": "Attribute und Node ID ersetzen bei Trigger , Conditions und Actions ( test nur Node )",
        "func": "var nodeold = 163; // zu ersetzende Node ID\nvar nodenew = 164; // neue Node ID \nvar attribute = global.get(\"homee.attributes\");\nvar nodes = global.get(\"homee.nodes\");\n\nif (Object.keys(msg.payload)[0] === \"homeegrams\"){\nvar hg = msg.payload.homeegrams;\nhg.forEach(function(hgs){\n    hgs.triggers.attribute_triggers.forEach(function(trigger){\n        if (trigger.node_id == nodeold){\n            var typeold = attribute.find(attri => attri.id === trigger.attribute_id );\n            var typenew = nodes.find(node => node.id === nodenew );\n            typenew.attributes.forEach(function(attritype){\n                if (attritype.type == typeold.type && attritype.instance == typeold.instance){\n        node.send({payload: \"PUT:homeegrams/\"+trigger.homeegram_id+\"/triggers/\"+trigger.id+\"?attribute_id=\"+attritype.id});\n        node.send({payload: \"PUT:homeegrams/\"+trigger.homeegram_id+\"/triggers/\"+trigger.id+\"?node_id=\"+nodenew})}\n            })\n        }\n    })\n\n    hgs.actions.attribute_actions.forEach(function(action){\n        if (action.node_id == nodeold){\n            var typeold = attribute.find(attri => attri.id === action.attribute_id );\n            var typenew = nodes.find(node => node.id === nodenew );\n            typenew.attributes.forEach(function(attritype){\n                if (attritype.type == typeold.type && attritype.instance == typeold.instance){\n        node.send({payload: \"PUT:homeegrams/\"+action.homeegram_id+\"/actions/\"+action.id+\"?node_id=\"+nodenew+\"&attribute_id=\"+attritype.id})}\n            })\n        }\n    })\n    \n    hgs.conditions.attribute_conditions.forEach(function(conditions){\n        if (conditions.node_id == nodeold ){\n            var typeold = attribute.find(attri => attri.id === conditions.attribute_id );\n            var typenew = nodes.find(node => node.id === nodenew );\n            typenew.attributes.forEach(function(attritype){\n                if (attritype.type == typeold.type && attritype.instance == typeold.instance){\n        node.send({payload: \"PUT:homeegrams/\"+conditions.homeegram_id+\"/conditions/\"+conditions.id+\"?node_id=\"+nodenew+\"&attribute_id=\"+attritype.id})}\n            })\n        }\n    })\n    \n})\n}\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1210,
        "y": 380,
        "wires": [
            [
                "945886b8.acd158",
                "767acccc.32ec64"
            ]
        ]
    },
    {
        "id": "945886b8.acd158",
        "type": "homeeApi",
        "z": "e435a8ce.c0d9c8",
        "homee": "",
        "name": "homeeApi",
        "messageTypeFilter": [],
        "nodeFilter": "",
        "attributeFilter": "",
        "x": 800,
        "y": 380,
        "wires": [
            [
                "9492b4bb.9b0458"
            ]
        ]
    },
    {
        "id": "343938e2.413288",
        "type": "inject",
        "z": "e435a8ce.c0d9c8",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "get:all",
        "payloadType": "str",
        "x": 250,
        "y": 300,
        "wires": [
            [
                "78be6296.1cfd8c",
                "945886b8.acd158"
            ]
        ]
    },
    {
        "id": "78be6296.1cfd8c",
        "type": "delay",
        "z": "e435a8ce.c0d9c8",
        "name": "",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 420,
        "y": 380,
        "wires": [
            [
                "5201123d.badb0c"
            ]
        ]
    },
    {
        "id": "5201123d.badb0c",
        "type": "function",
        "z": "e435a8ce.c0d9c8",
        "name": "",
        "func": "msg.payload = \"get:homeegrams\";\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 600,
        "y": 380,
        "wires": [
            [
                "945886b8.acd158"
            ]
        ]
    },
    {
        "id": "767acccc.32ec64",
        "type": "debug",
        "z": "e435a8ce.c0d9c8",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1430,
        "y": 560,
        "wires": []
    }
]

Der passende Flow zum Video.

15 Like

Hallo @Micha,
danke für deine Bemühungen. Heute habe auch ich dein Projekt erfolgreich nuten können.

Wenn man mal alles beinander hat, Node-Red anfängt zu verstehen, dann geht´s ja recht einfach :wink: Ich hatte vor ein paar Wochen etwas Startschwierigkeit mit Node-Red, da sich das Package nicht auf meinem Win10-Rechner installieren lies. Habs dann erstmal gelassen. Ein 1-2 Wochen später gab es ein neues Package, dann hat es funktioniert :man_shrugging:
Ein Video wie man das Ganze grundsätzlich installiert, wäre wahrscheinlich für den ein oder anderen auch noch hilfreich. Mir hat das am meisten Zeit gekostet.

Ich hatte ja dann Grundsätzlich das Problem das ich 2 hue Dimmer ersetzen bzw. neu anlernen musste. Nun hatte ich aber keinen neuen hue Dimmer V1 mehr und kaufen wollte ich auch keinen mehr. Dann ist mir die Idee mit einem virtuellen Gerät gekommen und ich habe mir Michas Video dazu auch noch angesehen. Dann habe ich mir so ein Hilfsgerät in Node-Red mit angelegt.

Ich habe dann immer die Geräte ID des ausgefallen hue Dimmers mit der ID des virtuellen Dimmers ersetzt. Dann den ausgefallen hue Dimmer in homee gelöscht und neu angelernt. Und dann wieder die ID´s ausgetauscht. Ging alles ruckzuck und ohne Probleme. :+1:

Mal schaun was ich jetzt mit dem ganzen neuen Wissen in Zukunft alles anstelle :joy:

Anmerken möchte ich noch @Steffen :
Die hue Dimmer haben sich problemlos wieder anlernen lassen und funktionieren momentan. Ich kann mir daher nicht vorstellen, dass die Geräte das Problem sind. Da ihr seit Jahren nicht einmal das Problem bei den V1-Dimmern gelöst habt, wundert es mich, dass der V2-Dimmer als Gerätevorschlag zur Abstimmung gelistet wurde. :see_no_evil:

2 Like

Das freut mich das es dir geholfen hat.
:relaxed::+1:

1 Like

Es gibt jetzt eine Automatische Funktion zum Geräte ersetzen.


[
    {
        "id": "39fe227c.afd74e",
        "type": "function",
        "z": "92bbd3bd.5be8f",
        "name": "Attribute und Node ID ersetzen bei Trigger , Conditions und Actions ( test nur vhih mit Host nicht verfügbar )",
        "func": "var nodeold = 0;\nvar nodenew = 0;\nvar attribute = global.get(\"homee.attributes\");\nvar nodes = global.get(\"homee.nodes\");\n\n\n\nif (msg.payload === \"start\"){\n    \n    var hg = global.get(\"homee.homeegrams\");\n    hg.forEach(function(hgs){\n     nodes.forEach(function(nodei){\n        if(nodei.protocol === msg.protocol && nodei.state === msg.stateold) {\n            nodeold = nodei.id\n            nodes.forEach(function(noden){\n                if(noden.name === nodei.name && noden.state === msg.statenew && noden.protocol === msg.protocol) {\n                        nodenew = noden.id\n            \n                        hgs.triggers.attribute_triggers.forEach(function(trigger){\n            \n            \n        if (trigger.node_id == nodeold){\n            var typeold = attribute.find(attri => attri.id === trigger.attribute_id );\n            var typenew = nodes.find(node => node.id === nodenew );\n            typenew.attributes.forEach(function(attritype){\n                if (attritype.type == typeold.type && attritype.instance == typeold.instance){\n        node.send({payload: \"PUT:homeegrams/\"+trigger.homeegram_id+\"/triggers/\"+trigger.id+\"?attribute_id=\"+attritype.id});\n        node.send({payload: \"PUT:homeegrams/\"+trigger.homeegram_id+\"/triggers/\"+trigger.id+\"?node_id=\"+nodenew})}\n            })\n        }\n    })\n                        hgs.actions.attribute_actions.forEach(function(action){\n        if (action.node_id == nodeold){\n            var typeold = attribute.find(attri => attri.id === action.attribute_id );\n            var typenew = nodes.find(node => node.id === nodenew );\n            typenew.attributes.forEach(function(attritype){\n                if (attritype.type == typeold.type && attritype.instance == typeold.instance){\n        node.send({payload: \"PUT:homeegrams/\"+action.homeegram_id+\"/actions/\"+action.id+\"?node_id=\"+nodenew+\"&attribute_id=\"+attritype.id})}\n            })\n        }\n    })\n                        hgs.conditions.attribute_conditions.forEach(function(conditions){\n        if (conditions.node_id == nodeold ){\n            var typeold = attribute.find(attri => attri.id === conditions.attribute_id );\n            var typenew = nodes.find(node => node.id === nodenew );\n            typenew.attributes.forEach(function(attritype){\n                if (attritype.type == typeold.type && attritype.instance == typeold.instance){\n        node.send({payload: \"PUT:homeegrams/\"+conditions.homeegram_id+\"/conditions/\"+conditions.id+\"?node_id=\"+nodenew+\"&attribute_id=\"+attritype.id})\n                }\n            })\n        }\n    })\n                }\n                \n            })\n            \n        }\n    })\n})\n}\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 750,
        "y": 580,
        "wires": [
            [
                "b14b612b.3aa3",
                "931bde81.11fb3"
            ]
        ]
    },
    {
        "id": "931bde81.11fb3",
        "type": "link out",
        "z": "92bbd3bd.5be8f",
        "name": "",
        "links": [
            "e204158a.3c9808"
        ],
        "x": 1195,
        "y": 540,
        "wires": []
    },
    {
        "id": "6bc91db4.26fa94",
        "type": "inject",
        "z": "92bbd3bd.5be8f",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "protocol",
                "v": "21",
                "vt": "num"
            },
            {
                "p": "stateold",
                "v": "8",
                "vt": "num"
            },
            {
                "p": "statenew",
                "v": "1",
                "vt": "num"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "start",
        "payloadType": "str",
        "x": 130,
        "y": 580,
        "wires": [
            [
                "76d88f4e.bfbee",
                "82c49a74.a93868"
            ]
        ],
        "info": "CANodeProtocol: {\r\n        CANodeProtocolNone: 0,\r\n        CANodeProtocolZWave: 1,\r\n        CANodeProtocolZigBee: 2,\r\n        CANodeProtocolEnOcean: 3,\r\n        CANodeProtocolWMBus: 4,\r\n        CANodeProtocolHomematic: 5,\r\n        CANodeProtocolKNXRF: 6,\r\n        CANodeProtocolInova: 7,\r\n        CANodeProtocolHTTPAVM: 8,\r\n        CANodeProtocolHTTPNetatmo: 9,\r\n        CANodeProtocolHTTPKoubachi: 10,\r\n        CANodeProtocolHTTPNest: 11,\r\n        CANodeProtocolIOCube: 12,\r\n        CANodeProtocolHTTPCCU2: 13,\r\n        CANodeProtocolHTTPUPnP: 14,\r\n        CANodeProtocolHTTPNuki: 15,\r\n        CANodeProtocolHTTPSEMS: 16,\r\n        CANodeProtocolSigmaZWave: 17,\r\n        CANodeProtocolLoRa: 18,\r\n        CANodeProtocolBiSecur: 19,\r\n        CANodeProtocolHTTPWolf: 20,\r\n        CANodeProtocolExternalHomee: 21,\r\n        CANodeProtocolHTTPMyStrom: 24,\r\n        CANodeProtocolWMS: 23,\r\n        CANodeProtocolHTTPSteca: 25,\r\n        CANodeProtocolAll: 100\r\n    },\r\n    CANodeState: {\r\n        CANodeStateNone: 0,\r\n        CANodeStateAvailable: 1,\r\n        CANodeStateUnavailable: 2,\r\n        CANodeStateUpdateInProgress: 3,\r\n        CANodeStateWaitingForAttributes: 4,\r\n        CANodeStateInitializing: 5,\r\n        CANodeStateUserInteractionRequired: 6,\r\n        CANodeStatePasswordRequired: 7,\r\n        CANodeStateHostUnavailable: 8,\r\n        CANodeStateDeleteInProgress: 9,\r\n        CANodeStateCosiConnected: 10,\r\n        CANodeStateBlocked: 11,\r\n        CANodeStateWaitingForWakeup: 12,\r\n        CANodeStateRemoteNodeDeleted: 13\r\n    },"
    },
    {
        "id": "82c49a74.a93868",
        "type": "change",
        "z": "92bbd3bd.5be8f",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "get:all",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 470,
        "y": 540,
        "wires": [
            [
                "931bde81.11fb3"
            ]
        ]
    },
    {
        "id": "76d88f4e.bfbee",
        "type": "delay",
        "z": "92bbd3bd.5be8f",
        "name": "",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 280,
        "y": 580,
        "wires": [
            [
                "39fe227c.afd74e"
            ]
        ]
    },
    {
        "id": "b14b612b.3aa3",
        "type": "debug",
        "z": "92bbd3bd.5be8f",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1230,
        "y": 580,
        "wires": []
    }
]

Bei diesem Flow müssen die Geräte 1 zu 1 vorhanden sein. Also auch der Name muss absolut identisch und einmalig sein.
Im inject könnt ihr den Protokolltyp und den State des alten Gerätes und des neuen Gerätes an.

Es müssen keine ID‘s der alten oder neuen Geräte eingegeben werden.

Die Protokolle und auch die State sind im Inject hinterlegt.

Nutzung auf eigene Gefahr

Ich bin mir nicht sicher ob ich diesen Flow schon eingestellt hatte.
:see_no_evil::crazy_face:

Tante Edit

8 Like

Kurze Verständnis-Nachfrage:
wenn der Name gleich ist (sein muss), wir immer die alte Node-ID durch die neue ersetzt?

Wichtig ist bei diesem Flow
-Gleiches Protokoll ( enocean, zwave etc.)
-State der alten Geräte und neuen Geräte müssen angegeben werden
-Name muss absolut identisch und einmalig im homee sein

Der Flow entstand beinmir für die vhih Geräte da ein Raspi seinen Dienst verweigert hatte und da funzt das perfekt. So erspart man sich das raus suchen jeder Geräte ID.

Ja dann wird die alte node Id durch die neue node Id ersetzt. :+1:

Ok, muss ich mal ausprobieren.
Für meine Hauptanwendung (Hue Dimmer ersetzen :roll_eyes:) muss ich dann aber bei Version 1 bleiben, da ich ja erst einen Zigbee-Dimmer gegen einen vhih-Dimmer tausche und dann wieder retoure.

Stimmt :see_no_evil: