#include <ArduinoJson.h>
#include "PubSubClient.h"
#include <WiFi.h>
//要连接的自己手机WiFi热点名、WiFi热点密码
#define WIFI_AP "Wokwi-Guest"
#define WIFI_PASSWORD ""
//要修改以下三个变量的内容:根据自己在ThingsBoard服务器上创建的设备填写
//clientId: 添加设备时的客户端ID
//tenantName: 用户名
//tenantPassword: 密码
const char* clientId="first";
const char* tenantName="first";
const char* tenantPassword="first";
#define lightPin 2
#define lightSensor A0
int counter =0;
//不要修改!这是CPS技术与创客实践课程的物联网云服务器网址、端口号
char thingsboardServer[] = "thingsboard.cloud";
int port = 1883;
WiFiClient wifiClient;
PubSubClient client(wifiClient);
int status = WL_IDLE_STATUS;
//灯初始状态是熄灭的
boolean lightState = false;
void setup() {
Serial.begin(115200);
// 设置灯连接的引脚2作为输出引脚
pinMode(lightPin, OUTPUT);
delay(10);
InitWiFi();
client.setServer( thingsboardServer, port );
client.setCallback(on_message);
}
void loop() {
if ( !client.connected() ) {
reconnect();
}
client.loop();
if(counter>=20){
counter=0;
/*2秒钟上报1次传感器数据*/
int value = analogRead(lightSensor);
Serial.print("Light sensor:");
Serial.println(value);
// 准备JSON格式的数据payload
StaticJsonBuffer<200> jsonBuffer;
JsonObject& data = jsonBuffer.createObject();
data["sensor"] = value;
char payload[256];
data.printTo(payload, sizeof(payload));
String strPayload = String(payload);
Serial.print("light sensor: ");
Serial.println(strPayload);
client.publish("v1/devices/me/telemetry", strPayload.c_str());
} else {
counter++;
delay(100);
}
}
// 回调函数:当从服务器收到PUBLISH消息时触发
void on_message(char* topic, byte* payload, unsigned int length) {
Serial.println("On message");
char json[length + 1];
strncpy (json, (char*)payload, length);
json[length] = '\0';
Serial.print("Topic: ");
Serial.println(topic);
Serial.print("Message: ");
Serial.println(json);
// Decode JSON request
StaticJsonBuffer<200> jsonBuffer;
JsonObject& data = jsonBuffer.parseObject((char*)json);
if (!data.success())
{
Serial.println("parseObject() failed");
return;
}
// 检查请求的方法method
String methodName = String((const char*)data["method"]);
if (methodName.equals("getLightStatus")) {
// 应答灯状态
String responseTopic = String(topic);
responseTopic.replace("request", "response");
client.publish(responseTopic.c_str(), get_light_status().c_str());
} else if (methodName.equals("setLightStatus")) {
// 更新灯状态并应答
set_light_status(data["params"]["enabled"]);
String responseTopic = String(topic);
responseTopic.replace("request", "response");
client.publish(responseTopic.c_str(), get_light_status().c_str());
client.publish("v1/devices/me/attributes", get_light_status().c_str());
}
}
String get_light_status() {
// 准备JSON格式的数据payload
StaticJsonBuffer<200> jsonBuffer;
JsonObject& data = jsonBuffer.createObject();
data["enabled"] = lightState;
char payload[256];
data.printTo(payload, sizeof(payload));
String strPayload = String(payload);
Serial.print("Turn light: ");
Serial.println(strPayload);
return strPayload;
}
void set_light_status(boolean enabled) {
// 更新灯
digitalWrite(lightPin, enabled);
// 更新灯状态变量
lightState = enabled;
}
void InitWiFi() {
Serial.println("Connecting to AP ...");
// 连接WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_AP, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected to AP");
}
void reconnect() {
// 循环直到重新连接成功
while (!client.connected()) {
status = WiFi.status();
if ( status != WL_CONNECTED) {
WiFi.begin(WIFI_AP, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected to AP");
}
Serial.print("Connecting to IoT Server ...");
// 连接物联网云服务器,使用(clientId, username, password)
if ( client.connect(clientId, tenantName, tenantPassword) ) {
Serial.println( "[DONE]" );
// 订阅RPC请求
client.subscribe("v1/devices/me/rpc/request/+");
// 发送当前灯状态
Serial.println("Sending current light status ...");
client.publish("v1/devices/me/attributes", get_light_status().c_str());
} else {
Serial.print( "[FAILED] [ rc = " );
Serial.print( client.state() );
Serial.println( " : retrying in 5 seconds]" );
// 重连前,等待5秒
delay( 5000 );
}
}
}