ESP32与ThingsBoard的连接

以下是ESP32与ThingsBoard的连接的代码:

#if defined(ESP8266)
  #include <ESP8266WiFi.h>
  #define THINGSBOARD_ENABLE_PROGMEM 0
#elif defined(ARDUINO_NANO_RP2040_CONNECT)
  #include <WiFiNINA_Generic.h>
#elif defined(ESP32) || defined(RASPBERRYPI_PICO) || defined(RASPBERRYPI_PICO_W)
  #include <WiFi.h>
  #include <WiFiClientSecure.h>
#endif

#define THINGSBOARD_ENABLE_PSRAM 0
#define THINGSBOARD_ENABLE_DYNAMIC 1

#ifndef LED_BUILTIN
#define LED_BUILTIN 99
#endif

#include <ThingsBoard.h>

#include <HardwareSerial.h>    //导入ESP32串口操作库,使用这个库我们可以把串口映射到其他的引脚上使用
#include <Arduino.h>

HardwareSerial MySerial_stm32(1);  
unsigned short i;
char temp;
char buffer_1[10];  // 定义一个缓冲区,用于存储读取到的数据
char buffer_2[10];  // 定义一个缓冲区,用于存储读取到的数据
int j = 0;     // 缓冲区索引,用于记录当前读取到的位置
char temperature;
char humidity;
float a;
float b;

char temp_buffer[10];
char humi_buffer[10];

constexpr char WIFI_SSID[] = "WiFi名称";
constexpr char WIFI_PASSWORD[] = "WiFi密码";

// See https://thingsboard.io/docs/getting-started-guides/helloworld/
// to understand how to obtain an access token
constexpr char TOKEN[] = "ThingsBoard的访问令牌";

// Thingsboard we want to establish a connection too
constexpr char THINGSBOARD_SERVER[] = "ThingsBoard的地址";
// MQTT port used to communicate with the server, 1883 is the default unencrypted MQTT port.
constexpr uint16_t THINGSBOARD_PORT = 1883U;

// Maximum size packets will ever be sent or received by the underlying MQTT client,
// if the size is to small messages might not be sent or received messages will be discarded
constexpr uint32_t MAX_MESSAGE_SIZE = 256U;

// Baud rate for the debugging serial connection.
// If the Serial output is mangled, ensure to change the monitor speed accordingly to this variable
constexpr uint32_t SERIAL_DEBUG_BAUD = 115200U;


// Initialize underlying client, used to establish a connection
WiFiClient wifiClient;
// Initialize ThingsBoard instance with the maximum needed buffer size
ThingsBoard tb(wifiClient, MAX_MESSAGE_SIZE);

// Attribute names for attribute request and attribute updates functionality

constexpr char BLINKING_INTERVAL_ATTR[] = "blinkingInterval";
constexpr char LED_MODE_ATTR[] = "ledMode";
constexpr char LED_STATE_ATTR[] = "ledState";
constexpr char GATEWAY_DATA_ATTR[]="temp_humi_Mode";

// Statuses for subscribing to rpc
bool subscribed = false;

// handle led state and mode changes
volatile bool attributesChanged = false;

// LED modes: 0 - continious state, 1 - blinking
volatile int ledMode = 0;

// Current led state
volatile bool ledState = false;

// Settings for interval in blinking mode
constexpr uint16_t BLINKING_INTERVAL_MS_MIN = 10U;
constexpr uint16_t BLINKING_INTERVAL_MS_MAX = 60000U;
volatile uint16_t blinkingInterval = 1000U;

uint32_t previousStateChange;

// For telemetry
constexpr int16_t telemetrySendInterval = 2000U;
uint32_t previousDataSend;

// List of shared attributes for subscribing to their updates
constexpr std::array<const char *, 3U> SHARED_ATTRIBUTES_LIST = {
  LED_STATE_ATTR,
  BLINKING_INTERVAL_ATTR,
  GATEWAY_DATA_ATTR
};

// List of client attributes for requesting them (Using to initialize device states)
constexpr std::array<const char *, 1U> CLIENT_ATTRIBUTES_LIST = {
  LED_MODE_ATTR
};

//这个函数适用于清理串口读取缓存区的缓存,其实也就是用读一个删除一个的方式清理,我还会打印出有没有进行清理,清理了哪些内容
void clear_usart_buffer(){
  i = MySerial_stm32.available();
  if(i != 0){
    Serial.print("清空串口接收区的缓存......");
    Serial.println(MySerial_stm32.available());
    while(i--)
      MySerial_stm32.read();    //读取串口接收回来的数据但是不做处理只给与打印
    }
  else
    Serial.println("串口接收区的缓存为空!!!");
  }

