📡 Node-RED MQTT ノードガイド

📚 目次

📖 1. 概要

MQTT(Message Queuing Telemetry Transport)は、IoT向けの軽量メッセージングプロトコルです。センサーデータの収集や機器制御など、多数のデバイス間通信に最適化されています。

MQTTの特徴

📰 新聞配達に例えると:MQTTは「新聞配達システム」のようなものです。

📤 発行者(Publisher)
A新聞社
(一般1)
B新聞社
(経済)
C新聞社
(スポーツ)
D新聞社
(一般2)
▼ 新聞を届ける
🏪 仲介者(Broker)
📦 新聞配達店
各新聞社から届いた新聞を
購読者ごとに仕分けして配達
▼ 購読している新聞を届ける
📥 購読者(Subscriber)
🏠 田中家
A C
🏠 佐藤家
B D
🏠 鈴木家
A B
MQTTの概念新聞配達モデル具体例
Broker新聞配達店複数の新聞社から届いた新聞を仕分けして各家庭へ届ける
Publisher新聞社A新聞社、B新聞社、C新聞社...
Subscriber購読家庭田中家、佐藤家、鈴木家...
Topic新聞の銘柄A新聞、B新聞、C新聞、D新聞
Publish新聞を発行A新聞社が朝刊を配達店に届ける
Subscribe購読申込「うちはA新聞とC新聞をお願いします」

📥 MQTT In(Subscribe)

MQTT In

役割: トピックを購読してメッセージを受信

📤 MQTT Out(Publish)

MQTT Out

役割: トピックにメッセージを発行

⚙️ 2. MQTTブローカー設定

MQTTノードを使用するには、まずブローカー設定ノードを作成します。

公開MQTTブローカー(学習・テスト用)

🦟 test.mosquitto.org

Eclipse Mosquitto プロジェクト提供の公開ブローカー

Server: test.mosquitto.org / Port: 1883(非暗号化)

🐝 broker.hivemq.com

HiveMQ提供の公開ブローカー

Server: broker.hivemq.com / Port: 1883

📦 broker.emqx.io

EMQ X提供の公開ブローカー

Server: broker.emqx.io / Port: 1883

⚠️ 公開ブローカーの注意事項:

ブローカー設定のプロパティ

プロパティ説明
サーバブローカーのホスト名/IPtest.mosquitto.org
ポート接続ポート1883(非暗号化), 8883(TLS)
クライアントIDクライアント識別子(空欄で自動生成)nodered-client-001
Keep Alive接続維持間隔(秒)60
セッション初期化接続時にセッションをクリアtrue

認証設定(Security タブ)

プロパティ説明
ユーザ名認証ユーザー名
パスワード認証パスワード
TLS暗号化接続の設定

⚙️ 3. MQTT In / Out ノード

MQTT In ノード(購読)

プロパティ説明
サーバブローカー設定(設定ノード選択)
トピック購読するトピックsensors/+/temperature
QoSサービス品質0, 1, 2
出力出力形式auto, string, buffer, JSON

受信時の msg プロパティ:

プロパティ説明
msg.payload受信データ
msg.topicメッセージのトピック
msg.qosQoSレベル
msg.retainRetainフラグ

MQTT Out ノード(発行)

プロパティ説明
サーバブローカー設定(設定ノード選択)
トピック発行先トピック(空欄でmsg.topic使用)devices/lamp/control
QoSサービス品質0, 1, 2
保持メッセージを保持true/false

QoS(Quality of Service)レベル

QoS説明用途
0At most once(最大1回)センサーデータなど、多少のロスが許容できる場合
1At least once(最低1回)重要データ(重複の可能性あり)
2Exactly once(正確に1回)課金など、厳密な配信が必要な場合

🏷️ 4. トピックとワイルドカード

トピックの階層構造

MQTTのトピックは / で区切った階層構造で設計します:

📁 home
📁 livingroom
📄 temperature
📄 humidity
📄 light
📁 bedroom
📄 temperature
📄 humidity
// トピック例 home/livingroom/temperature → 25.5 home/livingroom/humidity → 60 home/bedroom/temperature → 22.0

ワイルドカード

ワイルドカード説明
+(シングルレベル) 1階層のみにマッチ home/+/temperature
→ home/livingroom/temperature ✓
→ home/bedroom/temperature ✓
#(マルチレベル) 以降の全階層にマッチ(末尾のみ) home/#
→ home/livingroom/temperature ✓
→ home/bedroom/humidity ✓

💡 トピック設計のベストプラクティス:

🔧 5. 実用的な使用パターン

📥 サンプルフローのインポート方法:

  1. 下のサンプルフローJSONをコピー
  2. Node-REDエディタで メニュー → 読み込み を選択
  3. JSONをペーストして「読み込み」をクリック

