#if defined(ESP8266) #include #define THINGSBOARD_ENABLE_PROGMEM 0 #elif defined(ESP32) || defined(RASPBERRYPI_PICO) || defined(RASPBERRYPI_PICO_W) #include #endif #ifndef LED_BUILTIN #define LED_BUILTIN 99 #endif #include #include #include #include #include // Library untuk sensor DHT11 #include // Konfigurasi sensor DHT11 #define DHTPIN 12 // Pin GPIO 12 #define DHTTYPE DHT11 // Tipe sensor DHT11 // Inisialisasi sensor DHT DHT dht(DHTPIN, DHTTYPE); // Variabel untuk menyimpan data sensor float temperature = 0.0; float humidity = 0.0; constexpr char WIFI_SSID[] = "ITTS - REKTORAT"; constexpr char WIFI_PASSWORD[] = "itts@2024"; // See https://thingsboard.io/docs/getting-started-guides/helloworld/ // to understand how to obtain an access token constexpr char TOKEN[] = "6paKS9i9URmqWjlTK8RN"; // Thingsboard we want to establish a connection too constexpr char THINGSBOARD_SERVER[] = "192.168.70.106"; // 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; // Maximum amount of attributs we can request or subscribe, has to be set both in the ThingsBoard template list and Attribute_Request_Callback template list // and should be the same as the amount of variables in the passed array. If it is less not all variables will be requested or subscribed constexpr size_t MAX_ATTRIBUTES = 3U; constexpr uint64_t REQUEST_TIMEOUT_MICROSECONDS = 5000U * 1000U; // Attribute names for attribute request and attribute updates functionality constexpr const char BLINKING_INTERVAL_ATTR[] = "blinkingInterval"; constexpr const char LED_MODE_ATTR[] = "ledMode"; constexpr const char LED_STATE_ATTR[] = "ledState"; // Initialize underlying client, used to establish a connection WiFiClient wifiClient; // Initalize the Mqtt client instance Arduino_MQTT_Client mqttClient(wifiClient); // Initialize used apis Server_Side_RPC<3U, 5U> rpc; Attribute_Request<2U, MAX_ATTRIBUTES> attr_request; Shared_Attribute_Update<3U, MAX_ATTRIBUTES> shared_update; const std::array apis = { &rpc, &attr_request, &shared_update }; // Initialize ThingsBoard instance with the maximum needed buffer size, stack size and the apis we want to use ThingsBoard tb(mqttClient, MAX_MESSAGE_SIZE, // receive buffer MAX_MESSAGE_SIZE, // send buffer Default_Max_Stack_Size, // stack size apis); // 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 SHARED_ATTRIBUTES_LIST = { LED_STATE_ATTR, BLINKING_INTERVAL_ATTR }; // List of client attributes for requesting them (Using to initialize device states) constexpr std::array 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 void processSetLedMode(const JsonVariantConst &data, JsonDocument &response) { Serial.println("Received the set led state RPC method"); // Process data int new_mode = data; Serial.print("Mode to change: "); Serial.println(new_mode); StaticJsonDocument<1> response_doc; if (new_mode != 0 && new_mode != 1) { response_doc["error"] = "Unknown mode!"; response.set(response_doc); return; } ledMode = new_mode; attributesChanged = true; // Returning current mode response_doc["newMode"] = (int)ledMode; response.set(response_doc); } // 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 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 JsonObjectConst &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(); if (new_interval >= BLINKING_INTERVAL_MS_MIN && new_interval <= BLINKING_INTERVAL_MS_MAX) { blinkingInterval = new_interval; Serial.print("Blinking interval is set to: "); Serial.println(new_interval); } } else if (strcmp(it->key().c_str(), LED_STATE_ATTR) == 0) { ledState = it->value().as(); if (LED_BUILTIN != 99) { digitalWrite(LED_BUILTIN, ledState); } Serial.print("LED state is set to: "); Serial.println(ledState); } } attributesChanged = true; } void processClientAttributes(const JsonObjectConst &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(); ledMode = new_mode; } } } // Attribute request did not receive a response in the expected amount of microseconds void requestTimedOut() { Serial.printf("Attribute request timed out did not receive a response in (%llu) microseconds. Ensure client is connected to the MQTT broker and that the keys actually exist on the target device\n", REQUEST_TIMEOUT_MICROSECONDS); } const Shared_Attribute_Callback attributes_callback(&processSharedAttributes, SHARED_ATTRIBUTES_LIST.cbegin(), SHARED_ATTRIBUTES_LIST.cend()); const Attribute_Request_Callback attribute_shared_request_callback(&processSharedAttributes, REQUEST_TIMEOUT_MICROSECONDS, &requestTimedOut, SHARED_ATTRIBUTES_LIST); const Attribute_Request_Callback attribute_client_request_callback(&processClientAttributes, REQUEST_TIMEOUT_MICROSECONDS, &requestTimedOut, CLIENT_ATTRIBUTES_LIST); void setup() { // Initialize serial connection for debugging Serial.begin(SERIAL_DEBUG_BAUD); if (LED_BUILTIN != 99) { pinMode(LED_BUILTIN, OUTPUT); } // Inisialisasi sensor DHT11 dht.begin(); Serial.println("DHT11 sensor initialized"); delay(1000); InitWiFi(); } void loop() { delay(10); if (!reconnect()) { return; } if (!tb.connected()) { // 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.sendAttributeData("macAddress", WiFi.macAddress().c_str()); 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 (!rpc.RPC_Subscribe(callbacks.cbegin(), callbacks.cend())) { Serial.println("Failed to subscribe for RPC"); return; } if (!shared_update.Shared_Attributes_Subscribe(attributes_callback)) { Serial.println("Failed to subscribe for shared attribute updates"); return; } Serial.println("Subscribe done"); // Request current states of shared attributes if (!attr_request.Shared_Attributes_Request(attribute_shared_request_callback)) { Serial.println("Failed to request for shared attributes"); return; } // Request current states of client attributes if (!attr_request.Client_Attributes_Request(attribute_client_request_callback)) { Serial.println("Failed to request for client attributes"); return; } } if (attributesChanged) { attributesChanged = false; if (ledMode == 0) { previousStateChange = millis(); } tb.sendTelemetryData(LED_MODE_ATTR, ledMode); tb.sendTelemetryData(LED_STATE_ATTR, ledState); tb.sendAttributeData(LED_MODE_ATTR, ledMode); tb.sendAttributeData(LED_STATE_ATTR, ledState); } if (ledMode == 1 && millis() - previousStateChange > blinkingInterval) { previousStateChange = millis(); ledState = !ledState; tb.sendTelemetryData(LED_STATE_ATTR, ledState); tb.sendAttributeData(LED_STATE_ATTR, ledState); if (LED_BUILTIN == 99) { Serial.print("LED state changed to: "); Serial.println(ledState); } else { digitalWrite(LED_BUILTIN, ledState); } } // Sending telemetry every telemetrySendInterval time if (millis() - previousDataSend > telemetrySendInterval) { previousDataSend = millis(); // Baca data dari sensor DHT11 humidity = dht.readHumidity(); temperature = dht.readTemperature(); // Cek apakah pembacaan berhasil if (isnan(humidity) || isnan(temperature)) { Serial.println("Failed to read from DHT sensor!"); } else { // Tampilkan di Serial Monitor Serial.print("Temperature: "); Serial.print(temperature); Serial.print(" °C, Humidity: "); Serial.print(humidity); Serial.println(" %"); // Kirim data suhu dan kelembaban ke ThingsBoard tb.sendTelemetryData("temperature", temperature); tb.sendTelemetryData("humidity", humidity); } // Kirim data WiFi 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()); } tb.loop(); }