From 6fd9bdc8ce5af105855201c9e1d702ef4881bf7b Mon Sep 17 00:00:00 2001 From: Nicu Hodos Date: Sat, 4 May 2024 21:46:39 +0200 Subject: [PATCH] added oil tank room sensor --- gateway/include/Protocol_2.h | 12 ++++++ gateway/include/TinyComponent.h | 4 +- gateway/include/devices.h | 8 ++++ gateway/include/ha.h | 65 +++++++++++++++++++++++---------- gateway/include/huzzah.h | 7 ++++ gateway/include/mqtt.h | 16 ++++---- 6 files changed, 83 insertions(+), 29 deletions(-) diff --git a/gateway/include/Protocol_2.h b/gateway/include/Protocol_2.h index 589154e..f618898 100644 --- a/gateway/include/Protocol_2.h +++ b/gateway/include/Protocol_2.h @@ -33,4 +33,16 @@ 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; + } + }; \ No newline at end of file diff --git a/gateway/include/TinyComponent.h b/gateway/include/TinyComponent.h index beb5c12..725fce1 100644 --- a/gateway/include/TinyComponent.h +++ b/gateway/include/TinyComponent.h @@ -6,9 +6,11 @@ bool buildSensorJson(unsigned long value, JsonDocument& jsonDoc) { sensor["id"] = ID(value); float voltage = (float)GET_VCC(value) / 1000; + JsonObject diagnostic = sensor.createNestedObject("diagnostic"); if (voltage != 0) { - JsonObject diagnostic = sensor.createNestedObject("diagnostic"); diagnostic["voltage"] = voltage; + } else { + diagnostic["voltage"] = ""; } switch (GET_TYPE(value)) { diff --git a/gateway/include/devices.h b/gateway/include/devices.h index 0d58dec..3c7fdfe 100644 --- a/gateway/include/devices.h +++ b/gateway/include/devices.h @@ -9,6 +9,14 @@ using namespace Ha; DeviceConfig* gatewayDevice = (new DeviceConfig{MAIN_DEVICE_ID, "RC Gateway"})->withManufacturer("Adafruit")->withModel("Huzzah Esp8266"); DeviceConfig* atTinyDevice = (new DeviceConfig{})->withManufacturer("Atmel")->withModel("AtTiny85")->withParent(gatewayDevice); +struct SensorBuilder { + static Sensor* withVoltage(Sensor* sensor) { + (new VoltageSensor{sensor->id, "Battery voltage", "{{ value_json.sensor.diagnostic.voltage }}"})->asDevice(new DeviceConfig{sensor->mainDevice->id}); + (new BatterySensor{sensor->id, "Battery level", "{{ ((states('sensor.oil_tank_room_battery_voltage')|float-2.5)|round(2)*100/2)|int }}"})->asDevice(new DeviceConfig{sensor->mainDevice->id}); + return sensor; + } +}; + struct PollinSwitch : Switch { const char* group; unsigned char channel; diff --git a/gateway/include/ha.h b/gateway/include/ha.h index d7d550c..c69830b 100644 --- a/gateway/include/ha.h +++ b/gateway/include/ha.h @@ -18,22 +18,19 @@ namespace Ha { DeviceConfig* parent = nullptr; DeviceConfig() {} + DeviceConfig(const char* id) : id(id) {} DeviceConfig(const char* id, const char* name) : id(id), name(name) {} DeviceConfig(DeviceConfig& d) : id(d.id), name(d.name), model(d.model), manufacturer(d.manufacturer), area(d.area), parent(d.parent) {} void buildConfig(JsonDocument& jsonDoc) { JsonObject device = jsonDoc.createNestedObject("device"); - device["name"] = name; - // JsonArray connections = device.createNestedArray("connections"); - // JsonArray mac = connections.createNestedArray(); - // mac.add("mac"); - // mac.add(WiFi.macAddress()); - JsonArray identifiers = device.createNestedArray("identifiers"); - identifiers.add(id); + if (name) device["name"] = name; if (model) device["model"] = model; if (manufacturer) device["manufacturer"] = manufacturer; if (area) device["suggested_area"] = area; if (parent) device["via_device"] = parent->id; + JsonArray identifiers = device.createNestedArray("identifiers"); + identifiers.add(id); } DeviceConfig* withModel(const char* value) { @@ -58,6 +55,8 @@ namespace Ha { }; struct Component { + const char* entityCategory = nullptr; + const char* deviceClass = nullptr; const char* name = nullptr; char* id = nullptr; const char* type = nullptr; @@ -66,14 +65,19 @@ namespace Ha { static List components; Component(const char* name, const char* id, const char* type) : name(name), id((char*)id), type(type) { - sprintf(configTopic, "homeassistant/%s/%s/%s/config", type, MAIN_DEVICE_ID, id); components.add(this); } virtual void buildUniqueId(char* uniqueId) = 0; virtual void buildConfig(JsonDocument& jsonDoc) { + if (String{"diagnostic"}.equals(entityCategory)) { + 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); + } if (mainDevice) mainDevice->buildConfig(jsonDoc); + if (entityCategory) jsonDoc["entity_category"] = entityCategory; jsonDoc["name"] = name; char uniqueId[50]; buildUniqueId(uniqueId); @@ -101,6 +105,7 @@ namespace Ha { mainDevice = new DeviceConfig{*deviceConfig}; mainDevice->id = id; mainDevice->name = name; + mainDevice->parent = deviceConfig->parent; return static_cast(this); } }; @@ -166,23 +171,25 @@ namespace Ha { }; struct Sensor : EntityConfig, StateConfig { - const char* deviceClass = nullptr; const char* unitMeasure = nullptr; const char* valueTemplate = nullptr; - Sensor(const char* name, const char* id) : EntityConfig(name, id, "sensor") { + Sensor(const char* name, const char* id) : EntityConfig(name, Protocol_2::buildId(id), "sensor") { + withStateTopic(); } void buildUniqueId(char* uniqueId) override { - sprintf(uniqueId, "%s", id); + sprintf(uniqueId, "%s_%s", deviceClass, id); } void buildConfig(JsonDocument& jsonDoc) override { EntityConfig::buildConfig(jsonDoc); + if (entityCategory) jsonDoc["entity_category"] = entityCategory; jsonDoc["device_class"] = deviceClass; jsonDoc["unit_of_measurement"] = unitMeasure; - jsonDoc["value_template"] = valueTemplate; - if (stateTopic[0]) jsonDoc["state_topic"] = stateTopic; + if (valueTemplate) jsonDoc["value_template"] = valueTemplate; + jsonDoc["state_topic"] = stateTopic; + jsonDoc["suggested_display_precision"] = 2; } Sensor* withDeviceName(const char* value) { @@ -199,6 +206,24 @@ namespace Ha { } }; + struct VoltageSensor : Sensor { + VoltageSensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) { + this->valueTemplate = valueTemplate; + entityCategory = "diagnostic"; + deviceClass = "voltage"; + unitMeasure = "V"; + } + }; + + struct BatterySensor : Sensor { + BatterySensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) { + this->valueTemplate = valueTemplate; + entityCategory = "diagnostic"; + deviceClass = "battery"; + unitMeasure = "%"; + } + }; + struct HumiditySensor : Sensor { HumiditySensor(const char* name, const char* id) : Sensor(name, id) { name = "Humidity"; @@ -217,11 +242,11 @@ namespace Ha { } }; - struct AltitudeSensor : Sensor { - AltitudeSensor(const char* name, const char* id) : Sensor(name, id) { - deviceClass = "distance"; - unitMeasure = "m"; - valueTemplate = "{{ value_json.sensor.altitude }}"; - } - }; + // struct AltitudeSensor : Sensor { + // AltitudeSensor(const char* name, const char* id) : Sensor(name, id) { + // deviceClass = "distance"; + // unitMeasure = "m"; + // valueTemplate = "{{ value_json.sensor.altitude }}"; + // } + // }; } diff --git a/gateway/include/huzzah.h b/gateway/include/huzzah.h index 8fbfd02..b286363 100644 --- a/gateway/include/huzzah.h +++ b/gateway/include/huzzah.h @@ -79,6 +79,13 @@ namespace Board { } } } + 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) { diff --git a/gateway/include/mqtt.h b/gateway/include/mqtt.h index 0e9cd02..cd4950b 100644 --- a/gateway/include/mqtt.h +++ b/gateway/include/mqtt.h @@ -32,14 +32,6 @@ namespace Mqtt { return client.publish(topic, 0, true, message); } - Ha::Sensor* sensors[] = { - (new Ha::TemperatureSensor{"id4"})->withStateTopic()->copyFromDevice(atTinyDevice)->withDeviceName("Oil tank room1")->withArea("Basement") - // new Ha::TemperatureSensor{"Temperature", "temperature"}, - // new Ha::HumiditySensor{"Humidity", "humidity"}, - // new Ha::PressureSensor{"Pressure", "pressure"}, - // new Ha::AltitudeSensor{"Altitude", "altitude"} - }; - Ha::Button* buttons[] = { (new Ha::Button{"Restart", "restart", [](const char* msg) { @@ -57,6 +49,14 @@ namespace Mqtt { (new EasyHomeSwitch{"Outside", "easy_home_b", (unsigned long[4]) { 4483140, 4626804, 4661556, 4819636 }, (unsigned long[4]) { 4326548, 4537108, 4767524, 4972708 }})->withArea("Basement")->withStateTopic() }; + Ha::Sensor* sensors[] = { + SensorBuilder::withVoltage((new Ha::TemperatureSensor{"4"})->copyFromDevice(atTinyDevice)->withDeviceName("Oil tank room")->withArea("Basement")) + // new Ha::TemperatureSensor{"Temperature", "temperature"}, + // new Ha::HumiditySensor{"Humidity", "humidity"}, + // new Ha::PressureSensor{"Pressure", "pressure"}, + // new Ha::AltitudeSensor{"Altitude", "altitude"} + }; + void publishComponentConfig(Ha::Component& component) { StaticJsonDocument jsonDoc; component.buildConfig(jsonDoc);