#pragma once #include #define JSON_SIZE 512 #define TOPIC_SIZE 255 #define DEVICE_ID "rc-gateway" namespace Ha { struct Component { const char* name; char* id; const char* type; char configTopic[TOPIC_SIZE]; Component(const char* name, const char* id, const char* type) : name(name), id((char*)id), type(type) { sprintf(configTopic, "homeassistant/%s/rc-gateway/%s/config", type, id); } virtual void buildUniqueId(char* uniqueId) = 0; virtual void buildConfig(JsonDocument& jsonDoc) { buildDeviceConfig(jsonDoc); jsonDoc["name"] = name; char uniqueId[50]; buildUniqueId(uniqueId); jsonDoc["unique_id"] = uniqueId; } virtual void buildDeviceConfig(JsonDocument& jsonDoc) { JsonObject device = jsonDoc.createNestedObject("device"); device["name"] = "RC Gateway"; device["model"] = "Huzzah Esp8266"; device["manufacturer"] = "Adafruit"; JsonArray connections = device.createNestedArray("connections"); JsonArray mac = connections.createNestedArray(); mac.add("mac"); mac.add(WiFi.macAddress()); JsonArray identifiers = device.createNestedArray("identifiers"); identifiers.add(DEVICE_ID); } }; struct Command : Component { char commandTopic[TOPIC_SIZE]; Command(const char* name, const char* id, const char* type) : Component(name, id, type) { } void buildUniqueId(char* uniqueId) override { sprintf(uniqueId, "rc_gateway_%s", id); } void buildConfig(JsonDocument& jsonDoc) override { Component::buildConfig(jsonDoc); jsonDoc["command_topic"] = commandTopic; } }; typedef void (*onMessage)(const char* msg); struct Button : Command { static constexpr const char* type = "button"; onMessage f; Button(const char* name, const char* id, onMessage f) : Command(name, id, type), f(f) { sprintf(commandTopic, "homeassistant/%s/rc-gateway/%s", type, id); } }; typedef uint16_t (*publisherFunc)(const char* topic, const char* message); struct Switch : Command { static constexpr const char* type = "switch"; char stateTopic[TOPIC_SIZE]; const char* area; publisherFunc publisher; virtual void onCommand(const char* msg){} Switch(const char* name, const char* id, publisherFunc publisher = nullptr) : Command(name, id, type), publisher(publisher) { sprintf(commandTopic, "homeassistant/%s/rc-gateway/%s/set", type, id); } void buildDeviceConfig(JsonDocument& jsonDoc) override { JsonObject device = jsonDoc.createNestedObject("device"); device["name"] = name; device["via_device"] = DEVICE_ID; device["suggested_area"] = area; JsonArray identifiers = device.createNestedArray("identifiers"); identifiers.add(id); } void buildConfig(JsonDocument& jsonDoc) override { Command::buildConfig(jsonDoc); jsonDoc["name"] = nullptr; jsonDoc["device_class"] = "outlet"; jsonDoc["retain"] = true; if (stateTopic[0]) jsonDoc["state_topic"] = stateTopic; } Switch* withStateTopic() { sprintf(stateTopic, "homeassistant/%s/rc-gateway/%s/state", type, id); return this; } Switch* withArea(const char* area) { this->area = area; return this; } void publishState(bool state) { publisher(stateTopic, state ? "ON" : "OFF"); } }; struct PollinSwitch : Switch { const char* group; unsigned char channel; PollinSwitch(const char* name, const char* group, const unsigned char channel, publisherFunc publisher) : Switch(name, Protocol_1::buildId(group, channel), publisher), group(group), channel(channel) { sprintf(commandTopic, "homeassistant/%s/rc-gateway/%s/set", type, id); } void onCommand(const char* msg) override { (String{ "ON" }.equals(msg)) ? mySwitch.switchOn(group, channel) : mySwitch.switchOff(group, channel); publisher(stateTopic, msg); } void buildConfig(JsonDocument& jsonDoc) override { Switch::buildConfig(jsonDoc); JsonObject device = jsonDoc["device"]; device["manufacturer"] = "Pollin"; } }; struct EasyHomeSwitch : Switch { unsigned long *on; unsigned long *off; EasyHomeSwitch(const char* name, const char* id, unsigned long on[4], unsigned long off[4], publisherFunc publisher) : Switch(name, id, publisher), on(on), off(off) { sprintf(commandTopic, "homeassistant/%s/rc-gateway/%s/set", type, id); } void onCommand(const char* msg) override { mySwitch.setProtocol(4); String{ "ON" }.equals(msg) ? mySwitch.send(on[0], 24) : mySwitch.send(off[0], 24); publisher(stateTopic, msg); } void buildConfig(JsonDocument& jsonDoc) override { Switch::buildConfig(jsonDoc); JsonObject device = jsonDoc["device"]; device["manufacturer"] = "Intertek"; device["model"] = "Easy Home"; } }; struct Sensor : Component { const char* deviceClass; const char* unitMeasure; const char* valueTemplate; static constexpr const char* stateTopic = "homeassistant/sensor/rc-gateway/state"; Sensor(const char* name, const char* id) : Component(name, id, "sensor") { } void buildUniqueId(char* uniqueId) override { sprintf(uniqueId, "living_room_%s", id); } void buildConfig(JsonDocument& jsonDoc) override { Component::buildConfig(jsonDoc); jsonDoc["device_class"] = deviceClass; jsonDoc["unit_of_measurement"] = unitMeasure; jsonDoc["value_template"] = valueTemplate; jsonDoc["state_topic"] = stateTopic; } void buildDeviceConfig(JsonDocument& jsonDoc) override { JsonObject device = jsonDoc.createNestedObject("device"); device["name"] = "Living room"; device["model"] = "BPM280"; device["suggested_area"] = "Living room"; device["via_device"] = "rc-gateway"; JsonArray identifiers = device.createNestedArray("identifiers"); identifiers.add("esp-clock-living-room"); } }; struct TemperatureSensor : Sensor { TemperatureSensor(const char* name, const char* id) : Sensor(name, id) { deviceClass = "temperature"; unitMeasure = "°C"; valueTemplate = "{{ value_json.temperature }}"; } }; struct HumiditySensor : Sensor { HumiditySensor(const char* name, const char* id) : Sensor(name, id) { deviceClass = "humidity"; unitMeasure = "%"; valueTemplate = "{{ value_json.humidity }}"; } }; struct PressureSensor : Sensor { PressureSensor(const char* name, const char* id) : Sensor(name, id) { deviceClass = "pressure"; unitMeasure = "hPa"; valueTemplate = "{{ value_json.pressure }}"; } }; struct AltitudeSensor : Sensor { AltitudeSensor(const char* name, const char* id) : Sensor(name, id) { deviceClass = "distance"; unitMeasure = "m"; valueTemplate = "{{ value_json.altitude }}"; } }; }