void read_usart(){
  i = MySerial_stm32.available();  //返回目前串口接收区内的已经接受的数据量
  if(i != 0){
    while(i--){
      temp = MySerial_stm32.read();   //读取一个数据并且将它从缓存区删除
      // 将读取到的数据存储在缓冲区中
      if(j<5)
      {
        buffer_1[j] = temp;
      }
      else if (j>=5)
      {
        if(j==5)
        {
          buffer_1[j] = '\0';  // 在 buffer 数组的末尾添加一个空字符,表示字符串的结束
        }
        buffer_2[j-5] = temp;
      }
      j++;
      }
    // 在读取完成后,将 buffer 数组中的数据拼接成一个字符串
    buffer_2[j-5] = '\0';  // 在 buffer 数组的末尾添加一个空字符,表示字符串的结束
    j=0;
    // String temperature = String(buffer_1);  // 将 buffer 数组转换为一个字符串
    // String humidity = String(buffer_2);  // 将 buffer 数组转换为一个字符串

    dtostrf(atof(buffer_1), 5, 2, temp_buffer);
    temperature = (temp_buffer[0]-48)*10+(temp_buffer[1]-48);
    dtostrf(atof(buffer_2), 5, 2, humi_buffer);
    humidity = (humi_buffer[0]-48)*10+(humi_buffer[1]-48);

    Serial.println(temperature);
    Serial.println(humidity);
    a=temperature;
    b=humidity;

    }
  }

/// @brief Initalizes WiFi connection,
// will endlessly delay until a connection has been successfully established
void InitWiFi() {
  Serial.println("Connecting to AP ...");
  // Attempting to establish a connection to the given WiFi network
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    // Delay 500ms until a connection has been succesfully established
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected to AP");
}

/// @brief Reconnects the WiFi uses InitWiFi if the connection has been removed
/// @return Returns true as soon as a connection has been established again
const bool reconnect() {
  // Check to ensure we aren't connected yet
  const wl_status_t status = WiFi.status();
  if (status == WL_CONNECTED) {
    return true;
  }

  // If we aren't establish a new connection to the given WiFi network
  InitWiFi();
  return true;
}


/// @brief Processes function for RPC call "setLedMode"
/// RPC_Data is a JSON variant, that can be queried using operator[]
/// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
/// @param data Data containing the rpc data that was called and its current value
/// @return Response that should be sent to the cloud. Useful for getMethods
RPC_Response processSetLedMode(const RPC_Data &data) {
  Serial.println("Received the set led state RPC method");

  // Process data
  int new_mode = data;

  Serial.print("Mode to change: ");
  Serial.println(new_mode);

  if (new_mode != 0 && new_mode != 1) {
    return RPC_Response("error", "Unknown mode!");
  }

  ledMode = new_mode;

  attributesChanged = true;

  // Returning current mode
  return RPC_Response("newMode", (int)ledMode);
}


// Optional, keep subscribed shared attributes empty instead,
// and the callback will be called for every shared attribute changed on the device,
// instead of only the one that were entered instead
const std::array<RPC_Callback, 1U> callbacks = {
  RPC_Callback{ "setLedMode", processSetLedMode }
};


/// @brief Update callback that will be called as soon as one of the provided shared attributes changes value,
/// if none are provided we subscribe to any shared attribute change instead
/// @param data Data containing the shared attributes that were changed and their current value
void processSharedAttributes(const Shared_Attribute_Data &data) {
  for (auto it = data.begin(); it != data.end(); ++it) {
    if (strcmp(it->key().c_str(), BLINKING_INTERVAL_ATTR) == 0) {
      const uint16_t new_interval = it->value().as<uint16_t>();
      if (new_interval >= BLINKING_INTERVAL_MS_MIN && new_interval <= BLINKING_INTERVAL_MS_MAX) {
        blinkingInterval = new_interval;
        Serial.print("Updated blinking interval to: ");
        Serial.println(new_interval);
      }
    } else if(strcmp(it->key().c_str(), LED_STATE_ATTR) == 0) {
      ledState = it->value().as<bool>();
      digitalWrite(LED_BUILTIN, ledState ? HIGH : LOW);
      Serial.print("Updated state to: ");
      Serial.println(ledState);
    } 
  }
  attributesChanged = true;
}

void processClientAttributes(const Shared_Attribute_Data &data) {
  for (auto it = data.begin(); it != data.end(); ++it) {
    if (strcmp(it->key().c_str(), LED_MODE_ATTR) == 0) {
      const uint16_t new_mode = it->value().as<uint16_t>();
      ledMode = new_mode;
    }
  }
}

const Shared_Attribute_Callback attributes_callback(SHARED_ATTRIBUTES_LIST.cbegin(), SHARED_ATTRIBUTES_LIST.cend(), &processSharedAttributes);
const Attribute_Request_Callback attribute_shared_request_callback(SHARED_ATTRIBUTES_LIST.cbegin(), SHARED_ATTRIBUTES_LIST.cend(), &processSharedAttributes);
const Attribute_Request_Callback attribute_client_request_callback(CLIENT_ATTRIBUTES_LIST.cbegin(), CLIENT_ATTRIBUTES_LIST.cend(), &processClientAttributes);