このサンプルフローには、以下で説明するパターンの実例が含まれています。

⚠️ 使用前の準備:

  1. サンプルフローをインポート
  2. MQTT In/Out ノードをダブルクリック
  3. Server の鉛筆アイコンをクリックしてブローカー設定を確認
  4. 必要に応じて Server を test.mosquitto.org に変更
  5. デプロイ

※ トピック名の nodered-guide 部分を自分専用の名前に変更することを推奨します

📥 サンプルフロー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": [] } ]

使用パターン

パターン1: 基本 Publish(発行)

サンプルフローの「基本: Publish(発行)」を参照してください。

メッセージ MQTT Out

ポイント:

パターン2: 基本 Subscribe(購読)

サンプルフローの「基本: Subscribe(購読)」を参照してください。

MQTT In メッセージ表示

ポイント:

パターン3: JSONデータの送受信

サンプルフローの「JSON データの送受信」を参照してください。

JSON生成 送信 受信 JSON確認

ポイント:

パターン4: デバイス制御(コマンド送受信)

サンプルフローの「デバイス制御(コマンド送受信)」を参照してください。

コマンド受信 ON/OFF分岐 デバイス制御

ポイント:

📝 6. 演習問題

演習1: メッセージの発行 初級

📋 課題: ボタンをクリックすると、MQTTブローカーに「Hello MQTT!」を発行するフローを作成してください。

🎯 要求仕様:

✅ 成功の条件:

💡 ヒント

Inject ノード: msg.payload に「Hello MQTT!」を設定

MQTT Out ノード:

  • Server: test.mosquitto.org(新規作成)
  • Topic: あなたの名前/test/hello
  • QoS: 1
✅ 解答例フロー
[ {"id": "ex1_tab", "type": "tab", "label": "演習1"}, {"id": "ex1_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": "ex1_inject", "type": "inject", "z": "ex1_tab", "name": "Hello送信", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "Hello MQTT!", "payloadType": "str", "x": 160, "y": 100, "wires": [["ex1_mqtt_out"]]}, {"id": "ex1_mqtt_out", "type": "mqtt out", "z": "ex1_tab", "name": "Publish", "topic": "yourname/test/hello", "qos": "1", "retain": "false", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "ex1_broker", "x": 350, "y": 100, "wires": []} ]

演習2: メッセージの購読 初級

📋 課題: 演習1で発行したメッセージを購読して、Debugノードに表示してください。

🎯 要求仕様:

✅ 成功の条件:

💡 ヒント

MQTT In ノード:

  • Server: 演習1と同じブローカー設定
  • Topic: 演習1と同じトピック
  • QoS: 1
  • Output: auto-detect
✅ 解答例フロー
[ {"id": "ex2_tab", "type": "tab", "label": "演習2"}, {"id": "ex2_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": "ex2_mqtt_in", "type": "mqtt in", "z": "ex2_tab", "name": "Subscribe", "topic": "yourname/test/hello", "qos": "1", "datatype": "auto", "broker": "ex2_broker", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 160, "y": 100, "wires": [["ex2_debug"]]}, {"id": "ex2_debug", "type": "debug", "z": "ex2_tab", "name": "受信メッセージ", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "msg", "x": 380, "y": 100, "wires": []} ]

演習3: ワイルドカードによる複数トピック購読 中級

📋 課題: ワイルドカードを使って複数のセンサートピックを一括購読し、トピックごとに異なる処理を行ってください。

🎯 要求仕様:

✅ 成功の条件:

💡 ヒント

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デバイスを作成してください。

🎯 要求仕様:

✅ 成功の条件:

💡 ヒント

定期発行: 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": []} ]

✅ 7. まとめ

🎯 重要ポイント:

⚠️ 注意事項:

🔧 8. トラブルシューティング

症状原因解決方法
接続できないブローカー設定の誤りServer、Port を確認、ファイアウォール確認
メッセージが届かないトピック名の不一致発行/購読のトピック名を正確に一致させる
接続が切れるKeep Alive タイムアウトKeep Alive 値を調整
重複メッセージQoS 1 の再送アプリケーション側で重複排除
古いメッセージが届くRetain メッセージ空のRetainメッセージを発行してクリア

🏭 9. 実務活用例

ケース1: 分散センサーネットワーク

複数のRaspberry Pi からセンサーデータをMQTTで収集し、中央のNode-REDで集約・可視化

ケース2: スマートホーム制御

照明、エアコン、ドアロックなどをMQTTでコントロール

ケース3: 工場IoT

製造機器の状態監視、予知保全のためのデータ収集

ケース4: 車両追跡システム

GPSデータをMQTTで送信し、リアルタイム位置追跡

📚 Node-RED 公式ドキュメント - MQTT

🏠