UDP broadcast and response from a docker container

Im trying to perform a UDP broadcast to find a heatmiser neohub on the network.

My node red is running in a docker container on a device and has a port mapped to 50080.

This is the text from the heatmiser document

Finding neoHubs on the users local network has now become easier. UDP Broadcasting ‘hubseek’ on
port 19790 will prompt hubs to respond with their IP if they are available. This is all done over UDP
broadcast and so 3rd party systems would both need to be able to broadcast and listen for UDP on port
19790
Request example - echo -n "hubseek" | nc -b -u 255.255.255.255 19790
Response Example - {“ip”:”192.168.0.19”, “device_id”:” D8:80:39:AD:0D:F0”}

I want to perform this step if the connection to the neohub API fails, as the device is in DHCP mode only I cant rely on a fixed IP address.
Ive tried to send this command also from Windows Powershell but it didnt like the 'nc' in the command so not sure I really have a way to test.

This isnt my network so I thought I would attempt this before trying to liaise with the network management people.

Here is my flow that I have tried. I have attempted various versions of the commands but the UDP broadcast does seem to do anything ( I think maybe its not leaving the container ), and the exec command doesnt seem to error but also doesnt respond with the message Id like.

Any help appreciated, thanks

[
    {
        "id": "9035b297947e3291",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "ccaacc4978c32ba1",
        "type": "inject",
        "z": "9035b297947e3291",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 160,
        "y": 160,
        "wires": [
            [
                "3735b298d1b523b1"
            ]
        ]
    },
    {
        "id": "78f6245457b523fe",
        "type": "debug",
        "z": "9035b297947e3291",
        "name": "debug 125",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 690,
        "y": 240,
        "wires": []
    },
    {
        "id": "3aa5137fe3f12d4c",
        "type": "udp out",
        "z": "9035b297947e3291",
        "name": "",
        "addr": "255.255.255.55",
        "iface": "",
        "port": "19790",
        "ipv": "udp4",
        "outport": "",
        "base64": false,
        "multicast": "broad",
        "x": 680,
        "y": 160,
        "wires": []
    },
    {
        "id": "3735b298d1b523b1",
        "type": "function",
        "z": "9035b297947e3291",
        "name": "function 30",
        "func": "msg.payload = 'echo -n \"hubseek\" | nc -b -u'\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 370,
        "y": 160,
        "wires": [
            [
                "3aa5137fe3f12d4c"
            ]
        ]
    },
    {
        "id": "07800e0fedb557ed",
        "type": "udp in",
        "z": "9035b297947e3291",
        "name": "",
        "iface": "",
        "port": "19790",
        "ipv": "udp4",
        "multicast": "false",
        "group": "",
        "datatype": "buffer",
        "x": 240,
        "y": 240,
        "wires": [
            [
                "78f6245457b523fe"
            ]
        ]
    },
    {
        "id": "a229f82f969bc237",
        "type": "inject",
        "z": "9035b297947e3291",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 160,
        "y": 400,
        "wires": [
            [
                "2add065f1ab44994"
            ]
        ]
    },
    {
        "id": "2add065f1ab44994",
        "type": "exec",
        "z": "9035b297947e3291",
        "command": "echo -n \"hubseek\" | nc -b -u 255.255.255.255 19790",
        "addpay": "",
        "append": "",
        "useSpawn": "true",
        "timer": "30",
        "winHide": false,
        "oldrc": false,
        "name": "",
        "x": 500,
        "y": 400,
        "wires": [
            [
                "b69114f29e0a6018"
            ],
            [
                "d5b69c5bb741b7ff"
            ],
            [
                "b2b0339a58f670c7"
            ]
        ]
    },
    {
        "id": "b69114f29e0a6018",
        "type": "debug",
        "z": "9035b297947e3291",
        "name": "debug 126",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 870,
        "y": 360,
        "wires": []
    },
    {
        "id": "d5b69c5bb741b7ff",
        "type": "debug",
        "z": "9035b297947e3291",
        "name": "debug 127",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 870,
        "y": 400,
        "wires": []
    },
    {
        "id": "b2b0339a58f670c7",
        "type": "debug",
        "z": "9035b297947e3291",
        "name": "debug 128",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 870,
        "y": 440,
        "wires": []
    }
]

Have you opened the UDP port in your Docker config?

1 Like

No I didnt, its an existing container with only the one port mapped.

I will have a read through the details in the link. I was expecting it would be something like a port mapping.

Thanks

As an ex-network manager, let me warn you of the unpleasant side effects that will come your way if you make a mistake :slight_smile:

Its not a corporate network, Its a home network but for a very big expensive home with some network management. This UDP broadcast is only intended to ever occur if the API request to the IP address doesnt respond, then it will try to find the device to see if it has changed address.

I admit Im not used to UDP so hopefully the occasional broadcast wont be a bad thing??? Most UDP things in my works are built into the apps and programs so Im not doing anything manually, ie pressing a button to discover devices etc.

Apart from issues around security, UDP isn't hard to deal with and this requirement seems simple enough, you simply need to remember that a container is just that, it contains everything including network access. So to make something accessible outside the container, you need to configure it.

That is one of the reasons most of us recommend against using Docker for simple requirements. It can get confusing and easy to overlook an important detail.

In my case the only way to run node red on this device is within a preinstalled docker environment without additional hardware.

I can backup, recreate the container with the correct options, then restore the data and try again.

Why not use mDNS for this?

It's designed to announce and search out capability style information and does not need a DHCP server.

Drawback is that it will not cross network subnets or vlans without a repeater - this may be an issue in your case if the iot edge devices are separated from the server.

Ive never heard of it. Ill have a look, thanks

It goes under a fair number of names:

  • mDNS
  • ZeroConf
  • Bonjour
  • Avahi

You may also know it as that black box that handles the .local domain on Raspberry Pi boards (that's Avahi TBF) :grinning:

There is an old article (2016 but still valid in Bullseye IIRC) that shows how to configure a basic service at How to use Avahi to advertise an HTTP service that could be a good starting point for you.

Thing to remember about UDP - it's never guaranteed to reach the other end so you may need to build in a retry even if you are 100% the other end is present (grrrr)...

If you want retry's then use TCP. UDP is meant to be minimal.

The OP is trying to find a device where the IP address is not known and as TCP is a point to point protocol it needs to know the IP address of the far end so UDP is the only option I know off - it all depends how you dress it up and how much work you want to do to use it.

TBH - modern networks with decent switches do not really suffer packet loss unless you are really pushing packet bandwidth but better safe than sorry.