Administrator
发布于 2025-12-03 / 10 阅读
0
0

一个ESP连接Thingsboard的实例,发送并接受数据

实验的效果

本实验用ESP32发送模拟温度给Thingsboard,Thingsboard接受到温度后进行判断,如果温度大于30度,则返回一个指令给ESP32,ESP获得指令后,点亮板载LED等。

实验所需

  1. Arduino 软件

  2. ESP32 板卡

  3. thingsboard平台,使用本站的io.huakaka.com

  4. 规则链库的Json文件。tutorial_of_rpc_call_request.json

实验步骤

  1. 登录io.huakak.com

  2. 点击左侧实体->设备标签,复制访问令牌,备用3. 在Arduino里面,连接到ESP板卡,写入下面的代码,修改wifi信息,复制访问令牌,并粘贴到DEVICE_TOKEN处。编译运行。

Arduino代码

    ///LED根据产生的温度点亮或者熄灭,》=35度则点亮,否则熄灭
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

// 基础配置(替换为你的信息)
const char* WIFI_SSID = "wifi名称在这里";
const char* WIFI_PWD = "WiFi密码在这里";
const char* TB_IP = "47.98.193.197";
const uint16_t TB_PORT = 1883;//1883
const char* DEVICE_TOKEN = "uhiAgXTbAURp8lfXbzYi"//输入设备访问令牌;

// 硬件定义
const int LED_PIN = 2; // ESP32板载LED
WiFiClient espClient;
PubSubClient client(espClient);

// 全局变量:存储当前随机温度
float currentTemp;

