IoT百葉箱を作る
温度センサー、湿度センサー、気圧センサーとMQTT送信器としてのESP-WROOM-02を収納するだけ
なので昔小中学校にあったような大きなものは必要ない。
収納ケースとしては、未来工業製の屋根付きウォルボックスにした。
色はなるべくそれっぽいミルキーホワイトが良いかな。
そのまま使用すると密閉ケースなので宜しくないので「ガラリ」を付けることにした。
ガラリとは、通風や換気を行うためのブラインドのようなものです。
これを付けることにより、少しでも外気温や外湿度に近づけたいと思います。


未来工業 WB-1AM 杉田エース 50型ガラリ
購入先 モノタロウ ¥1,758 購入先 アマゾン¥429
配線図

シンプルな普通の回路で構成されている。
CPUはESP-WROOM-02を使用している。

AE-ESP-WROOM-02U-1100MIL
購入先 秋月電子 ¥600
肝心の温度、湿度、気圧センサーだが、スイッチサイエンスの「SSCI-096942」というのを使用した。
主な仕様は以下のとうり
特長
- 温湿度気圧センサBME280搭載
- Grove互換コネクタとQwiic/STEMMA QTコネクタ搭載
- 電源電圧3.3 V(Qwiic/STEMMA QTコネクタから給電時)
- 電源電圧5 V(Grove互換コネクタから給電時※信号レベルは3.3 V)
- I2Cアドレス:
77h(SDOを100 K抵抗でプルアップ)
BME280の仕様
測定精度:±1 hPa
動作電圧:1.71 V~ 3.6 V
IO電圧:1.2 V~ 3.6 V
消費電流:3.6 uA(温度・湿度・気圧の1 Hz測定)
動作温度範囲:-40°C~+85°C
気温
測定範囲:-40~+85℃
分解能:0.01℃
測定精度:±0.5℃(25℃)
湿度
測定範囲:0~100 %
分解能:0.008 %
測定精度:±3 %
気圧
測定範囲:300~1100 hPa
分解能:0.18 Pa

購入先 スイッチサイエンス SSCI-096942 ¥1,980
基板内配線図

