نحوه اتصال WeMos Lolin ESP32 OLED به ThingsConect

مقدمه

WeMos Lolin ESP32 OLED یک برد توسعه ESP32 با یک صفحه نمایش OLED با رزولوشن ۱۲۸×۶۴ پیکسل SSD1306 داخلی است.
صفحه نمایش از طریق پروتکل ارتباطی I2C با ESP32 ارتباط برقرار می‌کند.
ESP32 شامل آنتن یکپارچه، تقویت کننده توان، تقویت کننده نویز کم، فیلتر و ماژول مدیریت تامین برق است.

در این راهنما، یاد خواهیم گرفت که چگونه دستگاهی را در Thingsboard ایجاد کنیم، کتابخانه‌ها و ابزارهای مورد نیاز را نصب کنیم.
سپس کد خود را تغییر داده و بر روی دستگاه آپلود کنیم و نتایج کدنویسی خود را بررسی کرده و با استفاده از داشبورد وارد شده در ThingsBoard، داده‌های خود را بررسی کنیم. دستگاه ما با استفاده از قابلیت‌های درخواست‌های مشترک و ویژگی‌های اشتراکی با ThingsBoard همگام می‌شود.
به طور طبیعی، ما دستگاه خود را با استفاده از قابلیت‌های ارائه شده مانند ویژگی‌های اشتراکی یا درخواست‌های RPC کنترل خواهیم کرد.

پیش نیازها

برای ادامه دادن به این راهنما، نیاز به موارد زیر داریم:

  • WeMos Lolin ESP32 OLED
  • محیط توسعه Arduino IDE
  • حساب کاربری ThingsBoard

ایجاد دستگاه در ThingsBoard

به منظور سادگی، ما دستگاه را به صورت دستی با استفاده از رابط کاربری ارائه می‌دهیم.

  • به حساب کاربری ThingsBoard خود وارد شوید و به “Entities” بروید. سپس صفحه “Devices” را انتخاب کنید.
  • روی آیکون “+” در گوشه بالا و سمت راست جدول کلیک کنید و سپس “Add new device” را انتخاب کنید.
  • نام دستگاه را وارد کنید. به عنوان مثال، “دستگاه من”. هیچ تغییر دیگری در حال حاضر لازم نیست. برای افزودن دستگاه، روی “Add” کلیک کنید.
  • دستگاه شما افزوده شده است.

نصب کتابخانه‌ها و ابزارهای مورد نیاز

برای نصب برد در محیط توسعه Arduino IDE، به مسیر File > Preferences بروید و URL زیر را در فیلد Additional Boards Manager URLs اضافه کنید.

https://dl.espressif.com/dl/package_esp32_index.json

//Img

سپس به Tools > Board > Board Manager بروید و برد ESP32 توسط شرکت Espressif Systems را نصب کنید.

//img

پس از اتمام نصب، برد را از منوی Board انتخاب کنید:
Tools > Board > ESP32 > WEMOS LOLIN32.

همچنین، فراموش نکنید که پورت مربوط به دستگاه را مشخص کنید:

Tools > Port > /dev/ttyUSB0.

پورت بستگی به سیستم عامل شما دارد و ممکن است متفاوت باشد:

برای لینوکس/مک: /dev/ttyUSBX خواهد بود (جای X عددی است که توسط سیستم شما اختصاص داده شده است).
برای ویندوز: COMX خواهد بود (جای X عددی است که توسط سیستم شما اختصاص داده شده است).

برای نصب ThingsBoard Arduino SDK، باید مراحل زیر را انجام دهید:

به بخش “Tools” بروید و بر روی “Manage libraries” کلیک کنید.
“ThingsBoard” را در جعبه جستجو وارد کنید و برای کتابخانه پیدا شده روی دکمه “INSTALL” کلیک کنید.

//img

