refactoring: combine composition and inheritance for building the configuration
This commit is contained in:
parent
2a5fb84d83
commit
1787f20ddb
@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/schema/library.json",
|
||||
"name": "ha-mqtt",
|
||||
"version": "1.3.1",
|
||||
"version": "1.4.0",
|
||||
"description": "Home Assistant classes for integration with MQTT auto discovery",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
113
src/ha.h
113
src/ha.h
@ -13,7 +13,11 @@ namespace Ha {
|
||||
uint16_t(*publisher)(const char* topic, const char* message);
|
||||
typedef void (*onMessage)(const char* msg);
|
||||
|
||||
struct DeviceConfig {
|
||||
struct Config {
|
||||
virtual void buildConfig(JsonDocument& jsonDoc) = 0;
|
||||
};
|
||||
|
||||
struct DeviceConfig : Config {
|
||||
const char* id = nullptr;
|
||||
const char* name = nullptr;
|
||||
const char* model = nullptr;
|
||||
@ -50,7 +54,7 @@ namespace Ha {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) {
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
JsonObject device = jsonDoc.createNestedObject("device");
|
||||
if (name) device["name"] = name;
|
||||
if (model) device["model"] = model;
|
||||
@ -60,9 +64,12 @@ namespace Ha {
|
||||
JsonArray identifiers = device.createNestedArray("identifiers");
|
||||
identifiers.add(id);
|
||||
}
|
||||
|
||||
private:
|
||||
DeviceConfig(const char* id) : id(id) {}
|
||||
};
|
||||
|
||||
struct Component {
|
||||
struct Component : Config {
|
||||
|
||||
template <typename V>
|
||||
struct JsonPairs {
|
||||
@ -121,9 +128,7 @@ namespace Ha {
|
||||
snprintf(configTopic, sizeof(configTopic), BASE_TOPIC"/config", type, MAIN_DEVICE_ID, id);
|
||||
}
|
||||
|
||||
virtual void buildComponentConfig(JsonDocument& jsonDoc) = 0;
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) {
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
if (mainDevice) mainDevice->buildConfig(jsonDoc);
|
||||
if (entityCategory) jsonDoc["entity_category"] = entityCategory;
|
||||
if (deviceClass) jsonDoc["device_class"] = deviceClass;
|
||||
@ -132,8 +137,6 @@ namespace Ha {
|
||||
jsonDoc["unique_id"] = (const char*)uniqueId;
|
||||
buildConfigTopic();
|
||||
|
||||
buildComponentConfig(jsonDoc);
|
||||
|
||||
jsonBooleans.addToJson(jsonDoc);
|
||||
jsonNumbers.addToJson(jsonDoc);
|
||||
jsonStrings.addToJson(jsonDoc);
|
||||
@ -267,12 +270,12 @@ namespace Ha {
|
||||
}
|
||||
};
|
||||
|
||||
struct Command : Component {
|
||||
struct Command : Config {
|
||||
bool retain = false;
|
||||
static unordered_map<string, Command*> mapCommandTopics;
|
||||
|
||||
Command(const char* name, const char* id, const char* type, onMessage f) : Component(name, id, type), f(f) {
|
||||
snprintf(commandTopic, sizeof(commandTopic), BASE_TOPIC"/set", type, MAIN_DEVICE_ID, id);
|
||||
Command(Component* cmp, onMessage f) : f(f), cmp(cmp) {
|
||||
snprintf(commandTopic, sizeof(commandTopic), BASE_TOPIC"/set", cmp->type, MAIN_DEVICE_ID, cmp->id);
|
||||
mapCommandTopics.insert({ string(commandTopic), this });
|
||||
}
|
||||
|
||||
@ -283,28 +286,29 @@ namespace Ha {
|
||||
protected:
|
||||
char commandTopic[TOPIC_SIZE];
|
||||
onMessage f;
|
||||
virtual void buildCommandConfig(JsonDocument& jsonDoc) = 0;
|
||||
|
||||
void buildComponentConfig(JsonDocument& jsonDoc) override {
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
jsonDoc["command_topic"] = (const char*)commandTopic;
|
||||
if (retain) jsonDoc["retain"] = true;
|
||||
buildCommandConfig(jsonDoc);
|
||||
}
|
||||
private:
|
||||
Component* cmp;
|
||||
};
|
||||
|
||||
struct Button : Component, Command {
|
||||
|
||||
Button(const char* name, const char* id, onMessage f = nullptr) : Component(name, id, "button"), Command(this, f) {}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
Command::buildConfig(jsonDoc);
|
||||
}
|
||||
};
|
||||
|
||||
struct Button : Command {
|
||||
|
||||
Button(const char* name, const char* id, onMessage f = nullptr) : Command(name, id, "button", f) {}
|
||||
|
||||
protected:
|
||||
void buildCommandConfig(JsonDocument& jsonDoc) override {}
|
||||
|
||||
};
|
||||
|
||||
struct StateConfig {
|
||||
struct State : Config {
|
||||
char stateTopic[TOPIC_SIZE];
|
||||
|
||||
StateConfig(Component* cmp) : cmp(cmp) {}
|
||||
State(Component* cmp) : cmp(cmp) {}
|
||||
|
||||
void withStateTopic() {
|
||||
snprintf(stateTopic, sizeof(stateTopic), BASE_TOPIC"/state", cmp->type, MAIN_DEVICE_ID, cmp->id);
|
||||
@ -315,66 +319,80 @@ namespace Ha {
|
||||
}
|
||||
|
||||
protected:
|
||||
Component* cmp;
|
||||
void buildConfig(JsonDocument& jsonDoc) {
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
if (stateTopic[0]) jsonDoc["state_topic"] = (const char*)stateTopic;
|
||||
}
|
||||
private:
|
||||
Component* cmp;
|
||||
};
|
||||
|
||||
struct StatefulCommand : Command, StateConfig {
|
||||
struct StatefulCommand : Command, State {
|
||||
static unordered_map<string, Command*> mapRestoreStateTopics;
|
||||
|
||||
StatefulCommand(const char* name, const char* id, const char* type, onMessage f)
|
||||
: Command(name, id, type, f), StateConfig(this) {}
|
||||
StatefulCommand(Component* cmp, onMessage f) : Command(cmp, f), State(cmp) {}
|
||||
|
||||
void restoreFromState() {
|
||||
mapRestoreStateTopics.insert({stateTopic, this});
|
||||
}
|
||||
|
||||
protected:
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Command::buildConfig(jsonDoc);
|
||||
State::buildConfig(jsonDoc);
|
||||
}
|
||||
};
|
||||
|
||||
struct Switch : StatefulCommand {
|
||||
struct Switch : Component, StatefulCommand {
|
||||
|
||||
Switch(const char* name, const char* id, onMessage f = nullptr) : StatefulCommand(name, id, "switch", f) {}
|
||||
Switch(const char* name, const char* id, onMessage f = nullptr) : Component(name, id, "switch"), StatefulCommand(this, f) {}
|
||||
|
||||
void updateState(bool state) {
|
||||
StateConfig::updateState(state ? "ON" : "OFF");
|
||||
State::updateState(state ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
protected:
|
||||
void buildCommandConfig(JsonDocument& jsonDoc) override {
|
||||
StateConfig::buildConfig(jsonDoc);
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
StatefulCommand::buildConfig(jsonDoc);
|
||||
}
|
||||
};
|
||||
|
||||
struct Number : StatefulCommand {
|
||||
struct Number : Component, StatefulCommand {
|
||||
unsigned int min, max, step;
|
||||
|
||||
Number(const char* name, const char* id, onMessage f) : StatefulCommand(name, id, "number", f) {}
|
||||
Number(const char* name, const char* id, onMessage f) : Component(name, id, "number"), StatefulCommand(this, f) {}
|
||||
|
||||
void updateState(unsigned int value) {
|
||||
StateConfig::updateState(to_string(value).c_str());
|
||||
State::updateState(to_string(value).c_str());
|
||||
}
|
||||
|
||||
protected:
|
||||
void buildCommandConfig(JsonDocument& jsonDoc) override {
|
||||
StateConfig::buildConfig(jsonDoc);
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
StatefulCommand::buildConfig(jsonDoc);
|
||||
jsonDoc["min"] = min;
|
||||
jsonDoc["max"] = max;
|
||||
jsonDoc["step"] = step;
|
||||
}
|
||||
};
|
||||
|
||||
struct Sensor : Component, StateConfig {
|
||||
struct Sensor : Component, State {
|
||||
const char* unitMeasure = nullptr;
|
||||
const char* valueTemplate = nullptr;
|
||||
unsigned int precision = 2;
|
||||
static unordered_map<string, Sensor*> mapSensors;
|
||||
|
||||
Sensor(const char* name, const char* id) : Component(name, id, "sensor"), StateConfig(this) {
|
||||
Sensor(const char* name, const char* id) : Component(name, id, "sensor"), State(this) {
|
||||
withStateTopic();
|
||||
mapSensors.insert({ string(id), this });
|
||||
}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
State::buildConfig(jsonDoc);
|
||||
if (unitMeasure) jsonDoc["unit_of_measurement"] = unitMeasure;
|
||||
if (valueTemplate) jsonDoc["value_template"] = valueTemplate;
|
||||
if (isNumericSensor()) jsonDoc["suggested_display_precision"] = precision;
|
||||
}
|
||||
|
||||
protected:
|
||||
void buildUniqueId() override {
|
||||
if (multiValueComponent && deviceClass) {
|
||||
@ -392,13 +410,6 @@ namespace Ha {
|
||||
}
|
||||
}
|
||||
|
||||
void buildComponentConfig(JsonDocument& jsonDoc) override {
|
||||
StateConfig::buildConfig(jsonDoc);
|
||||
if (unitMeasure) jsonDoc["unit_of_measurement"] = unitMeasure;
|
||||
if (valueTemplate) jsonDoc["value_template"] = valueTemplate;
|
||||
if (isNumericSensor()) jsonDoc["suggested_display_precision"] = precision;
|
||||
}
|
||||
|
||||
private:
|
||||
bool isNumericSensor() {
|
||||
return deviceClass || unitMeasure;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user