I2Cラインは、基板上で4.7kΩでプルアップ済なので何もしなくていい。
CSBラインは、I2CとSPI通信機能を切り替える為のラインなので基板上で半田盛にて3.3vラインに接続
SDO端子は、内部で100kΩで3.3vラインに接続されている。これにより、I2Cのアドレスは、77hになる
コネクターが2つあるが、今回は使用しないで基板上のホールに直接配線した。
スクリプト ESP-WROOM-02 向け
スイッチサイエンスのサイトにサンプルスクリプトが掲載されているのでそのまま持ってくればOK。
私の場合には、NORE-REDのMQTTサーバーに送信するのでその部分の処理を加えている。
このセンサー搭載のESP-WROOM-02のIPアドレスは、固定した方が使いやすいので
WiFi.config(IPAddress(192, 168, 1, 100), IPAddress(192, 168, 1, 1), IPAddress(255, 255, 255, 0));
で直接アドレスを指定している。
WiFiconfig(IPアドレス,デフォルトゲートウェイアドレス,サブネットマスク)
自分の家の空いているIPアドレスを調べるには以下のソフト「Advanced IP Scanner」を使用すると
便利。
https://forest.watch.impress.co.jp/library/software/advipscanner/
3.3v系のLED制限抵抗は、200Ω~程度だが、ここではループ動作しているかどうか確認が目的なので
消費電流を抑える為あえて大き目の1kΩにしている。
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#define BME280_ADDRESS 0x77
unsigned long int hum_raw,temp_raw,pres_raw;
signed long int t_fine;
uint16_t dig_T1;
int16_t dig_T2;
int16_t dig_T3;
uint16_t dig_P1;
int16_t dig_P2;
int16_t dig_P3;
int16_t dig_P4;
int16_t dig_P5;
int16_t dig_P6;
int16_t dig_P7;
int16_t dig_P8;
int16_t dig_P9;
int8_t dig_H1;
int16_t dig_H2;
int8_t dig_H3;
int16_t dig_H4;
int16_t dig_H5;
int8_t dig_H6;
//アサインI2C SCL SDA ポート番号
const int sclPin = 5;
const int sdaPin = 4;
const int LED = 16;
const char* ssid = "your_ssid";
const char* password = "your_passwd";
const char* mqtt_server = "192.168.1.200";// your_MQTT Server Address
long lastMsg = 0;
float msg;
WiFiClient espClient;
PubSubClient client(espClient);
void setup()
{
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
Serial.begin(9600);
Wire.begin(sdaPin, sclPin);
setup_wifi();
client.setServer(mqtt_server, 1883);
WiFi.config(IPAddress(192, 168, 1, 100), IPAddress(192, 168, 1, 1), IPAddress(255, 255, 255, 0));//IP Address
uint8_t osrs_t = 1; //Temperature oversampling x 1
uint8_t osrs_p = 1; //Pressure oversampling x 1
uint8_t osrs_h = 1; //Humidity oversampling x 1
uint8_t mode = 3; //Normal mode
uint8_t t_sb = 5; //Tstandby 1000ms
uint8_t filter = 0; //Filter off
uint8_t spi3w_en = 0; //3-wire SPI Disable
uint8_t ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode;
uint8_t config_reg = (t_sb << 5) | (filter << 2) | spi3w_en;
uint8_t ctrl_hum_reg = osrs_h;
Serial.begin(9600);
Wire.begin();
writeReg(0xF2,ctrl_hum_reg);
writeReg(0xF4,ctrl_meas_reg);
writeReg(0xF5,config_reg);
readTrim();
}
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
client.subscribe("inTopic");
} else {
// Wait 0.5 seconds before retrying
delay(500);
}
}
}
void readTrim()
{
uint8_t data[32],i=0; // Fix 2014/04/06
Wire.beginTransmission(BME280_ADDRESS);
Wire.write(0x88);
Wire.endTransmission();
Wire.requestFrom(BME280_ADDRESS,24); // Fix 2014/04/06
while(Wire.available()){
data[i] = Wire.read();
i++;
}
Wire.beginTransmission(BME280_ADDRESS); // Add 2014/04/06
Wire.write(0xA1); // Add 2014/04/06
Wire.endTransmission(); // Add 2014/04/06
Wire.requestFrom(BME280_ADDRESS,1); // Add 2014/04/06
data[i] = Wire.read(); // Add 2014/04/06
i++; // Add 2014/04/06
Wire.beginTransmission(BME280_ADDRESS);
Wire.write(0xE1);
Wire.endTransmission();
Wire.requestFrom(BME280_ADDRESS,7); // Fix 2014/04/06
while(Wire.available()){
data[i] = Wire.read();
i++;
}
dig_T1 = (data[1] << 8) | data[0];
dig_T2 = (data[3] << 8) | data[2];
dig_T3 = (data[5] << 8) | data[4];
dig_P1 = (data[7] << 8) | data[6];
dig_P2 = (data[9] << 8) | data[8];
dig_P3 = (data[11]<< 8) | data[10];
dig_P4 = (data[13]<< 8) | data[12];
dig_P5 = (data[15]<< 8) | data[14];
dig_P6 = (data[17]<< 8) | data[16];
dig_P7 = (data[19]<< 8) | data[18];
dig_P8 = (data[21]<< 8) | data[20];
dig_P9 = (data[23]<< 8) | data[22];
dig_H1 = data[24];
dig_H2 = (data[26]<< 8) | data[25];
dig_H3 = data[27];
dig_H4 = (data[28]<< 4) | (0x0F & data[29]);
dig_H5 = (data[30] << 4) | ((data[29] >> 4) & 0x0F); // Fix 2014/04/06
dig_H6 = data[31]; // Fix 2014/04/06
}
void writeReg(uint8_t reg_address, uint8_t data)
{
Wire.beginTransmission(BME280_ADDRESS);
Wire.write(reg_address);
Wire.write(data);
Wire.endTransmission();
}
void readData()
{
int i = 0;
uint32_t data[8];
Wire.beginTransmission(BME280_ADDRESS);
Wire.write(0xF7);
Wire.endTransmission();
Wire.requestFrom(BME280_ADDRESS,8);
while(Wire.available()){
data[i] = Wire.read();
i++;
}
pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
hum_raw = (data[6] << 8) | data[7];
}
signed long int calibration_T(signed long int adc_T)
{
signed long int var1, var2, T;
var1 = ((((adc_T >> 3) - ((signed long int)dig_T1<<1))) * ((signed long int)dig_T2)) >> 11;
var2 = (((((adc_T >> 4) - ((signed long int)dig_T1)) * ((adc_T>>4) - ((signed long int)dig_T1))) >> 12) * ((signed long int)dig_T3)) >> 14;
t_fine = var1 + var2;
T = (t_fine * 5 + 128) >> 8;
return T;
}
unsigned long int calibration_P(signed long int adc_P)
{
signed long int var1, var2;
unsigned long int P;
var1 = (((signed long int)t_fine)>>1) - (signed long int)64000;
var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed long int)dig_P6);
var2 = var2 + ((var1*((signed long int)dig_P5))<<1);
var2 = (var2>>2)+(((signed long int)dig_P4)<<16);
var1 = (((dig_P3 * (((var1>>2)*(var1>>2)) >> 13)) >>3) + ((((signed long int)dig_P2) * var1)>>1))>>18;
var1 = ((((32768+var1))*((signed long int)dig_P1))>>15);
if (var1 == 0)
{
return 0;
}
P = (((unsigned long int)(((signed long int)1048576)-adc_P)-(var2>>12)))*3125;
if(P<0x80000000)
{
P = (P << 1) / ((unsigned long int) var1);
}
else
{
P = (P / (unsigned long int)var1) * 2;
}
var1 = (((signed long int)dig_P9) * ((signed long int)(((P>>3) * (P>>3))>>13)))>>12;
var2 = (((signed long int)(P>>2)) * ((signed long int)dig_P8))>>13;
P = (unsigned long int)((signed long int)P + ((var1 + var2 + dig_P7) >> 4));
return P;
}
unsigned long int calibration_H(signed long int adc_H)
{
signed long int v_x1;
v_x1 = (t_fine - ((signed long int)76800));
v_x1 = (((((adc_H << 14) -(((signed long int)dig_H4) << 20) - (((signed long int)dig_H5) * v_x1)) +
((signed long int)16384)) >> 15) * (((((((v_x1 * ((signed long int)dig_H6)) >> 10) *
(((v_x1 * ((signed long int)dig_H3)) >> 11) + ((signed long int) 32768))) >> 10) + (( signed long int)2097152)) *
((signed long int) dig_H2) + 8192) >> 14));
v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((signed long int)dig_H1)) >> 4));
v_x1 = (v_x1 < 0 ? 0 : v_x1);
v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1);
return (unsigned long int)(v_x1 >> 12);
}
void loop()
{
digitalWrite(LED,HIGH);
delay(500);
if (!client.connected()) {
reconnect();
}
client.loop();
double temp_act = 0.0, press_act = 0.0,hum_act=0.0;
signed long int temp_cal;
unsigned long int press_cal,hum_cal;
readData();
temp_cal = calibration_T(temp_raw);
press_cal = calibration_P(pres_raw);
hum_cal = calibration_H(hum_raw);
temp_act = (double)temp_cal / 100.0;
press_act = (double)press_cal / 100.0;
hum_act = (double)hum_cal / 1024.0;
char buf0[12]="";
char buf1[12]="";
char buf2[12]="";
char buf3[12]="";
dtostrf(temp_act, 2, 1, buf0);
dtostrf(hum_act, 3, 1, buf1);
dtostrf(press_act, 4, 0, buf2);
delay(50);
client.publish("temperature",buf0);
delay(50);
client.publish("humidity",buf1);
delay(50);
client.publish("pressure",buf2);
digitalWrite(LED,LOW);
delay(500);
}
IoT百葉箱完成品
NODE-RED
事前に以下のページを参考にRaspberry PiにNODE-REDさらにMQTTサーバーをインストールして下さい。
https://marginalvillage.com/page/4/
NODE-REDで右上にある三のアイコンをクリックして「パレットの管理」を開き
「ノードを追加」で「@flexdash/node-red-fd-corewidgets」を追加して下さい。
ちょっと前までは通常「node-red-dashboard」を使っていましたが、最近不具合が発生しております。
具体的には、ダッシュボードが開かなる現象です。
正常動作する場合もあるので厄介です。
現在「非推奨」マークが付いているのでインストールしている場合にはアンインストールして下さい、同時に2つは干渉しますので注意して下さい。