همچنین، برای کنترل صفحه نمایش، باید کتابخانه Adafruit SSD1306 را نصب کنیم.

  • عبارت “Adafruit SSD1306” را در جعبه جستجوی کتابخانه وارد کنید و کتابخانه “Adafruit SSD1306 by Adafruit” را نصب کنید.

//img

در این نقطه، ما تمام کتابخانه‌ها و ابزارهای مورد نیاز را نصب کرده‌ایم.

اتصال دستگاه به ThingsConnect

برای اتصال دستگاه به ThingsBoard، ابتدا باید اطلاعات احراز هویت دستگاه را دریافت کنید. ThingsBoard از انواع مختلفی از اطلاعات احراز هویت دستگاه پشتیبانی می‌کند. ما توصیه می‌کنیم از اطلاعات پیش‌فرض خودکار تولید شده استفاده کنید که در این راهنما یک توکن دسترسی است.

  • روی سطر دستگاه در جدول کلیک کنید تا جزئیات دستگاه باز شود.
  • روی “کپی کردن توکن دسترسی” کلیک کنید. توکن در کلیپبورد شما کپی خواهد شد. لطفاً آن را در یک مکان امن ذخیره کنید.

//img

حالا وقت آن رسیده است که برد را برنامه‌ریزی کنید تا به ThingsBoard متصل شود.
برای این کار، می‌توانید از کد زیر استفاده کنید. این کد شامل تمام قابلیت‌های مورد نیاز برای این راهنما است.

#include <WiFi.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define THINGSBOARD_ENABLE_PSRAM 0
#define THINGSBOARD_ENABLE_DYNAMIC 1

#ifndef LED_BUILTIN
#define LED_BUILTIN 99
#endif

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

constexpr char WIFI_SSID[] = "YOUR_WIFI_SSID";
constexpr char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";

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

// Thingsboard we want to establish a connection too
constexpr char THINGSBOARD_SERVER[] = "demo.thingsboard.io";
// 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 = 1024U;

// 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 = ThingsBoard(wifiClient, MAX_MESSAGE_SIZE, false, 1024);

// 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 SCREEN_TEXT_ATTR[] = "screenText";

String screenText;
volatile bool screenTextUpdated;

// 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,
  SCREEN_TEXT_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
};

/// @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(), SCREEN_TEXT_ATTR) == 0) {
      screenText = String(it->value().as<const char*>());
      screenText.replace("\\n", "\n");
      screenText.replace("\\t", "    ");
      screenTextUpdated = true;
    } 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);
  pinMode(LED_BUILTIN, OUTPUT);
  Wire.begin(5, 4);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) { 
    Serial.println("Cannot initialize screen!");
  }
  delay(2000);
  display.clearDisplay();
  display.display();  
  InitWiFi();
}

void loop() {
  delay(10);

  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");
      delay(2000);
      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;
    }
  }

  if (screenTextUpdated) {
    screenTextUpdated = false;
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.println(screenText);
    display.display();
    Serial.println("Screen updated!");
  }

  if (attributesChanged) {
    attributesChanged = false;
    if (ledMode == 0) {
      previousStateChange = millis();
    }
    tb.sendTelemetryInt(LED_MODE_ATTR, ledMode);
    tb.sendTelemetryBool(LED_STATE_ATTR, ledState);
    tb.sendAttributeInt(LED_MODE_ATTR, ledMode);
    tb.sendAttributeBool(LED_STATE_ATTR, ledState);
  }

  if (ledMode == 1 && millis() - previousStateChange > blinkingInterval) {
    previousStateChange = millis();
    ledState = !ledState;
    digitalWrite(LED_BUILTIN, ledState);
    tb.sendTelemetryBool(LED_STATE_ATTR, ledState);
    tb.sendAttributeBool(LED_STATE_ATTR, ledState);
    if (LED_BUILTIN == 99) {
      Serial.print("LED state changed to: ");
      Serial.println(ledState);
    }
  }

  // Sending telemetry every telemetrySendInterval time
  if (millis() - previousDataSend > telemetrySendInterval) {
    previousDataSend = millis();
    tb.sendTelemetryInt("temperature", random(10, 20));
    tb.sendAttributeInt("rssi", WiFi.RSSI());
    tb.sendAttributeInt("channel", WiFi.channel());
    tb.sendAttributeString("bssid", WiFi.BSSIDstr().c_str());
    tb.sendAttributeString("localIp", WiFi.localIP().toString().c_str());
    tb.sendAttributeString("ssid", WiFi.SSID().c_str());
  }

  tb.loop();
}

