2025年7月1日 星期二

WOKWI ESP32 4 LED + Thingboard UI 控制

WOKWI ESP32 4 LED + Thingboard UI 控制

























Thingboard dashboard儀表板的檔案

https://mega.nz/file/p4dDCSaS#QrfrVfoW55pXwiXqSYSgZPomXUtQFzqIj8fpIAGUQA4


ThingsBoard Dashboard JSON 是用來實作「ESP32 四顆 LED 控制」的儀表板,

透過 setLED1~setLED4 四個 RPC 方法,

從雲端控制 ESP32 上的四個 GPIO(每顆 LED)。


下面是詳細的說明重點:


🔧 每顆 LED 控制元件設定說明(以 LED1 為例)

1. 控制元件類型:

"typeFullFqn": "system.power_button",

"type": "rpc"

表示這是一個「開關按鈕」並連接 ThingsBoard 的 RPC 控制功能。


2. 方法定義:

"method": "setLED1"

按下按鈕時會呼叫 ESP32 上實作的 setLED1 RPC 方法。


方法名稱需與 Arduino 程式碼中的 RPC_Callback 一致。


3. 送出參數:

"valueToData": {

  "type": "CONSTANT",

  "constantValue": true

}

「開」按鈕會傳送 true,代表開啟 LED。


「關」按鈕則送出 false。


4. 初始化狀態(選擇性):

"initialState": {

  "executeRpc": {

    "method": "getState"

  }

}

儀表板載入時,會執行 getState RPC 方法詢問目前狀態,雖然這方法尚未實作,但可以視需要在 ESP32 中加入。


🧠 裝置連結設定

"targetDevice": {

  "type": "device",

  "deviceId": "f78040d0-56f1-11f0-9664-ff13eccb47ff"

}

每個按鈕都綁定同一台裝置(ESP32),需確認這個 deviceId 是你的 ESP32 裝置 ID(可以在 ThingsBoard 裡點裝置查詢)。


🔁 RPC 回應建議

在 ESP32 Arduino 程式中,你需要定義:

RPC_Callback callbacks[] = {

  {"setLED1", callback_LED1},

  {"setLED2", callback_LED2},

  {"setLED3", callback_LED3},

  {"setLED4", callback_LED4}

};

每個 callback 例如:


void callback_LED1(const JsonVariantConst &params, JsonDocument &response) {

  digitalWrite(LED1_PIN, params.as<bool>());

  response["result"] = true;

}

✅ 匯入方法教學

進入 ThingsBoard → 登入 → 左側點選 Dashboards。


點右上角「+」 → Import Dashboard。


貼上你給的 JSON 或上傳 .json 檔案 → 儲存。


確認你的 ESP32 裝置已上線並註冊對應的 Access Token。

WokWI程式

#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h> // 新增 ArduinoJson 函式庫

// --- Wi-Fi 配置 ---
//const char* ssid = "您的Wi-Fi名稱";      // 替換成您的 Wi-Fi 名稱
//const char* password = "您的Wi-Fi密碼";  // 替換成您的 Wi-Fi 密碼
const char* ssid = "Wokwi-GUEST";    
const char* password = "";    

// ==== ThingBoard 設定 ====
const char* mqtt_server = "demo.thingsboard.io"; // 或你自己的伺服器 IP
const int mqtt_port = 1883;
const char* token = "sd63q6qm7r1108u49iji"; // 來自設備的 Access Token

WiFiClient espClient;
PubSubClient client(espClient);

// ==== LED 腳位設定 ====
const int ledPins[4] = {18, 5, 17, 16};



// MQTT RPC 指令處理
void callback(char* topic, byte* payload, unsigned int length) {
  StaticJsonDocument<256> doc;
  DeserializationError error = deserializeJson(doc, payload, length);
  if (error) {
    Serial.print("JSON 解析錯誤: ");
    Serial.println(error.c_str());
    return;
  }

  String method = doc["method"];
  bool value = doc["params"];
  int request_id = -1;

  // 解析 request_id(從 topic 路徑取出)
  String topicStr = String(topic);  // 例如 "v1/devices/me/rpc/request/42"
  int lastSlash = topicStr.lastIndexOf('/');
  if (lastSlash != -1) {
    request_id = topicStr.substring(lastSlash + 1).toInt();
  }

  Serial.print("Received RPC: ");
  Serial.println(method + " = " + (value ? "true" : "false"));

  int ledIndex = -1;
  if (method == "setLED1") ledIndex = 0;
  if (method == "setLED2") ledIndex = 1;
  if (method == "setLED3") ledIndex = 2;
  if (method == "setLED4") ledIndex = 3;

  if (ledIndex != -1) {
    digitalWrite(ledPins[ledIndex], value ? HIGH : LOW);

    // 回覆狀態(如果 request_id 合法)
    if (request_id >= 0) {
      String responseTopic = "v1/devices/me/rpc/response/" + String(request_id);
      StaticJsonDocument<64> resp;
      resp["status"] = "ok";
      resp["led"] = value;
      char response[64];
      serializeJson(resp, response);
      client.publish(responseTopic.c_str(), response);
      Serial.print("Sent RPC response: ");
      Serial.println(response);
    }
  }
}

void publishLEDStatus(int ledIndex, bool state) {
  StaticJsonDocument<64> doc;
  doc["led" + String(ledIndex + 1)] = state;
  char payload[64];
  serializeJson(doc, payload);
  client.publish("v1/devices/me/telemetry", payload);
}


// 重新連線
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP32Client", token, NULL)) {
      Serial.println("connected");
      client.subscribe("v1/devices/me/rpc/request/+"); // RPC 控制
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);

  // 初始化 LED 腳位
  for (int i = 0; i < 4; i++) {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], LOW);
  }

  // Wi-Fi 連線
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");

  // MQTT 設定
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

}


沒有留言:

張貼留言

ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite

 ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite  ESP32 VS Code 程式 ; PlatformIO Project Configuration File ; ;   Build op...