add Number, refactor StateConfig and add support for restoring state at startup
This commit is contained in:
parent
661eea9db8
commit
c7b6c382f8
@ -3,6 +3,8 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
#define JSON_SIZE 512
|
#define JSON_SIZE 512
|
||||||
#define TOPIC_SIZE 255
|
#define TOPIC_SIZE 255
|
||||||
|
|
||||||
@ -180,11 +182,20 @@ namespace Ha {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Builder& withStateTopic() {
|
||||||
|
cmp->withStateTopic();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Builder& withRetain(bool retain = true) {
|
Builder& withRetain(bool retain = true) {
|
||||||
cmp->retain = retain;
|
cmp->retain = retain;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Builder& restoreFromState() {
|
||||||
|
cmp->restoreFromState();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Command : Component {
|
struct Command : Component {
|
||||||
@ -216,37 +227,76 @@ namespace Ha {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct StateConfig {
|
struct StateConfig {
|
||||||
char stateTopic[TOPIC_SIZE];
|
char stateTopic[TOPIC_SIZE];
|
||||||
|
static unordered_map<string, Command*> mapStateTopics;
|
||||||
|
Component* cmp;
|
||||||
|
|
||||||
T* withStateTopic() {
|
StateConfig(Component* cmp) : cmp(cmp) {}
|
||||||
sprintf(stateTopic, "homeassistant/%s/%s/%s/state", ((T*)this)->type, MAIN_DEVICE_ID, ((T*)this)->id);
|
|
||||||
return static_cast<T*>(this);
|
void withStateTopic() {
|
||||||
|
sprintf(stateTopic, "homeassistant/%s/%s/%s/state", cmp->type, MAIN_DEVICE_ID, cmp->id);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
struct Switch : Command, StateConfig<Switch> {
|
void buildConfig(JsonDocument& jsonDoc) {
|
||||||
|
|
||||||
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;
|
|
||||||
if (stateTopic[0]) jsonDoc["state_topic"] = stateTopic;
|
if (stateTopic[0]) jsonDoc["state_topic"] = stateTopic;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateState(bool state) {
|
void updateState(const char* message) {
|
||||||
publisher(stateTopic, state ? "ON" : "OFF");
|
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* unitMeasure = nullptr;
|
||||||
const char* valueTemplate = nullptr;
|
const char* valueTemplate = nullptr;
|
||||||
static unordered_map<string, Sensor*> mapSensors;
|
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();
|
withStateTopic();
|
||||||
mapSensors.insert({ id, this });
|
mapSensors.insert({ id, this });
|
||||||
}
|
}
|
||||||
@ -269,15 +319,11 @@ namespace Ha {
|
|||||||
|
|
||||||
void buildConfig(JsonDocument& jsonDoc) override {
|
void buildConfig(JsonDocument& jsonDoc) override {
|
||||||
Component::buildConfig(jsonDoc);
|
Component::buildConfig(jsonDoc);
|
||||||
|
StateConfig::buildConfig(jsonDoc);
|
||||||
if (unitMeasure) jsonDoc["unit_of_measurement"] = unitMeasure;
|
if (unitMeasure) jsonDoc["unit_of_measurement"] = unitMeasure;
|
||||||
if (valueTemplate) jsonDoc["value_template"] = valueTemplate;
|
if (valueTemplate) jsonDoc["value_template"] = valueTemplate;
|
||||||
jsonDoc["state_topic"] = stateTopic;
|
|
||||||
jsonDoc["suggested_display_precision"] = 2;
|
jsonDoc["suggested_display_precision"] = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateState(const char* message) {
|
|
||||||
publisher(stateTopic, message);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TemperatureSensor : Sensor {
|
struct TemperatureSensor : Sensor {
|
||||||
@ -307,7 +353,6 @@ namespace Ha {
|
|||||||
HumiditySensor(const char* id, const char* name = "Humidity") : Sensor(name, id) {
|
HumiditySensor(const char* id, const char* name = "Humidity") : Sensor(name, id) {
|
||||||
deviceClass = "humidity";
|
deviceClass = "humidity";
|
||||||
unitMeasure = "%";
|
unitMeasure = "%";
|
||||||
// valueTemplate = "{{ value_json.sensor.humidity }}";
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -315,7 +360,6 @@ namespace Ha {
|
|||||||
PressureSensor(const char* id, const char* name = "Pressure") : Sensor(name, id) {
|
PressureSensor(const char* id, const char* name = "Pressure") : Sensor(name, id) {
|
||||||
deviceClass = "pressure";
|
deviceClass = "pressure";
|
||||||
unitMeasure = "hPa";
|
unitMeasure = "hPa";
|
||||||
// valueTemplate = "{{ value_json.sensor.pressure }}";
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -323,4 +367,5 @@ namespace Ha {
|
|||||||
List<AbstractBuilder> AbstractBuilder::builders;
|
List<AbstractBuilder> AbstractBuilder::builders;
|
||||||
unordered_map<string, Command*> Command::mapCommands;
|
unordered_map<string, Command*> Command::mapCommands;
|
||||||
unordered_map<string, Sensor*> Sensor::mapSensors;
|
unordered_map<string, Sensor*> Sensor::mapSensors;
|
||||||
|
unordered_map<string, Command*> StateConfig::mapStateTopics;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,8 +42,15 @@ namespace Mqtt {
|
|||||||
char msg[len + 1];
|
char msg[len + 1];
|
||||||
memcpy(msg, payload, len);
|
memcpy(msg, payload, len);
|
||||||
msg[len] = 0;
|
msg[len] = 0;
|
||||||
Command* cmd = Command::mapCommands[string{ topic }];
|
auto strTopic = string{ topic };
|
||||||
|
auto cmd = Command::mapCommands[strTopic];
|
||||||
if (cmd) cmd->onCommand(msg);
|
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) {
|
void setup(Scheduler* ts = nullptr, void(*onConnected)() = nullptr, void(*onDisconnected)() = nullptr) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user