mirror of
https://github.com/kerwincui/FastBee.git
synced 2025-09-26 20:31:12 +08:00
256 lines
8.3 KiB
C++
256 lines
8.3 KiB
C++
/*********************************************************************
|
||
* function: 用户自定义功能
|
||
* board: esp8266 core for arduino v3.0.2
|
||
* library: PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
|
||
* source: https://gitee.com/kerwincui/wumei-smart
|
||
* copyright: FastBee and kerwincui all rights reserved.
|
||
********************************************************************/
|
||
|
||
#include "User.h"
|
||
#define BUTTON 14 // 按键引脚
|
||
#define RELAY 12 // 继电器引脚
|
||
|
||
OneButton button;
|
||
// 按钮单击事件
|
||
static void buttonClick();
|
||
// 按钮双击事件
|
||
static void buttonDoubleClick();
|
||
// 按钮长按事件
|
||
static void buttonLongPress();
|
||
|
||
// 初始化用户配置
|
||
void initUser() {
|
||
// 初始化按键为低电平,并添加单击、双击、长按事件
|
||
button = OneButton(BUTTON, true, true);
|
||
button.attachClick(buttonClick);
|
||
button.attachDoubleClick(buttonDoubleClick);
|
||
button.attachLongPressStart(buttonLongPress);
|
||
}
|
||
|
||
// Mqtt回调
|
||
void mqttCallback(char *topic, byte *payload, unsigned int length) {
|
||
blink();
|
||
printMsg("接收数据:");
|
||
String data = "";
|
||
for (int i = 0; i < length; i++) {
|
||
Serial.print((char)payload[i]);
|
||
data += (char)payload[i];
|
||
}
|
||
|
||
if (strcmp(topic, (prefix + sOtaTopic).c_str()) == 0) {
|
||
printMsg("订阅到设备升级指令...");
|
||
StaticJsonDocument<256> doc;
|
||
DeserializationError error = deserializeJson(doc, payload);
|
||
if (error) {
|
||
Serial.print(F("deserializeJson() failed: "));
|
||
Serial.println(error.f_str());
|
||
return;
|
||
}
|
||
String newVersion = doc["version"];
|
||
String downloadUrl = doc["downloadUrl"];
|
||
printMsg("固件版本:" + newVersion);
|
||
printMsg("下载地址:" + downloadUrl);
|
||
} else if (strcmp(topic, (prefix + sInfoTopic).c_str()) == 0) {
|
||
printMsg("订阅到设备信息...");
|
||
// 发布设备信息
|
||
publishInfo();
|
||
} else if (strcmp(topic, (prefix + sNtpTopic).c_str()) == 0) {
|
||
printMsg("订阅到NTP时间...");
|
||
StaticJsonDocument<256> doc;
|
||
DeserializationError error = deserializeJson(doc, payload);
|
||
if (error) {
|
||
Serial.print(F("deserializeJson() failed: "));
|
||
Serial.println(error.f_str());
|
||
return;
|
||
}
|
||
// 计算设备当前时间:(${serverRecvTime} + ${serverSendTime} + ${deviceRecvTime} - ${deviceSendTime}) / 2
|
||
float deviceSendTime = doc["deviceSendTime"];
|
||
float serverSendTime = doc["serverSendTime"];
|
||
float serverRecvTime = doc["serverRecvTime"];
|
||
float deviceRecvTime = millis();
|
||
float now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2;
|
||
printMsg("当前时间:" + String(now, 0));
|
||
} else if (strcmp(topic, (prefix + sPropertyTopic).c_str()) == 0 || strcmp(topic, (prefix + sPropertyOnline).c_str()) == 0) {
|
||
printMsg("订阅到属性指令...");
|
||
processProperty(data);
|
||
} else if (strcmp(topic, (prefix + sFunctionTopic).c_str()) == 0 || strcmp(topic, (prefix + sFunctionOnline).c_str()) == 0) {
|
||
printMsg("订阅到功能指令...");
|
||
processFunction(data);
|
||
} else if (strcmp(topic, (prefix + sMonitorTopic).c_str()) == 0) {
|
||
printMsg("订阅到实时监测指令...");
|
||
StaticJsonDocument<128> doc;
|
||
DeserializationError error = deserializeJson(doc, payload);
|
||
if (error) {
|
||
Serial.print(F("deserializeJson() failed: "));
|
||
Serial.println(error.f_str());
|
||
return;
|
||
}
|
||
monitorCount = doc["count"];
|
||
monitorInterval = doc["interval"];
|
||
}
|
||
}
|
||
|
||
// 随机生成监测值
|
||
String randomPropertyData() {
|
||
// 匹配云端定义的监测数据,随机数代替监测值
|
||
float randFloat = 0;
|
||
int randInt = 0;
|
||
StaticJsonDocument<1024> doc;
|
||
JsonObject objTmeperature = doc.createNestedObject();
|
||
objTmeperature["id"] = "light_current";
|
||
randFloat = random(1000, 3000);
|
||
objTmeperature["value"] = (String)(randFloat / 100);
|
||
objTmeperature["remark"] = (String)millis();
|
||
|
||
JsonObject objHumidity = doc.createNestedObject();
|
||
objHumidity["id"] = "humidity";
|
||
randFloat = random(3000, 6000);
|
||
objHumidity["value"] = (String)(randFloat / 100);
|
||
objHumidity["remark"] = (String)millis();
|
||
|
||
JsonObject objCo2 = doc.createNestedObject();
|
||
objCo2["id"] = "co2";
|
||
randInt = random(400, 1000);
|
||
objCo2["value"] = (String)(randInt);
|
||
objCo2["remark"] = (String)millis();
|
||
|
||
JsonObject objBrightness = doc.createNestedObject();
|
||
objBrightness["id"] = "brightness";
|
||
randInt = random(1000, 10000);
|
||
objBrightness["value"] = (String)(randInt);
|
||
objBrightness["remark"] = (String)millis();
|
||
|
||
printMsg("模拟监测数据值:");
|
||
serializeJson(doc, Serial);
|
||
String output;
|
||
serializeJson(doc, output);
|
||
return output;
|
||
}
|
||
|
||
// 物模型-属性处理
|
||
void processProperty(String msg) {
|
||
StaticJsonDocument<1024> doc;
|
||
DeserializationError error = deserializeJson(doc, msg);
|
||
if (error) {
|
||
Serial.print(F("deserializeJson() failed: "));
|
||
Serial.println(error.f_str());
|
||
return;
|
||
}
|
||
for (JsonObject object : doc.as<JsonArray>()) {
|
||
// 匹配云端定义的属性(不包含属性中的监测数据)
|
||
const char *id = object["id"];
|
||
const char *value = object["value"];
|
||
printMsg((String)id + ":" + (String)value);
|
||
}
|
||
// 最后发布属性,服务端订阅存储(重要)
|
||
publishProperty(msg);
|
||
}
|
||
|
||
// 物模型-功能处理
|
||
void processFunction(String msg) {
|
||
StaticJsonDocument<1024> doc;
|
||
DeserializationError error = deserializeJson(doc, msg);
|
||
if (error) {
|
||
Serial.print(F("deserializeJson() failed: "));
|
||
Serial.println(error.f_str());
|
||
return;
|
||
}
|
||
for (JsonObject object : doc.as<JsonArray>()) {
|
||
// 匹配云端定义的功能
|
||
const char *id = object["id"];
|
||
const char *value = object["value"];
|
||
if (strcmp(id, "light_switch") == 0) {
|
||
printMsg("开关 switch:" + (String)value);
|
||
if (strcmp(value, "1") == 0) {
|
||
// 打开继电器
|
||
relayStatus(true);
|
||
} else if (strcmp(value, "0") == 0) {
|
||
// 关闭继电器
|
||
relayStatus(false);
|
||
}
|
||
} else if (strcmp(id, "gear") == 0) {
|
||
printMsg("档位 gear:" + (String)value);
|
||
} else if (strcmp(id, "light_color") == 0) {
|
||
printMsg("灯光颜色 light_color:" + (String)value);
|
||
} else if (strcmp(id, "message") == 0) {
|
||
printMsg("屏显消息 message:" + (String)value);
|
||
} else if (strcmp(id, "report_monitor") == 0) {
|
||
int number = atoi(value);
|
||
number > 10 ? number = 10 : number;
|
||
for (int i = 0; i < number; i++) {
|
||
Serial.println(number);
|
||
String msg = randomPropertyData();
|
||
printMsg("订阅到上报监测数据指令,上报数据:");
|
||
printMsg(msg);
|
||
publishProperty(msg);
|
||
delay(1000);
|
||
}
|
||
}
|
||
}
|
||
// 最后发布功能,服务端订阅存储(重要)
|
||
publishFunction(msg);
|
||
}
|
||
|
||
// 物模型-事件上传
|
||
void processEvent() {
|
||
// 匹配云端的事件
|
||
StaticJsonDocument<512> doc;
|
||
JsonObject objTmeperature = doc.createNestedObject();
|
||
objTmeperature["id"] = "height_temperature";
|
||
objTmeperature["value"] = "40";
|
||
objTmeperature["remark"] = "温度过高警告";
|
||
|
||
JsonObject objException = doc.createNestedObject();
|
||
objException["id"] = "exception";
|
||
objException["value"] = "异常消息,消息内容XXXXXXXX";
|
||
objException["remark"] = "设备发生错误";
|
||
|
||
printMsg("发布事件:");
|
||
serializeJson(doc, Serial);
|
||
String output;
|
||
serializeJson(doc, output);
|
||
|
||
// 最后发布功能,服务端订阅存储(重要)
|
||
publishEvent(output);
|
||
}
|
||
|
||
//打开继电器A
|
||
void relayStatus(bool status) {
|
||
pinMode(RELAY, OUTPUT);
|
||
if (status) {
|
||
digitalWrite(RELAY, HIGH);
|
||
} else {
|
||
digitalWrite(RELAY, LOW);
|
||
}
|
||
}
|
||
|
||
// 按钮单击事件
|
||
static void buttonClick() {
|
||
printMsg("检测到按键单击,打开继电器");
|
||
relayStatus(true);
|
||
// 匹配云端定义的开关,格式如:[{"id":"switch","value":"1"}]
|
||
String msg = "[{\"id\":\"switch\",\"value\":\"1\"}]";
|
||
publishProperty(msg);
|
||
}
|
||
|
||
// 按钮双击事件
|
||
static void buttonDoubleClick() {
|
||
printMsg("检测到按键双击,关闭继电器");
|
||
relayStatus(false);
|
||
// 匹配云端定义的开关,格式如:[{"id":"switch","value":"0"}]
|
||
String msg = "[{\"id\":\"switch\",\"value\":\"0\"}]";
|
||
publishProperty(msg);
|
||
}
|
||
|
||
// 按钮长按事件,进入配网模式
|
||
static void buttonLongPress() {
|
||
printMsg("检测到按键长按");
|
||
if (isApMode) {
|
||
printMsg("设备重启...");
|
||
ESP.restart();
|
||
} else {
|
||
printMsg("开始AP配网");
|
||
startApConfig();
|
||
}
|
||
}
|