Is there any visible difference, e.g. is there some sort of bitwise operation that I don't know about that happens with Modbus signals?
I don't understand what you mean by your friends numbers and your numbers. Are you both accessing the same server in the same way?
Same server is being accessed (code above).
I am accessing it via node-red installed on my machine (flow above in "Master"); my friend is using some proprietary software, but we're both getting different numbers to what is broadcast.
Physically the same machine, or the same code on a different machine.
Node-red Modbus Server is running on physical machine A and rebroadcasting signals received from other devices on LAN
My node-red Modbus Client is running on a separate physical machine B, connected via VPN to the same LAN as machine A
My co-worker's Modbus Client is not node-red and I believe running on a PLC (physical machine C); he obtains readings via proprietary software (GXWorks or similar?). It is on the same physical LAN as machine A.
Physical machines B & C are both reading from server on A. I can draw a network diagram if needed.
To investigate why the two are different, examine the raw data returned by the modbus requests. That may give a clue as to why they are both wrong.
Isn't raw data what is returned by the modbus read nodes? e.g. Inject --> modbus flex getter --> log. I was under the impression that was it...
Or is there a particulare software you could recommend to read the raw data?
Yes, so you need to compare that with the data your co-worker gets, as he is getting different data. The question is, is it the interpretation of the raw data or the raw data itself that is different.
Weirdest thing is that my raw data read differs from my raw data broadcast. e.g. debug log says I'm broadcasting ABCD, but I receive AXYZ, unless I explicitly force broadcast xOxx or xxOx etc. , then I receive xOxx etc. I'd be more confident in telling him his software is reading wrong if I was sure mine was reading write haha
Wondering if modbus broadcast is somehow overwriting itself...
EDIT: bad example. Here's a better one:
(Measured just now)
Address | Broadcast data | Received data | Notes |
---|---|---|---|
D401 | 4 | 4 | Seems to receive correctly |
D402 | 778 | 2560 | Later, 799 gives 6912 |
D403 | 2200 | 38912 | |
D404 | 2200 | 38912 |
If I force broadcast an arbitrary number to any of D401, D402, D403, D404, I will receive that number, without any weird scaling factor or whatever is going on. NB readings taken straight from endpoint debug log nodes' output to the log. But any "naturally read" number is scaled weirdly (looks like on the receiving end? or in the aether in between)
Sorry, I have no idea what you mean by that.
Thank you for your patience and help, Colin!
I just posted a better example. I was wondering from a couple other threads I saw, those numbers don't look like some sort of known weird endian or bitwise shenanigans going on to you, do they?
Here's another log, straight from the server:
Address | Server output |
---|---|
D401 | 0x4 |
D402 | 0x1e |
D403 | 0x98 |
D404 | 0x98 |
Seems to be in HEX, I wonder if something's getting misinterpreted...
Further weirdness: as a test, I'm writing to register 8 on the server, but reading back, register 8's value on the server comes in at 31 in the array on the client. Does this make sense to anyone? EDIT: Nevermind, that makes sense now. Every 4 slots in the array is used. It fits the pattern.
The more I and my colleague look at it, the more it looks like bytes are being swapped around, similar to the issue observed here, except my modbus master and slave are entirely in node-red, so I don't know why this is happening.
as a test, I broadcast 12345
on 4008
, and receive as much in my node-red client, but my colleague receives alternating FF 00
and 00 FF
his end.
He said:
Almost like it’s only using 8 bits and maxing out at 255, then either shifting or endian swapping it
Can you clarify your overall goal?
If you simply want to read/write values from a MitsiPLC, you can use node-red-contrib-mcprotocol
If you need to build a modbus server, then you should read the built in docs. For example, would be better off writing to the modbus server using the flex-write.
Built in help...
You can use the Modbus write nodes (FC) to write data to the server buffers.
You can use the Modbus read nodes (FC) to read data from the server buffers.
Here is how i would structure it:
My apologies for the delay in replying; I was called to other tasks by my work.
The overall goal with this system is to re-broadcast signals received from a PLC, but the best my colleague is seeing is the same replies coming back with alternating 8 bit “halves” of the 16 bit data, even when I broadcast 12345
. I think we need to do a byte swap using buffer-parser, but I've never got anything but errors from the buffer-parser node.
Current flow is (possibly broken? been a while):
[
{
"id": "3decb5f518882686",
"type": "subflow",
"name": "live debug",
"info": "",
"category": "",
"in": [
{
"x": 240,
"y": 160,
"wires": [
{
"id": "45dbf990.ba2408"
}
]
}
],
"out": [
{
"x": 560,
"y": 160,
"wires": [
{
"id": "45dbf990.ba2408",
"port": 1
}
]
}
],
"env": [
{
"name": "debug_name",
"type": "str",
"value": "Debug",
"ui": {
"label": {
"en-US": "Name"
},
"type": "input",
"opts": {
"types": [
"str"
]
}
}
},
{
"name": "debug_property",
"type": "str",
"value": "msg",
"ui": {
"label": {
"en-US": "Property Path"
},
"type": "input",
"opts": {
"types": [
"str"
]
}
}
},
{
"name": "pass_debug_property",
"type": "bool",
"value": "false",
"ui": {
"label": {
"en-US": "Pass Property Path"
},
"type": "input",
"opts": {
"types": [
"bool"
]
}
}
}
],
"meta": {},
"color": "#DDAA99"
},
{
"id": "45dbf990.ba2408",
"type": "function",
"z": "3decb5f518882686",
"name": "format time nicely",
"func": "let msg1 = {payload: RED.util.cloneMessage(msg)};\nmsg1.payload.debug_property = msg.debug_property || env.get(\"debug_property\") || \"msg\"\ntry {\n msg1.payload.debug_property_array = RED.util.normalisePropertyExpression(msg1.payload.debug_property)\n}\ncatch(error){\n msg.payload = error;\n msg1.payload.error = error;\n}\nmsg1.payload.debug_name = env.get(\"debug_name\") || msg._msgid || \"name error\"\nmsg1.payload.pass_debug_property = env.get(\"pass_debug_property\") || false\nreturn [msg1,msg];",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 390,
"y": 120,
"wires": [
[
"50da04b3.af25fc"
],
[]
]
},
{
"id": "50da04b3.af25fc",
"type": "websocket out",
"z": "3decb5f518882686",
"name": "",
"server": "985ecbc7.67a138",
"client": "",
"x": 680,
"y": 120,
"wires": []
},
{
"id": "1787be40.e87842",
"type": "http in",
"z": "3decb5f518882686",
"name": "",
"url": "/debug",
"method": "get",
"upload": false,
"swaggerDoc": "",
"x": 330,
"y": 40,
"wires": [
[
"1857548e.e7a8ab"
]
]
},
{
"id": "1857548e.e7a8ab",
"type": "template",
"z": "3decb5f518882686",
"name": "Simple Web Page",
"field": "payload",
"fieldType": "msg",
"format": "html",
"syntax": "mustache",
"template": "<!DOCTYPE HTML>\n<html>\n <head>\n <style>\n span.debug_name {\n color: black;\n }\n span.debug_error{\n color: red;\n }\n span.debug_date{\n color:blue;\n }\n pre[id^='json_data_']{\n font-size:20px;\n background-color: ghostwhite;\n border: 1px solid silver;\n padding: 10px 20px;\n margin: 20px; \n white-space: pre-wrap;\n }\n .json-key {\n color: olive;\n }\n .json-value {\n color: navy;\n }\n .json-string {\n color: brown;\n }\n\n </style>\n <title>Debug Messages</title>\n <script type=\"text/javascript\">\n var ws;\n var wsUri = \"ws:\";\n var loc = window.location;\n console.log(loc);\n if (loc.protocol === \"https:\") { wsUri = \"wss:\"; }\n // This needs to point to the web socket in the Node-RED flow\n wsUri += \"//\" + loc.host + loc.pathname.replace(\"debug\",\"ws/debug\");\n\n function wsConnect() {\n console.log(\"connect\",wsUri);\n ws = new WebSocket(wsUri);\n ws.onmessage = function(msg) {\n segments = document.getElementById('json_data').innerHTML;\n var paused = document.getElementById('paused').innerText === \"Pause\";\n var data;\n var line = \"\";\n var error = \"\";\n var date = new Date().toISOString();\n // parse the incoming message as a JSON object\n try { \n data = JSON.parse(msg.data);\n } catch (json_error) {\n data = {error: [\"json parse error\", json_error]};\n }; \n if(!data.error){\n var debug_name = data.debug_name ;\n var debug_property = data.debug_property_array;\n var original_property = data.debug_property;\n if(!data.pass_debug_property) delete data.debug_property;\n delete data.pass_debug_property;\n delete data.debug_property_array;\n delete data.debug_name;\n debug_property.slice(1).forEach((prop, index) => {\n if(data[prop]) { \n data = data[prop];\n }else{\n error = \"Property path Error on or after - \" + debug_property[index];\n }\n });\n\n line = `<div id=\"element${date}\">\n <hr/>\n <span class=\"debug_name\">${debug_name}</span> <span class=\"debug_date\">${date}</span> \n <span class=\"debug_orginal\">${original_property}</span> <span class=\"debug_error\">${error}</span> \n <button title=\"copy\" alt=\"copy\" onclick=\"copy_text('json_data_${date}')\"> ❒ </button>\n <button title=\"delete\" alt=\"delete\" onclick=\"delete_text('element${date}')\"> ❌ </button> \n <span class=\"json_data\">\n <pre id=\"json_data_${date}\"><code id=data>${library.json.prettyPrint(data)}</code></pre></span> \n </div>`;\n }else{\n line = `<div id=\"element${date}\">\n <hr/>\n <span class=\"debug_error\">Error: ${JSON.stringify(data.error)}</span> <span class=\"debug_date\">${date}</span> \n <button title=\"delete\" alt=\"delete\" onclick=\"delete_text('element${date}')\"> ❌ </button> \n </div>`;\n }\n // append line to segment\n if(paused){\n document.getElementById('json_data').innerHTML = line + segments;\n }\n }\n ws.onopen = function() {\n // update the status div with the connection status\n document.getElementById('status').innerHTML = \"connected\";\n //ws.send(\"Open for data\");\n console.log(\"connected\");\n }\n ws.onclose = function() {\n // update the status div with the connection status\n document.getElementById('status').innerHTML = \"not connected\";\n // in case of lost connection tries to reconnect every 3 secs\n setTimeout(wsConnect,3000);\n }\n }\n function copy_text(input) {\n // Get the text field\n var copyText = document.getElementById(input).innerText;\n var dummy = document.createElement(\"textarea\");\n document.body.appendChild(dummy);\n dummy.value = copyText;\n dummy.select();\n document.execCommand(\"copy\");\n document.body.removeChild(dummy);\n alert(\"Copied Data to Clipboard\\n\\n\" + copyText)\n }\n function delete_text(input) {\n // Get the text field\n document.getElementById(input).innerHTML = \"\";\n }\n if (!library) var library = {};\n library.json = {\n replacer: function(match, pIndent, pKey, pVal, pEnd) {\n var key = '<span class=json-key>\"';\n var val = '<span class=json-value>';\n var str = '<span class=json-string>';\n var r = pIndent || '';\n if (pKey)\n r = r + key + pKey.replace(/[\": ]/g, '') + '\"</span>: ';\n if (pVal)\n r = r + (pVal[0] == '\"' ? str : val) + pVal + '</span>';\n return r + (pEnd || '');\n },\n prettyPrint: function(obj) {\n var jsonLine = /^( *)(\"[\\w]+\": )?(\"[^\"]*\"|[\\w.+-]*)?([,[{])?$/mg;\n return JSON.stringify(obj, null, 4)\n .replace(/&/g, '&').replace(/\\\\\"/g, '"')\n .replace(/</g, '<').replace(/>/g, '>')\n .replace(jsonLine, library.json.replacer);\n }\n \n };\n function pause() {\n var element_paused = document.getElementById(\"paused\");\n paused = (element_paused.innerText === \"Resume\") ? \"Pause\" : \"Resume\";\n element_paused.innerText = paused;\n }\n \n </script>\n </head>\n <body onload=\"wsConnect();\" onunload=\"ws.disconnect();\">\n <font face=\"Arial\">\n <h1>Debug Messages <button id=\"paused\" value=\"pause\" onclick=\"pause()\">Pause</button> </h1>\n <div id=\"json_data\"></div>\n <hr/>\n <div id=\"status\">unknown</div>\n </font>\n </body>\n</html>\n",
"x": 550,
"y": 40,
"wires": [
[
"42a28745.bd5d78"
]
]
},
{
"id": "42a28745.bd5d78",
"type": "http response",
"z": "3decb5f518882686",
"name": "",
"x": 730,
"y": 40,
"wires": []
},
{
"id": "985ecbc7.67a138",
"type": "websocket-listener",
"z": "37f1be47da815ae1",
"path": "/ws/debug",
"wholemsg": "false"
},
{
"id": "37f1be47da815ae1",
"type": "tab",
"label": "Modbus Server",
"disabled": false,
"info": "",
"env": []
},
{
"id": "49c18e3ad19acbda",
"type": "group",
"z": "37f1be47da815ae1",
"style": {
"stroke": "#999999",
"stroke-opacity": "1",
"fill": "none",
"fill-opacity": "1",
"label": true,
"label-position": "nw",
"color": "#a4a4a4"
},
"nodes": [
"c5a0fdf6b8bb9850",
"ed36434616147015",
"248c46681d071246",
"62340306b6eaf6f0",
"f5457920917eb0f0",
"8512686ef7c21c3e",
"4cefa7be49623107",
"c396898e828dee2a",
"85ebfdbffa8d984b",
"8916057c5b4e9270",
"5d59c82badda5237",
"d04855631aecc823",
"3acabffc83517f90",
"134c7774ebcf3011",
"4486d6e85a7d3e1b",
"889f040436167658",
"99eb4635c1919a85",
"b3fc5514304b5242",
"a28bbddf98fa5939",
"290109b199a881e3",
"4f9540eaeb13509a",
"ad73abc4d0bad61d",
"f4d3a0e92cc61648",
"509b5b5744b44bea",
"2b2b6e5bf6a1669d",
"67a752c86bc8ca3c",
"bdc07397e20610c1"
],
"x": 14,
"y": 159,
"w": 1932,
"h": 444.5
},
{
"id": "5d59c82badda5237",
"type": "modbus-server",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "",
"logEnabled": true,
"hostname": "0.0.0.0",
"serverPort": 10502,
"responseDelay": 100,
"delayUnit": "ms",
"coilsBufferSize": "64",
"holdingBufferSize": "64",
"inputBufferSize": "64",
"discreteBufferSize": "64",
"showErrors": true,
"x": 1560,
"y": 540,
"wires": [
[
"d04855631aecc823",
"3acabffc83517f90"
],
[],
[],
[],
[]
]
},
{
"id": "d04855631aecc823",
"type": "debug",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Server output",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 1820,
"y": 440,
"wires": []
},
{
"id": "f5457920917eb0f0",
"type": "switch",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "gboiler_running_condition",
"vt": "str"
},
{
"t": "eq",
"v": "gsilo_level_0_1000",
"vt": "str"
},
{
"t": "eq",
"v": "gmax_stoker_speed",
"vt": "str"
},
{
"t": "eq",
"v": "gpid_stoker_output",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 4,
"x": 1030,
"y": 340,
"wires": [
[
"c396898e828dee2a"
],
[
"4cefa7be49623107"
],
[
"8512686ef7c21c3e"
],
[
"62340306b6eaf6f0"
]
]
},
{
"id": "b3fc5514304b5242",
"type": "comment",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Boiler Heat Meter kW & mWh [req. Serial RS485]",
"info": "",
"x": 240,
"y": 260,
"wires": []
},
{
"id": "290109b199a881e3",
"type": "inject",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Get Silo Level",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "5",
"crontab": "",
"once": true,
"onceDelay": "1",
"topic": "gsilo_level_0_1000",
"payload": "",
"payloadType": "date",
"x": 180,
"y": 320,
"wires": [
[
"889f040436167658"
]
]
},
{
"id": "889f040436167658",
"type": "link out",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Sensors out",
"mode": "link",
"links": [
"37db5198429b7396"
],
"x": 445,
"y": 340,
"wires": []
},
{
"id": "99eb4635c1919a85",
"type": "link in",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Processor in",
"links": [
"da25e4e66d04561c"
],
"x": 745,
"y": 340,
"wires": [
[
"134c7774ebcf3011"
]
]
},
{
"id": "134c7774ebcf3011",
"type": "modbus-flex-getter",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Boiler_getter",
"showStatusActivities": false,
"showErrors": false,
"showWarnings": true,
"logIOActivities": false,
"server": "d8b07ddb.c44d4",
"useIOFile": false,
"ioFile": "",
"useIOForPayload": false,
"emptyMsgOnFail": false,
"keepMsgProperties": false,
"delayOnStart": false,
"startDelayTime": "",
"x": 870,
"y": 340,
"wires": [
[
"f5457920917eb0f0"
],
[]
]
},
{
"id": "4486d6e85a7d3e1b",
"type": "comment",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "<-- I/O through lvc_labels -->",
"info": "",
"x": 600,
"y": 340,
"wires": []
},
{
"id": "85ebfdbffa8d984b",
"type": "debug",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "debug 10",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 1520,
"y": 280,
"wires": []
},
{
"id": "a28bbddf98fa5939",
"type": "inject",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Shutdown/Fireout",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "5",
"crontab": "",
"once": true,
"onceDelay": "1",
"topic": "gboiler_running_condition",
"payload": "",
"payloadType": "date",
"x": 190,
"y": 200,
"wires": [
[
"889f040436167658"
]
]
},
{
"id": "4f9540eaeb13509a",
"type": "inject",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Stoker at maximum speed",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "5",
"crontab": "",
"once": true,
"onceDelay": "1",
"topic": "gmax_stoker_speed",
"payload": "",
"payloadType": "date",
"x": 200,
"y": 440,
"wires": [
[
"889f040436167658"
]
]
},
{
"id": "ad73abc4d0bad61d",
"type": "inject",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Averaged stoker speed",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "5",
"crontab": "",
"once": true,
"onceDelay": "1",
"topic": "gpid_stoker_output",
"payload": "",
"payloadType": "date",
"x": 190,
"y": 520,
"wires": [
[
"889f040436167658"
]
]
},
{
"id": "c396898e828dee2a",
"type": "function",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Shutdown/Fireout scale",
"func": "// This node caused \"TypeError: Cannot read properties of undefined (reading 'length')\"\n// Fixed: https://discourse.nodered.org/t/is-not-a-valid-memory-write-message-to-server/77977/7?u=darren\n\nmsg.payload = { \n 'value': Number(msg.payload[0]),\n 'register': 'holding',\n 'address': 1,\n 'disableMsgOutput': 0 };\n \nreturn msg;\n\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1250,
"y": 280,
"wires": [
[
"85ebfdbffa8d984b",
"5d59c82badda5237"
]
]
},
{
"id": "4cefa7be49623107",
"type": "function",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Silo Level scale",
"func": "msg.payload = {\n 'value': msg.payload,\n 'register': 'holding',\n 'address': 2,\n 'disableMsgOutput': 0\n};\n\n// debug\n//msg.payload = {\n// 'value': 1337, 'register': 'holding',\n// 'address': 2, 'disableMsgOutput': 0\n//};\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1220,
"y": 320,
"wires": [
[
"8916057c5b4e9270",
"5d59c82badda5237"
]
]
},
{
"id": "8512686ef7c21c3e",
"type": "function",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Maximum stoker speed scale",
"func": "msg.payload = {\n 'value': msg.payload,\n 'register': 'holding',\n 'address': 3,\n 'disableMsgOutput': 0\n};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1260,
"y": 360,
"wires": [
[
"ed36434616147015",
"5d59c82badda5237"
]
]
},
{
"id": "62340306b6eaf6f0",
"type": "function",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Averaged stoker speed scale",
"func": "msg.payload = {\n 'value': msg.payload,\n 'register': 'holding',\n 'address': 4,\n 'disableMsgOutput': 0\n};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1260,
"y": 400,
"wires": [
[
"248c46681d071246",
"5d59c82badda5237"
]
]
},
{
"id": "c5a0fdf6b8bb9850",
"type": "comment",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "[Unavailable] Stoker at minimum speed",
"info": "",
"x": 190,
"y": 380,
"wires": []
},
{
"id": "8916057c5b4e9270",
"type": "debug",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "debug 11",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 1520,
"y": 320,
"wires": []
},
{
"id": "ed36434616147015",
"type": "debug",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "debug 12",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 1500,
"y": 360,
"wires": []
},
{
"id": "248c46681d071246",
"type": "debug",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "debug 13",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 1500,
"y": 400,
"wires": []
},
{
"id": "3acabffc83517f90",
"type": "subflow:3decb5f518882686",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "",
"x": 1830,
"y": 540,
"wires": [
[]
]
},
{
"id": "c1f1279b6bad34ee",
"type": "comment",
"z": "37f1be47da815ae1",
"name": "Brown & Carroll Modbus re-server",
"info": "",
"x": 920,
"y": 100,
"wires": []
},
{
"id": "f4d3a0e92cc61648",
"type": "modbus-write",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "",
"showStatusActivities": false,
"showErrors": false,
"showWarnings": true,
"unitid": "1",
"dataType": "HoldingRegister",
"adr": "60",
"quantity": "1",
"server": "06fb380adab7a3ac",
"emptyMsgOnFail": false,
"keepMsgProperties": false,
"delayOnStart": false,
"startDelayTime": "",
"x": 1140,
"y": 440,
"wires": [
[],
[]
]
},
{
"id": "509b5b5744b44bea",
"type": "inject",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "69",
"payloadType": "num",
"x": 970,
"y": 440,
"wires": [
[
"f4d3a0e92cc61648"
]
]
},
{
"id": "2b2b6e5bf6a1669d",
"type": "inject",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "5",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 710,
"y": 560,
"wires": [
[
"67a752c86bc8ca3c"
]
]
},
{
"id": "67a752c86bc8ca3c",
"type": "function",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "Debug 12345 to D408",
"func": "// debug\nmsg.payload = {\n 'value': 12345, 'register': 'holding',\n 'address': 8, 'disableMsgOutput': 0\n};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 900,
"y": 560,
"wires": [
[
"bdc07397e20610c1",
"5d59c82badda5237"
]
]
},
{
"id": "bdc07397e20610c1",
"type": "debug",
"z": "37f1be47da815ae1",
"g": "49c18e3ad19acbda",
"name": "debug 12345",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 1030,
"y": 520,
"wires": []
},
{
"id": "d8b07ddb.c44d4",
"type": "modbus-client",
"name": "Boiler_PLC",
"clienttype": "tcp",
"bufferCommands": true,
"stateLogEnabled": false,
"queueLogEnabled": false,
"failureLogEnabled": false,
"tcpHost": "192.168.127.2",
"tcpPort": "502",
"tcpType": "DEFAULT",
"serialPort": "/dev/ttyUSB",
"serialType": "RTU-BUFFERD",
"serialBaudrate": "9600",
"serialDatabits": "8",
"serialStopbits": "1",
"serialParity": "none",
"serialConnectionDelay": "100",
"serialAsciiResponseStartDelimiter": "",
"unit_id": "1",
"commandDelay": "1",
"clientTimeout": "1000",
"reconnectOnTimeout": true,
"reconnectTimeout": "2000",
"parallelUnitIdsAllowed": true
},
{
"id": "06fb380adab7a3ac",
"type": "modbus-client",
"name": "nodered_local_server",
"clienttype": "tcp",
"bufferCommands": true,
"stateLogEnabled": false,
"queueLogEnabled": false,
"failureLogEnabled": true,
"tcpHost": "127.0.0.1",
"tcpPort": "10502",
"tcpType": "DEFAULT",
"serialPort": "/dev/ttyUSB",
"serialType": "RTU-BUFFERD",
"serialBaudrate": "9600",
"serialDatabits": "8",
"serialStopbits": "1",
"serialParity": "none",
"serialConnectionDelay": "100",
"serialAsciiResponseStartDelimiter": "0x3A",
"unit_id": "1",
"commandDelay": "1",
"clientTimeout": "1000",
"reconnectOnTimeout": true,
"reconnectTimeout": "2000",
"parallelUnitIdsAllowed": true,
"showWarnings": true,
"showLogs": true
}
]
I tried doing something like that, but the server doesn't appear in the list of writable objects. I added a Modbus flex getter to the server's input, but that just gave us zeroes, so I had to revert in the end.
Some the weirdness my end was caused by Modbus broadcasting single-number arrays, rather than single numbers. Fixed with simple functions. Solution to that issue here
Issue still remains with byte-swapping on my colleague's end.
Solution: Turns out there was an error on my colleague's side, where his software was reading from addresses 4001
, where it should have been reading from address 1
as they were already denoted as holding registers to begin with and didn't need the 400
preamble.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.