#include <WiFi.h> // WiFi control for ESP32
#include <ThingsBoard.h>
#include <Arduino_MQTT_Client.h>
// Helper macro to calculate array size
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
// WiFi access point
#define WIFI_AP_NAME "Wokwi-GUEST"
// WiFi password
#define WIFI_PASSWORD ""
// See https://thingsboard.io/docs/getting-started-guides/helloworld/
// to understand how to obtain an access token
#define TOKEN "jODzBPyUzG5ZDIn1DAWj"
// ThingsBoard server instance.
#define THINGSBOARD_SERVER "thingsboard.cloud"
// Baud rate for debug serial
#define SERIAL_DEBUG_BAUD 115200
constexpr uint32_t MAX_MESSAGE_SIZE = 1024U;
volatile int ledMode = 0;
// Initialize ThingsBoard client
WiFiClient wifiClient;
Arduino_MQTT_Client mqttClient(wifiClient);
// Initialize ThingsBoard instance
ThingsBoard tb(mqttClient, MAX_MESSAGE_SIZE);
// the Wifi radio's status
int status = WL_IDLE_STATUS;
// Array with LEDs that should be controlled from ThingsBoard, one by one
uint8_t leds_control[] = { 2, 4, 35 };
// Main application loop delay
int quant = 20;
// Initial period of LED cycling.
int led_delay = 1000;
// Period of sending a temperature/humidity data.
int send_delay = 2000;
// Time passed after LED was turned ON, milliseconds.
int led_passed = 0;
// Time passed after temperature/humidity data was sent, milliseconds.
int send_passed = 0;
// Set to true if application is subscribed for the RPC messages.
bool subscribed = false;
bool check = false;
// LED number that is currenlty ON.
int current_led = 0;
// Processes function for RPC call "setValue"
// RPC_Data is a JSON variant, that can be queried using operator[]
// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
RPC_Response processDelayChange(const RPC_Data &data)
{
Serial.println("Received the set delay RPC method");
// Process data
led_delay = data;
Serial.print("Set new delay: ");
Serial.println(led_delay);
return RPC_Response(NULL, led_delay);
}
// Processes function for RPC call "getValue"
// RPC_Data is a JSON variant, that can be queried using operator[]
RPC_Response processGetDelay(const RPC_Data &data)
{
Serial.println("Received the get value method");
return RPC_Response(NULL, led_delay);
}
// Processes function for RPC call "setGpioStatus"
// RPC_Data is a JSON variant, that can be queried using operator[]
// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
RPC_Response processSetGpioState(const RPC_Data &data)
{
Serial.println("Received the set GPIO RPC method");
int pin = data["pin"];
bool enabled = data["enabled"];
if (pin < COUNT_OF(leds_control)) {
Serial.print("Setting LED ");
Serial.print(pin);
Serial.print(" to state ");
Serial.println(enabled);
digitalWrite(leds_control[pin], enabled);
}
return RPC_Response(data["pin"], (bool)data["enabled"]);
}
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;
check = true;
// attributesChanged = true;
// Returning current mode
return RPC_Response("newMode", (int)ledMode);
}
// RPC handlers
const std::array<RPC_Callback, 3U> callbacks = {
RPC_Callback{ "setValue", processDelayChange },
RPC_Callback{ "getValue", processGetDelay },
RPC_Callback{ "setGpioStatus", processSetGpioState },
};
// Setup an application
void setup() {
// Initialize serial for debugging
Serial.begin(SERIAL_DEBUG_BAUD);
WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
InitWiFi();
// Pinconfig
for (size_t i = 0; i < COUNT_OF(leds_control); ++i) {
pinMode(leds_control[i], OUTPUT);
Serial.println("led control nèeeeeeee: ");
Serial.println(leds_control[i]);
}
}
// Main application loop
void loop() {
delay(quant);
led_passed += quant;
send_passed += quant;
// Reconnect to WiFi, if needed
if (WiFi.status() != WL_CONNECTED) {
reconnect();
return;
}
tb.sendAttributeData("macAddress", WiFi.macAddress().c_str());
if(check){
check = false;
tb.sendAttributeData("ledMode1", leds_control[0]);
tb.sendAttributeData("ledMode2", leds_control[1]);
tb.sendAttributeData("ledMode3", leds_control[2]);
}
// Reconnect to ThingsBoard, if needed
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)) {
Serial.println("Failed to connect");
return;
}
tb.sendAttributeData("macAddress", WiFi.macAddress().c_str());
}
// Subscribe for RPC, if needed
if (!subscribed) {
Serial.println("Subscribing for RPC...");
// Perform a subscription. All consequent data processing will happen in
// callbacks as denoted by callbacks[] array.
if (!tb.RPC_Subscribe(callbacks.cbegin(), callbacks.cend())) {
Serial.println("Failed to subscribe for RPC");
return;
}
Serial.println("Subscribe done");
subscribed = true;
}
int count = 0;
if (count<100){
delay(10000);
tb.sendTelemetryData("humidity", random(1,50));
tb.sendTelemetryData("temperature", random(-10, 40));
tb.sendAttributeData("rssi", WiFi.RSSI());
tb.sendAttributeData("channel", WiFi.channel());
tb.sendAttributeData("bssid", WiFi.BSSIDstr().c_str());
tb.sendAttributeData("localIp", WiFi.localIP().toString().c_str());
tb.sendAttributeData("ssid", WiFi.SSID().c_str());
count++;
};
// Check if it is a time to send DHT22 temperature and humidity
// Process messages
tb.loop();
}
void InitWiFi()
{
Serial.println("Connecting to AP ...");
// attempt to connect to WiFi network
WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected to AP");
}
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;
}