در کد، مکان‌های نگه‌دارنده را با SSID شبکه WiFi، رمز عبور و توکن دسترسی دستگاه ThingsBoard خود جایگزین کنید.

متغیرهای ضروری برای اتصال عبارتند از:

//جدول

...

constexpr char WIFI_SSID[] = "YOUR_WIFI_SSID";
constexpr char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";

constexpr char TOKEN[] = "YOUR_ACCESS_TOKEN";

constexpr char THINGSBOARD_SERVER[] = "demo.thingsboard.io";
constexpr uint16_t THINGSBOARD_PORT = 1883U;

constexpr uint32_t MAX_MESSAGE_SIZE = 256U;
constexpr uint32_t SERIAL_DEBUG_BAUD = 115200U;

...

قسمت ارسال داده (به طور پیش فرض، مثال مقدار تصادفی برای کلید دما و برخی اطلاعات WiFi را ارسال می‌کند):

...
    tb.sendTelemetryInt("temperature", random(10, 20));
    tb.sendAttributeInt("rssi", WiFi.RSSI());
    tb.sendAttributeString("bssid", WiFi.BSSIDstr().c_str());
    tb.sendAttributeString("localIp", WiFi.localIP().toString().c_str());
    tb.sendAttributeString("ssid", WiFi.SSID().c_str());
    tb.sendAttributeInt("channel", WiFi.channel());
...

سپس با فشار دادن دکمه آپلود یا ترکیب صفحه کلید Ctrl+U، کد را به دستگاه بارگذاری کنید.

//img

اگر نمی‌توانید کد را بارگذاری کنید و خطای “Property ‘upload.tool.serial’ is undefined” دریافت می‌کنید، می‌توانید اقدامات زیر را انجام دهید:

  • بروید به “ابزارها” > “برنامه‌نویس” و “Esptool” را به عنوان برنامه‌نویس انتخاب کنید.
  • بروید به “Sketch” > “Upload Using Programmer”.

//img

 بررسی داده ها در ThingsConnect

برای بررسی داده‌ها و امکان ارسال دستور یا داده به دستگاه، می‌توانید یک داشبورد ایجاد کنید.

ابتدا فایل داشبورد “Check and control device data” را دانلود کنید.

برای اضافه کردن داشبورد به ThingsBoard، باید اقدامات زیر را انجام دهید:

  •  از طریق منوی اصلی در سمت چپ صفحه، به قسمت “Dashboards” بروید.
  •  بر روی دکمه “+” در گوشه بالا و سمت راست صفحه کلیک کنید و “Import dashboard” را انتخاب کنید.
  •  فایل dashboard.json خود را انتخاب کنید و دکمه import را فشار دهید.
  •  حالا می‌توانید داشبورد وارد شده را در جدول مشاهده کنید.

//img

پس از وارد کردن، باید برای دستگاه خود نام مستعار انتخاب کنیم.

برای انجام این کار، باید به آیکون قلم را بزنید و “entity aliases” را انتخاب کنید، سپس نام مستعار “My device” را انتخاب کرده و با فشردن آیکون قلم آن را برای ویرایش باز کنید.
سپس یک دستگاه با نام “My device” را از لیست کشویی انتخاب کنید و مستعار entity را ذخیره کنید. حالا باید بتوانید داده‌ها را از دستگاه مشاهده کنید.

