fixes:
- use HA's default values for min, max & step - initialize topic arrays with nullptr - re-order code
This commit is contained in:
parent
4873c26384
commit
803d969de6
352
src/ha.h
352
src/ha.h
@ -89,7 +89,7 @@ namespace Ha {
|
||||
StaticJsonDocument<JSON_SIZE> jsonDoc;
|
||||
buildConfig(jsonDoc);
|
||||
|
||||
char message[JSON_SIZE];
|
||||
char message[JSON_SIZE] = {};
|
||||
serializeJson(jsonDoc, message);
|
||||
|
||||
publisher(configTopic, message);
|
||||
@ -110,7 +110,7 @@ namespace Ha {
|
||||
buildConfigTopic();
|
||||
}
|
||||
private:
|
||||
char configTopic[TOPIC_SIZE];
|
||||
char configTopic[TOPIC_SIZE] = {};
|
||||
|
||||
void buildUniqueId(JsonDocument& jsonDoc) {
|
||||
char uniqueId[50];
|
||||
@ -131,6 +131,181 @@ namespace Ha {
|
||||
}
|
||||
};
|
||||
|
||||
struct Command : Config {
|
||||
bool retain = false;
|
||||
static unordered_map<string, Command*> mapCommandTopics;
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
virtual void onCommand(const char* msg) {
|
||||
if (f) f(msg);
|
||||
}
|
||||
|
||||
protected:
|
||||
char commandTopic[TOPIC_SIZE] = {};
|
||||
onMessage f;
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
jsonDoc["command_topic"] = (const char*)commandTopic;
|
||||
if (retain) jsonDoc["retain"] = true;
|
||||
}
|
||||
private:
|
||||
Component* cmp;
|
||||
};
|
||||
|
||||
struct State : Config {
|
||||
char stateTopic[TOPIC_SIZE] = {};
|
||||
const char* jsonAttributesTemplate = nullptr;
|
||||
|
||||
State(Component* cmp) : cmp(cmp) {}
|
||||
|
||||
void withStateTopic() {
|
||||
snprintf(stateTopic, sizeof(stateTopic), BASE_TOPIC"/state", cmp->type, MAIN_DEVICE_ID, cmp->id);
|
||||
}
|
||||
|
||||
void updateState(const char* message) {
|
||||
if (stateTopic[0]) publisher(stateTopic, message);
|
||||
}
|
||||
|
||||
protected:
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
if (stateTopic[0]) {
|
||||
jsonDoc["state_topic"] = (const char*)stateTopic;
|
||||
if (jsonAttributesTemplate) {
|
||||
jsonDoc["json_attributes_template"] = jsonAttributesTemplate;
|
||||
jsonDoc["json_attributes_topic"] = (const char*)stateTopic;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
Component* cmp;
|
||||
};
|
||||
|
||||
struct StatefulCommand : Command, State {
|
||||
static unordered_map<string, Command*> mapRestoreStateTopics;
|
||||
|
||||
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 Button : Component, Command {
|
||||
|
||||
Button(const char* name, const char* id, onMessage f = nullptr) : Component(id, name, "button"), Command(this, f) {}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
Command::buildConfig(jsonDoc);
|
||||
}
|
||||
};
|
||||
|
||||
struct Switch : Component, StatefulCommand {
|
||||
|
||||
Switch(const char* name, const char* id, onMessage f = nullptr) : Component(id, name, "switch"), StatefulCommand(this, f) {}
|
||||
|
||||
void updateState(bool state) {
|
||||
State::updateState(state ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
StatefulCommand::buildConfig(jsonDoc);
|
||||
}
|
||||
};
|
||||
|
||||
struct Number : Component, StatefulCommand {
|
||||
unsigned int min = 1;
|
||||
unsigned int max = 100;
|
||||
unsigned int step = 1;
|
||||
|
||||
Number(const char* name, const char* id, onMessage f) : Component(id, name, "number"), StatefulCommand(this, f) {}
|
||||
|
||||
void updateState(unsigned int value) {
|
||||
State::updateState(to_string(value).c_str());
|
||||
}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
StatefulCommand::buildConfig(jsonDoc);
|
||||
jsonDoc["min"] = min;
|
||||
jsonDoc["max"] = max;
|
||||
jsonDoc["step"] = step;
|
||||
}
|
||||
};
|
||||
|
||||
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(id, name, "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;
|
||||
}
|
||||
|
||||
private:
|
||||
bool isNumericSensor() {
|
||||
return deviceClass || unitMeasure;
|
||||
}
|
||||
};
|
||||
|
||||
struct TemperatureSensor : Sensor {
|
||||
TemperatureSensor(const char* id, const char* name = "Temperature") : Sensor(name, id) {
|
||||
deviceClass = "temperature";
|
||||
unitMeasure = "°C";
|
||||
}
|
||||
};
|
||||
|
||||
struct HumiditySensor : Sensor {
|
||||
HumiditySensor(const char* id, const char* name = "Humidity") : Sensor(name, id) {
|
||||
deviceClass = "humidity";
|
||||
unitMeasure = "%";
|
||||
}
|
||||
};
|
||||
|
||||
struct PressureSensor : Sensor {
|
||||
PressureSensor(const char* id, const char* name = "Pressure") : Sensor(name, id) {
|
||||
deviceClass = "pressure";
|
||||
unitMeasure = "hPa";
|
||||
}
|
||||
};
|
||||
|
||||
struct VoltageSensor : Sensor {
|
||||
VoltageSensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) {
|
||||
this->valueTemplate = valueTemplate;
|
||||
deviceClass = "voltage";
|
||||
unitMeasure = "V";
|
||||
}
|
||||
};
|
||||
|
||||
struct BatterySensor : Sensor {
|
||||
BatterySensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) {
|
||||
this->valueTemplate = valueTemplate;
|
||||
deviceClass = "battery";
|
||||
unitMeasure = "%";
|
||||
}
|
||||
};
|
||||
|
||||
struct AbstractBuilder {
|
||||
static List<AbstractBuilder> builders;
|
||||
|
||||
@ -248,179 +423,6 @@ namespace Ha {
|
||||
}
|
||||
};
|
||||
|
||||
struct Command : Config {
|
||||
bool retain = false;
|
||||
static unordered_map<string, Command*> mapCommandTopics;
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
virtual void onCommand(const char* msg) {
|
||||
if (f) f(msg);
|
||||
}
|
||||
|
||||
protected:
|
||||
char commandTopic[TOPIC_SIZE];
|
||||
onMessage f;
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
jsonDoc["command_topic"] = (const char*)commandTopic;
|
||||
if (retain) jsonDoc["retain"] = true;
|
||||
}
|
||||
private:
|
||||
Component* cmp;
|
||||
};
|
||||
|
||||
struct Button : Component, Command {
|
||||
|
||||
Button(const char* name, const char* id, onMessage f = nullptr) : Component(id, name, "button"), Command(this, f) {}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
Command::buildConfig(jsonDoc);
|
||||
}
|
||||
};
|
||||
|
||||
struct State : Config {
|
||||
char stateTopic[TOPIC_SIZE];
|
||||
const char* jsonAttributesTemplate = nullptr;
|
||||
|
||||
State(Component* cmp) : cmp(cmp) {}
|
||||
|
||||
void withStateTopic() {
|
||||
snprintf(stateTopic, sizeof(stateTopic), BASE_TOPIC"/state", cmp->type, MAIN_DEVICE_ID, cmp->id);
|
||||
}
|
||||
|
||||
void updateState(const char* message) {
|
||||
if (stateTopic[0]) publisher(stateTopic, message);
|
||||
}
|
||||
|
||||
protected:
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
if (stateTopic[0]) {
|
||||
jsonDoc["state_topic"] = (const char*)stateTopic;
|
||||
if (jsonAttributesTemplate) {
|
||||
jsonDoc["json_attributes_template"] = jsonAttributesTemplate;
|
||||
jsonDoc["json_attributes_topic"] = (const char*)stateTopic;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
Component* cmp;
|
||||
};
|
||||
|
||||
struct StatefulCommand : Command, State {
|
||||
static unordered_map<string, Command*> mapRestoreStateTopics;
|
||||
|
||||
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 : Component, StatefulCommand {
|
||||
|
||||
Switch(const char* name, const char* id, onMessage f = nullptr) : Component(id, name, "switch"), StatefulCommand(this, f) {}
|
||||
|
||||
void updateState(bool state) {
|
||||
State::updateState(state ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
StatefulCommand::buildConfig(jsonDoc);
|
||||
}
|
||||
};
|
||||
|
||||
struct Number : Component, StatefulCommand {
|
||||
unsigned int min, max, step;
|
||||
|
||||
Number(const char* name, const char* id, onMessage f) : Component(id, name, "number"), StatefulCommand(this, f) {}
|
||||
|
||||
void updateState(unsigned int value) {
|
||||
State::updateState(to_string(value).c_str());
|
||||
}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
StatefulCommand::buildConfig(jsonDoc);
|
||||
jsonDoc["min"] = min;
|
||||
jsonDoc["max"] = max;
|
||||
jsonDoc["step"] = step;
|
||||
}
|
||||
};
|
||||
|
||||
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(id, name, "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;
|
||||
}
|
||||
|
||||
private:
|
||||
bool isNumericSensor() {
|
||||
return deviceClass || unitMeasure;
|
||||
}
|
||||
};
|
||||
|
||||
struct TemperatureSensor : Sensor {
|
||||
TemperatureSensor(const char* id, const char* name = "Temperature") : Sensor(name, id) {
|
||||
deviceClass = "temperature";
|
||||
unitMeasure = "°C";
|
||||
}
|
||||
};
|
||||
|
||||
struct VoltageSensor : Sensor {
|
||||
VoltageSensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) {
|
||||
this->valueTemplate = valueTemplate;
|
||||
deviceClass = "voltage";
|
||||
unitMeasure = "V";
|
||||
}
|
||||
};
|
||||
|
||||
struct BatterySensor : Sensor {
|
||||
BatterySensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) {
|
||||
this->valueTemplate = valueTemplate;
|
||||
deviceClass = "battery";
|
||||
unitMeasure = "%";
|
||||
}
|
||||
};
|
||||
|
||||
struct HumiditySensor : Sensor {
|
||||
HumiditySensor(const char* id, const char* name = "Humidity") : Sensor(name, id) {
|
||||
deviceClass = "humidity";
|
||||
unitMeasure = "%";
|
||||
}
|
||||
};
|
||||
|
||||
struct PressureSensor : Sensor {
|
||||
PressureSensor(const char* id, const char* name = "Pressure") : Sensor(name, id) {
|
||||
deviceClass = "pressure";
|
||||
unitMeasure = "hPa";
|
||||
}
|
||||
};
|
||||
|
||||
List<Component> Component::components;
|
||||
List<AbstractBuilder> AbstractBuilder::builders;
|
||||
unordered_map<string, Command*> Command::mapCommandTopics;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user