NEWS
Modbus als Slave
-
Hallo,
anbei ein Beispiel, wie der Modbus Adapter als Slave genutzt werden kann.
Als Gegenpart habe ich Node-Red (node-red-contrib-modbus) auf dem selben ioBroker auf meinem Testsystem genutzt.Die Einstellungen vom Modbus-Adapter sind wie folgt:
Ein Javascript unterstützt mit einer Uhr und kopieren der empfangen Werte in die Ausgangsregister. Die Uhr muss von Hand aktualisiert werden, damit die nicht in die Tests reingrätscht.
//Modbus Test createState('0_userdata.0.Modbus.Uhrakt', { type: 'boolean', def: false, role: 'value' }); function Uhr(){ var today = new Date(); var Stunde = today.getHours(); var Minute = today.getMinutes(); var Sekunde = today.getSeconds(); var Wochentag = today.getDay(); var Tag = today.getDate(); var Monat = today.getMonth()+1; var Jahr = today.getFullYear(); setState("modbus.0.inputRegisters.30001",Stunde); setState("modbus.0.inputRegisters.30002",Minute); setState("modbus.0.inputRegisters.30003",Sekunde); setState("modbus.0.inputRegisters.30004",Tag); setState("modbus.0.inputRegisters.30005",Monat); setState("modbus.0.inputRegisters.30006",Jahr); setState("modbus.0.holdingRegisters.40001",Stunde); setState("modbus.0.holdingRegisters.40002",Minute); setState("modbus.0.holdingRegisters.40003",Sekunde); setState("modbus.0.holdingRegisters.40004",Tag); setState("modbus.0.holdingRegisters.40005",Monat); setState("modbus.0.holdingRegisters.40006",Jahr); } on({id: /modbus.0.coils.*/, change: 'ne'}, function (dp) { log(dp.id); var nr = dp.id.substring(15); if(nr.length == 1){ nr = "0"+nr; } nr="modbus.0.discreteInputs.100"+nr; setState(nr,dp.state.val); }); on({id: "0_userdata.0.Modbus.Uhrakt", change: 'any'}, function (dp) { Uhr(); });
Node-Red Übersicht:
Node-Red Export:
[ { "id": "076b7140f384fc31", "type": "tab", "label": "Flow 2", "disabled": false, "info": "", "env": [] }, { "id": "43e4d53f0aa39c48", "type": "inject", "z": "076b7140f384fc31", "name": "Uhr lesen", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "true", "payloadType": "bool", "x": 220, "y": 100, "wires": [ [ "ef3b8568dabbb9a9" ] ] }, { "id": "ef3b8568dabbb9a9", "type": "modbus-getter", "z": "076b7140f384fc31", "name": "FC4 lesen", "showStatusActivities": false, "showErrors": false, "showWarnings": true, "logIOActivities": false, "unitid": "1", "dataType": "InputRegister", "adr": "0", "quantity": "6", "server": "8f608791ee2c56ec", "useIOFile": false, "ioFile": "", "useIOForPayload": false, "emptyMsgOnFail": false, "keepMsgProperties": false, "delayOnStart": false, "startDelayTime": "", "x": 390, "y": 100, "wires": [ [ "70de74696eb9b0a9" ], [] ] }, { "id": "785e128808df5243", "type": "modbus-getter", "z": "076b7140f384fc31", "name": "HR 3 lesen", "showStatusActivities": false, "showErrors": false, "showWarnings": true, "logIOActivities": false, "unitid": "1", "dataType": "HoldingRegister", "adr": "0", "quantity": "6", "server": "8f608791ee2c56ec", "useIOFile": false, "ioFile": "", "useIOForPayload": false, "emptyMsgOnFail": false, "keepMsgProperties": false, "delayOnStart": false, "startDelayTime": "", "x": 390, "y": 200, "wires": [ [ "a8f80e0b0790e348" ], [] ] }, { "id": "9dd6f491f92368e1", "type": "catch", "z": "076b7140f384fc31", "name": "", "scope": null, "uncaught": false, "x": 180, "y": 620, "wires": [ [ "67f50288d77837d7" ] ] }, { "id": "67f50288d77837d7", "type": "debug", "z": "076b7140f384fc31", "name": "debug", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 410, "y": 620, "wires": [] }, { "id": "8237112949c7f3af", "type": "modbus-getter", "z": "076b7140f384fc31", "name": "Discrete Inputs lesen", "showStatusActivities": false, "showErrors": false, "showWarnings": true, "logIOActivities": false, "unitid": "1", "dataType": "Input", "adr": "0", "quantity": "16", "server": "8f608791ee2c56ec", "useIOFile": false, "ioFile": "", "useIOForPayload": false, "emptyMsgOnFail": false, "keepMsgProperties": false, "delayOnStart": false, "startDelayTime": "", "x": 400, "y": 520, "wires": [ [ "911846b7835d27b1" ], [] ] }, { "id": "afdcf980395e649d", "type": "inject", "z": "076b7140f384fc31", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "true", "payloadType": "bool", "x": 210, "y": 200, "wires": [ [ "785e128808df5243" ] ] }, { "id": "7b47194372033d3a", "type": "inject", "z": "076b7140f384fc31", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "true", "payloadType": "bool", "x": 190, "y": 380, "wires": [ [ "38dce709eb85f4cd" ] ] }, { "id": "dad7162bfc539315", "type": "inject", "z": "076b7140f384fc31", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "true", "payloadType": "bool", "x": 190, "y": 520, "wires": [ [ "8237112949c7f3af" ] ] }, { "id": "70de74696eb9b0a9", "type": "function", "z": "076b7140f384fc31", "name": "Input Register", "func": "\nnode.status({ text: msg.payload[3] + \".\" + msg.payload[4] + \".\" + msg.payload[5] + \", \" + msg.payload[0] + \":\" + msg.payload[1] + \":\" + msg.payload[2] });\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 840, "y": 80, "wires": [ [] ] }, { "id": "a8f80e0b0790e348", "type": "function", "z": "076b7140f384fc31", "name": "Holding Register", "func": "\nnode.status({ text: msg.payload[3] + \".\" + msg.payload[4] + \".\" + msg.payload[5] + \", \" + msg.payload[0] + \":\" + msg.payload[1] + \":\" + msg.payload[2] });\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 850, "y": 180, "wires": [ [] ] }, { "id": "911846b7835d27b1", "type": "function", "z": "076b7140f384fc31", "name": "Discrete Inputs", "func": "\nnode.status({ text: msg.payload[0] + \",\" + msg.payload[1] + \",\" + msg.payload[2] + \",\" + msg.payload[3] + \",\" + msg.payload[4] + \",\" + msg.payload[5] + \",\" + msg.payload[6] + \",\" + msg.payload[7] + \",\" + msg.payload[8] + \",\" + msg.payload[9] + \",\" + msg.payload[10] + \",\" + msg.payload[11] + \",\" + msg.payload[12] + \",\" + msg.payload[13] + \",\" + msg.payload[14] + \",\" + msg.payload[15] });\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 780, "y": 520, "wires": [ [] ] }, { "id": "f6bbf853944e2b8e", "type": "inject", "z": "076b7140f384fc31", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "0_userdata.0.Modbus.Uhrakt", "payload": "true", "payloadType": "bool", "x": 290, "y": 40, "wires": [ [ "2ecfa1e07d7ac8ce" ] ] }, { "id": "2ecfa1e07d7ac8ce", "type": "ioBroker out", "z": "076b7140f384fc31", "name": "", "topic": "", "ack": "false", "autoCreate": "false", "stateName": "", "role": "", "payloadType": "", "readonly": "", "stateUnit": "", "stateMin": "", "stateMax": "", "x": 540, "y": 40, "wires": [] }, { "id": "e0e451832374cbb0", "type": "modbus-write", "z": "076b7140f384fc31", "name": "FC 15 Coils schreiben", "showStatusActivities": true, "showErrors": true, "showWarnings": true, "unitid": "77", "dataType": "MCoils", "adr": "0", "quantity": "16", "server": "8f608791ee2c56ec", "emptyMsgOnFail": false, "keepMsgProperties": false, "delayOnStart": false, "startDelayTime": "", "x": 900, "y": 380, "wires": [ [], [] ] }, { "id": "2a3a2f3bd75e5784", "type": "inject", "z": "076b7140f384fc31", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "false", "payloadType": "bool", "x": 190, "y": 440, "wires": [ [ "38dce709eb85f4cd" ] ] }, { "id": "38dce709eb85f4cd", "type": "function", "z": "076b7140f384fc31", "name": "Coils erstellen", "func": "var bool = msg.payload;\nmsg.payload = [bool, !bool, bool, !bool, bool, !bool, bool, !bool, bool, !bool, bool, !bool, bool, !bool, bool, !bool]\nnode.status({ text: msg.payload[0] + \",\" + msg.payload[1] + \",\" + msg.payload[2] + \",\" + msg.payload[3] + \",\" + msg.payload[4] + \",\" + msg.payload[5] + \",\" + msg.payload[6] + \",\" + msg.payload[7] + \",\" + msg.payload[8] + \",\" + msg.payload[9] + \",\" + msg.payload[10] + \",\" + msg.payload[11] + \",\" + msg.payload[12] + \",\" + msg.payload[13] + \",\" + msg.payload[14] + \",\" + msg.payload[15] });\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 380, "y": 380, "wires": [ [ "e0e451832374cbb0" ] ] }, { "id": "f49483843b20ed8f", "type": "modbus-write", "z": "076b7140f384fc31", "name": "Mehrere Register schreiben", "showStatusActivities": false, "showErrors": false, "showWarnings": true, "unitid": "1", "dataType": "MHoldingRegisters", "adr": "0", "quantity": "6", "server": "8f608791ee2c56ec", "emptyMsgOnFail": false, "keepMsgProperties": false, "delayOnStart": false, "startDelayTime": "", "x": 680, "y": 300, "wires": [ [], [] ] }, { "id": "13dc061ca308d6c3", "type": "function", "z": "076b7140f384fc31", "name": "Werte erstellen", "func": "var fak = 1;\nif(msg.payload){\n fak=10;\n}\nmsg.payload = [1 * fak, 2 * fak, 3 * fak, 4 * fak, 5 * fak, 6 * fak]\nnode.status({ text: msg.payload[0] + \",\" + msg.payload[1] + \",\" + msg.payload[2] + \",\" + msg.payload[3] + \",\" + msg.payload[4] + \",\" + msg.payload[5]});\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 380, "y": 300, "wires": [ [ "f49483843b20ed8f" ] ] }, { "id": "9929366dd363ba55", "type": "inject", "z": "076b7140f384fc31", "name": "*10", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "true", "payloadType": "bool", "x": 190, "y": 280, "wires": [ [ "13dc061ca308d6c3" ] ] }, { "id": "6e7c45f923caa5db", "type": "inject", "z": "076b7140f384fc31", "name": "*1", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "false", "payloadType": "bool", "x": 190, "y": 320, "wires": [ [ "13dc061ca308d6c3" ] ] }, { "id": "8f608791ee2c56ec", "type": "modbus-client", "name": "", "clienttype": "tcp", "bufferCommands": true, "stateLogEnabled": false, "queueLogEnabled": true, "failureLogEnabled": true, "tcpHost": "127.0.0.1", "tcpPort": "502", "tcpType": "DEFAULT", "serialPort": "/dev/ttyUSB", "serialType": "RTU-BUFFERD", "serialBaudrate": "9600", "serialDatabits": "8", "serialStopbits": "1", "serialParity": "none", "serialConnectionDelay": "100", "serialAsciiResponseStartDelimiter": "0x3A", "unit_id": "77", "commandDelay": "1", "clientTimeout": "1000", "reconnectOnTimeout": true, "reconnectTimeout": "2000", "parallelUnitIdsAllowed": true, "showErrors": true, "showWarnings": true, "showLogs": true } ]
Man kann die Uhr stellen, die Werte ablegen und wieder einlesen.
-
@peterfido Hallo Peter, vielen Dank fürs Zeigen.
Das gibt mir auch gleich nen Einstieg in Nodered und JS:)Wird das JS-Uhraktscript irgendwo im Nodered eingebaut (mit Doppelklick auf blaue Box oben links "0_userdata.0.Modbus.Uhrakt:true") oder wird das im JS-Adapter erstellt und dann dort gestartet, wenn es benötigt wird?
Es scheint ja auch zwei verschiedene Skripte zu geben?
Das zweite sieht aus, als wäre es die Klartextdarstellung des Node-Flows, oder?
Kann ich das dann iwo reinkopieren und hab die Knoten? Wär ja geil:)
Oder gibts da Probleme mit den Hexen? ZB "server": "8f608791ee2c56ec"?Wie bei Dir zu sehen, habe auch ich keinen Var-Namen unter Discrete-Inputs im Modbus-Adapter angegeben, nur eine Adresse und trotzdem kommen Werte. Gespentisch:)
Wenn ich mehrere Byte-Typen habe, wäre allerdings schon eine Unterscheidung erforderlich, welches Bit ich gerade nutzen will. Da erschließt sich mir die Struktur des Adapters noch nicht so recht. Schließlich will man ja auch für die Les- und Wartbarkeit nicht nur Adress-Zahlen handlen...
Allein z.B. die Beschreibung oder einfach trotzdem einen Var-Namen zu vergeben, ist nicht eindeutig, wenn es denn scheinbar auch ohne geht.
Oder tauchen im Nodered dann konkrete Zuordnungen auf?ZB (Heimautomationsanwendung) Codesys-Gegenseite:
Var
Zi1 : Byte;Begin
if
Zi1.0 = %DI1; //(Rolladen_Endlage_offen)
...
Zi1.7 = Fenster_Fensterkontakt_auf;
usw.
End;Erwartung im Modbus-Adapter (Konfi-Tab Discrete Inputs):
Adresse: 0
Name: Zi1
Beschreibung: Rolladen offen
Role: state
usw. -
@minkhx Ich habe mein Post oben etwas um "Überschriften" ergänzt. Die Node-Red Grafik ist nur ein Überblick, den man nicht nachbauen braucht. Der Code darunter ist zum Import in Node-Red. Danach ist der Flow bereits fertig gebaut. Man braucht evtl. nur noch Parameter anpassen. (IP-Adressen; Geräte-IDs)
Das Javascript wird im Script Editor als Javascript importiert. Das lauscht auf einen Datenpunkt, welcher vom Node-Red aus getriggert wird. Da wird dann die aktuelle Zeit und Datum in den Registern abgelegt. Kommen Coils "rein", werden diese auf die Discreten Inputs gespiegelt.
-
@peterfido Alles klar, besten Dank.