#include #include #include #include "ha.h" #define MQTT_HOST IPAddress(192, 168, 5, 11) #define MQTT_PORT 1883 namespace Mqtt { void publishConfig(); void publishCommand(); void publishBmp280(); void connect(); void disconnect(); Task tReConnect(5 * TASK_MINUTE, TASK_FOREVER, connect, &ts); Task tPublishConfig(TASK_IMMEDIATE, TASK_ONCE, publishConfig, &ts); Task tPublishBmp(5 * TASK_MINUTE, TASK_FOREVER, publishBmp280, &ts); Task tPublishCommand(TASK_SECOND, TASK_FOREVER, publishCommand, &ts); AsyncMqttClient client; struct { const char* topic = "esp_clock/sensor/ir/value"; std::queue queue; uint8_t getCurrent() { return queue.empty() ? 0 : queue.front(); } void push(uint8_t el) { if (client.connected()) queue.push(el); } void pop() { queue.pop(); } } commands; const char* bmpTopic = "homeassistant/sensor/esp_clock/state"; const char* restartTopic = "homeassistant/button/esp_clock/restart"; const char* ledTopic = "homeassistant/switch/esp_clock/led/set"; const char* hourFormatTopic = "homeassistant/switch/esp_clock/hour_format/set"; const char* espClockTopic = "homeassistant/+/esp_clock/#"; void connect() { client.connect(); } void disconnect() { client.unsubscribe(espClockTopic); client.disconnect(); } Ha::Component components[] = { Ha::TemperatureSensor{"Living room Temperature", "living_room_temperature", "homeassistant/sensor/esp_clock/temperature/config", bmpTopic}, Ha::PressureSensor{"Living room Pressure", "living_room_pressure", "homeassistant/sensor/esp_clock/pressure/config", bmpTopic}, Ha::AltitudeSensor{"Living room Altitude", "living_room_altitude", "homeassistant/sensor/esp_clock/altitude/config", bmpTopic}, Ha::Command{"Restart", "esp_clock_restart", "homeassistant/button/esp_clock/restart/config", restartTopic}, Ha::Command{"ESP Clock Led", "esp_clock_led", "homeassistant/switch/esp_clock/led/config", ledTopic}, Ha::Command{"ESP Clock Format 24h", "esp_clock_format_24h", "homeassistant/switch/esp_clock/hour_format/config", hourFormatTopic} }; void publishComponentConfig(Ha::Component& component) { StaticJsonDocument jsonDoc; component.buildConfig(jsonDoc); char message[JSON_SIZE]; serializeJson(jsonDoc, message); client.publish(component.configTopic, 0, true, message); } void publishConfig() { for (Ha::Component cmp : components) { publishComponentConfig(cmp); } ts.deleteTask(tPublishConfig); } void publishBmp280() { Bmp::data.readAll(); StaticJsonDocument<255> jsonDoc; jsonDoc["temperature"] = Bmp::data.temp; jsonDoc["pressure"] = Bmp::data.pressure; jsonDoc["altitude"] = Bmp::data.altitude; char message[255]; serializeJson(jsonDoc, message); client.publish(bmpTopic, 0, true, message); } void publishCommand() { if (uint8_t cmd = commands.getCurrent()) { char message[32]; sprintf(message, "%X", cmd); if (client.publish(commands.topic, 0, true, message) != 0) { Serial.print(cmd, HEX); Serial.println(); commands.queue.pop(); } } } void onMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { char msg[len + 1]; memcpy(msg, payload, len); msg[len] = 0; if (String{ restartTopic }.equals(topic) && String { "PRESS" }.equals(msg)) { ESP.restart(); } if (String{ ledTopic }.equals(topic)) { if (String{ "ON" }.equals(msg)) { digitalWrite(LED_BUILTIN, LOW); } else { digitalWrite(LED_BUILTIN, HIGH); } } if (String{ hourFormatTopic }.equals(topic)) { if (String{ "ON" }.equals(msg)) { Display::hourFormat24 = true; Display::drawTime(); } else { Display::hourFormat24 = false; Display::drawTime(); } } } void setup() { client.onConnect([](bool sessionPresent) { tPublishConfig.enable(); tPublishBmp.enableIfNot(); tPublishCommand.enableDelayed(); client.subscribe(espClockTopic, 0); tReConnect.disable(); Serial.println("Connected to MQTT"); }); client.onDisconnect([](AsyncMqttClientDisconnectReason reason) { tReConnect.enableDelayed(); tPublishCommand.disable(); tPublishBmp.disable(); Serial.println("Disconnected from MQTT"); }); client.onMessage(onMessage); client.setServer(MQTT_HOST, MQTT_PORT); Serial.println("Connecting to MQTT..."); } }