ESP32フィールド観測システム(温度・湿度・PIR・RSSI)
完全仕様書(コピペ再現版)
作成日: 2026-01-05
1. システム概要
本書は、ESP32(WROOM/DevKit系 または ESP32-C3)複数台をフィールドに設置し、DHT11(温度・湿度)とPIR(人感)を計測して、WiFi経由でRaspberry Pi 5のMosquitto(MQTT)へ送信、Node-RED Dashboard(/ui)でグラフ表示し、外付けSSDへCSV保存するシステムの「完全再現」手順です。
初心者が、手順どおりに環境を作り、コードをカット&ペーストして同じシステムを再現できるよう、配線・設定・コード・Node-REDフローJSONをすべて含めます。
2. 構成(全体アーキテクチャ)
データの流れ:センサー(DHT11/PIR)→ ESP32(WiFi)→ MQTT(Mosquitto)→ Node-RED → Dashboard(/ui)+ CSV保存(SSD)
トピック設計:
・sensors/<NODE>/dht11 : {node,temp,hum,pir,rssi}
・sensors/<NODE>/pir : {node,pir,rssi}(変化時のみ)
NODEは field01 / field02 / field03 を想定します。複数台運用では NODE 名だけを変えて同じスケッチを書き込みます。
3. 必要機材
フィールド側(各ノード=1台あたり):ESP32(WROOM/DevKit系 または ESP32-C3)、DHT11、PIR、ジャンパ線、電源。
サーバ側:Raspberry Pi 5、Mosquitto、Node-RED(Dashboard)、外付けSSD(例:/media/PI_SHARE_500G)。
4. 配線(ESP32側)
本書では以下のGPIOを使用します(あなたの既存構成に合わせています)。
・DHT11 DATA → GPIO4
・PIR OUT → GPIO2
VCC/GNDは各モジュール仕様に従い、ESP32のGNDは必ず共通にします。
5. 事前準備(Raspberry Pi:Mosquitto / Node-RED / SSD)
5.1 MQTT動作確認(例)
mosquitto_sub -h localhost -t “sensors/#” -v
5.2 SSD保存先フォルダの準備(例)
sudo mkdir -p /media/PI_SHARE_500G/sensor_logs
sudo chown -R $USER:$USER /media/PI_SHARE_500G/sensor_logs
6. Arduino IDE 設定(Windows 11)
6.1 ボードマネージャ:ESP32 by Espressif Systems をインストール
6.2 ライブラリ:PubSubClient、DHT sensor library(Adafruit)
6.3 ボード選択:WROOM/DevKitは該当するESP32 DevKit、C3はXIAO ESP32C3等(S3と混同しない)
7. ESP32 スケッチ(WiFi + MQTT:WROOM/DevKit用)
/*
===== フィールド観測ノード(WiFi + MQTT)安定版 =====
– DHT11(温度・湿度)と PIR(人感)を読み取り、MQTTで送信します。
– RSSI(WiFi受信感度, dBm)も同時に送ります。0 に近いほど強い(例:-50は強い、-90は弱い)。
– 送信先トピック:
sensors/<NODE>/dht11 : {node,temp,hum,pir,rssi}
sensors/<NODE>/pir : {node,pir,rssi}(変化時のみ)
– 複数台運用:NODE 名だけ field01/02/03 に変えて焼きます。
/*
===== フィールド観測ノード(WiFi + MQTT)=====
*/
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
// --- 配線(GPIO番号で指定)---
#define DHTPIN 4
#define PIRPIN 2
#define DHTTYPE DHT11
// --- このノードの名前(field01/02/03 など)---
const char* NODE = "field01";
// --- WiFi ---
const char* WIFI_SSID = "YOUR_WIFI_SSID";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
// --- MQTT(あなたのRasPi)---
const char* MQTT_HOST = "192.168.50.150";
const int MQTT_PORT = 1883;
WiFiClient espClient;
PubSubClient mqtt(espClient);
DHT dht(DHTPIN, DHTTYPE);
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
Serial.print("WiFi connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("WiFi connected. IP=");
Serial.println(WiFi.localIP());
}
void connectMQTT() {
while (!mqtt.connected()) {
// ★clientIDを一意に(事故防止)
String clientId = String(NODE) + "-" + String((uint32_t)ESP.getEfuseMac(), HEX);
Serial.print("MQTT connecting as ");
Serial.print(clientId);
Serial.print(" ... ");
if (mqtt.connect(clientId.c_str())) {
Serial.println("OK");
} else {
Serial.print("FAIL rc=");
Serial.println(mqtt.state());
delay(1000);
}
}
}
void setup() {
Serial.begin(115200);
delay(200);
// ★PIR安定化:まずはこれ推奨(合わなければ INPUT_PULLUP を試す)
pinMode(PIRPIN, INPUT_PULLDOWN);
dht.begin();
connectWiFi();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
connectMQTT();
Serial.print("NODE="); Serial.println(NODE);
}
void loop() {
// ★WiFi復帰(屋外運用で重要)
if (WiFi.status() != WL_CONNECTED) connectWiFi();
if (!mqtt.connected()) connectMQTT();
mqtt.loop();
static unsigned long lastDhtMs = 0;
static int lastPir = -1;
int pir = digitalRead(PIRPIN);
int rssi = WiFi.RSSI();
// PIR:変化時のみ
if (pir != lastPir) {
lastPir = pir;
String topic = String("sensors/") + NODE + "/pir";
String payload = String("{") +
"\"node\":\"" + NODE + "\"," +
"\"pir\":" + String(pir) + "," +
"\"rssi\":" + String(rssi) +
"}";
mqtt.publish(topic.c_str(), payload.c_str());
}
// DHT:5秒ごと
if (millis() - lastDhtMs > 5000) {
lastDhtMs = millis();
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(t) || isnan(h)) {
Serial.println("DHT read failed");
return;
}
String topic = String("sensors/") + NODE + "/dht11";
String payload = String("{") +
"\"node\":\"" + NODE + "\"," +
"\"temp\":" + String(t, 1) + "," +
"\"hum\":" + String(h, 1) + "," +
"\"pir\":" + String(pir) + "," +
"\"rssi\":" + String(rssi) +
"}";
mqtt.publish(topic.c_str(), payload.c_str());
Serial.println(payload);
}
}
2)ESP32-C3(例:Seeed Studio XIAO ESP32C3)
ESP32-C3 向け。基本コードはESP32と同じですが、ボードによって ‘D2/D3’ 表記がある場合でも内部はGPIO番号です。
例として、DHT=GPIO4, PIR=GPIO2で記載します。
/*
===== フィールド観測ノード(WiFi + MQTT)=====
- DHT11(温度・湿度)と PIR(人感)を読み取り、MQTTで送信
- RSSI(WiFi受信感度, dBm)も同時に送信
- topics:
sensors/<NODE>/dht11 : {node,temp,hum,pir,rssi}
sensors/<NODE>/pir : {node,pir,rssi} ※変化時のみ
*/
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
// --- 配線(GPIO番号で指定)---
#define DHTPIN D3 // D3 = GPIO4
#define PIRPIN D2 // D2 = GPIO2
#define DHTTYPE DHT11
// --- ノード名(field01/field02/field03)---
const char* NODE = "field01";
// --- WiFi ---
const char* WIFI_SSID = "ASUS_76";
const char* WIFI_PASS = "59ygi7dkd@";
// --- MQTT(RasPi)---
const char* MQTT_HOST = "192.168.50.150";
const int MQTT_PORT = 1883;
WiFiClient espClient;
PubSubClient mqtt(espClient);
DHT dht(DHTPIN, DHTTYPE);
// ---- WiFi接続(復帰できるように関数化)----
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
Serial.print("WiFi connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("WiFi connected. IP=");
Serial.println(WiFi.localIP());
}
// ---- MQTT接続(clientID衝突防止)----
void connectMQTT() {
while (!mqtt.connected()) {
// ★複数台で確実にユニークにする(NODE + チップID)
// ESP32-C3でも ESP.getEfuseMac() が使えます
String clientId = String(NODE) + "-" + String((uint32_t)ESP.getEfuseMac(), HEX);
Serial.print("MQTT connecting as ");
Serial.print(clientId);
Serial.print(" ... ");
if (mqtt.connect(clientId.c_str())) {
Serial.println("OK");
} else {
Serial.print("FAIL rc=");
Serial.println(mqtt.state());
delay(1000);
}
}
}
void setup() {
Serial.begin(115200);
delay(200);
// ★PIR安定化:まずはこれ推奨(合わなければ INPUT_PULLUP を試す)
pinMode(PIRPIN, INPUT_PULLDOWN);
dht.begin();
connectWiFi();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
connectMQTT();
Serial.print("NODE="); Serial.println(NODE);
}
void loop() {
// ★WiFiが切れたら復帰(屋外運用で重要)
if (WiFi.status() != WL_CONNECTED) {
connectWiFi();
}
// MQTT再接続
if (!mqtt.connected()) connectMQTT();
mqtt.loop();
static unsigned long lastDhtMs = 0;
static int lastPir = -1;
int pir = digitalRead(PIRPIN);
int rssi = WiFi.RSSI();
// 1) PIR:変化時のみ送信
if (pir != lastPir) {
lastPir = pir;
String topic = String("sensors/") + NODE + "/pir";
String payload = String("{") +
"\"node\":\"" + NODE + "\"," +
"\"pir\":" + String(pir) + "," +
"\"rssi\":" + String(rssi) +
"}";
mqtt.publish(topic.c_str(), payload.c_str());
}
// 2) DHT:5秒ごと
if (millis() - lastDhtMs > 5000) {
lastDhtMs = millis();
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(t) || isnan(h)) {
Serial.println("DHT read failed");
return;
}
String topic = String("sensors/") + NODE + "/dht11";
String payload = String("{") +
"\"node\":\"" + NODE + "\"," +
"\"temp\":" + String(t, 1) + "," +
"\"hum\":" + String(h, 1) + "," +
"\"pir\":" + String(pir) + "," +
"\"rssi\":" + String(rssi) +
"}";
mqtt.publish(topic.c_str(), payload.c_str());
Serial.println(payload);
}
}
9. Node-RED フローJSON(/ui + PIR安定化 + RSSI棒グラフ + セッションCSV)
インポート:Node-RED右上メニュー → Import → Clipboard → 下のJSONを貼り付け → Import → Deploy
Dashboard: http://<RasPiのIP>:1880/nodered/ui
使い方
- Node-RED画面右上メニュー → Import → Clipboard
下のJSONを貼り付け → Import - Deploy
- Dashboard:http://<RasPiのIP>:1880/red/ui (あなたの環境に合わせること)
10. 保存データ(CSV)の確認方法
保存先(例)
/media/PI_SHARE_500G/sensor_logs/
基本確認(Raspberry Pi)
1) ファイル一覧(サイズと更新時刻)
ls -lh /media/PI_SHARE_500G/sensor_logs
2) 追記されているか(末尾を表示)
tail -n 5 /media/PI_SHARE_500G/sensor_logs/field01.csv
3) 先頭を表示(ヘッダがある場合や形式確認)
head -n 5 /media/PI_SHARE_500G/sensor_logs/field01.csv
4) 行数(データ件数の目安)
wc -l /media/PI_SHARE_500G/sensor_logs/field01.csv
5) 更新が止まっていないか(更新時刻の変化を見る)
watch -n 2 ‘ls -lh /media/PI_SHARE_500G/sensor_logs’
Node-RED側の確認ポイント
・fileノードの警告(プロパティ未設定)が出ていないこと
・createDir=false の場合、事前に sensor_logs フォルダが存在すること
・書き込み権限:Node-RED実行ユーザがそのフォルダに書き込めること(例:ls -ld で確認)
11. CSV 1行データの読み方
例:
2026-01-03T08:01:29.080Z,field01,17.0,51.0,0,-90
この1行は、カンマ区切り(CSV)で次の順番です。
1) timestamp:日時(ISO 8601)。末尾のZはUTCを意味します。
2) node:ノード名(field01/field02/field03 など)。
3) temp:温度(℃)。DHT11は分解能が粗く、誤差も大きい点に注意。
4) hum:湿度(%)。同様に誤差やばらつきがあります。
5) pir:人感(0/1)。0=非検知、1=検知。環境ノイズで1が続く場合は設置・電源・配線・Pull設定、またはNode-RED側のRBE/Delay等で安定化します。
6) rssi:WiFi受信感度(dBm)。0に近いほど強い(例:-50は強い、-90は弱い)。
時刻の注意(UTC→日本時間)
Node-REDの例では new Date().toISOString() を使うためUTCになります。日本時間(JST=UTC+9)で見たい場合:
・CSVはUTCのまま保存し、解析時にJSTへ変換(推奨:後処理が楽)
・またはNode-RED側でJSTの文字列にして保存(例:functionノードでtoLocaleString(‘ja-JP’, { timeZone: ‘Asia/Tokyo’ }))
12. RSSI(受信感度)の目安
RSSIは WiFi の受信信号強度(dBm)です。数値は「0に近いほど強い」ことを意味します(例:-50dBmは強い、-90dBmは弱い)。
本システムでは、各ESP32がMQTT送信時点で WiFi.RSSI() を取得し、payloadに rssi として含めています。
目安(環境により変動します)
・-30 ~ -55 dBm:非常に良い(近距離/見通し良好)
・-56 ~ -67 dBm:良い(安定しやすい)
・-68 ~ -75 dBm:普通(運用可能だが遮蔽物で不安定になり得る)
・-76 ~ -82 dBm:弱め(遅延・再送・切断が出やすいことがある)
・-83 ~ -90 dBm:かなり弱い(途切れやすい。設置位置・アンテナ・中継検討)
・-91 dBm以下:限界付近(接続維持が難しいことが多い)
注意
・RSSIは瞬間値で揺れます。Node-REDのグラフで「傾向」を見てください(平均的にどの範囲にいるか)。
・屋外は天候・植生・人や車の動きで変動します。設置後に数時間~1日ログを取り、最悪値も確認します。
・RSSIが悪いのに通信が安定している場合もあります(再送やスループットの要求が低い場合)。逆もあります。
[
{
"id": "0bb5efaeb009f607",
"type": "tab",
"label": "WiFi MQTT DHT11 PIR RSSI (Direct)",
"disabled": false,
"info": ""
},
{
"id": "7ce9febfdb39df7e",
"type": "ui_switch",
"z": "0bb5efaeb009f607",
"name": "Record ON/OFF",
"label": "記録(セッションCSV)",
"tooltip": "ONでセッションファイル作成→保存開始 / OFFで保存停止",
"group": "d890fb2cd2532e42",
"order": 1,
"width": 6,
"height": 1,
"passthru": true,
"decouple": "false",
"topic": "save",
"style": "",
"onvalue": "true",
"onvalueType": "bool",
"onicon": "",
"oncolor": "",
"offvalue": "false",
"offvalueType": "bool",
"officon": "",
"offcolor": "",
"animate": true,
"x": 200,
"y": 40,
"wires": [
[
"7ec46caad5fc991f"
]
]
},
{
"id": "5eb9b9a0cde1c535",
"type": "ui_text",
"z": "0bb5efaeb009f607",
"group": "d890fb2cd2532e42",
"order": 2,
"width": 6,
"height": 1,
"name": "Session filename",
"label": "保存ファイル",
"format": "{{msg.payload}}",
"layout": "row-spread",
"x": 520,
"y": 40,
"wires": []
},
{
"id": "7ec46caad5fc991f",
"type": "function",
"z": "0bb5efaeb009f607",
"name": "Start/Stop session (create filename + header)",
"func": "// UI switch: true=ON / false=OFF\nconst on = !!msg.payload;\nflow.set(\"saveEnabled\", on);\n\nif (!on) {\n flow.set(\"saveFile\", null);\n return [{ payload: \"(停止中)\" }, null];\n}\n\n// ON → セッションファイル名生成\nconst d = new Date();\nconst pad = n => String(n).padStart(2, \"0\");\nconst fname = `/media/PI_SHARE_500G/sensor_logs/session_${d.getFullYear()}${pad(d.getMonth()+1)}${pad(d.getDate())}_${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}.csv`;\n\nflow.set(\"saveFile\", fname);\n\n// ヘッダを書き込む(fileノードへ)\nconst headerMsg = {\n filename: fname,\n payload: \"timestamp,node,temp,hum,pir,rssi,linkAgeSec\\n\"\n};\n\n// UIに表示\nconst uiMsg = { payload: fname };\n\nreturn [uiMsg, headerMsg];",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 540,
"y": 80,
"wires": [
[
"5eb9b9a0cde1c535"
],
[
"c836fc9f41ab07b8"
]
]
},
{
"id": "c4b785b6fe0a1ddb",
"type": "mqtt in",
"z": "0bb5efaeb009f607",
"name": "MQTT IN sensors/+/dht11",
"topic": "sensors/+/dht11",
"qos": "0",
"datatype": "auto",
"broker": "mqtt_broker_local",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 180,
"y": 160,
"wires": [
[
"9ec43c1ba4f0c075"
]
]
},
{
"id": "2a57ba05046325ad",
"type": "mqtt in",
"z": "0bb5efaeb009f607",
"name": "MQTT IN sensors/+/pir",
"topic": "sensors/+/pir",
"qos": "0",
"datatype": "auto",
"broker": "mqtt_broker_local",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 170,
"y": 220,
"wires": [
[
"3cad5acdab48233c"
]
]
},
{
"id": "9ec43c1ba4f0c075",
"type": "json",
"z": "0bb5efaeb009f607",
"name": "JSON parse (dht11)",
"property": "payload",
"action": "",
"pretty": false,
"x": 410,
"y": 160,
"wires": [
[
"c8d1e69c861f5f5d",
"4ea616ecf2208591",
"24dd0282be683c6d"
]
]
},
{
"id": "3cad5acdab48233c",
"type": "json",
"z": "0bb5efaeb009f607",
"name": "JSON parse (pir)",
"property": "payload",
"action": "",
"pretty": false,
"x": 400,
"y": 220,
"wires": [
[
"1e286ef4f09b153e",
"4ea616ecf2208591"
]
]
},
{
"id": "c8d1e69c861f5f5d",
"type": "function",
"z": "0bb5efaeb009f607",
"name": "Validate & Split (temp/hum/rssi/pir)",
"func": "// msg.payload: { node, temp, hum, pir, rssi }\nconst p = msg.payload;\nif (!p || !p.node) return null;\n\nconst temp = Number(p.temp);\nconst hum = Number(p.hum);\nconst pir = Number(p.pir);\nconst rssi = Number(p.rssi);\n\nif (Number.isNaN(temp) || Number.isNaN(hum)) return null;\n\n// output1: temp, output2: hum, output3: rssi, output4: pir\nreturn [\n { topic: p.node, payload: temp },\n { topic: p.node, payload: hum },\n { topic: p.node, payload: rssi },\n { topic: p.node, payload: pir }\n];",
"outputs": 4,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 700,
"y": 160,
"wires": [
[
"064335ecca504ccb"
],
[
"3465a1591bf153cb"
],
[
"b8782fbd6166b427"
],
[
"81cd58e386d41fce"
]
]
},
{
"id": "1e286ef4f09b153e",
"type": "function",
"z": "0bb5efaeb009f607",
"name": "Validate PIR event (topic=node, payload=pir)",
"func": "// msg.payload: { node, pir, rssi? }\nconst p = msg.payload;\nif (!p || !p.node) return null;\n\nconst pir = Number(p.pir);\nif (Number.isNaN(pir)) return null;\n\nmsg.topic = p.node;\nmsg.payload = pir;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 720,
"y": 220,
"wires": [
[
"f7d8443264e2faa7",
"a53a2f38942ef6a5"
]
]
},
{
"id": "f7d8443264e2faa7",
"type": "rbe",
"z": "0bb5efaeb009f607",
"name": "PIR: Block unless value changes (RBE)",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"property": "payload",
"x": 1010,
"y": 220,
"wires": [
[
"a53a2f38942ef6a5"
]
]
},
{
"id": "4ea616ecf2208591",
"type": "function",
"z": "0bb5efaeb009f607",
"name": "LinkHealth: update lastSeen + emit age(sec)",
"func": "// dht11/pir の受信が来たら lastSeen を更新し、\n// field01/02/03 の「最終受信からの経過秒」を出力します。\n\nconst now = Date.now();\n\n// どのノードの受信か判定\nconst p = msg.payload;\nconst nodeName = (p && p.node) ? p.node : msg.topic;\nif (!nodeName) return null;\n\nflow.set(`lastSeen_${nodeName}`, now);\n\nconst out = [];\n[\"field01\",\"field02\",\"field03\"].forEach(n => {\n const last = flow.get(`lastSeen_${n}`);\n const sec = last ? Math.floor((now - last) / 1000) : 999;\n out.push({ topic: n, payload: sec });\n});\n\n// 1出力に複数メッセージとして返す\nreturn [out];",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 740,
"y": 300,
"wires": [
[
"bab6e4143c16f51e"
]
]
},
{
"id": "24dd0282be683c6d",
"type": "function",
"z": "0bb5efaeb009f607",
"name": "CSV: append (session file, if enabled)",
"func": "// msg.payload: { node, temp, hum, pir, rssi }\n// 記録ONのときだけ、セッションCSVへ追記します。\n\nconst enabled = !!flow.get(\"saveEnabled\");\nif (!enabled) return null;\n\nconst fname = flow.get(\"saveFile\");\nif (!fname) return null;\n\nconst p = msg.payload;\nif (!p || !p.node) return null;\n\nconst ts = new Date().toISOString();\n\n// LinkAge(秒)も一緒に保存\nconst last = flow.get(`lastSeen_${p.node}`);\nconst ageSec = last ? Math.floor((Date.now() - last) / 1000) : 999;\n\nmsg.filename = fname;\nmsg.payload = `${ts},${p.node},${p.temp},${p.hum},${p.pir},${p.rssi},${ageSec}\\n`;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 720,
"y": 360,
"wires": [
[
"c836fc9f41ab07b8"
]
]
},
{
"id": "c836fc9f41ab07b8",
"type": "file",
"z": "0bb5efaeb009f607",
"name": "Append CSV to SSD (session)",
"filename": "filename",
"filenameType": "msg",
"appendNewline": false,
"createDir": true,
"overwriteFile": "false",
"encoding": "none",
"x": 1040,
"y": 360,
"wires": [
[]
]
},
{
"id": "064335ecca504ccb",
"type": "switch",
"z": "0bb5efaeb009f607",
"name": "Route temp by node",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "field01",
"vt": "str"
},
{
"t": "eq",
"v": "field02",
"vt": "str"
},
{
"t": "eq",
"v": "field03",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 980,
"y": 120,
"wires": [
[
"abc96ec235c454fc"
],
[
"930a350aad89efde"
],
[
"7db7f2316125ce97"
]
]
},
{
"id": "3465a1591bf153cb",
"type": "switch",
"z": "0bb5efaeb009f607",
"name": "Route hum by node",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "field01",
"vt": "str"
},
{
"t": "eq",
"v": "field02",
"vt": "str"
},
{
"t": "eq",
"v": "field03",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 970,
"y": 160,
"wires": [
[
"1f569dc36776e9fb"
],
[
"e30fa7e8502946bd"
],
[
"16c1b84196473112"
]
]
},
{
"id": "b8782fbd6166b427",
"type": "switch",
"z": "0bb5efaeb009f607",
"name": "Route rssi by node",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "field01",
"vt": "str"
},
{
"t": "eq",
"v": "field02",
"vt": "str"
},
{
"t": "eq",
"v": "field03",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 970,
"y": 200,
"wires": [
[
"54c74b5e71151041"
],
[
"b5a2fbcc68cb2a76"
],
[
"69d6559ba6f7c4d5"
]
]
},
{
"id": "81cd58e386d41fce",
"type": "switch",
"z": "0bb5efaeb009f607",
"name": "Route pir (state, from dht11) by node",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "field01",
"vt": "str"
},
{
"t": "eq",
"v": "field02",
"vt": "str"
},
{
"t": "eq",
"v": "field03",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 1020,
"y": 240,
"wires": [
[
"e2bcf0f9addbec9e"
],
[
"5be35f5951381d5e"
],
[
"8519542856c1c396"
]
]
},
{
"id": "a53a2f38942ef6a5",
"type": "switch",
"z": "0bb5efaeb009f607",
"name": "Route PIR event by node",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "field01",
"vt": "str"
},
{
"t": "eq",
"v": "field02",
"vt": "str"
},
{
"t": "eq",
"v": "field03",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 1210,
"y": 260,
"wires": [
[
"e2bcf0f9addbec9e"
],
[
"5be35f5951381d5e"
],
[
"8519542856c1c396"
]
]
},
{
"id": "bab6e4143c16f51e",
"type": "switch",
"z": "0bb5efaeb009f607",
"name": "Route LinkAge (sec) by node",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "field01",
"vt": "str"
},
{
"t": "eq",
"v": "field02",
"vt": "str"
},
{
"t": "eq",
"v": "field03",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 1020,
"y": 320,
"wires": [
[
"bfcebff627fbd598"
],
[
"21a2c80e4473c969"
],
[
"c44a47261cfd1734"
]
]
},
{
"id": "abc96ec235c454fc",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "Temp field01",
"group": "427d7248a54e7bfc",
"order": 1,
"width": 0,
"height": 0,
"label": "Temperature (°C)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1450,
"y": 120,
"wires": [
[]
]
},
{
"id": "1f569dc36776e9fb",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "Hum field01",
"group": "427d7248a54e7bfc",
"order": 2,
"width": 0,
"height": 0,
"label": "Humidity (%)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1440,
"y": 160,
"wires": [
[]
]
},
{
"id": "e2bcf0f9addbec9e",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "PIR field01",
"group": "427d7248a54e7bfc",
"order": 3,
"width": 0,
"height": 0,
"label": "PIR (0/1)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "step",
"nodata": "",
"dot": false,
"ymin": "0",
"ymax": "1",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1440,
"y": 240,
"wires": [
[]
]
},
{
"id": "54c74b5e71151041",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "RSSI field01",
"group": "427d7248a54e7bfc",
"order": 4,
"width": 0,
"height": 0,
"label": "RSSI (dBm)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "-100",
"ymax": "-30",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1440,
"y": 200,
"wires": [
[]
]
},
{
"id": "bfcebff627fbd598",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "LinkAge field01",
"group": "427d7248a54e7bfc",
"order": 5,
"width": 0,
"height": 0,
"label": "LinkAge (sec) ※最終受信からの秒",
"chartType": "bar",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "0",
"ymax": "60",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": true,
"useUTC": true,
"outputs": 1,
"x": 1460,
"y": 280,
"wires": [
[]
]
},
{
"id": "930a350aad89efde",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "Temp field02",
"group": "143d906e362ee630",
"order": 1,
"width": 0,
"height": 0,
"label": "Temperature (°C)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1450,
"y": 320,
"wires": [
[]
]
},
{
"id": "e30fa7e8502946bd",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "Hum field02",
"group": "143d906e362ee630",
"order": 2,
"width": 0,
"height": 0,
"label": "Humidity (%)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1440,
"y": 360,
"wires": [
[]
]
},
{
"id": "5be35f5951381d5e",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "PIR field02",
"group": "143d906e362ee630",
"order": 3,
"width": 0,
"height": 0,
"label": "PIR (0/1)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "step",
"nodata": "",
"dot": false,
"ymin": "0",
"ymax": "1",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1440,
"y": 440,
"wires": [
[]
]
},
{
"id": "b5a2fbcc68cb2a76",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "RSSI field02",
"group": "143d906e362ee630",
"order": 4,
"width": 0,
"height": 0,
"label": "RSSI (dBm)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "-100",
"ymax": "-30",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1440,
"y": 400,
"wires": [
[]
]
},
{
"id": "21a2c80e4473c969",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "LinkAge field02",
"group": "143d906e362ee630",
"order": 5,
"width": 0,
"height": 0,
"label": "LinkAge (sec) ※最終受信からの秒",
"chartType": "bar",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "0",
"ymax": "60",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": true,
"useUTC": true,
"outputs": 1,
"x": 1460,
"y": 480,
"wires": [
[]
]
},
{
"id": "7db7f2316125ce97",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "Temp field03",
"group": "0a3d104aa2f4e548",
"order": 1,
"width": 0,
"height": 0,
"label": "Temperature (°C)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1450,
"y": 520,
"wires": [
[]
]
},
{
"id": "16c1b84196473112",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "Hum field03",
"group": "0a3d104aa2f4e548",
"order": 2,
"width": 0,
"height": 0,
"label": "Humidity (%)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1440,
"y": 560,
"wires": [
[]
]
},
{
"id": "8519542856c1c396",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "PIR field03",
"group": "0a3d104aa2f4e548",
"order": 3,
"width": 0,
"height": 0,
"label": "PIR (0/1)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "step",
"nodata": "",
"dot": false,
"ymin": "0",
"ymax": "1",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1440,
"y": 640,
"wires": [
[]
]
},
{
"id": "69d6559ba6f7c4d5",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "RSSI field03",
"group": "0a3d104aa2f4e548",
"order": 4,
"width": 0,
"height": 0,
"label": "RSSI (dBm)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "-100",
"ymax": "-30",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": true,
"outputs": 1,
"x": 1440,
"y": 600,
"wires": [
[]
]
},
{
"id": "c44a47261cfd1734",
"type": "ui_chart",
"z": "0bb5efaeb009f607",
"name": "LinkAge field03",
"group": "0a3d104aa2f4e548",
"order": 5,
"width": 0,
"height": 0,
"label": "LinkAge (sec) ※最終受信からの秒",
"chartType": "bar",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "0",
"ymax": "60",
"removeOlder": "12",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": true,
"useUTC": true,
"outputs": 1,
"x": 1460,
"y": 680,
"wires": [
[]
]
},
{
"id": "d890fb2cd2532e42",
"type": "ui_group",
"name": "Control",
"tab": "3b1f1ee7541e680e",
"order": 1,
"disp": true,
"width": "12",
"collapse": false
},
{
"id": "mqtt_broker_local",
"type": "mqtt-broker",
"name": "localhost",
"broker": "127.0.0.1",
"port": "1883",
"clientid": "",
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"willTopic": "",
"willQos": "0",
"willPayload": ""
},
{
"id": "427d7248a54e7bfc",
"type": "ui_group",
"name": "field01",
"tab": "3b1f1ee7541e680e",
"order": 2,
"disp": true,
"width": "4",
"collapse": false
},
{
"id": "143d906e362ee630",
"type": "ui_group",
"name": "field02",
"tab": "3b1f1ee7541e680e",
"order": 3,
"disp": true,
"width": "4",
"collapse": false
},
{
"id": "0a3d104aa2f4e548",
"type": "ui_group",
"name": "field03",
"tab": "3b1f1ee7541e680e",
"order": 4,
"disp": true,
"width": "4",
"collapse": false
},
{
"id": "3b1f1ee7541e680e",
"type": "ui_tab",
"name": "Field Sensors (WiFi/MQTT)",
"icon": "dashboard",
"disabled": false,
"hidden": false
},
{
"id": "1bbc5b47cb74479c",
"type": "global-config",
"env": [],
"modules": {
"node-red-dashboard": "3.6.5"
}
}
]