From a1e95ec23e5f3b7a928042852bd3ce91cdef181f Mon Sep 17 00:00:00 2001 From: Kristjan Komlosi Date: Thu, 5 Feb 2026 21:42:09 +0100 Subject: [PATCH] esp demo sketch --- esp-demo/esp-demo.ino | 284 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 esp-demo/esp-demo.ino diff --git a/esp-demo/esp-demo.ino b/esp-demo/esp-demo.ino new file mode 100644 index 0000000..578ad97 --- /dev/null +++ b/esp-demo/esp-demo.ino @@ -0,0 +1,284 @@ +#include +#include +#include +#include +#include + +// ---- Configure these ---- +const char *WIFI_SSID = "YOUR_WIFI_SSID"; +const char *WIFI_PASS = "YOUR_WIFI_PASS"; + +const char *MQTT_HOST = "192.168.1.10"; // broker address (use host running mosquitto) +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 = D1; // 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); +} + +String uuidV5(const uint8_t namespaceBytes[16], const String &name) { + // SHA1(namespace + name) + SHA1Builder sha; + sha.begin(); + sha.add(namespaceBytes, 16); + sha.add((const uint8_t *)name.c_str(), name.length()); + sha.calculate(); + uint8_t hash[20]; + sha.getHash(hash); + + uint8_t out[16]; + memcpy(out, hash, 16); + + // 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<512> 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[512]; + size_t n = serializeJson(doc, buf, sizeof(buf)); + + String topic = String(MQTT_TOPIC) + "/discovery"; + mqtt.publish(topic.c_str(), buf, n); +} + +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 publishActorState(int state) { + StaticJsonDocument<256> doc; + doc["type"] = "actor_state"; + doc["actor_id"] = actorId; + doc["value"] = state; + + 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); + publishActorState(value); +} + +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); + publishDiscovery(); + } else { + delay(2000); + } + } +} + +void setup() { + pinMode(ACTOR_PIN, OUTPUT); + digitalWrite(ACTOR_PIN, LOW); + + 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.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(); + } +}