برای بررسی داده‌ها از دستگاه خود، باید داشبورد وارد شده را باز کنید:

  •  با کلیک بر روی داشبورد در جدول آن را باز کنید.
  •  منظره‌ای برای بررسی داده‌ها و کنترل دستگاه ما.
  •  ویژگی‌های دریافت شده از دستگاه.
  •  اطلاعات دستگاه از سرور ThingsBoard.
  •  ابزارک برای مشاهده تاریخچه تغییرات حالت LED.
  •  ابزارک برای مشاهده تاریخچه دمای شبیه‌سازی شده.

//img

همگام‌سازی وضعیت دستگاه با استفاده از درخواست‌های کلاینت و صفات مشترک

برای دریافت وضعیت دستگاه از ThingsBoard در زمان بوت شدن، قابلیتی برای انجام این کار در کد وجود دارد.
قسمت‌های مسئول نمونه کد عبارتند از:

  • بازخوانی‌های ویژگی:
...
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 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);
...

همانطور که مشاهده می‌کنید، ما ۲ بازخوانی داریم. اولی برای صفات مشترک و دومی برای صفات کلاینتی است.
بازخوانی اول پاسخی را با فاصله‌ی چشمک زنی دریافت می‌کند تا دوره‌ی صحیح چشمک زنی را تنظیم کند.
بازخوانی دوم مود و وضعیت LED را دریافت و آنها را ذخیره و تنظیم می‌کند.
این قابلیت به ما امکان می‌دهد تا پس از راه‌اندازی مجدد، وضعیت واقعی را حفظ کنیم.

  • درخواست‌های صفات:
...
  // 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;
  }
...

برای اینکه بازخوانی‌های ما داده را دریافت کنند، باید یک درخواست به ThingsBoard ارسال کنیم.

کنترل دستگاه با استفاده از صفات مشترک

همچنین می‌توانیم با استفاده از قابلیت به‌روزرسانی صفات مشترک، دوره‌ی چشمک زنی را تغییر دهیم.

  • برای تغییر دوره‌ی چشمک زنی، فقط کافیست مقدار را در داشبورد خود تغییر دهید.
  • بعد از اعمال تغییر با فشردن علامت تیک، یک پیام تأیید را مشاهده خواهید کرد.

//img

برای تغییر وضعیت هنگامی که چشمک زنی غیرفعال است، می‌توانیم از سوئیچ موجود در همان ویجت استفاده کنیم:

  • این کار فقط زمانی امکان‌پذیر است که حالت چشمک زنی غیرفعال باشد.

//img

متأسفانه، این برد دارای نشانگر LED داخلی قابل کنترل نیست.
بنابراین شما می‌توانید نتایج تغییر صفات مشترک را با استفاده از مانیتور سریال (ابزارها -> مانیتور سریال) بررسی کنید و نرخ baud را 115200 انتخاب کنید.

برای دستیابی به این موضوع، متغیر “blinkingInterval” را در بخش‌های زیر از کد استفاده کرده‌ایم:

  • بازخوانی برای به‌روزرسانی صفات مشترک:
...

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;
}

...
const Shared_Attribute_Callback attributes_callback(SHARED_ATTRIBUTES_LIST.cbegin(), SHARED_ATTRIBUTES_LIST.cend(), &processSharedAttributes);
...
  • عضویت در به‌روزرسانی صفات مشترک:
...
    if (!tb.Shared_Attributes_Request(attribute_shared_request_callback)) {
      Serial.println("Failed to request for shared attributes");
      return;
    }
...

بخشی از کد برای چشمک زنی:

