Merge branch 'refactor' into huzzah

This commit is contained in:
Nicu Hodos 2024-05-16 17:27:24 +02:00
commit a44b890d43
7 changed files with 245 additions and 202 deletions

View File

@ -27,10 +27,9 @@ public:
rcSwitch["raw_value"] = value; rcSwitch["raw_value"] = value;
} }
static char* buildId(const char* group, const unsigned char channel) { static std::string buildId(const char* group, const unsigned char channel) {
char* uId = new char[30]; char uId[30];
sprintf(uId, "%s_%d", group, channel); sprintf(uId, "%s_%d", group, channel);
return uId; return std::string{ uId };
} }
}; };

View File

@ -33,16 +33,4 @@ public:
} }
} }
static char* buildId(const char* id) {
char* uId = new char[30];
sprintf(uId, "%s", id);
return uId;
}
static char* buildId(unsigned int id) {
char* uId = new char[30];
sprintf(uId, "%d", id);
return uId;
}
}; };

View File

@ -7,66 +7,66 @@
using namespace Ha; using namespace Ha;
DeviceConfig* gatewayDevice = (new DeviceConfig{MAIN_DEVICE_ID})->withName("RC Gateway")->withManufacturer("Adafruit")->withModel("Huzzah Esp8266"); DeviceConfig* gatewayDevice = (new DeviceConfig{MAIN_DEVICE_ID})->withName("RC Gateway")->withManufacturer("Adafruit")->withModel("Huzzah Esp8266");
DeviceConfig* atTinyDevice = (new DeviceConfig{})->withManufacturer("Atmel")->withModel("AtTiny85")->withParent(gatewayDevice);
struct OilTankRoomSensorBuilder { namespace OilTank {
static Sensor* build(const char* id) { Sensor* buildRoomSensor(const char* id) {
auto device = (new DeviceConfig{*atTinyDevice})->withName("Oil tank room")->withArea("Basement"); auto device = DeviceConfig::create(id)
device->id = id; ->withName("Oil tank room")
Sensor* sensor = (new Ha::TemperatureSensor(id))->asDevice(device); ->withManufacturer("Atmel")
(new VoltageSensor{sensor->id, "Battery voltage", "{{ value_json.sensor.diagnostic.voltage }}"})->ofDevice((id)); ->withModel("AtTiny85")
(new BatterySensor{sensor->id, "Battery level", "{{ ((states('sensor.oil_tank_room_battery_voltage')|float-2.5)|round(2)*100/2)|int }}"})->ofDevice(id); ->withArea("Basement")
return sensor; ->withParent(gatewayDevice);
} return Builder<TemperatureSensor>::instance(id)
}; .asDevice(device)
.withValueTemplate("{{ value_json.sensor.temperature }}")
struct OilTankSensor : Sensor { .withDiagnostic(new VoltageSensor{id, "Battery voltage", "{{ value_json.sensor.diagnostic.voltage }}"})
OilTankSensor(const char* id) : Sensor("Depth", id) { .withDiagnostic(new BatterySensor{id, "Battery level", "{{ ((states('sensor.oil_tank_room_battery_voltage')|float-2.5)|round(2)*100/2)|int }}"})
deviceClass = "distance"; .build();
unitMeasure = "cm";
valueTemplate = "{{ value_json.sensor.value }}";
}
};
struct OilTankLevelSensor : Sensor {
OilTankLevelSensor(const char* id) : Sensor("Level", id) {
unitMeasure = "%";
valueTemplate = "{{ 100 - ((value_json.sensor.value-7)|float*100/110)|round(2) }}";
} }
void buildUniqueId(char* uniqueId) override { Sensor* buildTankSensor(const char* id) {
sprintf(uniqueId, "level_%s", id); auto device = DeviceConfig::create(id)
->withName("Oil tank")
->withManufacturer("Arduino")
->withModel("Pro Mini")
->withArea("Basement")
->withParent(gatewayDevice);
return Builder<Sensor>::instance(new Sensor{ "Depth", id })
.asDevice(device)
.withDeviceClass("distance")
.withUnitMseasure("cm")
.withValueTemplate("{{ value_json.sensor.value }}")
.withSecondary(
Builder<Sensor>::instance(new Sensor{ "Level", id })
.withUnitMseasure("%")
.withValueTemplate("{{ 100 - ((value_json.sensor.value-7)|float*100/110)|round(2) }}")
.build()
)
.withDiagnostic(new VoltageSensor{id, "Battery voltage", "{{ value_json.sensor.diagnostic.voltage }}"})
.withDiagnostic(new BatterySensor{id, "Battery level", "{{ ((states('sensor.oil_tank_battery_voltage')|float-3.6)|round(2)*100/1.6)|int }}"})
.build();
} }
}
void buildConfigTopic() override {
sprintf(configTopic, "homeassistant/%s/%s/level_%s/config", type, MAIN_DEVICE_ID, id);
}
};
struct OilSensorBuilder {
static Sensor* build(const char* id) {
auto device = (new DeviceConfig{*atTinyDevice})->withName("Oil tank")->withArea("Basement");
device->id = id;
Sensor* sensor = (new OilTankSensor(id))->asDevice(device);
(new OilTankLevelSensor(sensor->id))->ofDevice(id);
(new VoltageSensor{id, "Battery voltage", "{{ value_json.sensor.diagnostic.voltage }}"})->ofDevice(id);
(new BatterySensor{id, "Battery level", "{{ ((states('sensor.oil_tank_battery_voltage')|float-3.6)|round(2)*100/1.6)|int }}"})->ofDevice(id);
return sensor;
}
};
struct PollinSwitch : Switch { struct PollinSwitch : Switch {
const char* group; const char* group;
unsigned char channel; unsigned char channel;
PollinSwitch(const char* name, const char* group, const unsigned char channel, const char* area = nullptr) PollinSwitch(const char* name, const char* group, const unsigned char channel, const char* area = nullptr)
: Switch(name, Protocol_1::buildId(group, channel)), group(group), channel(channel) { : Switch(name, [group, channel]{
asDevice((new DeviceConfig{id})->withName(name)->withManufacturer("Pollin")->withArea(area)->withParent(gatewayDevice)); // copy id from string into a new pointer, to avoid memory leaks
string s = Protocol_1::buildId(group, channel);
char* uId = new char[s.length() + 1];
strcpy(uId, s.c_str());
return uId;
}()), group(group), channel(channel) {
mainDevice = (new DeviceConfig{id})->withName(name)->withManufacturer("Pollin")->withArea(area)->withParent(gatewayDevice);
deviceClass = "outlet";
p1Switches.insert({ string(id), this }); p1Switches.insert({ string(id), this });
} }
void onCommand(const char* msg) override { void onCommand(const char* msg) override {
(String{ "ON" }.equals(msg)) ? mySwitch.switchOn(group, channel) : mySwitch.switchOff(group, channel); strcmp("ON", msg) == 0 ? mySwitch.switchOn(group, channel) : mySwitch.switchOff(group, channel);
publisher(stateTopic, msg); publisher(stateTopic, msg);
} }
@ -80,7 +80,8 @@ struct EasyHomeSwitch : Switch {
: Switch(name, id) { : Switch(name, id) {
memcpy(&this->on[4], on, 4 * sizeof(unsigned long)); memcpy(&this->on[4], on, 4 * sizeof(unsigned long));
memcpy(&this->off[4], off, 4 * sizeof(unsigned long)); memcpy(&this->off[4], off, 4 * sizeof(unsigned long));
asDevice((new DeviceConfig{id})->withName(name)->withManufacturer("Intertek")->withModel("Easy Home")->withArea(area)->withParent(gatewayDevice)); mainDevice = (new DeviceConfig{id})->withName(name)->withManufacturer("Intertek")->withModel("Easy Home")->withArea(area)->withParent(gatewayDevice);
deviceClass = "outlet";
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
onSwitches.insert({ this->on[i], this }); onSwitches.insert({ this->on[i], this });
offSwitches.insert({ this->off[i], this }); offSwitches.insert({ this->off[i], this });
@ -89,7 +90,7 @@ struct EasyHomeSwitch : Switch {
void onCommand(const char* msg) override { void onCommand(const char* msg) override {
mySwitch.setProtocol(4); mySwitch.setProtocol(4);
String{ "ON" }.equals(msg) ? mySwitch.send(on[4], 24) : mySwitch.send(off[4], 24); strcmp("ON", msg) == 0 ? mySwitch.send(on[4], 24) : mySwitch.send(off[4], 24);
publisher(stateTopic, msg); publisher(stateTopic, msg);
} }
}; };

View File

@ -8,6 +8,7 @@
namespace Ha { namespace Ha {
uint16_t (*publisher)(const char* topic, const char* message); uint16_t (*publisher)(const char* topic, const char* message);
typedef void (*onMessage)(const char* msg);
struct DeviceConfig { struct DeviceConfig {
const char* id = nullptr; const char* id = nullptr;
@ -17,9 +18,11 @@ namespace Ha {
const char* area = nullptr; const char* area = nullptr;
DeviceConfig* parent = nullptr; DeviceConfig* parent = nullptr;
DeviceConfig() {}
DeviceConfig(const char* id) : id(id) {} DeviceConfig(const char* id) : id(id) {}
DeviceConfig(DeviceConfig& d) : id(d.id), name(d.name), model(d.model), manufacturer(d.manufacturer), area(d.area), parent(d.parent) {}
static DeviceConfig* create(const char* id) {
return new DeviceConfig{ id };
}
void buildConfig(JsonDocument& jsonDoc) { void buildConfig(JsonDocument& jsonDoc) {
JsonObject device = jsonDoc.createNestedObject("device"); JsonObject device = jsonDoc.createNestedObject("device");
@ -72,18 +75,15 @@ namespace Ha {
components.add(this); components.add(this);
} }
virtual void buildUniqueId(char* uniqueId) = 0; virtual void buildUniqueId(char* uniqueId) {
sprintf(uniqueId, "%s_%s", MAIN_DEVICE_ID, id);
}
virtual void buildConfigTopic() { virtual void buildConfigTopic() {
if (String{"diagnostic"}.equals(entityCategory) && deviceClass) { sprintf(configTopic, "homeassistant/%s/%s/%s/config", type, MAIN_DEVICE_ID, id);
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);
}
} }
virtual void buildConfig(JsonDocument& jsonDoc) { virtual void buildConfig(JsonDocument& jsonDoc) {
buildConfigTopic();
if (mainDevice) mainDevice->buildConfig(jsonDoc); if (mainDevice) mainDevice->buildConfig(jsonDoc);
if (entityCategory) jsonDoc["entity_category"] = entityCategory; if (entityCategory) jsonDoc["entity_category"] = entityCategory;
if (deviceClass) jsonDoc["device_class"] = deviceClass; if (deviceClass) jsonDoc["device_class"] = deviceClass;
@ -91,52 +91,118 @@ namespace Ha {
char uniqueId[50]; char uniqueId[50];
buildUniqueId(uniqueId); buildUniqueId(uniqueId);
jsonDoc["unique_id"] = uniqueId; jsonDoc["unique_id"] = uniqueId;
buildConfigTopic();
}
void publishConfig() {
StaticJsonDocument<JSON_SIZE> jsonDoc;
buildConfig(jsonDoc);
char message[JSON_SIZE];
serializeJson(jsonDoc, message);
publisher(configTopic, message);
}
void publishCleanupConfig() {
publisher(configTopic, "");
} }
}; };
template <class T>
struct EntityConfig : Component {
EntityConfig(const char* name, const char* id, const char* type) : Component(name, id, type) {
}
T* asDevice(DeviceConfig* deviceConfig) {
mainDevice = deviceConfig;
return static_cast<T*>(this);
}
T* ofDevice(const char* id) {
mainDevice = new DeviceConfig{id};
return static_cast<T*>(this);
}
};
List<Component> Component::components; List<Component> Component::components;
template <class T> struct AbstractBuilder {
struct Command : EntityConfig<T> { static List<AbstractBuilder> builders;
char commandTopic[TOPIC_SIZE];
Command(const char* name, const char* id, const char* type) : EntityConfig<T>(name, id, type) { AbstractBuilder() {
sprintf(commandTopic, "homeassistant/%s/%s/%s", type, MAIN_DEVICE_ID, id); builders.add(this);
} }
void buildUniqueId(char* uniqueId) override { static void deleteAll() {
sprintf(uniqueId, "%s_%s", MAIN_DEVICE_ID, this->id); List<AbstractBuilder>::exec(builders, [](AbstractBuilder* builder)
{ delete builder; });
}
};
List<AbstractBuilder> AbstractBuilder::builders;
template <class T>
struct Builder : AbstractBuilder {
T* cmp;
Builder(T* cmp) : AbstractBuilder(), cmp(cmp) {}
Builder(const char* id) : AbstractBuilder() {
cmp = new T{id};
}
static Builder& instance(T* c) {
return *(new Builder<T>(c));
}
static Builder& instance(const char* id) {
return *(new Builder<T>(id));
}
T* build() {
return static_cast<T*>(cmp);
}
Builder& withDeviceClass(const char* value) {
cmp->deviceClass = value;
return *this;
}
Builder& withUnitMseasure(const char* value) {
cmp->unitMeasure = value;
return *this;
}
Builder& withValueTemplate(const char* value) {
cmp->valueTemplate = value;
return *this;
}
Builder& withSecondary(Component* c) {
c->mainDevice = new DeviceConfig{ cmp->id };
return *this;
}
Builder& withDiagnostic(Component* c) {
c->entityCategory = "diagnostic";
c->mainDevice = new DeviceConfig{ cmp->id };
return *this;
}
Builder& asDevice(DeviceConfig* deviceConfig) {
cmp->mainDevice = deviceConfig;
return *this;
}
};
struct Command : Component {
char commandTopic[TOPIC_SIZE];
onMessage f;
static unordered_map<string, Command*> mapCommands;
Command(const char* name, const char* id, const char* type, onMessage f) : Component(name, id, type), f(f) {
sprintf(commandTopic, "homeassistant/%s/%s/%s/set", type, MAIN_DEVICE_ID, id);
mapCommands.insert({ string(commandTopic), this });
}
virtual void onCommand(const char* msg) {
if (f) f(msg);
} }
void buildConfig(JsonDocument& jsonDoc) override { void buildConfig(JsonDocument& jsonDoc) override {
EntityConfig<T>::buildConfig(jsonDoc); Component::buildConfig(jsonDoc);
jsonDoc["command_topic"] = commandTopic; jsonDoc["command_topic"] = commandTopic;
} }
}; };
unordered_map<string, Command*> Command::mapCommands;
typedef void (*onMessage)(const char* msg); struct Button : Command {
struct Button : Command<Button> {
onMessage f;
Button(const char* name, const char* id, onMessage f) : Command(name, id, "button"), f(f) {} Button(const char* name, const char* id, onMessage f = nullptr) : Command(name, id, "button", f) {}
}; };
@ -150,18 +216,13 @@ namespace Ha {
} }
}; };
struct Switch : Command<Switch>, StateConfig<Switch> { struct Switch : Command, StateConfig<Switch> {
virtual void onCommand(const char* msg){} Switch(const char* name, const char* id, onMessage f = nullptr) : Command(name, id, "switch", f) {}
Switch(const char* name, const char* id) : Command(name, id, "switch") {
sprintf(commandTopic, "homeassistant/%s/%s/%s/set", type, MAIN_DEVICE_ID, id);
}
void buildConfig(JsonDocument& jsonDoc) override { void buildConfig(JsonDocument& jsonDoc) override {
Command::buildConfig(jsonDoc); Command::buildConfig(jsonDoc);
jsonDoc["name"] = nullptr; jsonDoc["name"] = nullptr;
jsonDoc["device_class"] = "outlet";
// jsonDoc["retain"] = true; // jsonDoc["retain"] = true;
if (stateTopic[0]) jsonDoc["state_topic"] = stateTopic; if (stateTopic[0]) jsonDoc["state_topic"] = stateTopic;
} }
@ -171,20 +232,36 @@ namespace Ha {
} }
}; };
struct Sensor : EntityConfig<Sensor>, StateConfig<Sensor> { struct Sensor : Component, StateConfig<Sensor> {
const char* unitMeasure = nullptr; const char* unitMeasure = nullptr;
const char* valueTemplate = nullptr; const char* valueTemplate = nullptr;
Sensor(const char* name, const char* id) : EntityConfig(name, Protocol_2::buildId(id), "sensor") { Sensor() : Component(name, id, "sensor") {
withStateTopic();
}
Sensor(const char* name, const char* id) : Component(name, id, "sensor") {
withStateTopic(); withStateTopic();
} }
void buildUniqueId(char* uniqueId) override { void buildUniqueId(char* uniqueId) override {
sprintf(uniqueId, "%s_%s", deviceClass, id); if (deviceClass) {
sprintf(uniqueId, "%s_%s_%s", MAIN_DEVICE_ID, deviceClass, id);
} else {
Component::buildUniqueId(uniqueId);
}
}
void buildConfigTopic() override {
if (deviceClass) {
sprintf(configTopic, "homeassistant/%s/%s/%s_%s/config", type, MAIN_DEVICE_ID, deviceClass, id);
} else {
Component::buildConfigTopic();
}
} }
void buildConfig(JsonDocument& jsonDoc) override { void buildConfig(JsonDocument& jsonDoc) override {
EntityConfig::buildConfig(jsonDoc); Component::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["state_topic"] = stateTopic;
@ -193,17 +270,15 @@ namespace Ha {
}; };
struct TemperatureSensor : Sensor { struct TemperatureSensor : Sensor {
TemperatureSensor(const char* id) : Sensor("Temperature", id) { TemperatureSensor(const char* id, const char* name = "Temperature") : Sensor(name, id) {
deviceClass = "temperature"; deviceClass = "temperature";
unitMeasure = "°C"; unitMeasure = "°C";
valueTemplate = "{{ value_json.sensor.temperature }}";
} }
}; };
struct VoltageSensor : Sensor { struct VoltageSensor : Sensor {
VoltageSensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) { VoltageSensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) {
this->valueTemplate = valueTemplate; this->valueTemplate = valueTemplate;
entityCategory = "diagnostic";
deviceClass = "voltage"; deviceClass = "voltage";
unitMeasure = "V"; unitMeasure = "V";
} }
@ -212,27 +287,24 @@ namespace Ha {
struct BatterySensor : Sensor { struct BatterySensor : Sensor {
BatterySensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) { BatterySensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) {
this->valueTemplate = valueTemplate; this->valueTemplate = valueTemplate;
entityCategory = "diagnostic";
deviceClass = "battery"; deviceClass = "battery";
unitMeasure = "%"; unitMeasure = "%";
} }
}; };
struct HumiditySensor : Sensor { struct HumiditySensor : Sensor {
HumiditySensor(const char* name, const char* id) : Sensor(name, id) { HumiditySensor(const char* id, const char* name = "Humidity") : Sensor(name, id) {
name = "Humidity";
deviceClass = "humidity"; deviceClass = "humidity";
unitMeasure = "%"; unitMeasure = "%";
valueTemplate = "{{ value_json.sensor.humidity }}"; // valueTemplate = "{{ value_json.sensor.humidity }}";
} }
}; };
struct PressureSensor : Sensor { struct PressureSensor : Sensor {
PressureSensor(const char* name, const char* id) : Sensor(name, id) { PressureSensor(const char* id, const char* name = "Pressure") : Sensor(name, id) {
name = "Pressure";
deviceClass = "pressure"; deviceClass = "pressure";
unitMeasure = "hPa"; unitMeasure = "hPa";
valueTemplate = "{{ value_json.sensor.pressure }}"; // valueTemplate = "{{ value_json.sensor.pressure }}";
} }
}; };
} }

View File

@ -48,44 +48,46 @@ namespace Board {
ts.execute(); ts.execute();
} }
void parseSwitches(JsonDocument& jsonDoc) {
JsonObjectConst rcSwitch = jsonDoc["rcSwitch"];
switch ((unsigned int)rcSwitch["protocol"]) {
case 1: {
string id = Protocol_1::buildId((const char*)rcSwitch["group"], (int)rcSwitch["channel"]);
Ha::Switch* el = p1Switches[id];
if (el) el->publishState((bool)rcSwitch["state"]);
break;
}
case 2:
break;
default: {
unsigned long value = rcSwitch["value"];
auto range = onSwitches.equal_range(value);
for_each(range.first, range.second, [](mapswitches::value_type& x){
x.second->publishState(true);
});
range = offSwitches.equal_range(value);
for_each(range.first, range.second, [](mapswitches::value_type& x){
x.second->publishState(false);
});
}
}
}
void parseSensors(JsonDocument& jsonDoc, char* message) {
JsonObjectConst json = jsonDoc["sensor"];
string id = to_string((unsigned int)json["id"]);
char stateTopic[TOPIC_SIZE];
sprintf(stateTopic, "homeassistant/sensor/%s/%s/state", MAIN_DEVICE_ID, id.c_str());
Mqtt::publish(stateTopic, message);
}
void publishResponse(JsonDocument& jsonDoc) { void publishResponse(JsonDocument& jsonDoc) {
char message[255]; char message[255];
serializeJson(jsonDoc, message); serializeJson(jsonDoc, message);
Mqtt::publish("homeassistant/sensor/rc-gateway/raw", message); Mqtt::publish("homeassistant/sensor/rc-gateway/raw", message);
if (jsonDoc.containsKey("rcSwitch")) { if (jsonDoc.containsKey("rcSwitch")) parseSwitches(jsonDoc);
JsonObjectConst rcSwitch = jsonDoc["rcSwitch"]; if (jsonDoc.containsKey("sensor")) parseSensors(jsonDoc, message);
switch ((unsigned int)rcSwitch["protocol"]) {
case 1: {
// buildId returns a new pointer, should it be deleted, or string will take care of it?
string id = Protocol_1::buildId((const char*)rcSwitch["group"], (int)rcSwitch["channel"]);
Ha::Switch* el = p1Switches[id];
if (el != nullptr) {
el->publishState((bool)rcSwitch["state"]);
}
break;
}
case 2:
break;
default: {
unsigned long value = rcSwitch["value"];
auto range = onSwitches.equal_range(value);
for_each(range.first, range.second, [](mapswitches::value_type& x){
x.second->publishState(true);
});
range = offSwitches.equal_range(value);
for_each(range.first, range.second, [](mapswitches::value_type& x){
x.second->publishState(false);
});
}
}
}
if (jsonDoc.containsKey("sensor")) {
JsonObjectConst json = jsonDoc["sensor"];
string id = Protocol_2::buildId((unsigned int)json["id"]);
char stateTopic[TOPIC_SIZE];
sprintf(stateTopic, "homeassistant/sensor/%s/%s/state", MAIN_DEVICE_ID, id.c_str());
Mqtt::publish(stateTopic, message);
}
} }
void handleJsonError(JsonDocument& jsonError) { void handleJsonError(JsonDocument& jsonError) {

View File

@ -12,12 +12,11 @@ namespace Mqtt {
AsyncMqttClient client; AsyncMqttClient client;
void publishInit();
void disconnect();
Task tReConnect(5 * TASK_MINUTE, TASK_FOREVER, []() { Task tReConnect(5 * TASK_MINUTE, TASK_FOREVER, []() {
Serial.println("Connecting to MQTT..."); Serial.println("Connecting to MQTT...");
client.connect(); client.connect();
}, &ts); }, &ts);
void publishInit();
Task tPublishInit(TASK_IMMEDIATE, TASK_ONCE, publishInit, &ts); Task tPublishInit(TASK_IMMEDIATE, TASK_ONCE, publishInit, &ts);
const char* mainTopic = "homeassistant/+/rc-gateway/#"; const char* mainTopic = "homeassistant/+/rc-gateway/#";
@ -31,68 +30,44 @@ namespace Mqtt {
return client.publish(topic, 0, true, message); return client.publish(topic, 0, true, message);
} }
Ha::Button* buttons[] = { Command* commands[] = {
(new Ha::Button{"Restart", "restart", Builder<Button>::instance(new Button{"Restart", "restart",
[](const char* msg) { [](const char* msg) {
if (String { "PRESS" }.equals(msg)) ESP.restart(); if (strcmp("PRESS", msg) == 0) ESP.restart();
} }
})->asDevice(gatewayDevice) }).asDevice(gatewayDevice).build(),
}; (new EasyHomeSwitch{"FritzBox", "easy_home_a", (unsigned long[4]) { 4483136, 4626800, 4661552, 4819632 }, (unsigned long[4]) { 4326544, 4537104, 4767520, 4972704 }, "Basement"})->withStateTopic(),
(new EasyHomeSwitch{"Outside", "easy_home_b", (unsigned long[4]) { 4483140, 4626804, 4661556, 4819636 }, (unsigned long[4]) { 4326548, 4537108, 4767524, 4972708 }, "Basement"})->withStateTopic(),
Ha::Switch* switches[] = {
(new PollinSwitch{"Meeting sensor", "00001", 1, "Dining room"})->withStateTopic(), (new PollinSwitch{"Meeting sensor", "00001", 1, "Dining room"})->withStateTopic(),
(new PollinSwitch{"Fire Tv", "00001", 2, "Living room"})->withStateTopic(), (new PollinSwitch{"Fire Tv", "00001", 2, "Living room"})->withStateTopic(),
(new PollinSwitch{"Diningroom player", "00001", 3, "Dining room"})->withStateTopic(), (new PollinSwitch{"Diningroom player", "00001", 3, "Dining room"})->withStateTopic(),
(new PollinSwitch{"Train", "11111", 4, "Playroom"})->withStateTopic(), (new PollinSwitch{"Train", "11111", 4, "Playroom"})->withStateTopic()
(new EasyHomeSwitch{"FritzBox", "easy_home_a", (unsigned long[4]) { 4483136, 4626800, 4661552, 4819632 }, (unsigned long[4]) { 4326544, 4537104, 4767520, 4972704 }, "Basement"})->withStateTopic(),
(new EasyHomeSwitch{"Outside", "easy_home_b", (unsigned long[4]) { 4483140, 4626804, 4661556, 4819636 }, (unsigned long[4]) { 4326548, 4537108, 4767524, 4972708 }, "Basement"})->withStateTopic()
}; };
Ha::Sensor* sensors[] = { Sensor* sensors[] = {
OilTankRoomSensorBuilder::build("4"), OilTank::buildRoomSensor("4"),
OilSensorBuilder::build("7") OilTank::buildTankSensor("7")
}; };
void publishComponentConfig(Ha::Component& component) {
StaticJsonDocument<JSON_SIZE> jsonDoc;
component.buildConfig(jsonDoc);
char message[JSON_SIZE];
serializeJson(jsonDoc, message);
publish(component.configTopic, message);
}
void publishInit() { void publishInit() {
Ha::publisher = publish; Ha::publisher = publish;
for (List<Ha::Component>::Container* c = Ha::Component::components.first; c; c = c->next) { List<Component>::exec(Component::components, [](Component* c)
publishComponentConfig(*c->t); { c->publishConfig(); });
} AbstractBuilder::deleteAll();
ts.deleteTask(tPublishInit); ts.deleteTask(tPublishInit);
} }
void publishCleanupConfig() { void publishCleanupConfig() {
for (List<Ha::Component>::Container* c = Ha::Component::components.first; c; c = c->next) { List<Component>::exec(Component::components, [](Component* c)
publish(c->t->configTopic, ""); { c->publishCleanupConfig(); });
}
} }
void onMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { void onMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
char msg[len + 1]; char msg[len + 1];
memcpy(msg, payload, len); memcpy(msg, payload, len);
msg[len] = 0; msg[len] = 0;
for (Ha::Button* cmd : buttons) { Command* cmd = Command::mapCommands[string{ topic }];
if (String{ cmd->commandTopic }.equals(topic) && cmd->f != nullptr) { if (cmd) cmd->onCommand(msg);
cmd->f(msg);
return;
}
}
for (Ha::Switch* cmd : switches) {
if (String{ cmd->commandTopic }.equals(topic)) {
cmd->onCommand(msg);
return;
}
}
} }
void setup() { void setup() {

View File

@ -17,4 +17,10 @@ struct List {
last = c; last = c;
} }
static void exec(List list, void(*f)(T*)) {
for (List::Container *c = list.first; c; c = c->next) {
f(c->t);
}
}
}; };