add Number, refactor StateConfig and add support for restoring state at startup

This commit is contained in:
Nicu Hodos 2024-05-29 16:12:17 +02:00
parent 661eea9db8
commit c7b6c382f8
2 changed files with 76 additions and 24 deletions

View File

@ -3,6 +3,8 @@
#include <ArduinoJson.h>
#include "utils.h"
using namespace std;
#define JSON_SIZE 512
#define TOPIC_SIZE 255
@ -180,11 +182,20 @@ namespace Ha {
return *this;
}
Builder& withStateTopic() {
cmp->withStateTopic();
return *this;
}
Builder& withRetain(bool retain = true) {
cmp->retain = retain;
return *this;
}
Builder& restoreFromState() {
cmp->restoreFromState();
return *this;
}
};
struct Command : Component {
@ -216,37 +227,76 @@ namespace Ha {
};
template <class T>
struct StateConfig {
char stateTopic[TOPIC_SIZE];
static unordered_map<string, Command*> mapStateTopics;
Component* cmp;
T* withStateTopic() {
sprintf(stateTopic, "homeassistant/%s/%s/%s/state", ((T*)this)->type, MAIN_DEVICE_ID, ((T*)this)->id);
return static_cast<T*>(this);
StateConfig(Component* cmp) : cmp(cmp) {}
void withStateTopic() {
sprintf(stateTopic, "homeassistant/%s/%s/%s/state", cmp->type, MAIN_DEVICE_ID, cmp->id);
}
};
struct Switch : Command, StateConfig<Switch> {
Switch(const char* name, const char* id, onMessage f = nullptr) : Command(name, id, "switch", f) {}
void buildConfig(JsonDocument& jsonDoc) override {
Command::buildConfig(jsonDoc);
// jsonDoc["retain"] = true;
void buildConfig(JsonDocument& jsonDoc) {
if (stateTopic[0]) jsonDoc["state_topic"] = stateTopic;
}
void updateState(bool state) {
publisher(stateTopic, state ? "ON" : "OFF");
void updateState(const char* message) {
if (stateTopic[0]) publisher(stateTopic, message);
}
};
struct Sensor : Component, StateConfig<Sensor> {
struct Switch : Command, StateConfig {
Switch(const char* name, const char* id, onMessage f = nullptr) : Command(name, id, "switch", f), StateConfig(this) {}
void buildConfig(JsonDocument& jsonDoc) override {
Command::buildConfig(jsonDoc);
StateConfig::buildConfig(jsonDoc);
}
void updateState(bool state) {
StateConfig::updateState(state ? "ON" : "OFF");
}
void restoreFromState() {
mapStateTopics.insert({stateTopic, this});
}
};
struct Number : Command, StateConfig {
unsigned int min, max, step;
Number(const char* name, const char* id, unsigned int min, unsigned int max, unsigned int step, onMessage f)
: Command(name, id, "number", f), StateConfig(this), min(min), max(max), step(step) {}
void buildConfig(JsonDocument& jsonDoc) override {
Command::buildConfig(jsonDoc);
StateConfig::buildConfig(jsonDoc);
jsonDoc["min"] = min;
jsonDoc["max"] = max;
jsonDoc["step"] = step;
}
void updateState(unsigned int value) {
char message[32];
sprintf(message, "%u", value);
StateConfig::updateState(message);
}
void restoreFromState() {
mapStateTopics.insert({stateTopic, this});
}
};
struct Sensor : Component, StateConfig {
const char* unitMeasure = nullptr;
const char* valueTemplate = nullptr;
static unordered_map<string, Sensor*> mapSensors;
Sensor(const char* name, const char* id) : Component(name, id, "sensor") {
Sensor(const char* name, const char* id) : Component(name, id, "sensor"), StateConfig(this) {
withStateTopic();
mapSensors.insert({ id, this });
}
@ -269,15 +319,11 @@ namespace Ha {
void buildConfig(JsonDocument& jsonDoc) override {
Component::buildConfig(jsonDoc);
StateConfig::buildConfig(jsonDoc);
if (unitMeasure) jsonDoc["unit_of_measurement"] = unitMeasure;
if (valueTemplate) jsonDoc["value_template"] = valueTemplate;
jsonDoc["state_topic"] = stateTopic;
jsonDoc["suggested_display_precision"] = 2;
}
void updateState(const char* message) {
publisher(stateTopic, message);
}
};
struct TemperatureSensor : Sensor {
@ -307,7 +353,6 @@ namespace Ha {
HumiditySensor(const char* id, const char* name = "Humidity") : Sensor(name, id) {
deviceClass = "humidity";
unitMeasure = "%";
// valueTemplate = "{{ value_json.sensor.humidity }}";
}
};
@ -315,7 +360,6 @@ namespace Ha {
PressureSensor(const char* id, const char* name = "Pressure") : Sensor(name, id) {
deviceClass = "pressure";
unitMeasure = "hPa";
// valueTemplate = "{{ value_json.sensor.pressure }}";
}
};
@ -323,4 +367,5 @@ namespace Ha {
List<AbstractBuilder> AbstractBuilder::builders;
unordered_map<string, Command*> Command::mapCommands;
unordered_map<string, Sensor*> Sensor::mapSensors;
unordered_map<string, Command*> StateConfig::mapStateTopics;
}

View File

@ -42,8 +42,15 @@ namespace Mqtt {
char msg[len + 1];
memcpy(msg, payload, len);
msg[len] = 0;
Command* cmd = Command::mapCommands[string{ topic }];
auto strTopic = string{ topic };
auto cmd = Command::mapCommands[strTopic];
if (cmd) cmd->onCommand(msg);
cmd = StateConfig::mapStateTopics[strTopic];
if (cmd) {
cmd->onCommand(msg);
StateConfig::mapStateTopics.erase(strTopic);
}
}
void setup(Scheduler* ts = nullptr, void(*onConnected)() = nullptr, void(*onDisconnected)() = nullptr) {