// 限定ブロードキャスト(同一サブネット内)
192.168.1.255 ← サブネット 192.168.1.0/24 の場合
// ローカルブロードキャスト
255.255.255.255
📥 サンプルフローJSON(クリックで展開)
[
{
"id": "udp_sample_tab",
"type": "tab",
"label": "UDP サンプル",
"disabled": false,
"info": ""
},
{
"id": "udp_comment1",
"type": "comment",
"z": "udp_sample_tab",
"name": "━━━ 基本: UDP受信 ━━━",
"info": "ポート8000でUDPパケットを受信",
"x": 170,
"y": 40,
"wires": []
},
{
"id": "udp_in_basic",
"type": "udp in",
"z": "udp_sample_tab",
"name": "UDP In :8000",
"iface": "",
"port": "8000",
"ipv": "udp4",
"multicast": "false",
"group": "",
"datatype": "utf8",
"x": 170,
"y": 100,
"wires": [["udp_debug_received", "udp_func_info"]]
},
{
"id": "udp_debug_received",
"type": "debug",
"z": "udp_sample_tab",
"name": "受信データ",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "ip",
"statusType": "msg",
"x": 390,
"y": 100,
"wires": []
},
{
"id": "udp_func_info",
"type": "function",
"z": "udp_sample_tab",
"name": "送信元情報",
"func": "msg.senderInfo = {\n ip: msg.ip,\n port: msg.port,\n data: msg.payload,\n timestamp: new Date().toISOString()\n};\nnode.status({fill: \"green\", shape: \"dot\", text: msg.ip + \":\" + msg.port});\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 390,
"y": 140,
"wires": [["udp_debug_info"]]
},
{
"id": "udp_debug_info",
"type": "debug",
"z": "udp_sample_tab",
"name": "送信元情報",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "senderInfo",
"targetType": "msg",
"x": 590,
"y": 140,
"wires": []
},
{
"id": "udp_comment2",
"type": "comment",
"z": "udp_sample_tab",
"name": "━━━ 基本: UDP送信(ユニキャスト) ━━━",
"info": "",
"x": 210,
"y": 220,
"wires": []
},
{
"id": "udp_inject_unicast",
"type": "inject",
"z": "udp_sample_tab",
"name": "ユニキャスト送信",
"props": [{"p": "payload"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "Hello UDP!",
"payloadType": "str",
"x": 180,
"y": 280,
"wires": [["udp_out_unicast"]]
},
{
"id": "udp_out_unicast",
"type": "udp out",
"z": "udp_sample_tab",
"name": "UDP Out (localhost:8000)",
"addr": "localhost",
"iface": "",
"port": "8000",
"ipv": "udp4",
"outport": "",
"base64": false,
"multicast": "false",
"x": 440,
"y": 280,
"wires": []
},
{
"id": "udp_comment3",
"type": "comment",
"z": "udp_sample_tab",
"name": "━━━ ブロードキャスト送信 ━━━",
"info": "同一サブネット内の全デバイスに送信",
"x": 190,
"y": 360,
"wires": []
},
{
"id": "udp_inject_broadcast",
"type": "inject",
"z": "udp_sample_tab",
"name": "ブロードキャスト送信",
"props": [{"p": "payload"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "BROADCAST: Hello everyone!",
"payloadType": "str",
"x": 190,
"y": 420,
"wires": [["udp_out_broadcast"]]
},
{
"id": "udp_out_broadcast",
"type": "udp out",
"z": "udp_sample_tab",
"name": "UDP Broadcast",
"addr": "255.255.255.255",
"iface": "",
"port": "8000",
"ipv": "udp4",
"outport": "",
"base64": false,
"multicast": "broadcast",
"x": 440,
"y": 420,
"wires": []
},
{
"id": "udp_comment4",
"type": "comment",
"z": "udp_sample_tab",
"name": "━━━ JSON データの送受信 ━━━",
"info": "",
"x": 190,
"y": 500,
"wires": []
},
{
"id": "udp_in_json",
"type": "udp in",
"z": "udp_sample_tab",
"name": "UDP In :8001 (JSON)",
"iface": "",
"port": "8001",
"ipv": "udp4",
"multicast": "false",
"group": "",
"datatype": "utf8",
"x": 190,
"y": 560,
"wires": [["udp_func_json_parse"]]
},
{
"id": "udp_func_json_parse",
"type": "function",
"z": "udp_sample_tab",
"name": "JSONパース",
"func": "try {\n msg.data = JSON.parse(msg.payload);\n msg.data.receivedAt = new Date().toISOString();\n msg.data.from = msg.ip;\n node.status({fill: \"green\", shape: \"dot\", text: \"JSON OK\"});\n} catch(e) {\n msg.data = {error: \"Invalid JSON\", raw: msg.payload};\n node.status({fill: \"red\", shape: \"ring\", text: \"JSON Error\"});\n}\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 430,
"y": 560,
"wires": [["udp_debug_json"]]
},
{
"id": "udp_debug_json",
"type": "debug",
"z": "udp_sample_tab",
"name": "JSON データ",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "data",
"targetType": "msg",
"x": 610,
"y": 560,
"wires": []
},
{
"id": "udp_inject_json",
"type": "inject",
"z": "udp_sample_tab",
"name": "JSON送信",
"props": [{"p": "payload"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "{\"sensor\":\"temp\",\"value\":25.5,\"unit\":\"C\"}",
"payloadType": "str",
"x": 170,
"y": 620,
"wires": [["udp_out_json"]]
},
{
"id": "udp_out_json",
"type": "udp out",
"z": "udp_sample_tab",
"name": "UDP Out :8001",
"addr": "localhost",
"iface": "",
"port": "8001",
"ipv": "udp4",
"outport": "",
"base64": false,
"multicast": "false",
"x": 400,
"y": 620,
"wires": []
},
{
"id": "udp_comment5",
"type": "comment",
"z": "udp_sample_tab",
"name": "━━━ 受信元への返信(エコー) ━━━",
"info": "msg.ip と msg.port を使って返信",
"x": 200,
"y": 700,
"wires": []
},
{
"id": "udp_in_echo",
"type": "udp in",
"z": "udp_sample_tab",
"name": "UDP In :8002",
"iface": "",
"port": "8002",
"ipv": "udp4",
"multicast": "false",
"group": "",
"datatype": "utf8",
"x": 170,
"y": 760,
"wires": [["udp_func_echo"]]
},
{
"id": "udp_func_echo",
"type": "function",
"z": "udp_sample_tab",
"name": "エコー処理",
"func": "// 送信元情報を保持(返信用)\nvar replyTo = {\n ip: msg.ip,\n port: msg.port\n};\n\n// エコー応答を作成\nmsg.payload = \"[ECHO] \" + msg.payload;\n\n// 返信先を設定\nmsg.ip = replyTo.ip;\nmsg.port = replyTo.port;\n\nnode.status({fill: \"blue\", shape: \"dot\", text: \"Reply to \" + replyTo.ip});\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 390,
"y": 760,
"wires": [["udp_out_echo", "udp_debug_echo"]]
},
{
"id": "udp_out_echo",
"type": "udp out",
"z": "udp_sample_tab",
"name": "UDP Reply (msg.ip/port)",
"addr": "",
"iface": "",
"port": "",
"ipv": "udp4",
"outport": "",
"base64": false,
"multicast": "false",
"x": 620,
"y": 760,
"wires": []
},
{
"id": "udp_debug_echo",
"type": "debug",
"z": "udp_sample_tab",
"name": "エコー送信",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "ip",
"statusType": "msg",
"x": 590,
"y": 800,
"wires": []
},
{
"id": "udp_comment6",
"type": "comment",
"z": "udp_sample_tab",
"name": "━━━ 定期的なセンサーデータ送信 ━━━",
"info": "",
"x": 210,
"y": 880,
"wires": []
},
{
"id": "udp_inject_periodic",
"type": "inject",
"z": "udp_sample_tab",
"name": "3秒ごと",
"props": [{"p": "payload"}],
"repeat": "3",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 160,
"y": 940,
"wires": [["udp_func_sensor"]]
},
{
"id": "udp_func_sensor",
"type": "function",
"z": "udp_sample_tab",
"name": "センサーデータ生成",
"func": "var temp = (20 + Math.random() * 10).toFixed(1);\nvar humidity = Math.floor(40 + Math.random() * 40);\n\nmsg.payload = JSON.stringify({\n deviceId: \"sensor-001\",\n temperature: parseFloat(temp),\n humidity: humidity,\n timestamp: new Date().toISOString()\n});\n\nnode.status({fill: \"green\", shape: \"dot\", text: temp + \"°C\"});\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 380,
"y": 940,
"wires": [["udp_out_sensor", "udp_debug_sensor"]]
},
{
"id": "udp_out_sensor",
"type": "udp out",
"z": "udp_sample_tab",
"name": "UDP Broadcast :8003",
"addr": "255.255.255.255",
"iface": "",
"port": "8003",
"ipv": "udp4",
"outport": "",
"base64": false,
"multicast": "broadcast",
"x": 620,
"y": 940,
"wires": []
},
{
"id": "udp_debug_sensor",
"type": "debug",
"z": "udp_sample_tab",
"name": "送信データ",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "\"送信\"",
"statusType": "str",
"x": 590,
"y": 980,
"wires": []
}
]
演習4: ブロードキャストによるデバイス発見 上級
📋 課題: 「DISCOVER」ブロードキャストを送信し、応答したデバイスを一覧表示するシステムを作成してください。
🎯 要求仕様:
- 発見側: ポート9003にブロードキャスト「DISCOVER」を送信
- デバイス側: 「DISCOVER」受信時に自デバイス情報を返信
- 発見側: 応答を収集して一覧表示
✅ 成功の条件:
- 「DISCOVER送信」ボタンを押すと自デバイスからの応答がデバッグパネルに表示される
- 受信した応答メッセージに
deviceId やデバイス情報が含まれている
- 「DISCOVER」メッセージは Switch ノードで振り分けられ、応答メッセージは発見リストに蓄積される
- ボタンを押すたびに発見リストがリセットされ、再収集が行われる
💡 ヒント
「発見側」と「デバイス側」両方の機能を同一フローに実装します。
デバイス側: 受信データが「DISCOVER」なら自デバイス情報を返信
発見側: 応答(DISCOVER以外)を収集してリスト化
✅ 解答例フロー
[
{"id": "ex4_tab", "type": "tab", "label": "演習4"},
{"id": "ex4_comment1", "type": "comment", "z": "ex4_tab", "name": "【発見リクエスト送信】", "info": "", "x": 170, "y": 40, "wires": []},
{"id": "ex4_inject_discover", "type": "inject", "z": "ex4_tab", "name": "DISCOVER送信", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "DISCOVER", "payloadType": "str", "x": 180, "y": 100, "wires": [["ex4_func_clear", "ex4_udp_broadcast"]]},
{"id": "ex4_func_clear", "type": "function", "z": "ex4_tab", "name": "リストクリア", "func": "flow.set('discoveredDevices', {});\nreturn null;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 390, "y": 100, "wires": [[]]},
{"id": "ex4_udp_broadcast", "type": "udp out", "z": "ex4_tab", "name": "Broadcast :9003", "addr": "255.255.255.255", "iface": "", "port": "9003", "ipv": "udp4", "outport": "", "base64": false, "multicast": "broadcast", "x": 400, "y": 140, "wires": []},
{"id": "ex4_comment2", "type": "comment", "z": "ex4_tab", "name": "【デバイス側(応答)】", "info": "", "x": 160, "y": 200, "wires": []},
{"id": "ex4_udp_in", "type": "udp in", "z": "ex4_tab", "name": "UDP In :9003", "iface": "", "port": "9003", "ipv": "udp4", "multicast": "false", "group": "", "datatype": "utf8", "x": 170, "y": 260, "wires": [["ex4_switch"]]},
{"id": "ex4_switch", "type": "switch", "z": "ex4_tab", "name": "DISCOVER判定", "property": "payload", "propertyType": "msg", "rules": [{"t": "eq", "v": "DISCOVER", "vt": "str"}, {"t": "else"}], "checkall": "false", "repair": false, "outputs": 2, "x": 380, "y": 260, "wires": [["ex4_func_response"], ["ex4_func_collect"]]},
{"id": "ex4_func_response", "type": "function", "z": "ex4_tab", "name": "デバイス情報返信", "func": "// デバイス情報を作成\nvar deviceInfo = JSON.stringify({\n type: \"DEVICE_INFO\",\n deviceId: \"my-device-\" + Math.floor(Math.random() * 1000),\n name: \"Node-RED Device\",\n timestamp: new Date().toISOString()\n});\n\nmsg.payload = deviceInfo;\n// msg.ip と msg.port は保持されている\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 620, "y": 240, "wires": [["ex4_udp_reply"]]},
{"id": "ex4_udp_reply", "type": "udp out", "z": "ex4_tab", "name": "Reply", "addr": "", "iface": "", "port": "", "ipv": "udp4", "outport": "", "base64": false, "multicast": "false", "x": 810, "y": 240, "wires": []},
{"id": "ex4_func_collect", "type": "function", "z": "ex4_tab", "name": "応答収集", "func": "try {\n var data = JSON.parse(msg.payload);\n if (data.type === \"DEVICE_INFO\") {\n var devices = flow.get('discoveredDevices') || {};\n devices[data.deviceId] = {\n name: data.name,\n ip: msg.ip,\n timestamp: data.timestamp\n };\n flow.set('discoveredDevices', devices);\n msg.devices = devices;\n node.status({fill: \"green\", shape: \"dot\", text: Object.keys(devices).length + \" found\"});\n return msg;\n }\n} catch(e) {}\nreturn null;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 600, "y": 280, "wires": [["ex4_debug"]]},
{"id": "ex4_debug", "type": "debug", "z": "ex4_tab", "name": "発見デバイス", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "devices", "targetType": "msg", "x": 790, "y": 280, "wires": []}
]