// トピック例
home/livingroom/temperature → 25.5
home/livingroom/humidity → 60
home/bedroom/temperature → 22.0
📥 サンプルフローJSON(クリックで展開)
[
{
"id": "mqtt_sample_tab",
"type": "tab",
"label": "MQTT サンプル",
"disabled": false,
"info": ""
},
{
"id": "mqtt_broker_public",
"type": "mqtt-broker",
"name": "Public Broker",
"broker": "test.mosquitto.org",
"port": "1883",
"tls": "",
"clientid": "",
"autoConnect": true,
"usetls": false,
"verifyservercert": false,
"compatmode": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"autoUnsubscribe": true,
"birthTopic": "",
"birthQos": "0",
"birthRetain": "false",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closeRetain": "false",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willRetain": "false",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": 0
},
{
"id": "mqtt_comment1",
"type": "comment",
"z": "mqtt_sample_tab",
"name": "━━━ 基本: Publish(発行) ━━━",
"info": "",
"x": 180,
"y": 40,
"wires": []
},
{
"id": "mqtt_inject_temp",
"type": "inject",
"z": "mqtt_sample_tab",
"name": "温度データ送信",
"props": [{"p": "payload"}, {"p": "topic", "vt": "str"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "nodered-guide/sensors/temperature",
"payload": "25.5",
"payloadType": "num",
"x": 180,
"y": 100,
"wires": [["mqtt_out_sensor"]]
},
{
"id": "mqtt_inject_humidity",
"type": "inject",
"z": "mqtt_sample_tab",
"name": "湿度データ送信",
"props": [{"p": "payload"}, {"p": "topic", "vt": "str"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "nodered-guide/sensors/humidity",
"payload": "60",
"payloadType": "num",
"x": 180,
"y": 140,
"wires": [["mqtt_out_sensor"]]
},
{
"id": "mqtt_out_sensor",
"type": "mqtt out",
"z": "mqtt_sample_tab",
"name": "Publish Sensor",
"topic": "",
"qos": "1",
"retain": "false",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "mqtt_broker_public",
"x": 420,
"y": 120,
"wires": []
},
{
"id": "mqtt_comment2",
"type": "comment",
"z": "mqtt_sample_tab",
"name": "━━━ 基本: Subscribe(購読) ━━━",
"info": "",
"x": 190,
"y": 220,
"wires": []
},
{
"id": "mqtt_in_sensors",
"type": "mqtt in",
"z": "mqtt_sample_tab",
"name": "Subscribe sensors/#",
"topic": "nodered-guide/sensors/#",
"qos": "1",
"datatype": "auto",
"broker": "mqtt_broker_public",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 190,
"y": 280,
"wires": [["mqtt_debug_sensors", "mqtt_func_format"]]
},
{
"id": "mqtt_debug_sensors",
"type": "debug",
"z": "mqtt_sample_tab",
"name": "受信データ",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "true",
"targetType": "full",
"statusVal": "topic",
"statusType": "msg",
"x": 430,
"y": 280,
"wires": []
},
{
"id": "mqtt_func_format",
"type": "function",
"z": "mqtt_sample_tab",
"name": "データ整形",
"func": "var parts = msg.topic.split('/');\nvar sensorType = parts[parts.length - 1];\n\nmsg.formatted = {\n sensor: sensorType,\n value: msg.payload,\n topic: msg.topic,\n timestamp: new Date().toISOString()\n};\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 430,
"y": 320,
"wires": [["mqtt_debug_formatted"]]
},
{
"id": "mqtt_debug_formatted",
"type": "debug",
"z": "mqtt_sample_tab",
"name": "整形データ",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "formatted",
"targetType": "msg",
"statusVal": "formatted.sensor",
"statusType": "msg",
"x": 610,
"y": 320,
"wires": []
},
{
"id": "mqtt_comment3",
"type": "comment",
"z": "mqtt_sample_tab",
"name": "━━━ JSON データの送受信 ━━━",
"info": "",
"x": 190,
"y": 400,
"wires": []
},
{
"id": "mqtt_inject_json",
"type": "inject",
"z": "mqtt_sample_tab",
"name": "JSONデータ送信",
"props": [{"p": "payload"}, {"p": "topic", "vt": "str"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "nodered-guide/device/status",
"payload": "{\"device\":\"sensor-001\",\"temperature\":25.5,\"humidity\":60,\"battery\":85}",
"payloadType": "json",
"x": 180,
"y": 460,
"wires": [["mqtt_func_stringify"]]
},
{
"id": "mqtt_func_stringify",
"type": "function",
"z": "mqtt_sample_tab",
"name": "JSON文字列化",
"func": "msg.payload = JSON.stringify(msg.payload);\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 400,
"y": 460,
"wires": [["mqtt_out_json"]]
},
{
"id": "mqtt_out_json",
"type": "mqtt out",
"z": "mqtt_sample_tab",
"name": "Publish JSON",
"topic": "",
"qos": "1",
"retain": "false",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "mqtt_broker_public",
"x": 590,
"y": 460,
"wires": []
},
{
"id": "mqtt_in_json",
"type": "mqtt in",
"z": "mqtt_sample_tab",
"name": "Subscribe device/#",
"topic": "nodered-guide/device/#",
"qos": "1",
"datatype": "json",
"broker": "mqtt_broker_public",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 190,
"y": 520,
"wires": [["mqtt_debug_json"]]
},
{
"id": "mqtt_debug_json",
"type": "debug",
"z": "mqtt_sample_tab",
"name": "JSON受信",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "payload.device",
"statusType": "msg",
"x": 420,
"y": 520,
"wires": []
},
{
"id": "mqtt_comment4",
"type": "comment",
"z": "mqtt_sample_tab",
"name": "━━━ デバイス制御(コマンド送受信) ━━━",
"info": "",
"x": 210,
"y": 600,
"wires": []
},
{
"id": "mqtt_inject_on",
"type": "inject",
"z": "mqtt_sample_tab",
"name": "LED ON",
"props": [{"p": "payload"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "ON",
"payloadType": "str",
"x": 150,
"y": 660,
"wires": [["mqtt_out_control"]]
},
{
"id": "mqtt_inject_off",
"type": "inject",
"z": "mqtt_sample_tab",
"name": "LED OFF",
"props": [{"p": "payload"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "OFF",
"payloadType": "str",
"x": 150,
"y": 700,
"wires": [["mqtt_out_control"]]
},
{
"id": "mqtt_out_control",
"type": "mqtt out",
"z": "mqtt_sample_tab",
"name": "Publish Control",
"topic": "nodered-guide/control/led",
"qos": "1",
"retain": "true",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "mqtt_broker_public",
"x": 360,
"y": 680,
"wires": []
},
{
"id": "mqtt_in_control",
"type": "mqtt in",
"z": "mqtt_sample_tab",
"name": "Subscribe control/#",
"topic": "nodered-guide/control/#",
"qos": "1",
"datatype": "utf8",
"broker": "mqtt_broker_public",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 190,
"y": 760,
"wires": [["mqtt_switch_control"]]
},
{
"id": "mqtt_switch_control",
"type": "switch",
"z": "mqtt_sample_tab",
"name": "ON/OFF判定",
"property": "payload",
"propertyType": "msg",
"rules": [
{"t": "eq", "v": "ON", "vt": "str"},
{"t": "eq", "v": "OFF", "vt": "str"}
],
"checkall": "false",
"repair": false,
"outputs": 2,
"x": 410,
"y": 760,
"wires": [["mqtt_debug_on"], ["mqtt_debug_off"]]
},
{
"id": "mqtt_debug_on",
"type": "debug",
"z": "mqtt_sample_tab",
"name": "LED ON!",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "\"💡 ON\"",
"statusType": "str",
"x": 580,
"y": 740,
"wires": []
},
{
"id": "mqtt_debug_off",
"type": "debug",
"z": "mqtt_sample_tab",
"name": "LED OFF!",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "\"⚫ OFF\"",
"statusType": "str",
"x": 580,
"y": 780,
"wires": []
}
]
演習3: ワイルドカードによる複数トピック購読 中級
📋 課題: ワイルドカードを使って複数のセンサートピックを一括購読し、トピックごとに異なる処理を行ってください。
🎯 要求仕様:
- 発行トピック:
yourname/sensors/temperature, yourname/sensors/humidity
- 購読トピック:
yourname/sensors/+(ワイルドカード使用)
- トピックから「temperature」か「humidity」かを判定
✅ 成功の条件:
- 「温度送信」ボタンを押すと「温度データ」デバッグノードにのみ値が表示される
- 「湿度送信」ボタンを押すと「湿度データ」デバッグノードにのみ値が表示される
- どちらのトピックも1つの MQTT In ノード(ワイルドカード購読)で受信される
💡 ヒント
Switch ノード:
- プロパティ: msg.topic
- 条件1: contains "temperature"
- 条件2: contains "humidity"
✅ 解答例フロー
[
{"id": "ex3_tab", "type": "tab", "label": "演習3"},
{"id": "ex3_broker", "type": "mqtt-broker", "name": "Public Broker", "broker": "test.mosquitto.org", "port": "1883", "tls": "", "clientid": "", "autoConnect": true, "usetls": false, "verifyservercert": false, "compatmode": false, "protocolVersion": "4", "keepalive": "60", "cleansession": true, "autoUnsubscribe": true, "birthTopic": "", "birthQos": "0", "birthRetain": "false", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closeRetain": "false", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willRetain": "false", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": 0},
{"id": "ex3_inject_temp", "type": "inject", "z": "ex3_tab", "name": "温度送信", "props": [{"p": "payload"}, {"p": "topic", "vt": "str"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "yourname/sensors/temperature", "payload": "25.5", "payloadType": "num", "x": 160, "y": 80, "wires": [["ex3_mqtt_out"]]},
{"id": "ex3_inject_humidity", "type": "inject", "z": "ex3_tab", "name": "湿度送信", "props": [{"p": "payload"}, {"p": "topic", "vt": "str"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "yourname/sensors/humidity", "payload": "60", "payloadType": "num", "x": 160, "y": 120, "wires": [["ex3_mqtt_out"]]},
{"id": "ex3_mqtt_out", "type": "mqtt out", "z": "ex3_tab", "name": "Publish", "topic": "", "qos": "1", "retain": "false", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "ex3_broker", "x": 350, "y": 100, "wires": []},
{"id": "ex3_mqtt_in", "type": "mqtt in", "z": "ex3_tab", "name": "Subscribe +", "topic": "yourname/sensors/+", "qos": "1", "datatype": "auto", "broker": "ex3_broker", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 170, "y": 200, "wires": [["ex3_switch"]]},
{"id": "ex3_switch", "type": "switch", "z": "ex3_tab", "name": "トピック分岐", "property": "topic", "propertyType": "msg", "rules": [{"t": "cont", "v": "temperature", "vt": "str"}, {"t": "cont", "v": "humidity", "vt": "str"}], "checkall": "false", "repair": false, "outputs": 2, "x": 370, "y": 200, "wires": [["ex3_debug_temp"], ["ex3_debug_humidity"]]},
{"id": "ex3_debug_temp", "type": "debug", "z": "ex3_tab", "name": "温度データ", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "\"🌡️\"", "statusType": "str", "x": 570, "y": 180, "wires": []},
{"id": "ex3_debug_humidity", "type": "debug", "z": "ex3_tab", "name": "湿度データ", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "\"💧\"", "statusType": "str", "x": 570, "y": 220, "wires": []}
]
演習4: IoTデバイスシミュレーション 上級
📋 課題: 定期的にセンサーデータを発行し、制御コマンドを受け付ける仮想IoTデバイスを作成してください。
🎯 要求仕様:
- 発行: 10秒ごとにランダムな温度・湿度を発行
- トピック:
yourname/device001/telemetry
- 購読: 制御コマンド(ON/OFF)を受信
- トピック:
yourname/device001/command
✅ 成功の条件:
- デプロイ後、10秒ごとにデバッグパネルに温度・湿度データが自動表示される
- 送信データに
deviceId, temperature, humidity, timestamp が含まれている
- MQTTクライアントから
yourname/device001/command に「ON」や「OFF」を発行するとデバッグパネルに受信内容が表示される
💡 ヒント
定期発行: Inject ノードの repeat を 10 秒に設定
ランダム値:
var temp = 20 + Math.random() * 10;
var humidity = 40 + Math.random() * 40;
msg.payload = JSON.stringify({temperature: temp.toFixed(1), humidity: Math.floor(humidity)});
return msg;
✅ 解答例フロー
[
{"id": "ex4_tab", "type": "tab", "label": "演習4"},
{"id": "ex4_broker", "type": "mqtt-broker", "name": "Public Broker", "broker": "test.mosquitto.org", "port": "1883", "tls": "", "clientid": "", "autoConnect": true, "usetls": false, "verifyservercert": false, "compatmode": false, "protocolVersion": "4", "keepalive": "60", "cleansession": true, "autoUnsubscribe": true, "birthTopic": "", "birthQos": "0", "birthRetain": "false", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closeRetain": "false", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willRetain": "false", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": 0},
{"id": "ex4_inject", "type": "inject", "z": "ex4_tab", "name": "10秒ごと", "props": [{"p": "payload"}], "repeat": "10", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 160, "y": 100, "wires": [["ex4_func_sensor"]]},
{"id": "ex4_func_sensor", "type": "function", "z": "ex4_tab", "name": "センサー値生成", "func": "var temp = 20 + Math.random() * 10;\nvar humidity = 40 + Math.random() * 40;\nmsg.payload = JSON.stringify({deviceId: \"device001\", temperature: parseFloat(temp.toFixed(1)), humidity: Math.floor(humidity), timestamp: new Date().toISOString()});\nmsg.topic = \"yourname/device001/telemetry\";\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 370, "y": 100, "wires": [["ex4_mqtt_out", "ex4_debug_send"]]},
{"id": "ex4_mqtt_out", "type": "mqtt out", "z": "ex4_tab", "name": "Publish Telemetry", "topic": "", "qos": "1", "retain": "false", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "ex4_broker", "x": 590, "y": 100, "wires": []},
{"id": "ex4_debug_send", "type": "debug", "z": "ex4_tab", "name": "送信データ", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "\"送信\"", "statusType": "str", "x": 570, "y": 140, "wires": []},
{"id": "ex4_mqtt_in", "type": "mqtt in", "z": "ex4_tab", "name": "Subscribe Command", "topic": "yourname/device001/command", "qos": "1", "datatype": "utf8", "broker": "ex4_broker", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 190, "y": 220, "wires": [["ex4_debug_cmd"]]},
{"id": "ex4_debug_cmd", "type": "debug", "z": "ex4_tab", "name": "コマンド受信", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "msg", "x": 430, "y": 220, "wires": []}
]