2025年7月2日 星期三

WOKWI RFID + Thingboard

 WOKWI RFID + Thingboard 

✅ 使用 demo.thingsboard.io 與提供的設備 token
✅ 顯示 UID 至 LCD
✅ 每次模擬讀取 UID 時,自動上傳 id, UID, date, time 到 ThingsBoard
✅ 使用 JSON 格式發佈至 v1/devices/me/telemetry 主題
✅ 使用 FreeRTOS 雙核心架構運行


🧪 測試說明

  1. 開啟序列監控器(波特率 115200)

  2. 按下「Enter」即可模擬一筆 RFID 資料

  3. LCD 顯示 RFID IOT 與 UID

  4. MQTT 上傳格式如下:

json
{ "id": 1, "UID": "8EED71A2", "date": "2025-07-02", "time": "15:12:30" }

📊 ThingsBoard Table 設定

  1. 進入 demo.thingsboard.io,找到此裝置

  2. 點選 Telemetry 確認有 id, UID, date, time

  3. 新增 Table Widget:

    • 類型:Latest Telemetry

    • 顯示欄位:id, UID, date, time


 建立 Dashboard + Table Widget

  1. Dashboards,新增或打開一個 dashboard

  2. 點右上角 加號 ➜ Add new widget

  3. 選擇:

    • Type:Timeseries

    • Display: Table

  4. 點選 Entity,選擇剛剛建立的 Entity View(例如 RFID View

  5. 在 Widget 的資料欄位中輸入:

    • id

    • UID

    • date

    • time

  6. 儲存 Widget。


🧪 成效結果

你現在會看到一個完整的歷史表格,其中每一筆都包含:

idUIDdatetime
18EED712A2025-07-0215:10:21
28EED713F2025-07-0215:11:04
............

Thingboard dashboard儀表板的檔案

https://mega.nz/file/d91SzRLR#yZEu_8giQIZkl7_w2iqdyM1gQxb4bXUXZc3DeJvb4-E





WOKWI程式

#include <WiFi.h>
#include <PubSubClient.h>
#include <SPI.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
#include <freertos/task.h>
#include <time.h>

#define SS_PIN 5
#define RST_PIN 27
#define LED_PIN 2

MFRC522 mfrc522(SS_PIN, RST_PIN);
LiquidCrystal_I2C lcd(0x27, 16, 2);

// WiFi & ThingsBoard
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* tb_host = "demo.thingsboard.io";
const int tb_port = 1883;
const char* tb_token = "1fj3t0cg5es1mr1cnwab";

WiFiClient espClient;
PubSubClient client(espClient);
QueueHandle_t uidQueue;

int record_id = 0;

// Function: Format UID data as JSON
String formatTelemetryJson(String uid) {
  time_t now;
  struct tm timeinfo;
  time(&now);
  localtime_r(&now, &timeinfo);

  char dateStr[11]; // yyyy-mm-dd
  char timeStr[9];  // HH:MM:SS
  strftime(dateStr, sizeof(dateStr), "%Y-%m-%d", &timeinfo);
  strftime(timeStr, sizeof(timeStr), "%H:%M:%S", &timeinfo);

  String json = "{";
  json += "\"id\":" + String(++record_id) + ",";
  json += "\"UID\":\"" + uid + "\",";
  json += "\"date\":\"" + String(dateStr) + "\",";
  json += "\"time\":\"" + String(timeStr) + "\"";
  json += "}";

  return json;
}

void reconnectMQTT() {
  while (!client.connected()) {
    Serial.println("Connecting to ThingsBoard...");
    if (client.connect("ESP32_Client", tb_token, NULL)) {
      Serial.println("Connected to ThingsBoard.");
    } else {
      Serial.print("Failed MQTT connection. rc=");
      Serial.print(client.state());
      Serial.println(" Retrying in 5 seconds...");
      delay(5000);
    }
  }
}

// Core 0: 處理 WiFi + MQTT 傳送
void mqttTask(void *pvParameters) {
  Serial.begin(115200);
  SPI.begin();
  mfrc522.PCD_Init();
  pinMode(LED_PIN, OUTPUT);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected.");
  Serial.println(WiFi.localIP());

  configTime(8 * 3600, 0, "pool.ntp.org"); // 設定台灣時間

  client.setServer(tb_host, tb_port);

  String receivedUid;
  while (true) {
    if (!client.connected()) {
      reconnectMQTT();
    }
    client.loop();

    if (xQueueReceive(uidQueue, &receivedUid, portMAX_DELAY) == pdPASS) {
      String payload = formatTelemetryJson(receivedUid);
      Serial.println("Sending to ThingsBoard: " + payload);

      if (client.publish("v1/devices/me/telemetry", payload.c_str())) {
        digitalWrite(LED_PIN, HIGH);
        vTaskDelay(500 / portTICK_PERIOD_MS);
        digitalWrite(LED_PIN, LOW);

        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("RFID IOT");
        lcd.setCursor(0, 1);
        lcd.print(receivedUid);
      } else {
        Serial.println("Failed to publish to ThingsBoard.");
      }
    }
    vTaskDelay(10 / portTICK_PERIOD_MS);
  }
}

// Core 1: 模擬 RFID 掃描(按下 ENTER 觸發)
void rfidSimTask(void *pvParameters) {
  Serial.println("Press ENTER to simulate RFID scan.");
  while (true) {
    if (Serial.available()) {
      char c = Serial.read();
      if (c == '\n' || c == '\r') {
        while(Serial.available() && (Serial.peek() == '\n' || Serial.peek() == '\r')) {
          Serial.read();
        }

        String uid = generateSpecificRangeUID();
        Serial.print("Simulated UID: ");
        Serial.println(uid);

        if (xQueueSend(uidQueue, &uid, portMAX_DELAY) != pdPASS) {
          Serial.println("Failed to send UID to queue.");
        }
      }
    }
    vTaskDelay(100 / portTICK_PERIOD_MS);
  }
}

// 產生 UID 模擬資料
String generateSpecificRangeUID() {
  unsigned long start_val = 0x8EED7100;
  unsigned long end_val   = 0x8EED71FF;
  unsigned long random_val = random(start_val, end_val + 1);
  char hex_uid[9];
  sprintf(hex_uid, "%08lX", random_val);
  return String(hex_uid);
}

void setup() {
  lcd.init();
  lcd.backlight();
  Serial.begin(115200);

  uidQueue = xQueueCreate(5, sizeof(String));
  if (uidQueue == NULL) {
    Serial.println("Queue creation failed. System halt.");
    while (true);
  }

  xTaskCreatePinnedToCore(
    mqttTask,
    "MQTT_Task",
    10000,
    NULL,
    1,
    NULL,
    0
  );

  xTaskCreatePinnedToCore(
    rfidSimTask,
    "RFID_Sim_Task",
    4000,
    NULL,
    1,
    NULL,
    1
  );
}

void loop() {
  vTaskDelay(1);
}

沒有留言:

張貼留言

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...