Hardware components | ||||||
| × | 1 | ||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
![]() |
| |||||
| ||||||
![]() |
| |||||
![]() |
| |||||
| ||||||
![]() |
|
I've been a devoted bonsai enthusiast for over a decade, and currently take care of about 200 little trees. Each one is like a tiny universe, demanding patience, precision, and a little bit of love every day.
私は盆栽の愛好家で、10年以上のキャリアがあり、現在は約200鉢の盆栽の世話をしています。それぞれが小さな宇宙のような存在で、日々の忍耐と正確さ、そして少しの愛情が必要です。
There’s a saying in the bonsai world: “It takes three years to learn how to water properly.” It sounds simple, but good watering is an art — and experience is the best teacher.
盆栽の世界には「水やり三年」という言葉があります。一見簡単そうですが、水やりは奥が深く、経験こそが最良の教師なのです。
Seven years ago, I started developing my own automatic watering systems. Not out of laziness — but to care for these bonsai more precisely, especially when I wasn’t home.
7年前、自動水やり装置の開発に着手しました。決して手抜きではなく、外出中でも正確に水やりを行うための工夫でした。
This year’s device isn’t just a watering machine — it’s a “肥培装置 (hibai-souchi), ” designed to accelerate trunk thickening by optimizing nutrient delivery.
今年の装置は、単なる水やり装置ではありません。幹を太らせることを目的とした「肥培装置」なのです。
The soil I use is called “Okayama-sand, ” known for excellent drainage. Every 3 hours, the device delivers a nutrient-rich solution for exactly 3 minutes. This boosts root growth and trunk development.
用土には水はけの良い「岡山砂」を使用し、3時間おきに3分間、液肥を混ぜた溶液を与え、根張りと幹の太りを促進します。
My bonsai buddy, cell-plus, developed a plant-growing kit called Strawberry-Pi Pico. I wanted to evolve it — turn it into a powerful hibai machine.
盆栽仲間のcell-plusさんが開発した「Strawberry-Pi Pico」という植物栽培キットを、より強化して肥培装置に仕立て上げたいと考えました。
https://github.com/cell-plus/StrawberryPi-Pico_V0.1
I also wanted to reuse ideas from my previous M5WateringUnit project. But to make this happen, I needed to give wireless powers to the otherwise offline Strawberry-Pi Pico.
以前作成したM5WateringUnitの自動水やり装置のアイデアも活かしたかったのですが、Strawberry-Pi Picoには無線機能がなかったため、それを補う必要がありました。
Enter Atom Lite. By combining it with Node-RED MCU, I created a wireless broker that could command the Strawberry-Pi Pico effortlessly.
そこで登場したのがAtom Lite。Node-RED MCUと組み合わせて、Strawberry-Pi Picoを自在に制御できる無線ブローカーを構築しました。
Yes — now I could control the Pico wirelessly. It may sound trivial, but this was the game-changer, and the part I’m most proud of.
そう、Picoを無線で制御できるようになったのです。一見簡単そうに聞こえるかもしれませんが、これこそが今回の一番の成果であり、最もアピールしたい部分です。
Node-RED MCU didn’t support serial communication out of the box. With invaluable help from mshioji and 404background, I overcame this hurdle step by step.
Node-RED MCUは標準ではシリアル通信に対応していません。しかし、mshiojiさんや404backgroundさんの助けを借りて、なんとか実現にこぎつけました。
Once the system became wireless and the UI cleanly organized, new ideas started flowing. I wanted to integrate more than just watering and fertilizing.
無線化されてUIも整うと、さらにやりたいことが湧いてきました。水やりや肥料だけでなく、装置の統合を目指したのです。
I had a mini Stevenson screen housing a SwitchBot Meter, which I had only used for environmental monitoring. But now, I saw its potential in this system.
今までは棚場の環境モニタ用に使っていたSwitchBot Meter入りのミニ百葉箱も、今回の装置に組み込みたくなりました。
With a forgotten SwitchBot Hub Mini lying around, I connected the meter to the cloud and started logging temperature and humidity data.
使っていなかったSwitchBot Hub Miniを活用し、SwitchBot Meterの情報をクラウド経由で取得できるようにしました。
Then came the final touch: I calculated the VPD (Vapor Pressure Deficit), a key indicator of photosynthesis conditions, and used a SwitchBot Plug Mini to trigger a gentle shower when needed.
最後の仕上げとして、光合成の指標であるVPD(蒸気圧不足)を計算し、必要に応じてSwitchBot Plug Miniでシャワーを作動させ、葉水を行うようにしました。
As for soil moisture sensors — I use them only to visualize dryness, not to control watering. In my environment, automation based on “dry then water deeply” didn’t work well.
なお、土壌水分計は乾燥状態の「見える化」のみに使っています。経験上、「乾いたらたっぷり水やり」を自動化するのは難しく、今回はあえて制御には使っていません。
By combining bonsai wisdom with open-source tools and DIY spirit, I’ve built a system that not only nourishes plants — but also grows with my curiosity.
盆栽の知恵とオープンソースの道具、そしてDIY精神を組み合わせることで、植物を育てるだけでなく、自分の好奇心も育てる装置が完成しました。
This time, I built a system that even I didn’t think was possible at first. To my surprise, I managed to connect previously incompatible devices into a unified, higher-level ecosystem.
今回は、自分でも想像していなかったような装置を作ることができました。今までうまくつながらなかったデバイス同士を、高い次元で関連づけることに成功したのです。
As a result, I believe I’ve expanded what can be handled by M5Stack-based microcontrollers. It’s like unlocking new superpowers for them!
その結果、M5Stack系のマイコンで扱える領域が広がったと感じています。まるで新しいスーパーパワーを得たかのようです!
Moving forward, I want to keep solving everyday frustrations through electronics — whether it’s in bonsai, gardening, or beyond.
これからも、盆栽や園芸に限らず、日々の困りごとを電子工作の力で解決していきたいと思います。
Thank you for reading — and may your tech roots grow deep and strong, just like bonsai.
最後まで読んでいただきありがとうございました。皆さんのテクノロジーの根も、盆栽のように深く、そしてたくましく育ちますように。
SPP_20250707.ino
C/C++#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#define ONBOARD_NP_PIN 25
#define LINE_NP_PIN 24
#define NUMPIXELS 144
#define SENSORPIN A0
#define TRANSISTORPIN 23
Adafruit_NeoPixel pixel0(1, ONBOARD_NP_PIN, NEO_GRB + NEO_KHZ800);
bool bPump = false; //
int pumpSec = 60 * 3; // ()
int waitSec = 60 * 60 * 3; // ()
int moisture = 0; //
unsigned long startTime = 0;//
unsigned long waitTime = 0; //
unsigned long dispTime = 0; //
bool bDisp = false; //
int extractValueFromCommand(const String& cmd) {
if (cmd.length() > 1) {
return cmd.substring(1).toInt();
} else {
return 0;
}
}
String CommandProcess(const String& cmd) {
//
if (cmd.startsWith("W")) {
int remainSec = extractValueFromCommand(cmd);
bPump = true;
startTime = millis();
waitTime = remainSec * 1000;
return "W1";
}
if (cmd.startsWith("T")) {
pumpSec = extractValueFromCommand(cmd);
if (bPump) {
startTime = millis();
waitTime = pumpSec * 1000;
}
return "T1";
}
if (cmd.startsWith("I")) {
waitSec = extractValueFromCommand(cmd);
if (!bPump) {
startTime = millis();
waitTime = waitSec * 1000;
}
return "I1";
}
if (cmd == "R") {
int remainSec = (waitTime + startTime - millis()) / 1000;
String response = "R" + String(remainSec);
return response;
}
if (cmd == "S") {
String response = "S" + String(bPump);
return response;
}
if (cmd == "U") {
String response = "U" + String(pumpSec);
return response;
}
if (cmd == "J") {
String response = "J" + String(waitSec);
return response;
}
if (cmd == "M") {
moisture = analogRead(SENSORPIN);
String response = "M" + String(moisture);
return response;
}
return "E1"; //
}
void pumpOn() {
Serial.println("ON");
digitalWrite(TRANSISTORPIN, HIGH);
}
void pumpOff() {
Serial.println("OFF");
digitalWrite(TRANSISTORPIN, LOW);
}
void setup() {
Serial.begin(9600); //
pixel0.begin();
pixel0.setBrightness(50);
pinMode(TRANSISTORPIN, OUTPUT);
digitalWrite(TRANSISTORPIN, LOW);
Serial1.setTX(0); // TXGPIO 0
Serial1.setRX(1); // RXGPIO 1
Serial1.begin(9600);
Serial.println("SST");
bPump = false;
startTime = millis(); //
waitTime = 5 * 1000;
dispTime = millis();
bDisp = false;
}
void loop() {
// PC
if (Serial1.available()) {
String cmd = Serial1.readStringUntil('\n');
cmd.trim();
Serial.print(" : ");
Serial.println(cmd);
String response = CommandProcess(cmd);
//
Serial.print(" : ");
Serial.println(response);
Serial1.println(response);
delay(100);
}
//
//(https://garretlab.web.fc2.com/arduino/lab/millis/)
//
if (millis() - startTime > waitTime) {
//
if (bPump) {
pumpOff();
bPump = false;
startTime = millis();
waitTime = waitSec * 1000;
}
else {
pumpOn();
bPump = true;
startTime = millis();
waitTime = pumpSec * 1000;
}
}
//
if (bPump) {
if (millis() - dispTime > 500) {
pixel0.setPixelColor(0, pixel0.Color(0, 0, 50 * bDisp));
pixel0.show();
dispTime = millis();
bDisp = !bDisp;
}
}
else {
if (millis() - dispTime > 1000) {
float ratio = (float)(millis() - startTime) / (float)waitTime;
ratio = constrain(ratio, 0.0, 1.0); // 0.01.0
pixel0.setPixelColor(0, pixel0.Color((uint8_t)(ratio * 50.0 * (float)bDisp), (uint8_t)((1.0 - ratio) * 50.0 * (float)bDisp), 0));
pixel0.show();
dispTime = millis();
bDisp = !bDisp;
}
}
}
Strawberry-Pi-Pico_Broker.json
JSON[
{
"id": "de63ccaac6c54193",
"type": "tab",
"label": "Strawberry-Pi Pico Broker",
"disabled": false,
"info": "",
"env": [],
"_mcu": {
"mcu": true
}
},
{
"id": "inject_test",
"type": "inject",
"z": "de63ccaac6c54193",
"name": "W1",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "W1",
"payloadType": "str",
"_mcu": {
"mcu": true
},
"x": 150,
"y": 260,
"wires": [
[
"func_parse"
]
]
},
{
"id": "func_parse",
"type": "function",
"z": "de63ccaac6c54193",
"name": "Cmd+Value > JSON",
"func": "// 例: \"S1\" や \"R1234\" をパースして JSON に変換\nlet str = msg.payload;\nlet cmd = str.charAt(0);\nlet valueStr = str.substring(1);\nlet value = isNaN(valueStr) ? valueStr : Number(valueStr);\nmsg.payload = {\n cmd: cmd,\n value: value\n};\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": true
},
"x": 400,
"y": 220,
"wires": [
[
"mqtt_out"
]
]
},
{
"id": "mqtt_out",
"type": "mqtt out",
"z": "de63ccaac6c54193",
"name": "",
"topic": "SPP/out",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "6b4a7676fb401863",
"_mcu": {
"mcu": true
},
"x": 620,
"y": 220,
"wires": []
},
{
"id": "4e83e1c3456a51e1",
"type": "inject",
"z": "de63ccaac6c54193",
"name": "T1",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "T1",
"payloadType": "str",
"_mcu": {
"mcu": true
},
"x": 150,
"y": 300,
"wires": [
[
"func_parse"
]
]
},
{
"id": "badf37736fc97ca1",
"type": "inject",
"z": "de63ccaac6c54193",
"name": "I1",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "I1",
"payloadType": "str",
"_mcu": {
"mcu": true
},
"x": 150,
"y": 340,
"wires": [
[
"func_parse"
]
]
},
{
"id": "3ecb92334d7f2fdf",
"type": "inject",
"z": "de63ccaac6c54193",
"name": "R1234",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "R1234",
"payloadType": "str",
"_mcu": {
"mcu": true
},
"x": 150,
"y": 380,
"wires": [
[
"func_parse"
]
]
},
{
"id": "05c484e7e02a678f",
"type": "inject",
"z": "de63ccaac6c54193",
"name": "S1",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "S1",
"payloadType": "str",
"_mcu": {
"mcu": true
},
"x": 150,
"y": 420,
"wires": [
[
"func_parse"
]
]
},
{
"id": "e877528cef011fe9",
"type": "inject",
"z": "de63ccaac6c54193",
"name": "S0",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "S0",
"payloadType": "str",
"_mcu": {
"mcu": true
},
"x": 150,
"y": 460,
"wires": [
[
"func_parse"
]
]
},
{
"id": "e2dca2c1c6cb7445",
"type": "inject",
"z": "de63ccaac6c54193",
"name": "U180",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "U180",
"payloadType": "str",
"_mcu": {
"mcu": true
},
"x": 150,
"y": 500,
"wires": [
[
"func_parse"
]
]
},
{
"id": "04226f8ef648e4fe",
"type": "inject",
"z": "de63ccaac6c54193",
"name": "J10800",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "J10800",
"payloadType": "str",
"_mcu": {
"mcu": true
},
"x": 150,
"y": 540,
"wires": [
[
"func_parse"
]
]
},
{
"id": "7a162fcce4df1b4f",
"type": "inject",
"z": "de63ccaac6c54193",
"name": "M1234",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "M1234",
"payloadType": "str",
"_mcu": {
"mcu": true
},
"x": 150,
"y": 580,
"wires": [
[
"func_parse"
]
]
},
{
"id": "5d828bbdf3c31bdd",
"type": "inject",
"z": "de63ccaac6c54193",
"name": "E1",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "E1",
"payloadType": "str",
"_mcu": {
"mcu": true
},
"x": 150,
"y": 620,
"wires": [
[
"func_parse"
]
]
},
{
"id": "2fa57be624085cf4",
"type": "function",
"z": "de63ccaac6c54193",
"name": "mcu serial in",
"func": "// code or port settings are written in 'On Start' tab.\n// please ignore red triangle on this node.\n\n// コードやポート設定は「初期化処理(On Start)」にあります。\n// ノードに赤い三角マークがつきますが無視してください。",
"outputs": 1,
"timeout": 0,
"noerr": 4,
"initialize": "// Code added here will be run once\n// whenever the node is started.\n\nlet serial = new device.io.Serial({\n ...device.Serial.default,\n baud: 9600,\n receive: 32,\n transmit: 26,\n format: \"buffer\",\n onReadable: function (count) {\n let msg = {};\n msg.payload = String.fromArrayBuffer(this.read());\n msg.payload = msg.payload.trimEnd();\n node.send(msg);\n },\n});\nflow.set('serial', serial); // provide 'serial' for 'mcu serial out' node.\n",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": true
},
"x": 130,
"y": 220,
"wires": [
[
"func_parse"
]
]
},
{
"id": "99c649e1127deaed",
"type": "function",
"z": "de63ccaac6c54193",
"name": "mcu serial out",
"func": "let serial = flow.get('serial'); // get 'serial' from 'mcu serial in'\n\nif (msg.payload != null){\n serial.write(ArrayBuffer.fromString(msg.payload + \"\\n\"));\n}\n",
"outputs": 0,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": true
},
"x": 640,
"y": 780,
"wires": []
},
{
"id": "7adf52005f7c2259",
"type": "mqtt in",
"z": "de63ccaac6c54193",
"name": "",
"topic": "SPP/in",
"qos": "2",
"datatype": "auto-detect",
"broker": "6b4a7676fb401863",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"_mcu": {
"mcu": true
},
"x": 130,
"y": 780,
"wires": [
[
"3a4d65c7e0517f6f"
]
]
},
{
"id": "25a7c828d870984d",
"type": "comment",
"z": "de63ccaac6c54193",
"name": "Strawberry Pi Pico >> in",
"info": "",
"_mcu": {
"mcu": true
},
"x": 120,
"y": 160,
"wires": []
},
{
"id": "691b57f567e078c9",
"type": "comment",
"z": "de63ccaac6c54193",
"name": "out >> Raspberry Pi",
"info": "",
"_mcu": {
"mcu": true
},
"x": 650,
"y": 160,
"wires": []
},
{
"id": "3a4d65c7e0517f6f",
"type": "function",
"z": "de63ccaac6c54193",
"name": "cmd + value",
"func": "let obj = JSON.parse(msg.payload);\n\nlet cmd = obj.cmd ?? \"\";\nlet value = obj.value ?? \"\";\n\nmsg.payload = cmd + value;\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": true
},
"x": 350,
"y": 780,
"wires": [
[
"99c649e1127deaed"
]
]
},
{
"id": "249951672a3f861a",
"type": "comment",
"z": "de63ccaac6c54193",
"name": "Raspberry Pi >> in",
"info": "",
"_mcu": {
"mcu": true
},
"x": 110,
"y": 720,
"wires": []
},
{
"id": "f712ae310e2d27ca",
"type": "comment",
"z": "de63ccaac6c54193",
"name": "out >> Strawberry Pi Pico",
"info": "",
"_mcu": {
"mcu": true
},
"x": 670,
"y": 720,
"wires": []
},
{
"id": "6b4a7676fb401863",
"type": "mqtt-broker",
"name": "",
"broker": "192.168.64.59",
"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": "",
"_mcu": {
"mcu": false
}
}
]
Raspberry Pi Base.json
JSONIt manages the MQTT server, displays signals emitted from the broker on the UI, and transmits changed values.
[
{
"id": "309997a2fd87c15a",
"type": "tab",
"label": "Raspberry Pi Base",
"disabled": false,
"info": "",
"env": [],
"_mcu": {
"mcu": false
}
},
{
"id": "1490d21255099ebb",
"type": "junction",
"z": "309997a2fd87c15a",
"x": 940,
"y": 440,
"wires": [
[
"ad5569d57e27a655"
]
]
},
{
"id": "db2c3a53b69af5ac",
"type": "aedes broker",
"z": "309997a2fd87c15a",
"name": "",
"mqtt_port": 1883,
"mqtt_ws_bind": "port",
"mqtt_ws_port": "",
"mqtt_ws_path": "",
"cert": "",
"key": "",
"certname": "",
"keyname": "",
"persistence_bind": "memory",
"dburl": "",
"usetls": false,
"_mcu": {
"mcu": false
},
"x": 170,
"y": 60,
"wires": [
[],
[]
]
},
{
"id": "e9c6645628be9509",
"type": "mqtt in",
"z": "309997a2fd87c15a",
"name": "",
"topic": "SPP/out",
"qos": "2",
"datatype": "auto-detect",
"broker": "6b4a7676fb401863",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"_mcu": {
"mcu": false
},
"x": 140,
"y": 440,
"wires": [
[
"80d2dc58410cd8a9"
]
]
},
{
"id": "80d2dc58410cd8a9",
"type": "switch",
"z": "309997a2fd87c15a",
"name": "",
"property": "payload.cmd",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "R",
"vt": "str"
},
{
"t": "eq",
"v": "S",
"vt": "str"
},
{
"t": "eq",
"v": "U",
"vt": "str"
},
{
"t": "eq",
"v": "J",
"vt": "str"
},
{
"t": "eq",
"v": "M",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 6,
"_mcu": {
"mcu": false
},
"x": 300,
"y": 440,
"wires": [
[
"01f672bdfd6503bc"
],
[
"e477f882f2fcb5e0"
],
[
"61e1982c6a927a7e"
],
[
"950cb41683f6dd44"
],
[
"59714174168a36a4"
],
[]
]
},
{
"id": "ad5569d57e27a655",
"type": "mqtt out",
"z": "309997a2fd87c15a",
"name": "",
"topic": "SPP/in",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "6b4a7676fb401863",
"_mcu": {
"mcu": false
},
"x": 1010,
"y": 440,
"wires": []
},
{
"id": "ac48e7fc758ff73b",
"type": "ui_button",
"z": "309997a2fd87c15a",
"name": "",
"group": "2a28fe2c9d53f257",
"order": 3,
"width": 0,
"height": 0,
"passthru": false,
"label": "",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "{ \"cmd\" : \"W\", \"value\" : 180 }",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"_mcu": {
"mcu": false
},
"x": 660,
"y": 520,
"wires": [
[
"1490d21255099ebb"
]
]
},
{
"id": "199eaaa074548d01",
"type": "ui_slider",
"z": "309997a2fd87c15a",
"name": "",
"label": "()",
"tooltip": "",
"group": "2a28fe2c9d53f257",
"order": 1,
"width": 0,
"height": 0,
"passthru": true,
"outs": "end",
"topic": "topic",
"topicType": "msg",
"min": "1",
"max": "100",
"step": "1",
"className": "",
"_mcu": {
"mcu": false
},
"x": 660,
"y": 400,
"wires": [
[
"f237f969f7c136b2"
]
]
},
{
"id": "ac47c1d47f804941",
"type": "ui_slider",
"z": "309997a2fd87c15a",
"name": "",
"label": "()",
"tooltip": "",
"group": "2a28fe2c9d53f257",
"order": 2,
"width": 0,
"height": 0,
"passthru": true,
"outs": "end",
"topic": "topic",
"topicType": "msg",
"min": "1",
"max": "180",
"step": "10",
"className": "",
"_mcu": {
"mcu": false
},
"x": 660,
"y": 460,
"wires": [
[
"a82e67c454b23b52"
]
]
},
{
"id": "5526a8bb2cd4e151",
"type": "ui_gauge",
"z": "309997a2fd87c15a",
"name": "",
"group": "2a28fe2c9d53f257",
"order": 4,
"width": 0,
"height": 0,
"gtype": "donut",
"title": "",
"label": "min.",
"format": "{{value}}",
"min": 0,
"max": "180",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"seg1": "",
"seg2": "",
"diff": false,
"className": "",
"_mcu": {
"mcu": false
},
"x": 640,
"y": 580,
"wires": []
},
{
"id": "742e384f00279995",
"type": "ui_switch",
"z": "309997a2fd87c15a",
"name": "",
"label": "",
"tooltip": "",
"group": "2a28fe2c9d53f257",
"order": 5,
"width": 0,
"height": 0,
"passthru": false,
"decouple": "true",
"topic": "topic",
"topicType": "msg",
"style": "",
"onvalue": "true",
"onvalueType": "bool",
"onicon": "",
"oncolor": "",
"offvalue": "false",
"offvalueType": "bool",
"officon": "",
"offcolor": "",
"animate": false,
"className": "",
"_mcu": {
"mcu": false
},
"x": 640,
"y": 640,
"wires": [
[]
]
},
{
"id": "ab4d895a73351fda",
"type": "ui_numeric",
"z": "309997a2fd87c15a",
"name": "",
"label": "",
"tooltip": "",
"group": "2a28fe2c9d53f257",
"order": 6,
"width": 0,
"height": 0,
"wrap": false,
"passthru": true,
"topic": "topic",
"topicType": "msg",
"format": "{{value}}",
"min": 0,
"max": 10,
"step": 1,
"className": "",
"_mcu": {
"mcu": false
},
"x": 630,
"y": 700,
"wires": [
[]
]
},
{
"id": "f237f969f7c136b2",
"type": "change",
"z": "309997a2fd87c15a",
"name": "\"T\"+value",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{ \"cmd\" : \"T\", \"value\" : $number(payload)*60 }",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 820,
"y": 400,
"wires": [
[
"1490d21255099ebb"
]
]
},
{
"id": "a82e67c454b23b52",
"type": "change",
"z": "309997a2fd87c15a",
"name": "\"I\"+value",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{ \"cmd\" : \"I\", \"value\" : $number(payload)*60 }",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 820,
"y": 460,
"wires": [
[
"1490d21255099ebb"
]
]
},
{
"id": "431e69ae3b848d6e",
"type": "inject",
"z": "309997a2fd87c15a",
"name": "first time",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"_mcu": {
"mcu": false
},
"x": 140,
"y": 160,
"wires": [
[]
]
},
{
"id": "c8bbd9ae0474da30",
"type": "change",
"z": "309997a2fd87c15a",
"name": "\"R\"",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{ \"cmd\" : \"R\" }",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 510,
"y": 160,
"wires": [
[
"1490d21255099ebb"
]
]
},
{
"id": "8b9d4885a9ddc88a",
"type": "change",
"z": "309997a2fd87c15a",
"name": "\"S\"",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{ \"cmd\" : \"S\" }",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 510,
"y": 200,
"wires": [
[
"1490d21255099ebb"
]
]
},
{
"id": "ef544a3171bc0229",
"type": "change",
"z": "309997a2fd87c15a",
"name": "\"M\"",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{ \"cmd\" : \"M\" }",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 510,
"y": 320,
"wires": [
[
"1490d21255099ebb"
]
]
},
{
"id": "8f8902b19ed1c723",
"type": "change",
"z": "309997a2fd87c15a",
"name": "\"U\"",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{ \"cmd\" : \"U\" }",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 510,
"y": 240,
"wires": [
[
"1490d21255099ebb"
]
]
},
{
"id": "08312d9071f1315f",
"type": "change",
"z": "309997a2fd87c15a",
"name": "\"J\"",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{ \"cmd\" : \"J\" }",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 510,
"y": 280,
"wires": [
[
"1490d21255099ebb"
]
]
},
{
"id": "61e1982c6a927a7e",
"type": "change",
"z": "309997a2fd87c15a",
"name": "value",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.value / 60",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 510,
"y": 400,
"wires": [
[
"199eaaa074548d01"
]
]
},
{
"id": "950cb41683f6dd44",
"type": "change",
"z": "309997a2fd87c15a",
"name": "value",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.value / 60",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 510,
"y": 460,
"wires": [
[
"ac47c1d47f804941"
]
]
},
{
"id": "01f672bdfd6503bc",
"type": "change",
"z": "309997a2fd87c15a",
"name": "value",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "$round(payload.value / 60 * 10) / 10",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 510,
"y": 580,
"wires": [
[
"5526a8bb2cd4e151"
]
]
},
{
"id": "e477f882f2fcb5e0",
"type": "change",
"z": "309997a2fd87c15a",
"name": "value",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.value = 1 ? true : false",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 510,
"y": 640,
"wires": [
[
"742e384f00279995"
]
]
},
{
"id": "59714174168a36a4",
"type": "change",
"z": "309997a2fd87c15a",
"name": "value",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.value",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 510,
"y": 700,
"wires": [
[
"ab4d895a73351fda",
"c4e74f0a62526eb5"
]
]
},
{
"id": "3ad61da910c16d61",
"type": "inject",
"z": "309997a2fd87c15a",
"name": "evrey 1 sec.",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "1",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"_mcu": {
"mcu": false
},
"x": 160,
"y": 220,
"wires": [
[
"c8bbd9ae0474da30",
"8b9d4885a9ddc88a",
"ef544a3171bc0229",
"8f8902b19ed1c723",
"08312d9071f1315f"
]
]
},
{
"id": "30814bf03b72c61a",
"type": "ui_chart",
"z": "309997a2fd87c15a",
"name": "",
"group": "2a28fe2c9d53f257",
"order": 6,
"width": 0,
"height": 0,
"label": "",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": 1,
"removeOlderPoints": "",
"removeOlderUnit": "604800",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"outputs": 1,
"useDifferentColor": false,
"className": "",
"_mcu": {
"mcu": false
},
"x": 850,
"y": 740,
"wires": [
[]
]
},
{
"id": "c4e74f0a62526eb5",
"type": "delay",
"z": "309997a2fd87c15a",
"name": "every 20min.",
"pauseType": "rate",
"timeout": "5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "20",
"rateUnits": "minute",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": true,
"allowrate": false,
"outputs": 1,
"_mcu": {
"mcu": false
},
"x": 650,
"y": 740,
"wires": [
[
"30814bf03b72c61a"
]
]
},
{
"id": "3751b8bd99ad401c",
"type": "mqtt in",
"z": "309997a2fd87c15a",
"name": "",
"topic": "switchbot-meter/vpd",
"qos": "2",
"datatype": "auto-detect",
"broker": "6b4a7676fb401863",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"_mcu": {
"mcu": false
},
"x": 170,
"y": 880,
"wires": [
[
"65e6ebef26b073cb",
"41da90ce6733a387"
]
]
},
{
"id": "65e6ebef26b073cb",
"type": "ui_gauge",
"z": "309997a2fd87c15a",
"name": "",
"group": "760af579a075de14",
"order": 5,
"width": 0,
"height": 0,
"gtype": "gage",
"title": "VPD",
"label": "kPa",
"format": "{{value}}",
"min": 0,
"max": "3",
"colors": [
"#a38800",
"#00b500",
"#ca3838"
],
"seg1": "0.8",
"seg2": "1.2",
"diff": true,
"className": "",
"_mcu": {
"mcu": false
},
"x": 370,
"y": 880,
"wires": []
},
{
"id": "41da90ce6733a387",
"type": "ui_chart",
"z": "309997a2fd87c15a",
"name": "",
"group": "760af579a075de14",
"order": 6,
"width": 0,
"height": 0,
"label": "VPD",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": 1,
"removeOlderPoints": "",
"removeOlderUnit": "604800",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"outputs": 1,
"useDifferentColor": false,
"className": "",
"_mcu": {
"mcu": false
},
"x": 370,
"y": 920,
"wires": [
[]
]
},
{
"id": "e62c077f9a42f751",
"type": "mqtt in",
"z": "309997a2fd87c15a",
"name": "",
"topic": "switchbot-meter/temp",
"qos": "2",
"datatype": "auto-detect",
"broker": "6b4a7676fb401863",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"_mcu": {
"mcu": false
},
"x": 180,
"y": 800,
"wires": [
[
"17774e9aa7f055e1"
]
]
},
{
"id": "8b8cb637a7f88b36",
"type": "mqtt in",
"z": "309997a2fd87c15a",
"name": "",
"topic": "switchbot-meter/hum",
"qos": "2",
"datatype": "auto-detect",
"broker": "6b4a7676fb401863",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"_mcu": {
"mcu": false
},
"x": 170,
"y": 840,
"wires": [
[
"56c0bc0765c33d5f"
]
]
},
{
"id": "17774e9aa7f055e1",
...
This file has been truncated, please download it to see its full contents.
SwitchBot Handler.json
JSONSet the Open Token and Secret Key obtained from the SwitchBot app on your smartphone, and use the results to obtain VPD.
[
{
"id": "40184443b1291b03",
"type": "tab",
"label": "SwitchBot Handler",
"disabled": false,
"info": "",
"env": [],
"_mcu": {
"mcu": false
}
},
{
"id": "929eda5930975394",
"type": "inject",
"z": "40184443b1291b03",
"name": "Initialize",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"_mcu": {
"mcu": false
},
"x": 140,
"y": 80,
"wires": [
[
"f566e82019707ab0",
"0e4706c85a456a5a",
"1ba070e60caf48c4",
"4d5f4eedb8a3afd6"
]
]
},
{
"id": "f566e82019707ab0",
"type": "change",
"z": "40184443b1291b03",
"name": "set flow.switchbot_open_token",
"rules": [
{
"t": "set",
"p": "switchbot_open_token",
"pt": "flow",
"to": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 410,
"y": 80,
"wires": [
[]
]
},
{
"id": "0e4706c85a456a5a",
"type": "change",
"z": "40184443b1291b03",
"name": "set flow.switchbot_secret_key",
"rules": [
{
"t": "set",
"p": "switchbot_secret_key",
"pt": "flow",
"to": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 410,
"y": 120,
"wires": [
[]
]
},
{
"id": "1ba070e60caf48c4",
"type": "change",
"z": "40184443b1291b03",
"name": "set flow.meter_status_url",
"rules": [
{
"t": "set",
"p": "meter_status_url",
"pt": "flow",
"to": "https://api.switch-bot.com/v1.1/devices/XXXXXXXXXXXXXXXX/status",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 390,
"y": 160,
"wires": [
[]
]
},
{
"id": "7da1c5a8eb03b1a6",
"type": "inject",
"z": "40184443b1291b03",
"name": "every 30 min.",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "1800",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"_mcu": {
"mcu": false
},
"x": 160,
"y": 300,
"wires": [
[
"658bb8ae3c357b0e"
]
]
},
{
"id": "658bb8ae3c357b0e",
"type": "change",
"z": "40184443b1291b03",
"name": "Meter GET",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{\"command\":\"on_bright\",\"parameter\":\"default\",\"commandType\":\"customize\"}",
"tot": "json"
},
{
"t": "set",
"p": "url",
"pt": "msg",
"to": "meter_status_url",
"tot": "flow"
},
{
"t": "set",
"p": "method",
"pt": "msg",
"to": "GET",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 350,
"y": 300,
"wires": [
[
"3e4a6222098fba1a"
]
]
},
{
"id": "3e4a6222098fba1a",
"type": "function",
"z": "40184443b1291b03",
"name": "Setup to call SwitchBotAPI",
"func": "const crypto = global.get('crypto');\n\nconst token = flow.get(\"switchbot_open_token\");\nconst secret = flow.get(\"switchbot_secret_key\");\n\nif (!token || !secret) {\n node.error(\"token or secret is undefined \");\n return null;\n}\n\nconst t = Date.now().toString();\nconst nonce = crypto.randomBytes(16).toString('base64').substring(0, 16);\nconst data = token + t + nonce;\nconst sign = crypto.createHmac('sha256', secret)\n .update(Buffer.from(data, 'utf-8'))\n .digest()\n .toString(\"base64\");\n\nmsg.token = token;\nmsg.sign = sign;\nmsg.t = t;\nmsg.nonce = nonce;\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": false
},
"x": 560,
"y": 300,
"wires": [
[
"787894589a193107"
]
]
},
{
"id": "787894589a193107",
"type": "http request",
"z": "40184443b1291b03",
"name": "Request to SwitchBot http",
"method": "use",
"ret": "txt",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [
{
"keyType": "Content-Type",
"keyValue": "",
"valueType": "other",
"valueValue": "application/json"
},
{
"keyType": "Authorization",
"keyValue": "",
"valueType": "msg",
"valueValue": "token"
},
{
"keyType": "other",
"keyValue": "sign",
"valueType": "msg",
"valueValue": "sign"
},
{
"keyType": "other",
"keyValue": "t",
"valueType": "msg",
"valueValue": "t"
},
{
"keyType": "other",
"keyValue": "nonce",
"valueType": "msg",
"valueValue": "nonce"
}
],
"_mcu": {
"mcu": false
},
"x": 810,
"y": 300,
"wires": [
[
"2a289686ca1a6971",
"fb0411288231bd79",
"d040c00760062bfd"
]
]
},
{
"id": "2a289686ca1a6971",
"type": "function",
"z": "40184443b1291b03",
"name": "get VPD",
"func": "let data = JSON.parse(msg.payload);\n\nlet temp = data.body.temperature;\nlet hum = data.body.humidity;\n\nlet e_s = 0.6108 * Math.exp((17.27 * temp) / (temp + 237.3));\nlet e_a = e_s * (hum / 100);\nlet vpd = e_s - e_a;\n\nmsg.payload = Number(vpd.toFixed(2));\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": false
},
"x": 1020,
"y": 340,
"wires": [
[
"7466fe9aea83a072",
"c980fccb66cf5dbc"
]
]
},
{
"id": "c980fccb66cf5dbc",
"type": "switch",
"z": "40184443b1291b03",
"name": "VPD >= 1.5 ",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "gte",
"v": "1.5",
"vt": "num"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"_mcu": {
"mcu": false
},
"x": 250,
"y": 400,
"wires": [
[
"a81032d966e9d076"
]
]
},
{
"id": "7466fe9aea83a072",
"type": "mqtt out",
"z": "40184443b1291b03",
"name": "",
"topic": "switchbot-meter/vpd",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "6b4a7676fb401863",
"_mcu": {
"mcu": false
},
"x": 1240,
"y": 340,
"wires": []
},
{
"id": "a81032d966e9d076",
"type": "change",
"z": "40184443b1291b03",
"name": "Plug turn on POST",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{\"command\":\"turnOn\",\"parameter\":\"default\",\"commandType\":\"command\"}",
"tot": "json"
},
{
"t": "set",
"p": "url",
"pt": "msg",
"to": "plug_commands_url",
"tot": "flow"
},
{
"t": "set",
"p": "method",
"pt": "msg",
"to": "POST",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 370,
"y": 460,
"wires": [
[
"062fdb824990a89b"
]
]
},
{
"id": "4d5f4eedb8a3afd6",
"type": "change",
"z": "40184443b1291b03",
"name": "set flow.plug_commands_url",
"rules": [
{
"t": "set",
"p": "plug_commands_url",
"pt": "flow",
"to": "https://api.switch-bot.com/v1.1/devices/XXXXXXXXXX/commands",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 400,
"y": 200,
"wires": [
[]
]
},
{
"id": "062fdb824990a89b",
"type": "function",
"z": "40184443b1291b03",
"name": "Setup to call SwitchBotAPI",
"func": "const crypto = global.get('crypto');\n\nconst token = flow.get(\"switchbot_open_token\");\nconst secret = flow.get(\"switchbot_secret_key\");\n\nif (!token || !secret) {\n node.error(\"token or secret is undefined \");\n return null;\n}\n\nconst t = Date.now().toString();\nconst nonce = crypto.randomBytes(16).toString('base64').substring(0, 16);\nconst data = token + t + nonce;\nconst sign = crypto.createHmac('sha256', secret)\n .update(Buffer.from(data, 'utf-8'))\n .digest()\n .toString(\"base64\");\n\nmsg.token = token;\nmsg.sign = sign;\nmsg.t = t;\nmsg.nonce = nonce;\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": false
},
"x": 620,
"y": 460,
"wires": [
[
"7df20d82d13ea040"
]
]
},
{
"id": "7df20d82d13ea040",
"type": "http request",
"z": "40184443b1291b03",
"name": "Request to SwitchBot http",
"method": "use",
"ret": "txt",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [
{
"keyType": "Content-Type",
"keyValue": "",
"valueType": "other",
"valueValue": "application/json"
},
{
"keyType": "Authorization",
"keyValue": "",
"valueType": "msg",
"valueValue": "token"
},
{
"keyType": "other",
"keyValue": "sign",
"valueType": "msg",
"valueValue": "sign"
},
{
"keyType": "other",
"keyValue": "t",
"valueType": "msg",
"valueValue": "t"
},
{
"keyType": "other",
"keyValue": "nonce",
"valueType": "msg",
"valueValue": "nonce"
}
],
"_mcu": {
"mcu": false
},
"x": 890,
"y": 460,
"wires": [
[
"61df1c73357945b7"
]
]
},
{
"id": "e69a543bdaa52ccd",
"type": "change",
"z": "40184443b1291b03",
"name": "Plug turn off POST",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{\"command\":\"turnOff\",\"parameter\":\"default\",\"commandType\":\"command\"}",
"tot": "json"
},
{
"t": "set",
"p": "url",
"pt": "msg",
"to": "plug_commands_url",
"tot": "flow"
},
{
"t": "set",
"p": "method",
"pt": "msg",
"to": "POST",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"_mcu": {
"mcu": false
},
"x": 370,
"y": 580,
"wires": [
[
"bbcb09cc57fb5311"
]
]
},
{
"id": "bbcb09cc57fb5311",
"type": "function",
"z": "40184443b1291b03",
"name": "Setup to call SwitchBotAPI",
"func": "const crypto = global.get('crypto');\n\nconst token = flow.get(\"switchbot_open_token\");\nconst secret = flow.get(\"switchbot_secret_key\");\n\nif (!token || !secret) {\n node.error(\"token or secret is undefined \");\n return null;\n}\n\nconst t = Date.now().toString();\nconst nonce = crypto.randomBytes(16).toString('base64').substring(0, 16);\nconst data = token + t + nonce;\nconst sign = crypto.createHmac('sha256', secret)\n .update(Buffer.from(data, 'utf-8'))\n .digest()\n .toString(\"base64\");\n\nmsg.token = token;\nmsg.sign = sign;\nmsg.t = t;\nmsg.nonce = nonce;\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": false
},
"x": 620,
"y": 580,
"wires": [
[
"cabc75c219df82b6"
]
]
},
{
"id": "cabc75c219df82b6",
"type": "http request",
"z": "40184443b1291b03",
"name": "Request to SwitchBot http",
"method": "use",
"ret": "txt",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [
{
"keyType": "Content-Type",
"keyValue": "",
"valueType": "other",
"valueValue": "application/json"
},
{
"keyType": "Authorization",
"keyValue": "",
"valueType": "msg",
"valueValue": "token"
},
{
"keyType": "other",
"keyValue": "sign",
"valueType": "msg",
"valueValue": "sign"
},
{
"keyType": "other",
"keyValue": "t",
"valueType": "msg",
"valueValue": "t"
},
{
"keyType": "other",
"keyValue": "nonce",
"valueType": "msg",
"valueValue": "nonce"
}
],
"_mcu": {
"mcu": false
},
"x": 890,
"y": 580,
"wires": [
[]
]
},
{
"id": "61df1c73357945b7",
"type": "delay",
"z": "40184443b1291b03",
"name": "",
"pauseType": "delay",
"timeout": "10",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"_mcu": {
"mcu": false
},
"x": 240,
"y": 520,
"wires": [
[
"e69a543bdaa52ccd"
]
]
},
{
"id": "bfb62571fc18db77",
"type": "inject",
"z": "40184443b1291b03",
"name": "for test",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"_mcu": {
"mcu": false
},
"x": 190,
"y": 460,
"wires": [
[
"a81032d966e9d076"
]
]
},
{
"id": "d040c00760062bfd",
"type": "function",
"z": "40184443b1291b03",
"name": "get temperature",
"func": "let data = JSON.parse(msg.payload);\n\nlet temp = data.body.temperature;\nlet hum = data.body.humidity;\n\nmsg.payload = Number(temp.toFixed(2));\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": false
},
"x": 1040,
"y": 260,
"wires": [
[
"46987fcdb41886e5"
]
]
},
{
"id": "fb0411288231bd79",
"type": "function",
"z": "40184443b1291b03",
"name": "get humidity",
"func": "let data = JSON.parse(msg.payload);\n\nlet temp = data.body.temperature;\nlet hum = data.body.humidity;\n\nmsg.payload = Number(hum.toFixed(2));\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": false
},
"x": 1030,
"y": 300,
"wires": [
[
"31b3653355001aa7"
]
]
},
{
"id": "31b3653355001aa7",
"type": "mqtt out",
"z": "40184443b1291b03",
"name": "",
"topic": "switchbot-meter/hum",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "6b4a7676fb401863",
"_mcu": {
"mcu": false
},
"x": 1240,
"y": 300,
"wires": []
},
{
"id": "46987fcdb41886e5",
"type": "mqtt out",
"z": "40184443b1291b03",
"name": "",
"topic": "switchbot-meter/temp",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "6b4a7676fb401863",
"_mcu": {
"mcu": false
},
"x": 1240,
"y": 260,
"wires": []
},
{
"id": "6b4a7676fb401863",
"type": "mqtt-broker",
"name": "",
"broker": "000.000.000.000",
"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": "",
"_mcu": {
"mcu": false
}
}
]
Comments