Differences

This shows you the differences between two versions of the page.

Link to this comparison view

iothings:laboratoare:2025:lab3 [2025/10/11 12:23]
dan.tudose
iothings:laboratoare:2025:lab3 [2025/10/13 17:20] (current)
dan.tudose [Platformio.ini]
Line 2: Line 2:
  
 **MQTT (Message Queuing Telemetry Transport)** is a lightweight,​ publish-subscribe network protocol designed for efficient communication in constrained environments. Originally developed by IBM in the late 1990s, MQTT has become a standard for IoT (Internet of Things) systems due to its low bandwidth requirements and minimal overhead. It is mostly used in Home Automation systems, Industrial IoT applications and Mobile Messaging and Telemetry. **MQTT (Message Queuing Telemetry Transport)** is a lightweight,​ publish-subscribe network protocol designed for efficient communication in constrained environments. Originally developed by IBM in the late 1990s, MQTT has become a standard for IoT (Internet of Things) systems due to its low bandwidth requirements and minimal overhead. It is mostly used in Home Automation systems, Industrial IoT applications and Mobile Messaging and Telemetry.
 +
 +There are advantages which mare MQTT the protocol of choice for deploying scalable applications,​ such as being lightweight and efficient – ideal for low-power and low-bandwidth environments,​ decouples producers and consumers of data and scales well for large networks of devices.
  
 {{ :​iothings:​laboratoare:​2025:​mqtt-pubsub-model.jpg?​600 |}} {{ :​iothings:​laboratoare:​2025:​mqtt-pubsub-model.jpg?​600 |}}
Line 20: Line 22:
   - Subscriptions can use wildcards (e.g., ''​sensors/​+/​room1''​) to match multiple topics.   - Subscriptions can use wildcards (e.g., ''​sensors/​+/​room1''​) to match multiple topics.
  
-==== Advantages ​====+==== MQTT Wildcards and Topic Matching ​==== 
 + 
 +MQTT uses a **topic-based publish-subscribe** model, and part of its flexibility comes from the use of **wildcard characters** in topic **subscriptions**. 
 + 
 +=== Topic Structure === 
 +  * Topics are **case-sensitive** UTF-8 strings. 
 +  * Hierarchical,​ separated by slashes (''/''​):​ 
 + 
 +    Example topics: 
 +    * ''​sensors/​temperature/​room1''​ 
 +    * ''​sensors/​humidity/​room2''​ 
 + 
 +   * MQTT supports **two wildcard characters**,​ used **only in subscriptions**:​ 
 + 
 +== + (Single-Level Wildcard) == 
 + 
 +  * Matches **exactly one level** in a topic hierarchy. 
 +  * Example: ''​sensors/​+/​room1''​ 
 + 
 +    Matches: 
 +    * ''​sensors/​temperature/​room1''​ 
 +    * ''​sensors/​humidity/​room1''​ 
 + 
 +    Does **not** match: 
 +    * ''​sensors/​room1''​ 
 +    * ''​sensors/​temperature/​office/​room1''​ 
 +{{ :​iothings:​laboratoare:​2025:​single-level-wild-card--1-.png?​600 |}} 
 + 
 +== # (Multi-Level Wildcard) == 
 + 
 +  * Matches **all remaining levels** (including zero levels). 
 +  * Must be the **last character** in the topic filter. 
 +  * Example: ''​sensors/#''​ 
 + 
 +    Matches: 
 +    * ''​sensors/​temperature''​ 
 +    * ''​sensors/​temperature/​room1''​ 
 +    * ''​sensors/​humidity/​room2/​sensor3''​ 
 + 
 +  * ''#''​ alone matches **all topics**. 
 + 
 +{{ :​iothings:​laboratoare:​2025:​single-level-wild-card--1--1.png?​600 |}} 
 + 
 +== Rules and Constraints == 
 +  * Wildcards **can only be used in subscriptions**,​ **not in publish topics**. 
 +  * ''#''​ must appear only at the **end** of the topic filter. 
 +  * ''​+''​ must occupy **an entire level** (between slashes). 
 +  * Example: ''​sensor/​+/​status''​ subscribes to: 
 +    * ''​sensor/​device1/​status''​ 
 +    * ''​sensor/​device2/​status''​ 
 + 
 +== Use Case Tips == 
 + 
 +  * Use ''​+''​ to match variations at a single level. 
 +  * Use ''#''​ to subscribe to entire branches of the topic tree. 
 +  * Avoid ''#''​ in production if not necessary — it can overwhelm clients with messages.
  
