From e8e95c6b01068b11ece23099a17613173f181104 Mon Sep 17 00:00:00 2001 From: BlueAndi Date: Fri, 3 Jan 2025 11:13:43 +0100 Subject: [PATCH] Display can be switched on/off by homeassistant now too. #203 --- data/extra/display.json | 11 ++ lib/CountdownPlugin/src/CountdownPlugin.h | 16 +-- lib/DateTimePlugin/src/DateTimePlugin.h | 16 +-- lib/GrabViaMqttPlugin/src/GrabViaMqttPlugin.h | 16 +-- lib/GrabViaRestPlugin/src/GrabViaRestPlugin.h | 16 +-- lib/GruenbeckPlugin/src/GruenbeckPlugin.h | 16 +-- .../src/IconTextLampPlugin.cpp | 2 +- .../src/IconTextLampPlugin.h | 16 +-- lib/IconTextPlugin/src/IconTextPlugin.cpp | 6 +- lib/IconTextPlugin/src/IconTextPlugin.h | 16 +-- lib/JustTextPlugin/src/JustTextPlugin.cpp | 6 +- lib/JustTextPlugin/src/JustTextPlugin.h | 16 +-- .../src/HomeAssistantMqtt.h | 58 ++++----- lib/MultiIconPlugin/src/MultiIconPlugin.h | 16 +-- lib/OpenWeatherPlugin/src/OpenWeatherPlugin.h | 16 +-- lib/Plugin/src/IPluginMaintenance.hpp | 16 +-- lib/Plugin/src/Plugin.hpp | 16 +-- lib/SensorPlugin/src/SensorPlugin.h | 16 +-- .../src/SignalDetectorPlugin.h | 16 +-- .../src/SoundReactivePlugin.h | 16 +-- lib/SunrisePlugin/src/SunrisePlugin.h | 16 +-- .../src/TopicHandlerService.cpp | 72 +++++++---- .../src/TopicHandlerService.h | 14 +++ lib/VolumioPlugin/src/VolumioPlugin.h | 16 +-- src/Hal/SensorDataProvider.cpp | 112 ++++++++---------- src/Topics/Topics.cpp | 8 +- 26 files changed, 322 insertions(+), 239 deletions(-) create mode 100644 data/extra/display.json diff --git a/data/extra/display.json b/data/extra/display.json new file mode 100644 index 00000000..589a816c --- /dev/null +++ b/data/extra/display.json @@ -0,0 +1,11 @@ +{ + "ha": { + "component": "light", + "discovery": { + "name": "Display", + "ic": "mdi:clock-digital", + "pl_on": "{\"state\":\"on\"}", + "pl_off": "{\"state\":\"off\"}" + } + } +} diff --git a/lib/CountdownPlugin/src/CountdownPlugin.h b/lib/CountdownPlugin/src/CountdownPlugin.h index 5a1d6898..181555bd 100644 --- a/lib/CountdownPlugin/src/CountdownPlugin.h +++ b/lib/CountdownPlugin/src/CountdownPlugin.h @@ -273,26 +273,28 @@ class CountdownPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/DateTimePlugin/src/DateTimePlugin.h b/lib/DateTimePlugin/src/DateTimePlugin.h index efb24252..727ad84d 100644 --- a/lib/DateTimePlugin/src/DateTimePlugin.h +++ b/lib/DateTimePlugin/src/DateTimePlugin.h @@ -166,26 +166,28 @@ class DateTimePlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/GrabViaMqttPlugin/src/GrabViaMqttPlugin.h b/lib/GrabViaMqttPlugin/src/GrabViaMqttPlugin.h index d88a01af..4ddf73fd 100644 --- a/lib/GrabViaMqttPlugin/src/GrabViaMqttPlugin.h +++ b/lib/GrabViaMqttPlugin/src/GrabViaMqttPlugin.h @@ -162,26 +162,28 @@ class GrabViaMqttPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/GrabViaRestPlugin/src/GrabViaRestPlugin.h b/lib/GrabViaRestPlugin/src/GrabViaRestPlugin.h index 5b160117..ada88dfd 100644 --- a/lib/GrabViaRestPlugin/src/GrabViaRestPlugin.h +++ b/lib/GrabViaRestPlugin/src/GrabViaRestPlugin.h @@ -180,26 +180,28 @@ class GrabViaRestPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/GruenbeckPlugin/src/GruenbeckPlugin.h b/lib/GruenbeckPlugin/src/GruenbeckPlugin.h index c0c2dee5..ab0d9723 100644 --- a/lib/GruenbeckPlugin/src/GruenbeckPlugin.h +++ b/lib/GruenbeckPlugin/src/GruenbeckPlugin.h @@ -175,26 +175,28 @@ class GruenbeckPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/IconTextLampPlugin/src/IconTextLampPlugin.cpp b/lib/IconTextLampPlugin/src/IconTextLampPlugin.cpp index b4822246..228bdb54 100644 --- a/lib/IconTextLampPlugin/src/IconTextLampPlugin.cpp +++ b/lib/IconTextLampPlugin/src/IconTextLampPlugin.cpp @@ -85,7 +85,7 @@ void IconTextLampPlugin::getTopics(JsonArray& topics) const * The used icon is from MaterialDesignIcons.com (namespace: mdi). */ jsonText["name"] = TOPIC_TEXT; - jsonText["fileName"] = TOPIC_TEXT_EXTRA_FILE_NAME; + jsonText["extra"] = TOPIC_TEXT_EXTRA_FILE_NAME; jsonLamps["name"] = TOPIC_LAMPS; jsonLamps["access"] = "r"; /* Only read access allowed. */ diff --git a/lib/IconTextLampPlugin/src/IconTextLampPlugin.h b/lib/IconTextLampPlugin/src/IconTextLampPlugin.h index 462d5e0e..f2e31dd0 100644 --- a/lib/IconTextLampPlugin/src/IconTextLampPlugin.h +++ b/lib/IconTextLampPlugin/src/IconTextLampPlugin.h @@ -139,26 +139,28 @@ class IconTextLampPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/IconTextPlugin/src/IconTextPlugin.cpp b/lib/IconTextPlugin/src/IconTextPlugin.cpp index 2bf369ba..1f0e40b4 100644 --- a/lib/IconTextPlugin/src/IconTextPlugin.cpp +++ b/lib/IconTextPlugin/src/IconTextPlugin.cpp @@ -82,7 +82,7 @@ bool IconTextPlugin::isEnabled() const void IconTextPlugin::getTopics(JsonArray& topics) const { - JsonObject jsonText = topics.createNestedObject(); + JsonObject jsonText = topics.createNestedObject(); /* The topic contains Home Assistant support of the MQTT discovery * (https://www.home-assistant.io/integrations/mqtt). See the configured @@ -90,8 +90,8 @@ void IconTextPlugin::getTopics(JsonArray& topics) const * * The used icon is from MaterialDesignIcons.com (namespace: mdi). */ - jsonText["name"] = TOPIC_TEXT; - jsonText["fileName"] = TOPIC_TEXT_EXTRA_FILE_NAME; + jsonText["name"] = TOPIC_TEXT; + jsonText["extra"] = TOPIC_TEXT_EXTRA_FILE_NAME; } bool IconTextPlugin::getTopic(const String& topic, JsonObject& value) const diff --git a/lib/IconTextPlugin/src/IconTextPlugin.h b/lib/IconTextPlugin/src/IconTextPlugin.h index 4d34e42a..d386701f 100644 --- a/lib/IconTextPlugin/src/IconTextPlugin.h +++ b/lib/IconTextPlugin/src/IconTextPlugin.h @@ -167,26 +167,28 @@ class IconTextPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/JustTextPlugin/src/JustTextPlugin.cpp b/lib/JustTextPlugin/src/JustTextPlugin.cpp index 0d795c82..a90e553b 100644 --- a/lib/JustTextPlugin/src/JustTextPlugin.cpp +++ b/lib/JustTextPlugin/src/JustTextPlugin.cpp @@ -81,7 +81,7 @@ bool JustTextPlugin::isEnabled() const void JustTextPlugin::getTopics(JsonArray& topics) const { - JsonObject jsonText = topics.createNestedObject(); + JsonObject jsonText = topics.createNestedObject(); /* The topic contains Home Assistant support of the MQTT discovery * (https://www.home-assistant.io/integrations/mqtt). See the configured @@ -89,8 +89,8 @@ void JustTextPlugin::getTopics(JsonArray& topics) const * * The used icon is from MaterialDesignIcons.com (namespace: mdi). */ - jsonText["name"] = TOPIC_TEXT; - jsonText["fileName"] = TOPIC_TEXT_EXTRA_FILE_NAME; + jsonText["name"] = TOPIC_TEXT; + jsonText["extra"] = TOPIC_TEXT_EXTRA_FILE_NAME; } bool JustTextPlugin::getTopic(const String& topic, JsonObject& value) const diff --git a/lib/JustTextPlugin/src/JustTextPlugin.h b/lib/JustTextPlugin/src/JustTextPlugin.h index fb490365..f4edd7e3 100644 --- a/lib/JustTextPlugin/src/JustTextPlugin.h +++ b/lib/JustTextPlugin/src/JustTextPlugin.h @@ -164,26 +164,28 @@ class JustTextPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/MqttApiTopicHandler/src/HomeAssistantMqtt.h b/lib/MqttApiTopicHandler/src/HomeAssistantMqtt.h index c7b2002f..d0a6a9f5 100644 --- a/lib/MqttApiTopicHandler/src/HomeAssistantMqtt.h +++ b/lib/MqttApiTopicHandler/src/HomeAssistantMqtt.h @@ -97,7 +97,7 @@ class HomeAssistantMqtt /** * Process the Home Assistant extension. - * + * * @param[in] isConnected Is a MQTT broker connection established? */ void process(bool isConnected); @@ -106,7 +106,7 @@ class HomeAssistantMqtt * Register Home Assistant MQTT discovery. * It will not publish, just prepare the MQTT discovery information * and hold it internally. - * + * * @param[in] deviceId Device id. * @param[in] entityId Entity id. * @param[in] stateTopic The MQTT status topic. @@ -118,7 +118,7 @@ class HomeAssistantMqtt /** * Unregister Home Assistant MQTT discovery. - * + * * @param[in] deviceId Device id. * @param[in] entityId Entity id. * @param[in] stateTopic The MQTT status topic. @@ -129,44 +129,46 @@ class HomeAssistantMqtt private: /** Home Assistant discovery prefix key */ - static const char* KEY_HA_DISCOVERY_PREFIX; + static const char* KEY_HA_DISCOVERY_PREFIX; /**Home Assistant discovery prefix name */ - static const char* NAME_HA_DISCOVERY_PREFIX; + static const char* NAME_HA_DISCOVERY_PREFIX; /** Home Assistant discovery prefix default value */ - static const char* DEFAULT_HA_DISCOVERY_PREFIX; + static const char* DEFAULT_HA_DISCOVERY_PREFIX; /** Home Assistant discovery prefix min. length */ - static const size_t MIN_VALUE_HA_DISCOVERY_PREFIX = 0U; + static const size_t MIN_VALUE_HA_DISCOVERY_PREFIX = 0U; /** Home Assistant discovery prefix max. length */ - static const size_t MAX_VALUE_HA_DISCOVERY_PREFIX = 64U; + static const size_t MAX_VALUE_HA_DISCOVERY_PREFIX = 64U; /** Home Assistant discovery enable flag key */ - static const char* KEY_HA_DISCOVERY_ENABLE; + static const char* KEY_HA_DISCOVERY_ENABLE; /** Home Assistant discovery enable flag name */ - static const char* NAME_HA_DISCOVERY_ENABLE; + static const char* NAME_HA_DISCOVERY_ENABLE; /** Home Assistant discovery enable flag default value */ - static const bool DEFAULT_HA_DISCOVERY_ENABLE; + static const bool DEFAULT_HA_DISCOVERY_ENABLE; /** Information necessary for Home Assistant MQTT discovery. */ struct MqttDiscoveryInfo { - String component; /**< Home Assistant component */ - String nodeId; /**< Home Assistant node id */ - String objectId; /**< Home Assistant object id */ - DynamicJsonDocument discoveryDetails; /**< Additional discovery information. */ - bool isReqToPublish; /**< Is requested to publish this discovery info? */ + static const size_t JSON_DOC_SIZE = 768U; /**< JSON document size */ + + String component; /**< Home Assistant component */ + String nodeId; /**< Home Assistant node id */ + String objectId; /**< Home Assistant object id */ + DynamicJsonDocument discoveryDetails; /**< Additional discovery information. */ + bool isReqToPublish; /**< Is requested to publish this discovery info? */ /** Construct Home Assistant MQTT discovery information. */ MqttDiscoveryInfo() : component(), nodeId(), objectId(), - discoveryDetails(368U), + discoveryDetails(JSON_DOC_SIZE), isReqToPublish(true) { } @@ -175,21 +177,21 @@ class HomeAssistantMqtt /** List of Home Assistant MQTT discovery information. */ typedef std::vector ListOfMqttDiscoveryInfo; - KeyValueString m_haDiscoveryPrefixSetting; /**< Setting for the Home Assistant MQTT discovery prefix. */ - KeyValueBool m_haDiscoveryEnabledSetting; /**< Setting for the Home Assistant MQTT discovery enable flag. */ - String m_haDiscoveryPrefix; /**< Home Assistant MQTT discovery prefix. */ - bool m_haDiscoveryEnabled; /**< Is the Home Assistant MQTT discovery enabled or not. */ - ListOfMqttDiscoveryInfo m_mqttDiscoveryInfoList; /**< List of Home Assistant MQTT discovery informations. */ - bool m_isConnected; /**< Is MQTT broker connection established? */ + KeyValueString m_haDiscoveryPrefixSetting; /**< Setting for the Home Assistant MQTT discovery prefix. */ + KeyValueBool m_haDiscoveryEnabledSetting; /**< Setting for the Home Assistant MQTT discovery enable flag. */ + String m_haDiscoveryPrefix; /**< Home Assistant MQTT discovery prefix. */ + bool m_haDiscoveryEnabled; /**< Is the Home Assistant MQTT discovery enabled or not. */ + ListOfMqttDiscoveryInfo m_mqttDiscoveryInfoList; /**< List of Home Assistant MQTT discovery informations. */ + bool m_isConnected; /**< Is MQTT broker connection established? */ HomeAssistantMqtt(const HomeAssistantMqtt& ext); HomeAssistantMqtt& operator=(const HomeAssistantMqtt& ext); /** * Get the object id from the entity id. - * + * * @param[in] entityId The entity id. - * + * * @return Object id */ String getObjectId(const String& entityId); @@ -201,7 +203,7 @@ class HomeAssistantMqtt /** * Get the discovery configuration topic. - * + * * @param[out] haConfigTopic Discovery configuration topic * @param[in] component Home Assistant component * @param[in] nodeId Home Assistant node id @@ -221,7 +223,7 @@ class HomeAssistantMqtt /** * Publish MQTT auto discovery informations, which are requested. - * + * * Note: Need to be called continously and will only publish one info per * call cycle. */ @@ -232,6 +234,6 @@ class HomeAssistantMqtt * Functions *****************************************************************************/ -#endif /* HOME_ASSISTANT_MQTT_H */ +#endif /* HOME_ASSISTANT_MQTT_H */ /** @} */ \ No newline at end of file diff --git a/lib/MultiIconPlugin/src/MultiIconPlugin.h b/lib/MultiIconPlugin/src/MultiIconPlugin.h index 8cd79678..71f8b743 100644 --- a/lib/MultiIconPlugin/src/MultiIconPlugin.h +++ b/lib/MultiIconPlugin/src/MultiIconPlugin.h @@ -133,26 +133,28 @@ class MultiIconPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/OpenWeatherPlugin/src/OpenWeatherPlugin.h b/lib/OpenWeatherPlugin/src/OpenWeatherPlugin.h index f38cac51..606dc535 100644 --- a/lib/OpenWeatherPlugin/src/OpenWeatherPlugin.h +++ b/lib/OpenWeatherPlugin/src/OpenWeatherPlugin.h @@ -202,26 +202,28 @@ class OpenWeatherPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/Plugin/src/IPluginMaintenance.hpp b/lib/Plugin/src/IPluginMaintenance.hpp index 2493e270..0996bd05 100644 --- a/lib/Plugin/src/IPluginMaintenance.hpp +++ b/lib/Plugin/src/IPluginMaintenance.hpp @@ -153,26 +153,28 @@ class IPluginMaintenance * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/Plugin/src/Plugin.hpp b/lib/Plugin/src/Plugin.hpp index 530007b3..b913ea29 100644 --- a/lib/Plugin/src/Plugin.hpp +++ b/lib/Plugin/src/Plugin.hpp @@ -169,26 +169,28 @@ class Plugin : public IPluginMaintenance * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/SensorPlugin/src/SensorPlugin.h b/lib/SensorPlugin/src/SensorPlugin.h index 4bc626bb..955715b5 100644 --- a/lib/SensorPlugin/src/SensorPlugin.h +++ b/lib/SensorPlugin/src/SensorPlugin.h @@ -160,26 +160,28 @@ class SensorPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/SignalDetectorPlugin/src/SignalDetectorPlugin.h b/lib/SignalDetectorPlugin/src/SignalDetectorPlugin.h index 83e2800f..96738141 100644 --- a/lib/SignalDetectorPlugin/src/SignalDetectorPlugin.h +++ b/lib/SignalDetectorPlugin/src/SignalDetectorPlugin.h @@ -170,26 +170,28 @@ class SignalDetectorPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/SoundReactivePlugin/src/SoundReactivePlugin.h b/lib/SoundReactivePlugin/src/SoundReactivePlugin.h index fcc6cbed..f5a35884 100644 --- a/lib/SoundReactivePlugin/src/SoundReactivePlugin.h +++ b/lib/SoundReactivePlugin/src/SoundReactivePlugin.h @@ -151,26 +151,28 @@ class SoundReactivePlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/SunrisePlugin/src/SunrisePlugin.h b/lib/SunrisePlugin/src/SunrisePlugin.h index 9979c883..e1794249 100644 --- a/lib/SunrisePlugin/src/SunrisePlugin.h +++ b/lib/SunrisePlugin/src/SunrisePlugin.h @@ -182,26 +182,28 @@ class SunrisePlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/lib/TopicHandlerService/src/TopicHandlerService.cpp b/lib/TopicHandlerService/src/TopicHandlerService.cpp index 4a4d46c1..a12ca2f4 100644 --- a/lib/TopicHandlerService/src/TopicHandlerService.cpp +++ b/lib/TopicHandlerService/src/TopicHandlerService.cpp @@ -124,8 +124,8 @@ void TopicHandlerService::registerTopics(const String& deviceId, IPluginMaintena for (JsonVariantConst jsonTopic : jsonTopics) { String topicName; - DynamicJsonDocument jsonDocExtra(JSON_DOC_SIZE); JsonObjectConst jsonExtra; + String extraFileName; String topicAccess = DEFAULT_ACCESS; ITopicHandler::GetTopicFunc getTopicFunc = nullptr; ITopicHandler::SetTopicFunc setTopicFunc = nullptr; @@ -136,7 +136,7 @@ void TopicHandlerService::registerTopics(const String& deviceId, IPluginMaintena { JsonVariantConst jsonTopicName = jsonTopic["name"]; JsonVariantConst jsonTopicAccess = jsonTopic["access"]; - JsonVariantConst jsonFileName = jsonTopic["fileName"]; + JsonVariantConst jsonExtraVar = jsonTopic["extra"]; if (true == jsonTopicName.is()) { @@ -148,27 +148,18 @@ void TopicHandlerService::registerTopics(const String& deviceId, IPluginMaintena topicAccess = jsonTopicAccess.as(); } - /* Shall extra info be loaded from a JSON file? */ - if (true == jsonFileName.is()) + if (true == jsonExtraVar.is()) { - JsonFile jsonFile(FILESYSTEM); - String fileName = jsonFileName.as(); - - LOG_INFO("Load extra info from file: %s", fileName.c_str()); - - if (false == jsonFile.load(fileName, jsonDocExtra)) - { - LOG_WARNING("Failed to load extra info from file: %s", fileName.c_str()); - } - else - { - jsonExtra = jsonDocExtra.as(); - } + jsonExtra = jsonExtraVar.as(); + } + else if (true == jsonExtraVar.is()) + { + extraFileName = jsonExtraVar.as(); } - /* Extra info may be part of the topic object. */ else { - jsonExtra = jsonTopic; + /* Skip */ + ; } } /* Only topic name is available */ @@ -187,12 +178,26 @@ void TopicHandlerService::registerTopics(const String& deviceId, IPluginMaintena strToAccess(plugin, topicAccess, getTopicFunc, setTopicFunc, uploadReqFunc); /* Register plugin topic with plugin UID as entity id. */ - registerTopic(deviceId, getEntityIdByPluginUid(plugin->getUID()), topicName, jsonExtra, getTopicFunc, nullptr, setTopicFunc, uploadReqFunc); + if (true == extraFileName.isEmpty()) + { + registerTopic(deviceId, getEntityIdByPluginUid(plugin->getUID()), topicName, jsonExtra, getTopicFunc, nullptr, setTopicFunc, uploadReqFunc); + } + else + { + registerTopic(deviceId, getEntityIdByPluginUid(plugin->getUID()), topicName, extraFileName.c_str(), getTopicFunc, nullptr, setTopicFunc, uploadReqFunc); + } /* Register plugin topic with plugin alias as entity id (if possible). */ if (false == plugin->getAlias().isEmpty()) { - registerTopic(deviceId, getEntityIdByPluginAlias(plugin->getAlias()), topicName, jsonExtra, getTopicFunc, nullptr, setTopicFunc, uploadReqFunc); + if (true == extraFileName.isEmpty()) + { + registerTopic(deviceId, getEntityIdByPluginUid(plugin->getUID()), topicName, jsonExtra, getTopicFunc, nullptr, setTopicFunc, uploadReqFunc); + } + else + { + registerTopic(deviceId, getEntityIdByPluginUid(plugin->getUID()), topicName, extraFileName.c_str(), getTopicFunc, nullptr, setTopicFunc, uploadReqFunc); + } } addToPluginMetaDataList(deviceId, plugin, topicName); @@ -313,6 +318,31 @@ void TopicHandlerService::registerTopic(const String& deviceId, const String& en } } +void TopicHandlerService::registerTopic(const String& deviceId, const String& entityId, const String& topic, const char* extraFileName, ITopicHandler::GetTopicFunc getTopicFunc, HasChangedFunc hasChangedFunc, ITopicHandler::SetTopicFunc setTopicFunc, ITopicHandler::UploadReqFunc uploadReqFunc) +{ + const size_t JSON_DOC_SIZE = 1024U; + DynamicJsonDocument jsonDocExtra(JSON_DOC_SIZE); + JsonObjectConst jsonExtra; + + if (nullptr != extraFileName) + { + JsonFile jsonFile(FILESYSTEM); + + LOG_INFO("Load extra info from file: %s", extraFileName); + + if (false == jsonFile.load(extraFileName, jsonDocExtra)) + { + LOG_WARNING("Failed to load extra info from file: %s", extraFileName); + } + else + { + jsonExtra = jsonDocExtra.as(); + } + } + + registerTopic(deviceId, entityId, topic, jsonExtra, getTopicFunc, hasChangedFunc, setTopicFunc, uploadReqFunc); +} + void TopicHandlerService::unregisterTopic(const String& deviceId, const String& entityId, const String& topic) { if ((false == deviceId.isEmpty()) && diff --git a/lib/TopicHandlerService/src/TopicHandlerService.h b/lib/TopicHandlerService/src/TopicHandlerService.h index 0d1c7cc7..cc5c7cc2 100644 --- a/lib/TopicHandlerService/src/TopicHandlerService.h +++ b/lib/TopicHandlerService/src/TopicHandlerService.h @@ -127,6 +127,20 @@ class TopicHandlerService : public IService */ void registerTopic(const String& deviceId, const String& entityId, const String& topic, JsonObjectConst& jsonExtra, ITopicHandler::GetTopicFunc getTopicFunc, HasChangedFunc hasChangedFunc, ITopicHandler::SetTopicFunc setTopicFunc, ITopicHandler::UploadReqFunc uploadReqFunc); + /** + * Register a topic. + * + * @param[in] deviceId The device id which represents the physical device. + * @param[in] entityId The entity id which represents the entity of the device. + * @param[in] topic The topic which to register. + * @param[in] extraFileName Name of the file with extra JSON parameters for concrete topic handlers, which are pushed through. + * @param[in] getTopicFunc Function which is called to read the topic. + * @param[in] hasChangedFunc Function which is periodically called to check whether the topic has changed. + * @param[in] setTopicFunc Function which is called to set the topic. + * @param[in] uploadReqFunc Function which is called to accept a file upload or not. + */ + void registerTopic(const String& deviceId, const String& entityId, const String& topic, const char* extraFileName, ITopicHandler::GetTopicFunc getTopicFunc, HasChangedFunc hasChangedFunc, ITopicHandler::SetTopicFunc setTopicFunc, ITopicHandler::UploadReqFunc uploadReqFunc); + /** * Unregister a topic. * diff --git a/lib/VolumioPlugin/src/VolumioPlugin.h b/lib/VolumioPlugin/src/VolumioPlugin.h index 1e41a6e3..a4efd982 100644 --- a/lib/VolumioPlugin/src/VolumioPlugin.h +++ b/lib/VolumioPlugin/src/VolumioPlugin.h @@ -157,26 +157,28 @@ class VolumioPlugin : public PluginWithConfig * } * * - * Homeassistant MQTT discovery support can be added with the "ha" key. + * Homeassistant MQTT discovery support can be added with the "ha" JSON object inside + * the "extra" JSON object. * {.json} * { * "topics": [{ * "name": "/text", - * "ha": { - * ... everything here will be used for MQTT discovery ... + * "extra": { + * "ha": { + * ... everything here will be used for MQTT discovery ... + * } * } * }] * } * * - * Additional information can be loaded from a file too. It will be appended - * to the topic data (parallel to "name" and "access"). If a file is used, - * any other key than "name" and "access" will be ignored. + * Extra information can be loaded from a file too. This is useful for complex + * configurations and to keep program memory usage low. * {.json} * { * "topics": [{ * "name": "/text", - * "fileName": "haText.json" + * "extra": "extra.json" * }] * } * diff --git a/src/Hal/SensorDataProvider.cpp b/src/Hal/SensorDataProvider.cpp index 85e6cbfd..c2bcbc53 100644 --- a/src/Hal/SensorDataProvider.cpp +++ b/src/Hal/SensorDataProvider.cpp @@ -61,7 +61,7 @@ typedef struct { ISensorChannel::Type sensorChannelType; /**< Sensor channel type. */ - const char* extraFilename; /**< Filename of extra data in JSON format, e.g. for homeassistant extension. */ + const char* extraFileName; /**< Filename of extra data in JSON format, e.g. for homeassistant extension. */ uint32_t updatePeriod; /**< Max. sensor data update period in ms regarding publishing. */ } SensorTopic; @@ -512,73 +512,65 @@ void SensorDataProvider::registerSensorTopics() { const SensorTopic* sensorTopic = &gSensorTopics[index]; SensorTopicRunData* sensorTopicRunData = &gSensorLastValue[index]; - const size_t JSON_DOC_SIZE = 512U; - DynamicJsonDocument jsonDoc(JSON_DOC_SIZE); - JsonFile jsonFile(FILESYSTEM); + uint8_t sensorIndex = 0U; + uint8_t channelIndex = 0U; - if (true == jsonFile.load(sensorTopic->extraFilename, jsonDoc)) + /* Try to find a sensor channel which provides the required information. */ + if (true == find(sensorIndex, channelIndex, sensorTopic->sensorChannelType)) { - JsonObjectConst extra = jsonDoc.as(); - uint8_t sensorIndex = 0U; - uint8_t channelIndex = 0U; - - /* Try to find a sensor channel which provides the required information. */ - if (true == find(sensorIndex, channelIndex, sensorTopic->sensorChannelType)) - { - const uint32_t VALUE_PRECISION = 2U; /* 2 digits after the . */ - ISensor* sensor = this->getSensor(sensorIndex); - ISensorChannel* sensorChannel = sensor->getChannel(channelIndex); - String channelName = "/" + ISensorChannel::channelTypeToName(sensorTopic->sensorChannelType); - String entityId = "sensors/"; - ITopicHandler::GetTopicFunc getTopicFunc = - [sensorTopic, sensorChannel, VALUE_PRECISION](const String& topic, JsonObject& jsonValue) -> bool { - bool isSuccessful = false; - String value = sensorChannel->getValueAsString(VALUE_PRECISION); - - /* The callback is dedicated to a topic, therefore the - * topic parameter is not used. - */ - UTIL_NOT_USED(topic); - - /* Floating point channels may provide NaN. */ - if (value != "NAN") - { - jsonValue["value"] = value; + const uint32_t VALUE_PRECISION = 2U; /* 2 digits after the . */ + ISensor* sensor = this->getSensor(sensorIndex); + ISensorChannel* sensorChannel = sensor->getChannel(channelIndex); + String channelName = "/" + ISensorChannel::channelTypeToName(sensorTopic->sensorChannelType); + String entityId = "sensors/"; + ITopicHandler::GetTopicFunc getTopicFunc = + [sensorTopic, sensorChannel, VALUE_PRECISION](const String& topic, JsonObject& jsonValue) -> bool { + bool isSuccessful = false; + String value = sensorChannel->getValueAsString(VALUE_PRECISION); + + /* The callback is dedicated to a topic, therefore the + * topic parameter is not used. + */ + UTIL_NOT_USED(topic); + + /* Floating point channels may provide NaN. */ + if (value != "NAN") + { + jsonValue["value"] = value; - isSuccessful = true; - } + isSuccessful = true; + } - return isSuccessful; - }; - TopicHandlerService::HasChangedFunc hasChangedFunc = - [sensorTopic, sensorChannel, sensorTopicRunData, VALUE_PRECISION](const String& topic) -> bool { - bool hasChanged = false; - String value = sensorChannel->getValueAsString(VALUE_PRECISION); - uint32_t timestamp = millis(); - uint32_t delta = timestamp - sensorTopicRunData->lastTimestamp; - - /* The callback is dedicated to a topic, therefore the - * topic parameter is not used. - */ - UTIL_NOT_USED(topic); - - if ((value != "NAN") && /* Floating point channels may provide NaN. */ - (sensorTopicRunData->lastValue != value) && /* Value changed? */ - (sensorTopic->updatePeriod <= delta)) /* Update period expired? */ - { - sensorTopicRunData->lastValue = value; - sensorTopicRunData->lastTimestamp = timestamp; + return isSuccessful; + }; + TopicHandlerService::HasChangedFunc hasChangedFunc = + [sensorTopic, sensorChannel, sensorTopicRunData, VALUE_PRECISION](const String& topic) -> bool { + bool hasChanged = false; + String value = sensorChannel->getValueAsString(VALUE_PRECISION); + uint32_t timestamp = millis(); + uint32_t delta = timestamp - sensorTopicRunData->lastTimestamp; + + /* The callback is dedicated to a topic, therefore the + * topic parameter is not used. + */ + UTIL_NOT_USED(topic); + + if ((value != "NAN") && /* Floating point channels may provide NaN. */ + (sensorTopicRunData->lastValue != value) && /* Value changed? */ + (sensorTopic->updatePeriod <= delta)) /* Update period expired? */ + { + sensorTopicRunData->lastValue = value; + sensorTopicRunData->lastTimestamp = timestamp; - hasChanged = true; - } + hasChanged = true; + } - return hasChanged; - }; + return hasChanged; + }; - entityId += index; + entityId += index; - topicHandlerService.registerTopic(m_deviceId, entityId, channelName, extra, getTopicFunc, hasChangedFunc, nullptr, nullptr); - } + topicHandlerService.registerTopic(m_deviceId, entityId, channelName, sensorTopic->extraFileName, getTopicFunc, hasChangedFunc, nullptr, nullptr); } } } diff --git a/src/Topics/Topics.cpp b/src/Topics/Topics.cpp index 67c6d1ab..c9c1c7bf 100644 --- a/src/Topics/Topics.cpp +++ b/src/Topics/Topics.cpp @@ -58,6 +58,7 @@ typedef struct ITopicHandler::GetTopicFunc getTopicFunc; /**< Get topic function */ TopicHandlerService::HasChangedFunc hasChangedFunc; /**< Has changed function */ ITopicHandler::SetTopicFunc setTopicFunc; /**< Set topic function */ + const char* extraFileName; /**< File name of a file with extra information. */ } TopicElem; @@ -82,13 +83,13 @@ static String gDeviceId; * List of topics. */ static TopicElem gTopicList[] = { - { "display", "/power", getDisplayState, hasDisplayStateChanged, setDisplayState } + { "display", "/power", getDisplayState, hasDisplayStateChanged, setDisplayState, "/extra/display.json" } }; /** * Last display on state. */ -static bool gLastDisplayOnState = false; +static bool gLastDisplayOnState = false; /****************************************************************************** * Public Methods @@ -110,7 +111,6 @@ void Topics::begin() { SettingsService& settings = SettingsService::getInstance(); size_t idx; - JsonObjectConst jsonExtra; if (false == settings.open(true)) { @@ -132,7 +132,7 @@ void Topics::begin() gDeviceId, topicElem->entity, topicElem->topic, - jsonExtra, + topicElem->extraFileName, topicElem->getTopicFunc, topicElem->hasChangedFunc, topicElem->setTopicFunc,