説明
AM6:00~PM21:00迄1時間おきに外温度・湿度・気圧をGoogle HOMEへ送信して音声で報告します。
injectで文字の”1”を書き出すと日本語で、”2″を書き出すと英語で音声が出ます。
現在は”1″(日本語)の設定をしてあります。
必要なら変更して下さい。
1時間後にセンサーデーターが更新されていない場合には、Google HOMEから音声で「屋外の
温度系気象センサーが機能していません、点検して下さい。」と報告されます。
以下のリストをNODE-REDのメニュー「読み込み」からコピペすれば使用できます。
MQTTサーバーアドレス、Google HOME IPアドレスは自分のものに変更して下さい。
[{"id":"97c4136d2899d345","type":"tab","label":"フロー 1","disabled":false,"info":"","env":[]},{"id":"71705a05fce304b9","type":"mqtt in","z":"97c4136d2899d345","name":"","topic":"temperature","qos":"2","datatype":"auto-detect","broker":"a4ab6ee7518f1403","nl":false,"rap":true,"rh":0,"inputs":0,"x":130,"y":160,"wires":[["500e5bb504590a2d","3691fa41dcd9f286","f64296de16af15f5","64a1758de5a10549"]]},{"id":"500e5bb504590a2d","type":"debug","z":"97c4136d2899d345","name":"debug 1","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":340,"y":60,"wires":[]},{"id":"3691fa41dcd9f286","type":"function","z":"97c4136d2899d345","name":"書込み","func":"var data = String(msg.payload);\nglobal.set(\"out_temperature\", data);\nglobal.set(\"temperature_update_flg\", \"1\");\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":120,"wires":[[]]},{"id":"f64296de16af15f5","type":"ui-text","z":"97c4136d2899d345","group":"bf0acc3b3c4329c9","order":1,"width":0,"height":0,"name":"屋外温度","label":"屋外温度 ℃","format":"{{msg.payload}}","layout":"col-center","style":false,"font":"","fontSize":16,"color":"#717171","wrapText":false,"className":"","value":"payload","valueType":"msg","x":340,"y":160,"wires":[]},{"id":"64a1758de5a10549","type":"ui-chart","z":"97c4136d2899d345","group":"bf0acc3b3c4329c9","name":"グラフ","label":"","order":2,"chartType":"line","category":"topic","categoryType":"msg","xAxisLabel":"","xAxisProperty":"","xAxisPropertyType":"timestamp","xAxisType":"time","xAxisFormat":"","xAxisFormatType":"{HH}:{mm}","xmin":"","xmax":"","yAxisLabel":"","yAxisProperty":"payload","yAxisPropertyType":"msg","ymin":"-5","ymax":"40","bins":10,"action":"append","stackSeries":false,"pointShape":"dash","pointRadius":"0","showLegend":false,"removeOlder":1,"removeOlderUnit":"86400","removeOlderPoints":"","colors":["#0095ff","#ff0000","#ff7f0e","#2ca02c","#a347e1","#d62728","#ff9896","#9467bd","#c5b0d5"],"textColor":["#666666"],"textColorDefault":true,"gridColor":["#404040"],"gridColorDefault":false,"width":"6","height":"3","className":"","interpolation":"linear","x":330,"y":200,"wires":[[]]},{"id":"333d9fc2c517b19c","type":"mqtt in","z":"97c4136d2899d345","name":"","topic":"humidity","qos":"2","datatype":"auto-detect","broker":"a4ab6ee7518f1403","nl":false,"rap":true,"rh":0,"inputs":0,"x":120,"y":400,"wires":[["fd9b944cb53abaa2","3c702113cdebf002","bb2df56d67c5f829","81d965e31a8a2e69"]]},{"id":"81d965e31a8a2e69","type":"debug","z":"97c4136d2899d345","name":"debug 2","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":340,"y":300,"wires":[]},{"id":"bb2df56d67c5f829","type":"function","z":"97c4136d2899d345","name":"書込み","func":"global.set(\"out_humidity\", msg.payload);\nglobal.set(\"humidity_update_flg\", \"1\");\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":360,"wires":[[]]},{"id":"fd9b944cb53abaa2","type":"ui-text","z":"97c4136d2899d345","group":"bf0acc3b3c4329c9","order":3,"width":0,"height":0,"name":"屋外湿度","label":"屋外湿度 %","format":"{{msg.payload}}","layout":"col-center","style":false,"font":"","fontSize":16,"color":"#717171","wrapText":false,"className":"","value":"payload","valueType":"msg","x":340,"y":400,"wires":[]},{"id":"3c702113cdebf002","type":"ui-chart","z":"97c4136d2899d345","group":"bf0acc3b3c4329c9","name":"グラフ","label":"","order":4,"chartType":"line","category":"topic","categoryType":"msg","xAxisLabel":"","xAxisProperty":"","xAxisPropertyType":"timestamp","xAxisType":"time","xAxisFormat":"","xAxisFormatType":"{HH}:{mm}","xmin":"","xmax":"","yAxisLabel":"","yAxisProperty":"payload","yAxisPropertyType":"msg","ymin":"0","ymax":"100","bins":10,"action":"append","stackSeries":false,"pointShape":"dash","pointRadius":"0","showLegend":false,"removeOlder":1,"removeOlderUnit":"86400","removeOlderPoints":"","colors":["#0095ff","#ff0000","#ff7f0e","#2ca02c","#a347e1","#d62728","#ff9896","#9467bd","#c5b0d5"],"textColor":["#666666"],"textColorDefault":true,"gridColor":["#404040"],"gridColorDefault":false,"width":"6","height":"3","className":"","interpolation":"linear","x":330,"y":440,"wires":[[]]},{"id":"0821f3d8d67c3f17","type":"mqtt in","z":"97c4136d2899d345","name":"","topic":"pressure","qos":"2","datatype":"auto-detect","broker":"a4ab6ee7518f1403","nl":false,"rap":true,"rh":0,"inputs":0,"x":120,"y":580,"wires":[["fd723ad4d4957cec","4949dd988087e572"]]},{"id":"fd723ad4d4957cec","type":"ui-text","z":"97c4136d2899d345","group":"bf0acc3b3c4329c9","order":5,"width":0,"height":0,"name":"気圧 ","label":"気圧 HPa","format":"{{msg.payload}}","layout":"col-center","style":false,"font":"","fontSize":16,"color":"#717171","wrapText":false,"className":"","value":"payload","valueType":"msg","x":330,"y":580,"wires":[]},{"id":"4949dd988087e572","type":"function","z":"97c4136d2899d345","name":"書込み","func":"global.set(\"out_pressure\", msg.payload);\nglobal.set(\"pressure_update_flg\", \"1\");\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":540,"wires":[[]]},{"id":"40c51f88164d7425","type":"inject","z":"97c4136d2899d345","name":"AM6:00~PM21:00 外温度・湿度・気圧報告","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"0 6-20 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"str","x":260,"y":780,"wires":[["03571a679351f5a3"]]},{"id":"03571a679351f5a3","type":"function","z":"97c4136d2899d345","name":"データー読み込み、言語選択、送出","func":"var number = msg.payload;\nvar data =\"\";\nvar out_temp = \"\";\nvar out_humid = \"\";\nvar out_press = \"\";\nlet temp_bad = false;\nlet humi_bad = false;\nlet press_bad = false;\nvar out_temp_update_flg = global.get(\"temperatur_update_flg\");\nif (out_temp_update_flg != \"0\") {out_temp = global.get(\"out_temperature\");global.set(\"temperature_update_flg\",\"0\");}else{temp_bad = true;}\nvar out_humid_update_flg = global.get(\"humidity_update_flg\");\nif (out_humid_update_flg != \"0\") {out_humid = global.get(\"out_humidity\"); global.set(\"humidity_update_flg\", \"0\"); } else { humi_bad = true; }\nvar out_press_update_flg = global.get(\"pressure_update_flg\");\nif (out_press_update_flg != \"0\") {out_press = global.get(\"out_pressure\"); global.set(\"pressure_update_flg\", \"0\"); } else { press_bad = true; }\n\nlet date = new Date();\nvar hour = date.getHours();\n\n\nif(number == \"1\"){\n msg.language = \"ja\";\n if (temp_bad) { data = \"屋外の温度センサーが機能していません、点検して下さい。\"; } else {\n data = \"現在の時刻は\" + hour + \"時です。\" +\n \"外気温は\" + out_temp + \"度。\" +\n \"湿度は\" + out_humid + \"パーセント。\" +\n \"気圧は\" + out_press + \"ヘクトパスカルです。\";\n}\n}\nif(number == \"2\"){\n msg.language =\"en\"; \n if (temp_bad) { data = \"The outdoor temperature sensor is not working, please check.\"; } else { \n data = \"The time is \" + hour + \" o'clock. \" +\n \"The temperature is \" + out_temp + \" degrees. \" +\n \"Humidity is \" + out_humid + \" percent.\";\n \"The atmospheric pressure is \" + out_press + \"Hectopascals.\";\n} \n}\nmsg.payload = data;\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":650,"y":780,"wires":[["023adc96176b7b99"]]},{"id":"023adc96176b7b99","type":"cast-to-client","z":"97c4136d2899d345","name":"","url":"","contentType":"","message":"","language":"","ip":"192.168.1.100","port":"","volume":"","x":950,"y":780,"wires":[[]]},{"id":"a4ab6ee7518f1403","type":"mqtt-broker","name":"","broker":"192.168.1.200","port":"1883","clientid":"","autoConnect":true,"usetls":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":""},{"id":"bf0acc3b3c4329c9","type":"ui-group","name":"温度・湿度・気圧","page":"57fb0c8fb3ed880f","width":6,"height":1,"order":1,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"57fb0c8fb3ed880f","type":"ui-page","name":"気象","ui":"0bdcc053b020d9d6","path":"/page1","icon":"home","layout":"grid","theme":"2eaf27c68cb57512","breakpoints":[{"name":"Default","px":"0","cols":"3"},{"name":"Tablet","px":"576","cols":"6"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":1,"className":"","visible":"true","disabled":"false"},{"id":"0bdcc053b020d9d6","type":"ui-base","name":"気象観測","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"headerContent":"page","navigationStyle":"default","titleBarStyle":"default","showReconnectNotification":true,"notificationDisplayTime":1,"showDisconnectNotification":true,"allowInstall":false},{"id":"2eaf27c68cb57512","type":"ui-theme","name":"Default Theme","colors":{"surface":"#405959","primary":"#0094ce","bgPage":"#2c2c2c","groupBg":"#2c2c2c","groupOutline":"#2c2c2c"},"sizes":{"density":"compact","pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}},{"id":"11d8eacaf48bb3fe","type":"global-config","env":[],"modules":{"@flowfuse/node-red-dashboard":"1.30.2","node-red-contrib-cast":"0.2.17"}}]