void setup() {
  // Initalize serial connection for debugging
  Serial.begin(115200);
  //串口的开启,这里还可以传一些别的参数,但是我们只传入下面四个最重要的:波特率,默认SERIAL_8N1为8位数据位、无校验、1位停止位,后面两个分别为 RXD,TXD 引脚
  MySerial_stm32.begin(115200, SERIAL_8N1, 32, 33);
  // pinMode(LED_BUILTIN, OUTPUT);
  delay(1000);
  InitWiFi();
  clear_usart_buffer();  //清空接收区缓存函数
}

void loop() {
//  delay(10);
  read_usart();
  delay(500);
  read_usart();
  delay(500);
  read_usart();
  delay(500);

  if (!reconnect()) {
    subscribed = false;
    return;
  }

  if (!tb.connected()) {
    subscribed = false;
    // Connect to the ThingsBoard
    Serial.print("Connecting to: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" with token ");
    Serial.println(TOKEN);
    if (!tb.connect(THINGSBOARD_SERVER, TOKEN, THINGSBOARD_PORT)) {
      Serial.println("Failed to connect");
      return;
    }
    // Sending a MAC address as an attribute
    tb.sendAttributeString("macAddress", WiFi.macAddress().c_str());
  }

  if (!subscribed) {
    Serial.println("Subscribing for RPC...");
    // Perform a subscription. All consequent data processing will happen in
    // processSetLedState() and processSetLedMode() functions,
    // as denoted by callbacks array.
    if (!tb.RPC_Subscribe(callbacks.cbegin(), callbacks.cend())) {
      Serial.println("Failed to subscribe for RPC");
      return;
    }

    if (!tb.Shared_Attributes_Subscribe(attributes_callback)) {
      Serial.println("Failed to subscribe for shared attribute updates");
      return;
    }

    Serial.println("Subscribe done");
    subscribed = true;

    // Request current states of shared attributes
    if (!tb.Shared_Attributes_Request(attribute_shared_request_callback)) {
      Serial.println("Failed to request for shared attributes");
      return;
    }

    // Request current states of client attributes
    if (!tb.Client_Attributes_Request(attribute_client_request_callback)) {
      Serial.println("Failed to request for client attributes");
      return;
    }
  }

  // Sending telemetry every telemetrySendInterval time
  if (millis() - previousDataSend > telemetrySendInterval) {
    previousDataSend = millis();
    tb.sendTelemetryInt("temperature", a);
    tb.sendTelemetryInt("humidity", b);
  }

  tb.loop();
}

ESP32与ThingsBoard连接主要是通过RPC请求来完成的,在RPC中有两种属性,一种是私人属性,一种是共享属性,简单地理解,私人属性就是保证ESP32可以不断上传数据到ThingsBoard中,共享属性就是保证ThingsBoard可以发送命令到ESP32中。

目前我只用到了私人属性,共享属性暂时还未完全理解

在ThingsBoard和ESP32之间建立连接通常涉及以下步骤:

  1. 设置ThingsBoard实例:首先,您需要设置一个ThingsBoard实例。您可以选择在ThingsBoard云平台上创建一个帐户并使用其提供的托管服务,或者您可以在本地搭建一个ThingsBoard服务器。

  2. 创建设备和令牌:在ThingsBoard中,您需要创建一个设备实体,该设备将与ESP32进行通信。为此,您需要为设备分配一个唯一的标识符和一个访问令牌。这些信息将用于在ESP32上进行身份验证。

  3. 在ESP32上设置连接:在ESP32上,您需要使用适当的库和代码设置与ThingsBoard的连接。一种常用的方法是使用Arduino核心和Arduino IDE进行开发。您可以安装ESP32的Arduino核心和相应的ThingsBoard库。

    • 连接到Wi-Fi网络:首先,您需要将ESP32连接到Wi-Fi网络。您可以使用ESP32的WiFi库来执行此操作。提供所需的Wi-Fi SSID和密码。

    • 配置ThingsBoard连接:您需要在ESP32上配置与ThingsBoard的连接参数,包括ThingsBoard实例的URL和设备令牌。这些信息将用于建立与ThingsBoard的安全连接。您可以使用ThingsBoard提供的Arduino库来执行此操作。

  4. 数据发布和订阅:一旦ESP32成功连接到ThingsBoard,您可以使用ThingsBoard提供的方法将传感器数据发布到设备实体。这些数据将在ThingsBoard中显示和存储。您还可以订阅设备实体以接收来自ThingsBoard的命令和控制消息。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜雨星辰487

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值