This is an old revision of the document!
Goal: connect to Wi-Fi, connect to MQTT, then publish a heartbeat every 5s to iot/<yourname>/heartbeat.
// src/main.cpp #include <Arduino.h> #include <WiFi.h> #include <PubSubClient.h> //////////////// EDIT THESE //////////////// const char* WIFI_SSID = "TP-Link_2A64"; const char* WIFI_PASSWORD = "99481100"; const char* MQTT_HOST = "test.mosquitto.org"; // or your lab broker const uint16_t MQTT_PORT = 1883; const char* BASE_TOPIC = "iot/dantudose"; // change per student //////////////////////////////////////////// WiFiClient espClient; PubSubClient mqtt(espClient); 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\n", WiFi.localIP().toString().c_str()); } void ensureMQTT() { if (mqtt.connected()) return; String clientId = String("sparrow-c6-") + String((uint32_t)ESP.getEfuseMac(), HEX); Serial.println("MQTT connecting..."); Serial.println("Client ID:"); Serial.print(clientId); while (!mqtt.connect(clientId.c_str())) { Serial.print("."); delay(1000); } Serial.println("\nMQTT connected"); } unsigned long lastPub = 0; void setup() { Serial.begin(115200); delay(1000); WiFi.useStaticBuffers(true); // small memory win on C6 mqtt.setServer(MQTT_HOST, MQTT_PORT); } void loop() { ensureWiFi(); ensureMQTT(); mqtt.loop(); if (millis() - lastPub > 5000) { lastPub = millis(); String topic = String(BASE_TOPIC) + "/heartbeat"; String payload = String("{\"uptime_ms\":") + millis() + "}"; bool ok = mqtt.publish(topic.c_str(), payload.c_str()); Serial.printf("Publish %s => %s (%s)\n", topic.c_str(), payload.c_str(), ok ? "OK" : "FAIL"); } }
Test it out using this link.
Goal: subscribe to iot/<yourname>/led and set the Sparrow’s single WS2812 LED color from JSON payloads like {“r”:255,”g”:0,”b”:64}.
#include <Arduino.h> #include <WiFi.h> #include <PubSubClient.h> #include <ArduinoJson.h> #include <Adafruit_NeoPixel.h> //////////////// EDIT THESE //////////////// const char* WIFI_SSID = "TP-Link_2A64"; const char* WIFI_PASSWORD = "99481100"; const char* MQTT_HOST = "test.mosquitto.org"; // or your lab broker const uint16_t MQTT_PORT = 1883; const char* BASE_TOPIC = "iot/dantudose"; // change per student //////////////////////////////////////////// #define NEOPIXEL_PIN 3 Adafruit_NeoPixel pixel(1, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); WiFiClient espClient; PubSubClient mqtt(espClient); void ensureWiFi() { if (WiFi.status() == WL_CONNECTED) return; WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); while (WiFi.status() != WL_CONNECTED) { delay(400); Serial.print("."); } Serial.printf("\nIP: %s\n", WiFi.localIP().toString().c_str()); } void onMessage(char* topic, byte* payload, unsigned int len) { Serial.printf("MQTT msg on %s: %.*s\n", topic, len, (char*)payload); StaticJsonDocument<128> doc; DeserializationError err = deserializeJson(doc, payload, len); if (err) return; int r = doc["r"] | 0, g = doc["g"] | 0, b = doc["b"] | 0; pixel.setPixelColor(0, pixel.Color(r, g, b)); pixel.setBrightness(doc["brightness"] | 50); // optional 0..255 pixel.show(); // Acknowledge String ackTopic = String(BASE_TOPIC) + "/led/ack"; StaticJsonDocument<96> ack; ack["ok"] = true; ack["r"] = r; ack["g"] = g; ack["b"] = b; char buf[96]; size_t n = serializeJson(ack, buf); mqtt.publish(ackTopic.c_str(), buf, n); } void ensureMQTT() { if (mqtt.connected()) return; while (!mqtt.connected()) { String cid = String("sparrow-c6-led-") + String((uint32_t)ESP.getEfuseMac(), HEX); if (mqtt.connect(cid.c_str())) break; delay(1000); } String sub = String(BASE_TOPIC) + "/led"; mqtt.subscribe(sub.c_str()); Serial.printf("Subscribed: %s\n", sub.c_str()); } void setup() { Serial.begin(115200); pixel.begin(); pixel.clear(); pixel.show(); mqtt.setServer(MQTT_HOST, MQTT_PORT); mqtt.setCallback(onMessage); } void loop() { ensureWiFi(); ensureMQTT(); mqtt.loop(); }
Test it out using this link.
Goal: read temperature, humidity, pressure (and gas resistance) from the BME688 over I²C and publish every 10s to iot/<yourname>/bme688.
#include <Arduino.h> #include <WiFi.h> #include <Wire.h> #include <PubSubClient.h> #include <ArduinoJson.h> #include <Adafruit_BME680.h> //////////////// EDIT THESE //////////////// const char* WIFI_SSID = "TP-Link_2A64"; const char* WIFI_PASSWORD = "99481100"; const char* MQTT_HOST = "test.mosquitto.org"; // or your lab broker const uint16_t MQTT_PORT = 1883; const char* BASE_TOPIC = "iot/dantudose"; // change per student //////////////////////////////////////////// // Sparrow I2C: SDA=21, SCL=22 #define SDA_PIN 21 #define SCL_PIN 22 Adafruit_BME680 bme; // I2C WiFiClient espClient; PubSubClient mqtt(espClient); void ensureWiFi() { if (WiFi.status() == WL_CONNECTED) return; WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 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; while (!mqtt.connected()) { String cid = String("sparrow-c6-sense-") + String((uint32_t)ESP.getEfuseMac(), HEX); if (mqtt.connect(cid.c_str())) break; delay(1000); } } unsigned long lastPub = 0; void setup() { Serial.begin(115200); Wire.begin(SDA_PIN, SCL_PIN); mqtt.setServer(MQTT_HOST, MQTT_PORT); 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(); if (millis() - lastPub > 10000) { lastPub = millis(); if (!bme.performReading()) { Serial.println("BME read failed"); return; } StaticJsonDocument<192> 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; char payload[192]; size_t n = serializeJson(doc, payload); String topic = String(BASE_TOPIC) + "/bme688"; bool ok = mqtt.publish(topic.c_str(), payload, n); Serial.printf("Pub %s => %s (%s)\n", topic.c_str(), payload, ok ? "OK" : "FAIL"); } }
Test it out using this link.
Goal here is to add production-style robustness: MQTT session properties (LWT, retain, QoS), back-off reconnects, and how to flip to TLS.
#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 = "TP-Link_2A64"; const char* WIFI_PASSWORD = "99481100"; const char* MQTT_HOST = "test.mosquitto.org"; // or your lab broker const uint16_t MQTT_PORT = 1883; const char* BASE_TOPIC = "iot/dantudose"; // 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"); } } }
Test it out using this link.