Modbus Alive Unit Scanner

I am attempting to write a flow that reads from all possible Modbus UnitIds (1 - 254) on a single RS485 network to check to see if the slave is online.

If the unit is online (responds to the read request) I will add it as a property of a flow-scoped object.

After scanning, the units that respond will all be contained in the flow wide object and only those unitids will be polled regularly in the future for other values.

I have been successful in writing this using a flow-scoped counter variable and increment the counter when either a unit responds (message is passed from the modbus-flex-getter node into a function node) or the request hits the timeout limit (indicated by a status node passing a message to a separate function node which updates the global count when msg.status.text === "timeout").

However,
The challenge that I have been presented with is: this is a very slow process as I must wait about 1 second between each request to be sure it completes (which may only take ~20ms) or timeout (which may take 300ms to timeout and reconnect to the port upon timeout).

My Plan to Improve this:
Treat each Modbus Read read request as if its something like a network call. Instead of timing out to wait some arbitrary amount of time for the whole read to complete or to timeout I want to use a callback function to let the original function node know when to fire off the next unitid request.

This isn't difficult if the request hits a unitid that is on the network... because the modbus flex getter node will pass a message to a function block and that function block can handle the callback as it is interacting with the original msg object that was passed to the modbus flex getter node.
When a modbus request hits a timeout, however, it creates a new message when the status node is invoked which does not have the msg.callback that was created in the original function node that made the request. I am looking for a way to deal with this so that when the status node tells me that a request has timed out I can let the callback know that the original function node may fire off the next request.

Here is a flow that works asynchronously with live units but breaks when the timeout is hit:

[
    {
        "id": "83baa70e.e903d8",
        "type": "tab",
        "label": "Flow 4",
        "disabled": false,
        "info": ""
    },
    {
        "id": "5117a231.9bda0c",
        "type": "function",
        "z": "83baa70e.e903d8",
        "name": "run callback",
        "func": "msg.callback(msg.payload);",
        "outputs": "0",
        "noerr": 0,
        "x": 650,
        "y": 140,
        "wires": []
    },
    {
        "id": "759653a.244dcac",
        "type": "inject",
        "z": "83baa70e.e903d8",
        "name": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "",
        "once": true,
        "x": 90,
        "y": 140,
        "wires": [
            [
                "5d0de017.290a9"
            ]
        ]
    },
    {
        "id": "5d0de017.290a9",
        "type": "function",
        "z": "83baa70e.e903d8",
        "name": "set readModbus",
        "func": "var readModbus = function(unitid, address, quantity, callback) {\n    fc = 3;\n    unitid = unitid || 1;\n    address = address || 0;\n    quantity = quantity || 1;\n    \n    \n    // modbus request\n    msg= {payload:{fc, unitid, address, quantity}};\n    \n    // assign callback to msg\n    msg.callback = callback;\n    \n    // return copy of msg\n    node.send(Object.assign({}, msg));\n};\n\n\n// make global\nglobal.set('readModbus', readModbus);",
        "outputs": 1,
        "noerr": 0,
        "x": 260,
        "y": 140,
        "wires": [
            [
                "9202417e.dbc51"
            ]
        ]
    },
    {
        "id": "dbe64ea3.f3e2e",
        "type": "inject",
        "z": "83baa70e.e903d8",
        "name": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "0.5",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "x": 90,
        "y": 200,
        "wires": [
            [
                "866b7315.7bfe6"
            ]
        ]
    },
    {
        "id": "866b7315.7bfe6",
        "type": "function",
        "z": "83baa70e.e903d8",
        "name": "run readModbus(unitid, address, quantity, callback)",
        "func": "global.get('readModbus')(95, 26, 2, function (mbresponse) {\n    msg.payload = mbresponse;\n    node.send(msg);\n});",
        "outputs": 1,
        "noerr": 0,
        "x": 370,
        "y": 200,
        "wires": [
            [
                "c54cf931.be87c8"
            ]
        ]
    },
    {
        "id": "c54cf931.be87c8",
        "type": "debug",
        "z": "83baa70e.e903d8",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "false",
        "x": 670,
        "y": 200,
        "wires": []
    },
    {
        "id": "9202417e.dbc51",
        "type": "modbus-flex-getter",
        "z": "83baa70e.e903d8",
        "name": "",
        "showStatusActivities": false,
        "showErrors": false,
        "logIOActivities": false,
        "server": "4e882045.79912",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "x": 450,
        "y": 140,
        "wires": [
            [
                "5117a231.9bda0c"
            ],
            []
        ]
    },
    {
        "id": "9a8025fd.e44728",
        "type": "modbus-queue-info",
        "z": "83baa70e.e903d8",
        "name": "",
        "topic": "",
        "unitid": "",
        "queueReadIntervalTime": "500",
        "lowLowLevel": 25,
        "lowLevel": 75,
        "highLevel": 150,
        "highHighLevel": 300,
        "server": "4e882045.79912",
        "errorOnHighLevel": true,
        "x": 450,
        "y": 80,
        "wires": [
            []
        ]
    },
    {
        "id": "4e882045.79912",
        "type": "modbus-client",
        "z": "",
        "name": "",
        "clienttype": "serial",
        "bufferCommands": true,
        "stateLogEnabled": false,
        "tcpHost": "127.0.0.1",
        "tcpPort": "502",
        "tcpType": "DEFAULT",
        "serialPort": "/dev/ttyM0",
        "serialType": "RTU-BUFFERD",
        "serialBaudrate": "115200",
        "serialDatabits": "8",
        "serialStopbits": "1",
        "serialParity": "none",
        "serialConnectionDelay": "1000",
        "unit_id": "1",
        "commandDelay": "50",
        "clientTimeout": "100",
        "reconnectOnTimeout": true,
        "reconnectTimeout": "200",
        "parallelUnitIdsAllowed": true
    }
]

Any suggestions would be greatly appreciated!

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.