安信可ESP32点灯APP自动浇花和天气空气质量
本帖最后由 ht256929 于 2022-1-17 10:51 编辑本人是完全不懂C语言,大部分都是借鉴各位大佬的,没有时间和精力去学习C语言,能达到自己的使用效果就好。非常感谢各位大佬。上面是APP界面,下面是代码。错误地方多多指正新手#define BLINKER_WIFI
#include <ArduinoJson.h>//此库需要放在Blinker.h库前不然会出现编译错误
#include <Blinker.h>
#include <DHT.h>
#define JDQ 12 //继电器信号引脚
#define TR 35 //土壤传感器信号引脚
#define DHTPIN 25 //温湿度传感器信号引脚
#define DHTTYPE DHT11 //温湿度传感器类型
#define ran "SliderKey"
DHT dht(DHTPIN, DHTTYPE);
char auth[] = ".................";
/*********************************************************************************************************
新建数据类型组件对象,作用:将数据传输到手机blinker app
*********************************************************************************************************/
BlinkerNumber TRZ("TRZ"); //blinker-app创建名为TRZ的数据模块显示土壤值
BlinkerNumber HUMI("humi");//blinker-app创建名为humi的数据模块显示湿度值
BlinkerNumber TEMP("temp");//blinker-app创建名为temp的数据模块显示温度值
BlinkerNumber RSS("rssi");//blinker-app创建名为huashi的数据模块显示华式温度
BlinkerNumber LU("ludian");//blinker-app创建名为ludian的数据模块显示露点值
BlinkerNumber HUMISJ("humi9");//blinker-app创建名为humi9的图表显示湿度历史数据
BlinkerNumber TEMPSJ("temp9");//blinker-app创建名为temp9的图标显示温度历史数据
BlinkerNumber TRZSJ("TRZ9");//blinker-app创建名为TRZ9的图标显示土壤值历史数据
BlinkerNumber CI("ci");
BlinkerSlider Slider1("ran");
BlinkerButton Button1("zhaoming");
BlinkerButton Button2("jiaoshui");
BlinkerText TURANG("turang");
BlinkerText BENG("beng");
BlinkerText YUNHANG("yunhang");
BlinkerText CITY("city");
BlinkerText WURAN("wuran");
BlinkerText PM("pm");
BlinkerText BTQX("btqx");
BlinkerText WSQX("wsqx");
BlinkerText BTWD("btwd");
BlinkerText WSWD("wswd");
BlinkerText BTFX("btfx");
/*********************************************************************************************************变量*********************************************************************************************************/
//天气
String city1, level1, pm251, forecasts_0_date1, forecasts_0_week1, forecasts_0_dayweather1, forecasts_0_nightweather1, forecasts_0_daytemp1, forecasts_0_nighttemp1, forecasts_0_daywind1, forecasts_0_nightwind1, forecasts_0_daypower1, forecasts_0_nightpower1;//天气及空气质量
int a3 = 0; //用于间隔更新天气
bool first_label = false; //开机标签,开机第一时间更新天气信息
//土壤值读取
uint16_t LeiJi;//存储土壤累计读取数值
uint16_t TRzhi;//土壤值
uint16_t Amin = 60700; //土壤最小校准值
uint16_t Amax = 24200; //土壤最大校准值
//空气温湿度
floatn1 = 0.0, n2 = 0.0,t = 0, h = 0, rssi = 0;
double humi_read = 0, temp_read = 0, huashi_read = 0, ludian_read = 0, ci_read = 0;
//判断是否浇花
String turang_read, beng_read, T, B;
int ci = 0, zhi = 40;
//配网设置
int count = 0; //时间计数
bool WIFI_Status = true; //WIFI状态标志位
/********************************************************************************************************* Esptouch配网*********************************************************************************************************/
void blinkerConnect()//网络链接
{
WiFi.begin();//没有这行命令ESP32断电重启不会自动连接WIFI
BLINKER_LOG("\r\n正在连接WIFI...");
while (WiFi.status() != WL_CONNECTED) //判断是否连接WIFI成功
{
if (WIFI_Status)
{
BLINKER_LOG("WIFI连接中");
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
count++;
if (count >= 30) //5s
{
WIFI_Status = false;
BLINKER_LOG("WiFi连接失败,请用ESPtouch进行配网");
}
}
else
{
smartConfig();
}
}
BLINKER_LOG("连接成功IP地址为:", WiFi.localIP());
}
void smartConfig()//ESPtouch配网
{
WiFi.mode(WIFI_STA);//设置STA模式
BLINKER_LOG("\r\nWait for Smartconfig...");
WiFi.beginSmartConfig();//开始SmartConfig,等待手机端发出用户名和密码
while (1)
{
BLINKER_LOG("等待配网中");
digitalWrite(LED_BUILTIN, HIGH); //指示灯闪烁
delay(1000);
digitalWrite(LED_BUILTIN, LOW); //指示灯闪烁
delay(1000);
if (WiFi.smartConfigDone()) //配网成功,接收到SSID和密码
{
BLINKER_LOG("配网成功");
BLINKER_LOG("SSID:", WiFi.SSID().c_str());
BLINKER_LOG("PSK:", WiFi.psk().c_str());
break;
}
}
}
/********************************************************************************************************* 土壤值读取*********************************************************************************************************/
void turang()//土壤值读取
{
uint8_t i;
for (i = 0; i < 20; i++) { //连续取采集多个样本,缺点AD读取会有延迟
LeiJi = analogRead(TR); //读取土壤湿度传感器的值
Blinker.delay(100);
}
TRzhi = 0; //平均所有值
for (i = 0; i < 20; i++) {
TRzhi += LeiJi;
}
//Serial.println(TRzhi);//串口输出土壤值
TRzhi = map(TRzhi, Amin, Amax, 0, 100); //校准值转换成0-100
TRzhi = constrain(TRzhi, 0, 100); //将传感器值的范围限制在0到100之间
Blinker.delay(1000);
}
/*********************************************************************************************************室内温度值读取*********************************************************************************************************/
// 快速计算露点,速度是5倍dewPoint()
double dewPointFast(double celsius, double humidity)
{
double a = 17.271;
double b = 237.7;
double temp = (a * celsius) / (b + celsius) + log(humidity / 100);
double Td = (b * temp) / (a - temp);
return Td;
}
void wenshidu()//空气温湿度值读取
{
float h = dht.readHumidity();
float t = dht.readTemperature();
float hic = dht.computeHeatIndex(t, h, false);
float n2 = (((9.0 / 5.0) * t + 32.0));//摄氏温度转为华式温度
float n1 = dewPointFast(dht.readTemperature(), dht.readHumidity());//计算露点
humi_read = h;//湿度值
temp_read = t;//温度值
huashi_read = n2;//华式温度
ludian_read = n1;//露点值
rssi = (WiFi.RSSI());//WIFI信号强度
Blinker.delay(1000);
}
/*********************************************************************************************************判断是否浇水*********************************************************************************************************/
void slider1_callback(int32_t value)//读取设定自动浇水阈值,初始值为40
{
BLINKER_LOG("get slider value: ", value);
zhi = value;
}
void gh() //读取的土壤值与设定的浇水阈值对比判断是否浇水
{
if ((TRzhi < zhi) && (temp_read < 36) && (humi_read < 75)) { //如果读取土壤值小于自动浇水阈值且温度小于36度湿度低于75%则给继电器高电平信号打开水泵浇水
digitalWrite(JDQ, HIGH); //给继电器输出高电平打开水泵
Blinker.println("土壤干旱,需要浇水");
ci++;
T = "土壤干旱";
B = "水泵打开";
Blinker.delay(3000);
}
else if ((TRzhi > zhi) && (humi_read < 75)) { //如果读取土壤值大于设定浇水阈值且湿度小于75%则给继电器低电平信号关闭水泵
digitalWrite(JDQ, LOW); //关闭LED灯
Blinker.println("土壤潮湿,不需要浇水");
T = "土壤湿润";
B = "水泵关闭";
Blinker.delay(3000);
}
else if (t > 36)//如果读取温度值大于36℃则给继电器低电平信号关闭水泵
{
digitalWrite(JDQ, LOW);
Blinker.println("温度过高,不适宜浇水");
T = "温度过高不适宜浇水";
B = "水泵关闭";
Blinker.delay(3000);
}
else if (humi_read > 75)//如果读取湿度值大于75%则给继电器低电平信号关闭水泵
{
digitalWrite(JDQ, LOW);
Blinker.println("空气湿度高,可能会下雨!");
T = "空气湿度高可能会下雨";
B = "水泵关闭";
Blinker.delay(3000);
}
}
/*********************************************************************************************************记录历史数据*********************************************************************************************************/
void dataStorage()//记录历史数据
{
Blinker.dataStorage("humi9", humi_read);
Blinker.dataStorage("temp9", temp_read);
Blinker.dataStorage("TRZ9", TRzhi);
}
void printlf() //打印调试信息
{
BLINKER_LOG("空气湿度:", humi_read, " %");
BLINKER_LOG("摄氏温度: ", temp_read, " *C");
BLINKER_LOG("华氏温度: ", huashi_read, " °F");
BLINKER_LOG("露点: ", ludian_read, " Td");
BLINKER_LOG("土壤湿度: ", TRzhi, " %");
BLINKER_LOG("浇水阈值: ", zhi, " %");
BLINKER_LOG("自动浇水次数:", ci, " 次");
BLINKER_LOG("当前土壤状态:", T, "");
BLINKER_LOG("当前水泵状态:", B, "");
BLINKER_LOG("当前WIFI信号强度:", rssi, "db");
}
/********************************************************************************************************* 手动浇水*********************************************************************************************************/
void button2_callback(const String & state)//手动浇水
{
BLINKER_LOG("get button state: ", state);
if (state == "on")
{
digitalWrite(JDQ, HIGH);
// 反馈开关状态
Button2.print("on");
B = "开始手动浇水";
}if (state == "off") //按照例程else if无法关闭
{
digitalWrite(JDQ, LOW);
// 反馈开关状态
Button2.print("off");
B = "停止手动浇水";
}
Blinker.delay(300);
}
void button1_callback(const String & state) //原计划设置光照补偿(无用改为系统指示灯开关)
{
BLINKER_LOG("get button state: ", state);
if (state == "on") {
digitalWrite(LED_BUILTIN, HIGH);
// 反馈开关状态
Button1.print("on");
BENG.print("系统指示灯开启");
} if (state == "off") {
digitalWrite(LED_BUILTIN, LOW);
// 反馈开关状态
Button1.print("off");
BENG.print("系统指示灯关闭");
}
Blinker.delay(300);
}
/*********************************************************************************************************系统运行时间*********************************************************************************************************/
String rts()
{
int rt = Blinker.runTime();
int r, e, f, s;
String fh;
Blinker.delay(100);
if (rt >= 86400) //天数
{ r = rt / 86400;
e = rt / 3600 - r * 24;
f = rt / 60 - r * 1440 - e * 60;
s = rt - r * 86400 - e * 3600 - f * 60;
}
else if (rt >= 3600)
{ r = 0;
e = rt / 3600;
f = rt / 60 - e * 60;
s = rt - e * 3600 - f * 60;
}
else
{ r = 0;
e = 0;
f = rt / 60;
s = rt - f * 60;
}
if (f == 0 & e == 0 & r == 0)
{
fh = String("") + s + "秒";
}
else if (r == 0 & e == 0 )
{
fh = String("") + f + "分" + s + "秒";
}
else if (r == 0)
{
fh = String("") + e + "小时" + f + "分" + s + "秒";
}
else
{
fh = String("") + r + "天" + e + "小时" + f + "分" + s + "秒";
}
return (fh);
}
/*********************************************************************************************************天气数据及空气数据读取*********************************************************************************************************/
void airData(const String & data) //空气质量
{
BLINKER_LOG("air: ", data);
const size_t capacity = JSON_OBJECT_SIZE(11) + 120;
DynamicJsonDocument doc(capacity);
DeserializationError error = deserializeJson(doc, data);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
return;
}
const char* city = doc["city"];
const char* updateTime = doc["updateTime"];
const char* aqi = doc["aqi"];
const char* level = doc["level"];
const char* pm25 = doc["pm25"];
const char* pm10 = doc["pm10"];
const char* SO2 = doc["SO2"];
const char* NO2 = doc["NO2"];
const char* CO = doc["CO"];
const char* O3 = doc["O3"];
city1 = city;
level1 = level;
pm251 = pm25;
BLINKER_LOG("城市:", city1);//1
BLINKER_LOG("更新时间:", updateTime);
BLINKER_LOG("aqi:", aqi);
BLINKER_LOG("污染程度:", level1); //2
BLINKER_LOG("pm25:", pm251);//3
BLINKER_LOG("pm10:", pm10);
BLINKER_LOG("SO2:", SO2);
BLINKER_LOG("NO2:", NO2);
BLINKER_LOG("CO:", CO);
BLINKER_LOG("O3:", O3);
}
void weatherForecastData(const String & data)//天气
{
BLINKER_LOG("weather: ", data);
const size_t capacity = JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(4) + 4 * JSON_OBJECT_SIZE(10) + 650;
DynamicJsonDocument doc(capacity);
DeserializationError error = deserializeJson(doc, data);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
return;
}
const char* city = doc["city"];
const char* province = doc["province"];
const char* updateTime = doc["updateTime"];
JsonArray forecasts = doc["forecasts"];
JsonObject forecasts_0 = forecasts;
const char* forecasts_0_date = forecasts_0["date"];
const char* forecasts_0_week = forecasts_0["week"];
const char* forecasts_0_dayweather = forecasts_0["dayweather"];
const char* forecasts_0_nightweather = forecasts_0["nightweather"];
const char* forecasts_0_daytemp = forecasts_0["daytemp"];
const char* forecasts_0_nighttemp = forecasts_0["nighttemp"];
const char* forecasts_0_daywind = forecasts_0["daywind"];
const char* forecasts_0_nightwind = forecasts_0["nightwind"];
const char* forecasts_0_daypower = forecasts_0["daypower"];
const char* forecasts_0_nightpower = forecasts_0["nightpower"];
forecasts_0_dayweather1 = forecasts_0_dayweather;
forecasts_0_nightweather1 = forecasts_0_nightweather;
forecasts_0_daytemp1 = forecasts_0_daytemp;
forecasts_0_nighttemp1 = forecasts_0_nighttemp;
forecasts_0_daywind1 = forecasts_0_daywind;
BLINKER_LOG("城市:", city);
BLINKER_LOG("更新时间:", updateTime);
BLINKER_LOG("时间:", forecasts_0_date);
BLINKER_LOG("星期:", forecasts_0_week);
BLINKER_LOG("白天天气现象:", forecasts_0_dayweather);//4
BLINKER_LOG("晚上天气现象:", forecasts_0_nightweather);//5
BLINKER_LOG("白天温度:", forecasts_0_daytemp);//6
BLINKER_LOG("晚上温度:", forecasts_0_nighttemp);//7
BLINKER_LOG("白天风向:", forecasts_0_daywind);//8
BLINKER_LOG("晚上风向:", forecasts_0_nightwind);
BLINKER_LOG("白天风力:", forecasts_0_daypower);
BLINKER_LOG("晚上风力:", forecasts_0_nightpower);
}
void jggxtq() //时间段判断更新
{
int8_t hour = Blinker.hour();//时
int8_t min= Blinker.minute();//分
BLINKER_LOG("判断是否更新天气");
if (hour == 8) {
a3 = 8;
}
if (hour == 10) {
a3 = 10;
}
if (hour == 14) {
a3 = 14;
}
if (hour == 16) {
a3 = 16;
}
if (hour == 18) {
a3 = 18;
}
if (hour == 21) {
a3 = 21;
}
if (hour == 20) {
a3 = 20;
}
if (hour == 22) {
a3 = 22;
}
if (hour == 23) {
a3 = 23;
}
if (hour == a3) {
if (min == 0) {
BLINKER_LOG("开始更新天气");
Blinker.weatherForecast();
Blinker.air();
Blinker.delay(4000);
}
}
}
/*********************************************************************************************************心跳发送数据到手机APP*********************************************************************************************************/
void heartbeat()//心跳 发送数据到手机APP
{
HUMI.print(humi_read);//湿度
TEMP.print(temp_read);//温度
TRZ.print(TRzhi);//土壤值
RSS.print(rssi);//华式温度值
LU.print(ludian_read);//露点值
CI.print(ci_read);//水泵浇水次数
TURANG.print(T);//土壤状态
BENG.print(B);//水泵状态
YUNHANG.print(rts());//显示系统运行时间
Slider1.print(zhi);//浇水阈值
CITY.print(city1);//显示城市
WURAN.print(level1);//显示污染程度
PM.print(pm251);//显示PM值
BTQX.print(forecasts_0_dayweather1);//白天天气气象
WSQX.print(forecasts_0_nightweather1); //晚上天气气象
BTWD.print(forecasts_0_daytemp1);//白天温度
WSWD.print(forecasts_0_nighttemp1);//晚上温度
BTFX.print(forecasts_0_daywind1);//白天风向
}
void setup()
{
first_label = true;
pinMode (JDQ, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(115200);//打开串口波特率设置115200
BLINKER_DEBUG.debugAll();//开启调试
BLINKER_DEBUG.stream(Serial);
Blinker.begin(auth, WiFi.SSID().c_str(), WiFi.psk().c_str()); //根据配网得到的WIFI信息和设备秘钥,连接到Blinker云
blinkerConnect();//连接网络
Blinker.attachHeartbeat(heartbeat);
Blinker.attachDataStorage(dataStorage);//开启历史数据
Blinker.attachAir(airData);//注册空气质量
Blinker.attachWeatherForecast(weatherForecastData);//注册天气
Slider1.attach(slider1_callback);
Button1.attach(button1_callback);
Button2.attach(button2_callback);
dht.begin();
}
void loop()
{
Blinker.run();
//通电更新天气及空气质量
if ((first_label == true)) {
if (Blinker.init())
{
Blinker.weatherForecast();
Blinker.air();
Blinker.delay(2000);
first_label = false;
}
}
turang();
wenshidu();
Blinker.delay(2000);
gh();
printlf();
ci_read = ci;//浇水次数
jggxtq();
}
Blinker APP界面配置{¨version¨¨2.0.0¨¨config¨{¨headerColor¨¨transparent¨¨headerStyle¨¨dark¨¨background¨{¨img¨¨assets/img/bg/1.jpg¨}}¨dashboard¨|{¨type¨¨num¨¨t0¨¨土壤湿度¨¨ico¨¨fal fa-question¨¨clr¨¨#00A90C¨¨min¨É¨max¨¢1c¨uni¨´%´¨bg¨Ê¨cols¨Í¨rows¨Ë¨key¨¨TRZ¨´x´É´y´É¨lstyle¨Ë}{ßBßCßD¨室内湿度¨ßFßGßH¨#6010E4¨ßJÉßKº0ßL´%´ßMÊßNÍßOËßP¨humi¨´x´Í´y´ÉßRË}{ßBßCßD¨室内温度¨ßF¨fal fa-thermometer-three-quarters¨ßH¨#EA0909¨ßJÉßKº0ßL´℃´ßMËßNËßOËßP¨temp¨´x´Ë´y´Ë}{ßBßCßD¨信号强度¨ßF¨fal fa-signal-4¨ßHßIßJÉßKº0ßL¨Dbm¨ßMËßNËßOËßP¨rssi¨´x´Ï´y´ËßRÉ}{ßBßCßD¨空气露点¨ßF¨fal fa-cloud-hail¨ßH¨#389BEE¨ßJÉßKº0ßL¨Td¨ßMËßNËßOËßP¨ludian¨´x´Í´y´ËßRÉ}{ßB¨deb¨¨mode¨ÉßMÉßNÑßOÌßP¨debug¨´x´É´y´¤E}{ßB¨ran¨ßD¨自动浇水阀值¨ßH¨#076EEF¨ßKº0ßJÉßMËßNÑßOËßPßl´x´É´y´Ñ}{ßBßCßD¨自动浇水¨ßF¨fal fa-repeat-alt¨ßHßnßJÉßK¢2bIßL´次´ßMËßNËßOËßP¨ci¨´x´É´y´ËßRÉ}{ßB¨tex¨ßD¨土壤是否潮湿¨¨t1¨´´¨size¨´´ßMËßF¨fal fa-flower-tulip¨ßNÍßOÊßP¨turang¨´x´Ë´y´¤BßRÊ}{ßBßrßD¨水泵状态¨ßt´´ßu´´ßMËßF¨fal fa-fan¨ßNÍßOÊßP¨beng¨´x´Ë´y´¤AßRÊ}{ßB¨btn¨ßF¨fal fa-lightbulb-on¨ßjÊßD¨系统指示灯¨ßt¨文本2¨ßMËßNËßOËßP¨zhaoming¨´x´É´y´¤AßRÉßH¨#FBA613¨}{ßBß10ßF¨fal fa-faucet-drip¨ßjÊßD¨手动浇水¨ßtß13ßMËßNËßOËßP¨jiaoshui¨´x´Ï´y´¤AßRÉßHßn}{ßBßrßD´´ßt¨系统运行时间¨ßu´20´ßMËßF¨fal fa-plug¨ßNÑßOËßP¨yunhang¨´x´É´y´¤CßRÏßHßI}{ßBßrßD´´ßt¨当前城市¨ßu´18´ßMËßF¨fal fa-route¨ßNËßOËßP¨city¨´x´É´y´ÍßRËßHßI}{ßBßrßD´´ßt¨PM2.5¨ßu´18´ßMËßF¨fal fa-fog¨ßNËßOËßP´pm´´x´Ë´y´ÍßHßTßRË}{ßBßrßD´´ßt¨污染程度¨ßu´18´ßMËßF¨fal fa-clouds¨ßNËßOËßP¨wuran¨´x´Í´y´ÍßRËßHßX}{ßBßrßD´´ßt¨白天风向¨ßu´18´ßMËßF¨fal fa-smoke¨ßNËßOËßP¨btfx¨´x´Ï´y´ÍßHßnßRË}{ßBßrßD´´ßt¨白天天气¨ßu´18´ßMËßF¨fal fa-sun¨ßNËßOËßP¨btqx¨´x´É´y´ÏßRËßHß15}{ßBßrßD´´ßt¨晚上天气¨ßu´18´ßMËßF¨fal fa-moon-stars¨ßNËßOËßP¨wsqx¨´x´Ë´y´ÏßRËßHßT}{ßBßrßD´´ßt¨白天温度¨ßu´20´ßMËßF¨fal fa-house-day¨ßNËßOËßP¨btwd¨´x´Í´y´ÏßRËßHßI}{ßBßrßD´´ßt¨晚上温度¨ßu´20´ßMËßF¨fal fa-house-night¨ßNËßOËßP¨wswd¨´x´Ï´y´ÏßRËßH¨#595959¨}÷¨actions¨|÷¨triggers¨|÷´rt´|÷}
本帖最后由 ht256929 于 2022-1-17 10:45 编辑
1361139229 发表于 2022-1-16 10:14
兄弟,需要哪些硬件设备之类的能否罗列一下出来,感谢
我用的是下面的设备
安信可ESP32 NodeMCU-32S CH340
土壤湿度传感器:电容式土壤湿度传感器模块Molsture Sensor V1.2
温湿度传感器:DHT11
继电器;可以调高低电平触发的1路继电器
水泵;直流电机小潜水泵 2.5V-6V
电源供电是直接用手机充电器供电的,水泵的电源是单独的一个手机充电器供电。
天气及空气质量是用的Blinker请求返回的数据
继电器信号脚插在 esp32的 12脚
土壤湿度传感器信号脚插在esp32的 35脚
温湿度传感器信号脚插在esp32的 35脚
兄弟,需要哪些硬件设备之类的能否罗列一下出来,感谢
这只用了一个模拟脚,8266应该也可以吧? longjunling 发表于 2022-1-21 15:32
这只用了一个模拟脚,8266应该也可以吧?
8266可以 界面配置怎么搞?我复制粘贴过去没用
界面配置怎么搞?我复制粘贴过去没用 const size_t capacity = JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(4) + 4 * JSON_OBJECT_SIZE(10) + 650;
请问,这个空间的计算,可有什么依据? 我一直搞不懂 1361139229 发表于 2022-1-23 21:01
界面配置怎么搞?我复制粘贴过去没用
你依这个配置数据 文本的控件试试
Highnose 发表于 2022-1-23 21:35
const size_t capacity = JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(4) + 4 * JSON_OBJECT_SIZE(10) + 650;
...
https://www.arduino.cn/forum.php?mod=viewthread&tid=90648&highlight=json
具体我没仔细研究,因为我也不懂C语言