#include #include #include #include #include const char *WIFI_SSID = "seminardemo"; const char *WIFI_PASS = "seminardemo"; const char *MQTT_HOST = "192.168.1.16"; // broker const uint16_t MQTT_PORT = 1883; const char *MQTT_USER = "testuser"; // from test/.env const char *MQTT_PASS = "testpass"; // from test/.env const char *MQTT_TOPIC = "lambdaiot"; // main topic // GPIO const uint8_t ACTOR_PIN = 14; // digital output // Publishing interval (ms) const unsigned long SENSOR_PUBLISH_INTERVAL = 5000; WiFiClient wifiClient; PubSubClient mqtt(wifiClient); String macAddress; String deviceId; String sensorId; String actorId; unsigned long lastPublishAt = 0; // DNS namespace UUID bytes: 6ba7b810-9dad-11d1-80b4-00c04fd430c8 const char *DNS_NAMESPACE_UUID = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; // ---- UUID helpers ---- bool parseUuidBytes(const String &uuidStr, uint8_t out[16]) { String hex = uuidStr; hex.replace("-", ""); if (hex.length() != 32) { return false; } for (int i = 0; i < 16; i++) { char c1 = hex[i * 2]; char c2 = hex[i * 2 + 1]; auto hexVal = [](char c) -> int { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; }; int v1 = hexVal(c1); int v2 = hexVal(c2); if (v1 < 0 || v2 < 0) { return false; } out[i] = (uint8_t)((v1 << 4) | v2); } return true; } String formatUuid(const uint8_t bytes[16]) { char buf[37]; snprintf(buf, sizeof(buf), "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]); return String(buf); } bool parseHexBytes(const String &hex, uint8_t *out, size_t outLen) { if (hex.length() < (int)(outLen * 2)) { return false; } for (size_t i = 0; i < outLen; i++) { char c1 = hex[i * 2]; char c2 = hex[i * 2 + 1]; auto hexVal = [](char c) -> int { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; }; int v1 = hexVal(c1); int v2 = hexVal(c2); if (v1 < 0 || v2 < 0) { return false; } out[i] = (uint8_t)((v1 << 4) | v2); } return true; } String uuidV5(const uint8_t namespaceBytes[16], const String &name) { // SHA1(namespace + name) size_t totalLen = 16 + name.length(); uint8_t *buf = (uint8_t *)malloc(totalLen); if (!buf) { return String(""); } memcpy(buf, namespaceBytes, 16); memcpy(buf + 16, name.c_str(), name.length()); String hashHex = sha1(buf, totalLen); free(buf); uint8_t out[16]; if (!parseHexBytes(hashHex, out, sizeof(out))) { return String(""); } // Set version (5) and variant (RFC 4122) out[6] = (out[6] & 0x0F) | 0x50; out[8] = (out[8] & 0x3F) | 0x80; return formatUuid(out); } // ---- MQTT messaging ---- void publishDiscovery() { StaticJsonDocument<1024> doc; doc["mac_address"] = macAddress; JsonObject dev = doc.createNestedObject("device"); dev["id"] = deviceId; dev["name"] = "ESP8266 Demo"; dev["description"] = "ESP8266 MQTT demo device"; dev["location"] = "Lab"; dev["status_id"] = 1; JsonArray sensors = doc.createNestedArray("sensors"); JsonObject s0 = sensors.createNestedObject(); s0["id"] = sensorId; s0["name"] = "Temperature"; s0["type"] = "ADC"; s0["data_type_id"] = 2; JsonArray actors = doc.createNestedArray("actors"); JsonObject a0 = actors.createNestedObject(); a0["id"] = actorId; a0["name"] = "DigitalOut"; a0["type"] = "GPIO"; a0["data_type_id"] = 1; char buf[1024]; size_t n = serializeJson(doc, buf, sizeof(buf)); Serial.println(n); Serial.println(buf); String topic = String(MQTT_TOPIC) + "/discovery"; Serial.println(topic); int result = mqtt.publish(topic.c_str(), buf, n); Serial.println(result); } void publishSensorReading() { int adc = analogRead(A0); float value = (float)adc; // raw ADC value StaticJsonDocument<256> doc; doc["type"] = "sensor_reading"; doc["sensor_id"] = sensorId; doc["value"] = value; char buf[256]; size_t n = serializeJson(doc, buf, sizeof(buf)); mqtt.publish(MQTT_TOPIC, buf, n); } void publishDeviceCheckResponse() { StaticJsonDocument<256> doc; doc["type"] = "device_check_response"; doc["device_id"] = deviceId; doc["status"] = "ok"; char buf[256]; size_t n = serializeJson(doc, buf, sizeof(buf)); mqtt.publish(MQTT_TOPIC, buf, n); } void handleActorCommand(JsonObject payload) { if (!payload.containsKey("actor_id")) return; String id = payload["actor_id"].as(); if (id != actorId) return; int value = 0; if (payload.containsKey("value")) { if (payload["value"].is()) { value = payload["value"].as() ? 1 : 0; } else if (payload["value"].is()) { value = payload["value"].as() != 0 ? 1 : 0; } else if (payload["value"].is()) { value = payload["value"].as() != 0 ? 1 : 0; } else if (payload["value"].is()) { String v = payload["value"].as(); v.toLowerCase(); if (v == "true" || v == "1" || v == "on") value = 1; else value = 0; } } digitalWrite(ACTOR_PIN, value ? HIGH : LOW); } void handleSensorTrigger(JsonObject payload) { if (!payload.containsKey("sensor_id")) return; String id = payload["sensor_id"].as(); if (id != sensorId) return; publishSensorReading(); } void handleDeviceCheckRequest(JsonObject payload) { if (!payload.containsKey("device_id")) return; String id = payload["device_id"].as(); if (id != deviceId) return; publishDeviceCheckResponse(); } void mqttCallback(char *topic, uint8_t *payload, unsigned int length) { StaticJsonDocument<512> doc; DeserializationError err = deserializeJson(doc, payload, length); if (err) { return; } const char *type = doc["type"] | ""; String msgType = String(type); msgType.toLowerCase(); if (msgType == "actor_command") { handleActorCommand(doc.as()); return; } if (msgType == "sensor_trigger") { handleSensorTrigger(doc.as()); return; } if (msgType == "device_check_request") { handleDeviceCheckRequest(doc.as()); return; } } // ---- Setup/loop ---- void ensureMqtt() { while (!mqtt.connected()) { String clientId = "esp-demo-" + String(ESP.getChipId()); if (mqtt.connect(clientId.c_str(), MQTT_USER, MQTT_PASS)) { mqtt.subscribe(MQTT_TOPIC); delay(1000); publishDiscovery(); } else { delay(2000); } } } void setup() { pinMode(ACTOR_PIN, OUTPUT); digitalWrite(ACTOR_PIN, LOW); Serial.begin(9600); WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); } macAddress = WiFi.macAddress(); macAddress.toLowerCase(); uint8_t dnsNs[16]; parseUuidBytes(String(DNS_NAMESPACE_UUID), dnsNs); String macNoSep = macAddress; macNoSep.replace(":", ""); deviceId = uuidV5(dnsNs, macNoSep); uint8_t deviceNs[16]; parseUuidBytes(deviceId, deviceNs); sensorId = uuidV5(deviceNs, "sensor-0"); actorId = uuidV5(deviceNs, "actor-0"); mqtt.setBufferSize(4096); // Otherwise discovery fails spectacularly mqtt.setServer(MQTT_HOST, MQTT_PORT); mqtt.setCallback(mqttCallback); ensureMqtt(); lastPublishAt = millis(); } void loop() { ensureMqtt(); mqtt.loop(); unsigned long now = millis(); if (now - lastPublishAt >= SENSOR_PUBLISH_INTERVAL) { lastPublishAt = now; publishSensorReading(); } }