...

  if (ledMode == 1 && millis() - previousStateChange > blinkingInterval) {
    previousStateChange = millis();
    ledState = !ledState;
    digitalWrite(LED_BUILTIN, ledState);
    tb.sendTelemetryBool(LED_STATE_ATTR, ledState);
    tb.sendAttributeBool(LED_STATE_ATTR, ledState);
    if (LED_BUILTIN == 99) {
      Serial.print("LED state changed to: ");
      Serial.println(ledState);
    }
  }
...

همچنین، شما می‌توانید متن را در صفحه نمایش تغییر دهید. برای این کار می‌توانید صفت مشترک “screenText” را تغییر دهید یا از داشبورد نمونه استفاده کنید.

  • متن را در جعبه ورودی قرار داده و تغییرات را اعمال کنید. متن همچنین در فیلد بالا نمایش داده خواهد شد.

//img

شما می‌توانید از علامت‌های ویژه زیر استفاده کنید:

  • \n – خط جدید.
  • \t – چهار فضای خالی.
    برای اتصال صفحه نمایش OLED، از بخش‌های کد زیر استفاده می‌کنیم (ما یک خط I2C داریم که به پین‌های 5 و 4 برد متصل است):
...
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
...
Wire.begin(5, 4);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) { 
    Serial.println("Cannot initialize screen!");
}
...

برای پردازش متن و کنترل علامت‌های ویژه، از کد زیر استفاده می‌کنیم:

...
if (strcmp(it->key().c_str(), SCREEN_TEXT_ATTR) == 0) {
    screenText = String(it->value().as<const char*>());
    screenText.replace("\\n", "\n");
    screenText.replace("\\t", "    ");
    screenTextUpdated = true;
}
...

برای نمایش متن ورودی در صفحه نمایش، از بخش کد زیر استفاده می‌کنیم:

...

  if (screenTextUpdated) {
    screenTextUpdated = false;
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.println(screenText);
    display.display();
    Serial.println("Screen updated!");
  }
...

می‌توانید منطق را برای دستیابی به اهداف خود تغییر دهید و پردازشی برای صفات خود اضافه کنید.

کنترل دستگاه با استفاده از RPC

می‌توانید به صورت دستی وضعیت LED و حالت بین نور پیوسته و چشمک زنی را تغییر دهید. برای این کار، می‌توانید از بخش‌های زیر در داشبورد ما استفاده کنید:

  • تغییر وضعیت LED با استفاده از ویجت سوئیچ به نور پیوسته.
  • تغییر وضعیت LED با استفاده از ویجت سوئیچ گرد به حالت چشمک زنی.

//img

لطفاً توجه داشته باشید که شما تنها می‌توانید وضعیت LED را تغییر دهید اگر حالت چشمک زنی غیرفعال باشد.

در نمونه کد، قابلیت برای پردازش دستورات RPC وجود دارد.
برای دسترسی به قابلیت کنترل دستگاه، از بخش‌های زیر در کد استفاده کرده‌ایم:

  • بازخوانی برای درخواست‌های RPC:
...

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);
}

...

const std::array<RPC_Callback, 1U> callbacks = {
  RPC_Callback{ "setLedMode", processSetLedMode }
};

...
  • عضویت در درخواست‌های RPC:
...
    if (!tb.RPC_Subscribe(callbacks.cbegin(), callbacks.cend())) {
      Serial.println("Failed to subscribe for RPC");
      return;
    }
...

شما می‌توانید کد را تغییر دهید تا به اهداف خود دست یابید و پردازشی برای دستورات RPC خود اضافه کنید.

نتیجه‌گیری

با دانشی که در این راهنما آورده شده است، به راحتی می‌توانید WeMos Lolin ESP32 OLED خود را به ThingsBoard متصل کنید و داده‌ها را ارسال کنید.

برای کسب اطلاعات بیشتر درباره مفاهیم و ویژگی‌های کلیدی، به مستندات پلتفرم مراجعه کنید. به عنوان مثال، می‌توانید قوانین هشدار یا داشبوردها را پیکربندی کنید.

عناوین هر بخش