diff --git a/gateway/include/ha.h b/gateway/include/ha.h index 61515cc..c8a4f33 100644 --- a/gateway/include/ha.h +++ b/gateway/include/ha.h @@ -8,6 +8,7 @@ namespace Ha { uint16_t (*publisher)(const char* topic, const char* message); + typedef void (*onMessage)(const char* msg); struct DeviceConfig { const char* id = nullptr; @@ -17,9 +18,11 @@ namespace Ha { const char* area = nullptr; DeviceConfig* parent = nullptr; - DeviceConfig() {} DeviceConfig(const char* id) : id(id) {} - DeviceConfig(DeviceConfig& d) : id(d.id), name(d.name), model(d.model), manufacturer(d.manufacturer), area(d.area), parent(d.parent) {} + + static DeviceConfig* create(const char* id) { + return new DeviceConfig{ id }; + } void buildConfig(JsonDocument& jsonDoc) { JsonObject device = jsonDoc.createNestedObject("device"); @@ -72,18 +75,15 @@ namespace Ha { components.add(this); } - virtual void buildUniqueId(char* uniqueId) = 0; - + virtual void buildUniqueId(char* uniqueId) { + sprintf(uniqueId, "%s_%s", MAIN_DEVICE_ID, id); + } + virtual void buildConfigTopic() { - if (String{"diagnostic"}.equals(entityCategory) && deviceClass) { - sprintf(configTopic, "homeassistant/%s/%s/%s_%s/config", type, MAIN_DEVICE_ID, deviceClass, id); - } else { - sprintf(configTopic, "homeassistant/%s/%s/%s/config", type, MAIN_DEVICE_ID, id); - } + sprintf(configTopic, "homeassistant/%s/%s/%s/config", type, MAIN_DEVICE_ID, id); } virtual void buildConfig(JsonDocument& jsonDoc) { - buildConfigTopic(); if (mainDevice) mainDevice->buildConfig(jsonDoc); if (entityCategory) jsonDoc["entity_category"] = entityCategory; if (deviceClass) jsonDoc["device_class"] = deviceClass; @@ -91,52 +91,118 @@ namespace Ha { char uniqueId[50]; buildUniqueId(uniqueId); jsonDoc["unique_id"] = uniqueId; + buildConfigTopic(); + } + + void publishConfig() { + StaticJsonDocument jsonDoc; + buildConfig(jsonDoc); + + char message[JSON_SIZE]; + serializeJson(jsonDoc, message); + + publisher(configTopic, message); + } + + void publishCleanupConfig() { + publisher(configTopic, ""); } }; - - template - struct EntityConfig : Component { - - EntityConfig(const char* name, const char* id, const char* type) : Component(name, id, type) { - } - - T* asDevice(DeviceConfig* deviceConfig) { - mainDevice = deviceConfig; - return static_cast(this); - } - - T* ofDevice(const char* id) { - mainDevice = new DeviceConfig{id}; - return static_cast(this); - } - }; - List Component::components; - template - struct Command : EntityConfig { - char commandTopic[TOPIC_SIZE]; + struct AbstractBuilder { + static List builders; - Command(const char* name, const char* id, const char* type) : EntityConfig(name, id, type) { - sprintf(commandTopic, "homeassistant/%s/%s/%s", type, MAIN_DEVICE_ID, id); + AbstractBuilder() { + builders.add(this); } - void buildUniqueId(char* uniqueId) override { - sprintf(uniqueId, "%s_%s", MAIN_DEVICE_ID, this->id); + static void deleteAll() { + List::exec(builders, [](AbstractBuilder* builder) + { delete builder; }); + } + }; + List AbstractBuilder::builders; + + template + struct Builder : AbstractBuilder { + T* cmp; + + Builder(T* cmp) : AbstractBuilder(), cmp(cmp) {} + + Builder(const char* id) : AbstractBuilder() { + cmp = new T{id}; + } + + static Builder& instance(T* c) { + return *(new Builder(c)); + } + + static Builder& instance(const char* id) { + return *(new Builder(id)); + } + + T* build() { + return static_cast(cmp); + } + + Builder& withDeviceClass(const char* value) { + cmp->deviceClass = value; + return *this; + } + + Builder& withUnitMseasure(const char* value) { + cmp->unitMeasure = value; + return *this; + } + + Builder& withValueTemplate(const char* value) { + cmp->valueTemplate = value; + return *this; + } + + Builder& withSecondary(Component* c) { + c->mainDevice = new DeviceConfig{ cmp->id }; + return *this; + } + + Builder& withDiagnostic(Component* c) { + c->entityCategory = "diagnostic"; + c->mainDevice = new DeviceConfig{ cmp->id }; + return *this; + } + + Builder& asDevice(DeviceConfig* deviceConfig) { + cmp->mainDevice = deviceConfig; + return *this; + } + }; + + struct Command : Component { + char commandTopic[TOPIC_SIZE]; + onMessage f; + static unordered_map mapCommands; + + Command(const char* name, const char* id, const char* type, onMessage f) : Component(name, id, type), f(f) { + sprintf(commandTopic, "homeassistant/%s/%s/%s/set", type, MAIN_DEVICE_ID, id); + mapCommands.insert({ string(commandTopic), this }); + } + + virtual void onCommand(const char* msg) { + if (f) f(msg); } void buildConfig(JsonDocument& jsonDoc) override { - EntityConfig::buildConfig(jsonDoc); + Component::buildConfig(jsonDoc); jsonDoc["command_topic"] = commandTopic; } }; + unordered_map Command::mapCommands; - typedef void (*onMessage)(const char* msg); - struct Button : Command