-  * Lightweight and efficient – ideal for low-power and low-bandwidth environments. 
-  * Decouples producers and consumers of data. 
-  * Scales well for large networks of devices. 
  
 ==== Lab Applications ==== ==== Lab Applications ====
Line 32: Line 86:
  
 ==== Platformio.ini ==== ==== Platformio.ini ====
-You will need to add this to yout Platformio project: +You will need to add this to your Platformio project:
- +
-++++ Click here+
  
 <code bash platformio.ini>​ <code bash platformio.ini>​
Line 63: Line 115:
   adafruit/​Adafruit BME680 Library   adafruit/​Adafruit BME680 Library
   bblanchon/​ArduinoJson @ ^7   bblanchon/​ArduinoJson @ ^7
-  256dpi/MQTT @ ^2.5.2 ​      ​+  256dpi/MQTT @ ^2.5.2 ​   
 +  knolleary/​PubSubClient @ ^2.8    ​
 </​code>​ </​code>​
  
----- 
  
 ===== MQTT “Hello World” (publish a heartbeat) ===== ===== MQTT “Hello World” (publish a heartbeat) =====
Line 76: Line 128:
 Once connected, the ESP32 enters a loop where it continuously maintains the MQTT session, reconnects if needed, and publishes a heartbeat message every five seconds containing its uptime in milliseconds. This heartbeat acts as a regular signal that the device is alive. The code’s use of non-blocking MQTT functions keeps the system responsive, while the combination of retained status messages and the Last Will feature ensures other clients always know the ESP32’s current state — whether it’s online, offline, or actively sending updates. Once connected, the ESP32 enters a loop where it continuously maintains the MQTT session, reconnects if needed, and publishes a heartbeat message every five seconds containing its uptime in milliseconds. This heartbeat acts as a regular signal that the device is alive. The code’s use of non-blocking MQTT functions keeps the system responsive, while the combination of retained status messages and the Last Will feature ensures other clients always know the ESP32’s current state — whether it’s online, offline, or actively sending updates.
  
-<code C main.cpp> +[[iothings:​laboratoare:​2025_code:​lab3_1|Click here to get the code for this example.]]
-#include <​Arduino.h>​ +
-#include <​WiFi.h>​ +
-#include <​MQTT.h> ​  // 256dpi MQTT library+
  