// WiFi连接(带详细打印)
void connectWiFi() {
  Serial.print("正在连接WiFi: ");
  Serial.println(WIFI_SSID);
  
  WiFi.begin(WIFI_SSID, WIFI_PWD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("\nWiFi连接成功!");
  Serial.print("ESP32 IP地址: ");
  Serial.println(WiFi.localIP()); // 打印ESP32的IP端口相关信息
  Serial.print("MQTT服务器地址: ");
  Serial.print(TB_IP);
  Serial.print(":");
  Serial.println(TB_PORT); // 打印ThingsBoard MQTT端口
}

// MQTT重连+订阅RPC主题(带详细打印)
void reconnectMQTT() {
  while (!client.connected()) {
    Serial.print("尝试连接MQTT服务器: ");
    Serial.print(TB_IP);
    Serial.print(":");
    Serial.println(TB_PORT);
    
    // 连接MQTT:客户端ID=ESP32,用户名=设备令牌,密码空
    if (client.connect("ESP32-RPC-Client", DEVICE_TOKEN, "")) {
      Serial.println("MQTT连接成功!");
      // 订阅RPC请求主题(核心)
      client.subscribe("v1/devices/me/rpc/request/+");
      Serial.println("已订阅RPC主题: v1/devices/me/rpc/request/+");
    } else {
      Serial.print("MQTT连接失败,错误码: ");
      Serial.println(client.state());
      Serial.println("5秒后重试...");
      delay(5000);
    }
  }
}

// 生成30~37℃的随机温度(保留1位小数)
float generateRandomTemp() {
  // 初始化随机数种子(基于系统运行时间,避免重复)
  randomSeed(millis());
  // 生成300~370的整数 → 除以10得到30.0~37.0的浮点数
  int tempInt = random(300, 371);
  return (float)tempInt / 10.0;
}

// 根据温度控制LED(>35℃亮,≤35℃灭)
void controlLedByTemp(float temp) {
  if (temp > 35.0) {
    digitalWrite(LED_PIN, HIGH);
    Serial.printf("当前温度: %.1f℃ > 35℃ → LED点亮\n", temp);
  } else {
    digitalWrite(LED_PIN, LOW);
    Serial.printf("当前温度: %.1f℃ ≤ 35℃ → LED熄灭\n", temp);
  }
}

// RPC回调(核心:解析指令+返回响应,带完整打印)
void onRpcReceived(char* topic, byte* payload, unsigned int len) {
  Serial.println("\n=====================");
  Serial.println("收到RPC请求:");
  
  // 打印请求主题
  Serial.print("请求主题: ");
  Serial.println(topic);
  
  // 打印请求内容
  Serial.print("请求内容: ");
  for (int i = 0; i < len; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  // 提取requestId(用于响应)
  String topicStr = topic;
  int reqIdIndex = topicStr.lastIndexOf('/') + 1;
  String reqId = topicStr.substring(reqIdIndex);
  Serial.print("提取RequestID: ");
  Serial.println(reqId);

  // 解析RPC指令
  JsonDocument doc;
  DeserializationError error = deserializeJson(doc, payload, len);
  if (error) {
    Serial.print("JSON解析失败: ");
    Serial.println(error.c_str());
    // 返回错误响应
    JsonDocument resDoc;
    resDoc["success"] = false;
    resDoc["error"] = "JSON parse failed";
    String resPayload;
    serializeJson(resDoc, resPayload);
    client.publish(("v1/devices/me/rpc/response/" + reqId).c_str(), resPayload.c_str());
    Serial.print("错误响应: ");
    Serial.println(resPayload);
    return;
  }

  // 提取方法和参数
  String method = doc["method"];
  int params = doc["params"];
  Serial.print("RPC方法: ");
  Serial.println(method);
  Serial.print("RPC参数: ");
  Serial.println(params);

  // 处理set_led指令(保留RPC手动控制功能)
  bool success = false;
  String msg = "";
  if (method == "set_led") {
    digitalWrite(LED_PIN, params); // 控制LED
    success = true;
    msg = params ? "LED已开启" : "LED已关闭";
    Serial.println("执行结果: " + msg);
  } else {
    msg = "未知方法: " + method;
    Serial.println("执行结果: " + msg);
  }

  // 构建响应数据(新增当前温度和LED状态)
  JsonDocument resDoc;
  resDoc["success"] = success;
  resDoc["message"] = msg;
  resDoc["current_temperature"] = currentTemp; // 当前随机温度
  resDoc["led_state"] = digitalRead(LED_PIN);   // 当前LED状态
  String resPayload;
  serializeJson(resDoc, resPayload);

  // 发布响应
  String resTopic = "v1/devices/me/rpc/response/" + reqId;
  client.publish(resTopic.c_str(), resPayload.c_str());
  
  // 打印响应信息
  Serial.print("响应主题: ");
  Serial.println(resTopic);
  Serial.print("响应内容: ");
  Serial.println(resPayload);
  Serial.println("=====================\n");
}

// 上报温度数据(触发规则链,带打印)
void sendTempData() {
  Serial.println("\n---------- 上报遥测数据 ----------");
  // 生成30~37℃的随机温度
  currentTemp = generateRandomTemp();
  
  // 按温度自动控制LED
  controlLedByTemp(currentTemp);

  // 构建上报数据
  JsonDocument doc;
  doc["temperature"] = currentTemp; // 上报随机温度
  doc["led_state"] = digitalRead(LED_PIN); // 上报当前LED状态
  char payload[64];
  serializeJson(doc, payload);
  
  Serial.print("上报主题: v1/devices/me/telemetry");
  Serial.print(" | 上报内容: ");
  Serial.println(payload);
  
  // 发布数据
  bool publishOk = client.publish("v1/devices/me/telemetry", payload);
  if (publishOk) {
    Serial.println("数据上报成功!");
  } else {
    Serial.println("数据上报失败!");
  }
  Serial.println("----------------------------------");
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW); // 初始关闭LED
  
  Serial.println("======== ESP32启动 ========");
  connectWiFi(); // 连接WiFi(带端口打印)
  client.setServer(TB_IP, TB_PORT); // 设置MQTT服务器地址+端口
  client.setCallback(onRpcReceived); // 绑定RPC回调
}

void loop() {
  // 维持MQTT连接
  if (!client.connected()) {
    reconnectMQTT();
  }
  client.loop();

  // 每5秒上报一次温度数据(并自动控制LED)
  static unsigned long lastSend = 0;
  if (millis() - lastSend > 5000) {
    lastSend = millis();
    sendTempData();
  }
}输入以下代码: 
  1. 在io.huakaka.com里面,点击规则链库,再点击右上角+号,选择导入下载好的规则链JSON文件。

  2. 在设备配置里面,打开详情页面,选择默认的规则链为刚才导入的文件。6

  3. 再次打开刚才的规则链,点击下面的节点

  4. 把复制的diviceId替换成你的。

  5. 查看Arduino的串口输出信息,和ESP32板块上的LED灯,应该随着发送温度而变化。


评论