#pragma once #include #include "utils.h" #define JSON_SIZE 512 #define TOPIC_SIZE 255 namespace Ha { uint16_t (*publisher)(const char* topic, const char* message); struct DeviceConfig { const char* id = nullptr; const char* name = nullptr; const char* model = nullptr; const char* manufacturer = nullptr; const char* area = nullptr; DeviceConfig* parent = nullptr; DeviceConfig() {} DeviceConfig(const char* id) : id(id) {} DeviceConfig(const char* id, const char* name) : id(id), name(name) {} DeviceConfig(DeviceConfig& d) : id(d.id), name(d.name), model(d.model), manufacturer(d.manufacturer), area(d.area), parent(d.parent) {} void buildConfig(JsonDocument& jsonDoc) { JsonObject device = jsonDoc.createNestedObject("device"); if (name) device["name"] = name; if (model) device["model"] = model; if (manufacturer) device["manufacturer"] = manufacturer; if (area) device["suggested_area"] = area; if (parent) device["via_device"] = parent->id; JsonArray identifiers = device.createNestedArray("identifiers"); identifiers.add(id); } DeviceConfig* withModel(const char* value) { model = value; return this; } DeviceConfig* withManufacturer(const char* value) { manufacturer = value; return this; } DeviceConfig* withArea(const char* value) { area = value; return this; } DeviceConfig* withParent(DeviceConfig* deviceConfig) { parent = deviceConfig; return this; } }; struct Component { const char* entityCategory = nullptr; const char* deviceClass = nullptr; const char* name = nullptr; char* id = nullptr; const char* type = nullptr; char configTopic[TOPIC_SIZE]; DeviceConfig* mainDevice = nullptr; static List components; Component(const char* name, const char* id, const char* type) : name(name), id((char*)id), type(type) { components.add(this); } virtual void buildUniqueId(char* uniqueId) = 0; virtual void buildConfig(JsonDocument& jsonDoc) { if (String{"diagnostic"}.equals(entityCategory)) { 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); } if (mainDevice) mainDevice->buildConfig(jsonDoc); if (entityCategory) jsonDoc["entity_category"] = entityCategory; jsonDoc["name"] = name; char uniqueId[50]; buildUniqueId(uniqueId); jsonDoc["unique_id"] = uniqueId; } }; template struct EntityConfig : Component { EntityConfig(const char* name, const char* id, const char* type) : Component(name, id, type) { } T* withArea(const char* value) { if (mainDevice) mainDevice->withArea(value); return static_cast(this); } T* asDevice(DeviceConfig* deviceConfig) { mainDevice = deviceConfig; return static_cast(this); } T* copyFromDevice(DeviceConfig* deviceConfig) { mainDevice = new DeviceConfig{*deviceConfig}; mainDevice->id = id; mainDevice->name = name; mainDevice->parent = deviceConfig->parent; return static_cast(this); } }; List Component::components; template struct Command : EntityConfig { char commandTopic[TOPIC_SIZE]; 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); } void buildUniqueId(char* uniqueId) override { sprintf(uniqueId, "%s_%s", MAIN_DEVICE_ID, this->id); } void buildConfig(JsonDocument& jsonDoc) override { EntityConfig::buildConfig(jsonDoc); jsonDoc["command_topic"] = commandTopic; } }; typedef void (*onMessage)(const char* msg); struct Button : Command