-////////////////​ EDIT THESE ////////////////​ +After building and uploading to your Sparrow nodetest it out using [[https://​dantudose.github.io/​labs/​lab3_1.html | this link]].
-const char* WIFI_SSID ​    = "​YOUR_SSID";​ +
-const char* WIFI_PASSWORD = "​YOUR_PASSWORD";​ +
-const char* MQTT_HOST ​    = "​test.mosquitto.org"; ​  // or your lab broker +
-const uint16_t MQTT_PORT ​ = 1883; +
-const char* BASE_TOPIC ​   = "​iot/​studentname"; ​       // change per student +
-////////////////////////////////////////////​ +
- +
-WiFiClient net; +
-MQTTClient mqtt(1024); ​ // 1KB message buffer +
- +
-unsigned long lastPub = 0; +
- +
-void connectWiFi() { +
-  if (WiFi.status() == WL_CONNECTED) return; +
-  WiFi.mode(WIFI_STA);​ +
-  WiFi.begin(WIFI_SSIDWIFI_PASSWORD);​ +
-  Serial.print("​WiFi connecting"​);​ +
-  while (WiFi.status() != WL_CONNECTED) { +
-    delay(500);​ +
-    Serial.print("​."​);​ +
-  } +
-  Serial.printf("​\nWiFi OK, IP: %s\n", WiFi.localIP().toString().c_str());​ +
-+
- +
-void messageReceived(String &topic, String &​payload) { +
-  Serial.printf("​Message on %s: %s\n", topic.c_str(),​ payload.c_str());​ +
-+
- +
-void connectMQTT() { +
-  // Build a real String, then pass c_str() +
-  String clientId = "​esp32-client-"​ + String((uint32_t)ESP.getEfuseMac(),​ HEX); +
- +
-  Serial.println("​MQTT connecting..."​);​ +
-  while (!mqtt.connect(clientId.c_str())) { +
-    Serial.print("​."​);​ +
-    delay(1000);​ +
-  } +
-  Serial.println("​\nMQTT connected!"​);​ +
- +
-  // Optional subscription +
-  String subTopic = String(BASE_TOPIC) + "/#";​ +
-  mqtt.subscribe(subTopic);​ +
-  Serial.printf("​Subscribed to %s\n", subTopic.c_str());​ +
-+
- +
-void setup() { +
-  Serial.begin(115200);​ +
-  delay(500);​ +
- +
-  connectWiFi();​ +
- +
-  mqtt.begin(MQTT_HOST,​ MQTT_PORT, net); +
-  mqtt.onMessage(messageReceived);​ +
- +
-  // Optional: last will so brokers/​clients know if we drop +
-  String willTopic = String(BASE_TOPIC) + "/​status";​ +
-  mqtt.setWill(willTopic.c_str(),​ "​offline",​ true, 1); +
- +
-  connectMQTT();​ +
- +
-  // Publish "​online"​ once connected +
-  mqtt.publish(willTopic,​ "​online",​ true, 1); +
-+
- +
-void loop() { +
-  connectWiFi(); ​      // ensure WiFi +
-  if (!mqtt.connected()) connectMQTT();​ +
-  mqtt.loop(); ​        // non-blocking +
-  delay(10);​ +
- +
-  // Publish every 5 seconds +
-  if (millis() - lastPub > 5000) { +
-    lastPub = millis(); +
-    String topic = String(BASE_TOPIC) + "/​heartbeat";​ +
-    String payload = String("​{\"​uptime_ms\":"​) + millis() + "​}";​ +
-    bool ok = mqtt.publish(topic,​ payload); +
-    Serial.printf("​Publish %s => %s (%s)\n",​ +
-                  topic.c_str(),​ payload.c_str(),​ ok ? "​OK"​ : "​FAIL"​);​ +
-  } +
-+
- +
-</​code>​ +
- +
-Test it out using [[https://​dantudose.github.io/​labs/​lab3_1.html | this link]].+
  
 ===== Subscribe & control the on-board NeoPixel ===== ===== Subscribe & control the on-board NeoPixel =====
Line 176: Line 141:
 After setting the LED color, the device publishes an acknowledgment message to a separate MQTT topic, confirming the values it received and applied. This acknowledgment lets any remote controller or dashboard know that the LED update was successful. The whole process uses the non-blocking,​ event-driven design of the 256dpi library, meaning it can handle MQTT communication efficiently without freezing the microcontroller’s main loop. In essence, this sketch turns the ESP32 into a small, networked RGB controller that listens for MQTT commands and reports its actions back to the broker. After setting the LED color, the device publishes an acknowledgment message to a separate MQTT topic, confirming the values it received and applied. This acknowledgment lets any remote controller or dashboard know that the LED update was successful. The whole process uses the non-blocking,​ event-driven design of the 256dpi library, meaning it can handle MQTT communication efficiently without freezing the microcontroller’s main loop. In essence, this sketch turns the ESP32 into a small, networked RGB controller that listens for MQTT commands and reports its actions back to the broker.
  
-<code C main.cpp> +[[iothings:​laboratoare:​2025_code:​lab3_2| Click here to get the code for this example.]]
-#include <​Arduino.h>​ +
-#include <​WiFi.h>​ +
-#include <​MQTT.h> ​             // 256dpi MQTT library +
-#include <​ArduinoJson.h>​ +
-#include <​Adafruit_NeoPixel.h>​+
  
-////////////////​ EDIT THESE ////////////////​ 
-const char* WIFI_SSID ​    = "​YOUR_SSID";​ 
-const char* WIFI_PASSWORD = "​YOUR_PASSWORD";​ 
-const char* MQTT_HOST ​    = "​test.mosquitto.org"; ​  // or your lab broker 
-const uint16_t MQTT_PORT ​ = 1883; 
-const char* BASE_TOPIC ​   = "​iot/​studentname"; ​       // change per student 
-////////////////////////////////////////////​ 
- 
-#define NEOPIXEL_PIN 3 
-Adafruit_NeoPixel pixel(1, NEOPIXEL_PIN,​ NEO_GRB + NEO_KHZ800);​ 
- 
-WiFiClient net; 
-MQTTClient mqtt(1024); ​        // 1KB message buffer 
- 
-// ---------- Wi-Fi ---------- 
-void ensureWiFi() { 
-  if (WiFi.status() == WL_CONNECTED) return; 
-  WiFi.mode(WIFI_STA);​ 
-  WiFi.begin(WIFI_SSID,​ WIFI_PASSWORD);​ 
-  Serial.print("​WiFi connecting"​);​ 
-  while (WiFi.status() != WL_CONNECTED) { 
-    delay(400); 
-    Serial.print("​."​);​ 
-  } 
-  Serial.printf("​\nIP:​ %s\n", WiFi.localIP().toString().c_str());​ 
-} 
- 
-// ---------- MQTT message handler (256dpi signature) ---------- 
-void onMessage(String &topic, String &​payload) { 
-  Serial.printf("​MQTT msg on %s: %s\n", topic.c_str(),​ payload.c_str());​ 
- 
-  // Create a dynamic document on the stack with a defined capacity 
-  JsonDocument doc;  ​ 
-  DeserializationError err = deserializeJson(doc,​ payload); 
-  if (err) { 
-    Serial.printf("​JSON parse error: %s\n", err.c_str());​ 
-    return; 
-  } 
- 
-  int r = doc["​r"​] | 0; 
-  int g = doc["​g"​] | 0; 
-  int b = doc["​b"​] | 0; 
-  int brightness = doc["​brightness"​] | 50; 
- 
-  pixel.setPixelColor(0,​ pixel.Color(r,​ g, b)); 
-  pixel.setBrightness(brightness);​ 
-  pixel.show();​ 
- 
-  // Acknowledge 
-  String ackTopic = String(BASE_TOPIC) + "/​led/​ack";​ 
-  JsonDocument ack;  // also replace StaticJsonDocument here 
-  ack["​ok"​] = true; 
-  ack["​r"​] = r; 
-  ack["​g"​] = g; 
-  ack["​b"​] = b; 
-  ack["​brightness"​] = brightness; 
- 
-  char buf[96]; 
-  size_t n = serializeJson(ack,​ buf, sizeof(buf));​ 
-  mqtt.publish(ackTopic,​ String(buf, n)); 
-} 
- 
- 
-// ---------- MQTT connect / subscribe ---------- 
-void ensureMQTT() { 
-  if (mqtt.connected()) return; 
- 
-  String clientId = "​sparrow-c6-led-"​ + String((uint32_t)ESP.getEfuseMac(),​ HEX); 
- 
-  Serial.println("​MQTT connecting..."​);​ 
-  while (!mqtt.connect(clientId.c_str())) { 
-    Serial.print("​."​);​ 
-    delay(1000);​ 
-  } 
-  Serial.println("​\nMQTT connected"​);​ 
- 
-  String sub = String(BASE_TOPIC) + "/​led";​ 
-  mqtt.subscribe(sub);​ 
-  Serial.printf("​Subscribed:​ %s\n", sub.c_str());​ 
-} 
- 
-void setup() { 
-  Serial.begin(115200);​ 
-  delay(200); 
- 
-  pixel.begin();​ 
-  pixel.clear();​ 
-  pixel.show();​ 
- 
-  // Broker + transport setup and callback 
-  mqtt.begin(MQTT_HOST,​ MQTT_PORT, net); 
-  mqtt.onMessage(onMessage);​ 
-} 
- 
-void loop() { 
-  ensureWiFi();​ 
-  ensureMQTT();​ 
- 
-  // Process incoming packets and keepalive 
-  mqtt.loop();​ 
-  delay(10); 
-} 
- 
-</​code>​ 
 Test it out using [[https://​dantudose.github.io/​labs/​lab3_2.html | this link]]. Test it out using [[https://​dantudose.github.io/​labs/​lab3_2.html | this link]].
  
Line 295: Line 151:
 Every ten seconds, the ESP32 reads environmental data from the on-board BME680 sensor—including temperature,​ humidity, pressure, and gas resistance—and packages those readings into a JSON message. It then publishes this JSON payload to an MQTT topic dedicated to that device’s sensor data. Any other MQTT clients subscribed to that topic can instantly receive and process the latest environmental information,​ such as for logging, visualization,​ or automation. In short, this code makes the ESP32 function as a small, networked environmental node that continuously streams live sensor data to the MQTT ecosystem while maintaining reliable connection status reporting. Every ten seconds, the ESP32 reads environmental data from the on-board BME680 sensor—including temperature,​ humidity, pressure, and gas resistance—and packages those readings into a JSON message. It then publishes this JSON payload to an MQTT topic dedicated to that device’s sensor data. Any other MQTT clients subscribed to that topic can instantly receive and process the latest environmental information,​ such as for logging, visualization,​ or automation. In short, this code makes the ESP32 function as a small, networked environmental node that continuously streams live sensor data to the MQTT ecosystem while maintaining reliable connection status reporting.
  
-<code C main.cpp>​ +[[iothings:laboratoare:2025_code:​lab3_3|Click here to get the code for this example.]]
-#include <​Arduino.h>​ +
-#include <​WiFi.h>​ +
-#include <​Wire.h>​ +
-#include <​MQTT.h> ​              +
-#include <​ArduinoJson.h>​ +
-#include <​Adafruit_BME680.h>​ +
- +
-////////////////​ EDIT THESE ////////////////​ +
-const char* WIFI_SSID ​    = "​YOUR_SSID";​ +
-const char* WIFI_PASSWORD = "​YOUR_PASSWORD";​ +
-const char* MQTT_HOST ​    = "​test.mosquitto.org"; ​  // or your lab broker +
-const uint16_t MQTT_PORT ​ = 1883; +
-const char* BASE_TOPIC ​   = "​iot/​studentname"; ​       // change per student +
-////////////////////////////////////////////​ +
- +
-// Sparrow I2CSDA=21, SCL=22 +
-#define SDA_PIN 21 +
-#define SCL_PIN 22 +
-Adafruit_BME680 bme;  // I2C +
- +
-WiFiClient net; +
-MQTTClient mqtt(1024); ​  // 1KB message buffer +
- +
-void ensureWiFi() { +
-  if (WiFi.status() == WL_CONNECTED) return; +
-  WiFi.mode(WIFI_STA);​ +
-  WiFi.begin(WIFI_SSID,​ WIFI_PASSWORD);​ +
-  Serial.print("​WiFi connecting"​);​ +
-  while (WiFi.status() != WL_CONNECTED) { +
-    delay(400);​ +
-    Serial.print("​."​);​ +
-  } +
-  Serial.printf("​\nIP%s\n", WiFi.localIP().toString().c_str());​ +
-+
- +
-void ensureMQTT() { +
-  if (mqtt.connected()) return; +
- +
-  // Optional Last Will so dashboards see offline state +
-  String willTopic = String(BASE_TOPIC) + "/​bme688/​status";​ +
-  mqtt.setWill(willTopic.c_str(),​ "​offline",​ true, 1); +
- +
-  String cid = String("​sparrow-c6-sense-"​) + String((uint32_t)ESP.getEfuseMac(),​ HEX); +
-  Serial.println("​MQTT connecting..."​);​ +
-  while (!mqtt.connect(cid.c_str())) { +
-    Serial.print("​."​);​ +
-    delay(1000);​ +
-  } +
-  Serial.println("​\nMQTT connected"​);​ +
- +
-  // Publish "​online"​ status retained +
-  mqtt.publish(willTopic,​ "​online",​ true, 1); +
-+
- +
-unsigned long lastPub = 0; +
- +
-void setup() { +
-  Serial.begin(115200);​ +
-  delay(200);​ +
- +
-  Wire.begin(SDA_PIN,​ SCL_PIN); +
- +
-  // MQTT broker + transport +
-  mqtt.begin(MQTT_HOST,​ MQTT_PORT, net); +
- +
-  if (!bme.begin(0x76)) {           // Sparrow uses 0x76 +
-    Serial.println("​BME688 not found!"​);​ +
-    ​for(;;) { delay(1000);​ } +
-  } +
-  // Reasonable oversampling;​ heater off for simplicity +
-  bme.setTemperatureOversampling(BME680_OS_8X);​ +
-  bme.setHumidityOversampling(BME680_OS_2X);​ +
-  bme.setPressureOversampling(BME680_OS_4X);​ +
-  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);​ +
-  bme.setGasHeater(0,​ 0);  // off +
-+
- +
-void loop() { +
-  ensureWiFi();​ +
-  ensureMQTT();​ +
- +
-  mqtt.loop(); ​    // process incoming/​keepalive +
-  delay(10);​ +
- +
-  if (millis() - lastPub > 10000) { +
-    lastPub = millis(); +
- +
-    if (!bme.performReading()) { +
-      Serial.println("​BME read failed"​);​ +
-      return; +
-    } +
- +
-    // Build JSON (ArduinoJson v7 style, no deprecated StaticJsonDocument) +
-    JsonDocument doc; +
-    doc["​ts"​       = (uint32_t)(millis() / 1000); +
-    doc["​temp_c"​   = bme.temperature;​ +
-    doc["​hum_pct"​] ​  = bme.humidity;​ +
-    doc["​press_hpa"​] = bme.pressure / 100.0; +
-    doc["​gas_ohm"​] ​  = bme.gas_resistance;​ +
- +
-    String payload; +
-    serializeJson(doc,​ payload); +
- +
-    String topic = String(BASE_TOPIC) + "/​bme688";​ +
-    bool ok = mqtt.publish(topic,​ payload); ​ // QoS0, non-retained +
-    Serial.printf("​Pub %s => %s (%s)\n",​ +
-                  topic.c_str(),​ payload.c_str(),​ ok ? "​OK"​ : "​FAIL"​);​ +
-  } +
-+
- +
-</​code>​+
  
 Test it out using [[https://​dantudose.github.io/​labs/​lab3_3.html | this link]]. Test it out using [[https://​dantudose.github.io/​labs/​lab3_3.html | this link]].
Line 418: Line 163:
 At the same time, the ESP32 regularly publishes telemetry data through MQTT. It sends heartbeat messages with uptime, signal strength, and network information,​ and it transmits environmental sensor readings from the BME680 to a designated topic as JSON data. All MQTT communication uses Quality of Service level 1 to ensure that messages are delivered at least once, providing reliable data exchange between the device and the broker. The code also manages automatic reconnection with exponential backoff, meaning it gracefully retries connecting to the MQTT broker when disconnected without flooding the network. In essence, from the MQTT point of view, this device behaves as a resilient, bidirectional IoT client that reports data, accepts remote commands, and maintains a persistent, reliable session with the broker. At the same time, the ESP32 regularly publishes telemetry data through MQTT. It sends heartbeat messages with uptime, signal strength, and network information,​ and it transmits environmental sensor readings from the BME680 to a designated topic as JSON data. All MQTT communication uses Quality of Service level 1 to ensure that messages are delivered at least once, providing reliable data exchange between the device and the broker. The code also manages automatic reconnection with exponential backoff, meaning it gracefully retries connecting to the MQTT broker when disconnected without flooding the network. In essence, from the MQTT point of view, this device behaves as a resilient, bidirectional IoT client that reports data, accepts remote commands, and maintains a persistent, reliable session with the broker.
  
-<code C main.cpp>​ +[[iothings:laboratoare:2025_code:lab3_4|Click here to access your code for this example.]]
-#include <​Arduino.h>​ +
-#include <​WiFi.h>​ +
-#include <​WiFiClientSecure.h>​ +
-#include <​MQTT.h>​ +
-#include <​Wire.h>​ +
-#include <​Adafruit_BME680.h>​ +
-#include <​Adafruit_NeoPixel.h>​ +
-#include <​ArduinoJson.h>​ +
- +
-////////////////​ EDIT THESE ////////////////​ +
-const char* WIFI_SSID ​    = "​YOUR_SSID";​ +
-const char* WIFI_PASSWORD = "​YOUR_PASSWORD";​ +
-const char* MQTT_HOST ​    = "​test.mosquitto.org"; ​  // or your lab broker +
-const uint16_t MQTT_PORT ​ = 1883; +
-const char* BASE_TOPIC ​   = "​iot/​studentname"; ​        // change per student +
-////////////////////////////////////////////​ +
- +
-#define SDA_PIN 21 +
-#define SCL_PIN 22 +
-#define NEOPIXEL_PIN 3 +
- +
-WiFiClient net; +
-MQTTClient mqtt(2048);​ +
-Adafruit_BME680 bme; +
-Adafruit_NeoPixel pixel(1, NEOPIXEL_PIN,​ NEO_GRB + NEO_KHZ800);​ +
- +
-unsigned long nextConnTry = 0; +
-uint32_t backoffMs = 1000; +
-unsigned long lastHeartbeat = 0; +
-unsigned long lastSensorPub = 0; +
- +
-void ensureWiFi() { +
-  if (WiFi.status() == WL_CONNECTED) return; +
-  WiFi.mode(WIFI_STA);​ +
-  WiFi.begin(WIFI_SSID,​ WIFI_PASSWORD);​ +
-  Serial.print("​WiFi connecting"​);​ +
-  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("​."​);​ } +
-  Serial.printf("​\nWiFi OK, IP: %s, RSSI: %d dBm\n",​ WiFi.localIP().toString().c_str(),​ WiFi.RSSI());​ +
-+
- +
-void setLED(uint8_t r, uint8_t g, uint8_t b, uint8_t brightness) { +
-  pixel.setBrightness(brightness);​ +
-  pixel.setPixelColor(0,​ pixel.Color(r,​ g, b)); +
-  pixel.show();​ +
-+
- +
-void handleLEDJson(const String& payload) { +
-  JsonDocument doc; +
-  DeserializationError err = deserializeJson(doc,​ payload); +
-  if (err) { Serial.printf("​LED JSON parse error: %s\n", err.c_str());​ return; } +
-  uint8_t r = doc["​r"​].isNull() ? 0 : doc["​r"​].as<​uint8_t>​();​ +
-  uint8_t g = doc["​g"​].isNull() ? 0 doc["​g"​].as<​uint8_t>​();​ +
-  uint8_t b = doc["​b"​].isNull() ? 0 doc["​b"​].as<​uint8_t>​();​ +
-  uint8_t br = doc["​brightness"​].isNull() ? 100 doc["​brightness"​].as<​uint8_t>​();​ +
-  setLED(r,​g,​b,​br);​ +
- +
-  JsonDocument ack; +
-  ack["​ok"​] = true; ack["​r"​] = r; ack["​g"​] = g; ack["​b"​] = b; ack["​brightness"​] = br; +
-  String out; serializeJson(ack,​ out); +
-  mqtt.publish((String(BASE_TOPIC)+"/​led/​ack"​).c_str(),​ out.c_str(),​ false, 1); +
-+
- +
-void messageReceived(String &topic, String &​payload) { +
-  Serial.printf("​MSG [%s]: %s\n", topic.c_str(),​ payload.c_str());​ +
-  if (topic == String(BASE_TOPIC) + "/​led"​) handleLEDJson(payload);​ +
-+
- +
-bool connectMQTT() { +
-  String cid = String("​sparrow-c6-qos1-"​) + String((uint32_t)ESP.getEfuseMac(),​ HEX); +
-  mqtt.setCleanSession(true);​ +
-  mqtt.setKeepAlive(30);​ +
-  String willTopic = String(BASE_TOPIC) + "/​status";​ +
-  mqtt.setWill(willTopic.c_str(),​ "​{\"​status\":​\"​offline\"​}",​ true, 1); +
- +
-  Serial.printf("​MQTT connecting ​to %s:%u as %s ...\n", MQTT_HOST, MQTT_PORT, cid.c_str());​ +
-  bool ok = mqtt.connect(cid.c_str(),​ nullptr, nullptr); +
-  if (!ok) { Serial.printf("​MQTT connect failed, error=%d\n",​ mqtt.lastError());​ return false; } +
- +
-  mqtt.subscribe((String(BASE_TOPIC)+"/​led"​).c_str(),​ 1); +
-  mqtt.publish(willTopic.c_str(),​ "​{\"​status\":​\"​online\"​}",​ true, 1); +
-  Serial.println("​MQTT connected"​);​ +
-  return true; +
-+
- +
-void ensureMQTT() { +
-  if (mqtt.connected()) return; +
-  if (millis() < nextConnTry) return; +
-  if (!connectMQTT()) { +
-    backoffMs = min<​uint32_t>​(backoffMs * 2, 30000); +
-    nextConnTry = millis() + backoffMs;​ +
-    Serial.printf("​Retry in %lu ms\n", (unsigned long)backoffMs);​ +
-  } else { +
-    backoffMs = 1000; +
-  } +
-+
- +
-bool readBME(float&​ tC, float& hPct, float& pHpa, float& gas) { +
-  if (!bme.performReading()) return false; +
-  tC = bme.temperature;​ +
-  hPct = bme.humidity;​ +
-  pHpa = bme.pressure / 100.0; +
-  gas = bme.gas_resistance;​ +
-  return true; +
-+
- +
-void setup() { +
-  Serial.begin(115200);​ +
-  pixel.begin();​ +
-  setLED(0,​0,​0,​10);​ +
- +
-  Wire.begin(SDA_PIN,​ SCL_PIN); +
-  if (!bme.begin(0x76)) { +
-    Serial.println("​BME688/​BME680 not found at 0x76!"​);​ +
-  } else { +
-    bme.setTemperatureOversampling(BME680_OS_8X);​ +
-    bme.setHumidityOversampling(BME680_OS_2X);​ +
-    bme.setPressureOversampling(BME680_OS_4X);​ +
-    bme.setIIRFilterSize(BME680_FILTER_SIZE_3);​ +
-    bme.setGasHeater(0,​ 0); +
-  } +
- +
-  mqtt.begin(MQTT_HOST,​ MQTT_PORT, net); +
-  mqtt.onMessage(messageReceived);​ +
-+
- +
-void loop() { +
-  ensureWiFi();​ +
-  ensureMQTT();​ +
-  mqtt.loop();​ +
- +
-  if (mqtt.connected() && millis() - lastHeartbeat > 15000) { +
-    lastHeartbeat = millis(); +
-    JsonDocument hb; +
-    hb["​uptime_s"​= (uint32_t)(millis()/​1000);​ +
-    hb["​ip"​= WiFi.localIP().toString();​ +
-    hb["​rssi"​] = WiFi.RSSI();​ +
-    String out; serializeJson(hb,​ out); +
-    mqtt.publish((String(BASE_TOPIC)+"/​heartbeat"​).c_str(),​ out.c_str(),​ true, 1); +
-    Serial.printf("​Heartbeat -> %s\n", out.c_str());​ +
-  } +
- +
-  if (mqtt.connected() && millis() - lastSensorPub > 10000) { +
-    lastSensorPub = millis(); +
-    float tC, hPct, pHpa, gas; +
-    if (readBME(tC,​ hPct, pHpa, gas)) { +
-      JsonDocument s; +
-      s["​ts"​] = (uint32_t)(millis()/​1000);​ +
-      s["​temp_c"​] = tC; +
-      s["​hum_pct"​] = hPct; +
-      s["​press_hpa"​] = pHpa; +
-      s["​gas_ohm"​] = gas; +
-      String out; serializeJson(s,​ out); +
-      mqtt.publish((String(BASE_TOPIC)+"/​bme688"​).c_str(),​ out.c_str(),​ false, 1); +
-      Serial.printf("​Sensor -> %s\n", out.c_str());​ +
-    } else { +
-      Serial.println("​BME read failed"​);​ +
-    } +
-  } +
-+
- +
-</​code>​+
  
 Test it out using [[https://​dantudose.github.io/​labs/​lab3_4.html | this link]]. Test it out using [[https://​dantudose.github.io/​labs/​lab3_4.html | this link]].
iothings/laboratoare/2025/lab3.1760174613.txt.gz · Last modified: 2025/10/11 12:23 by dan.tudose
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0