From ded956ed63f5c2d6c6b166c7719eb4ac67a4f782 Mon Sep 17 00:00:00 2001 From: BlueAndi Date: Wed, 3 Jan 2024 11:55:37 +0100 Subject: [PATCH 1/3] Sensors like the SHT3x need to request the data periodically via bus. To avoid that for every e.g. readTemperature() call the data is requested from the physical sensor, it shall be done in the background every 10s. #157 --- lib/Common/src/ISensor.hpp | 6 ++ lib/Common/src/SensorChannelType.hpp | 4 +- lib/Common/src/SensorDataProviderImpl.cpp | 13 +++ lib/Common/src/SensorDataProviderImpl.h | 5 ++ lib/Sensors/src/SensorBattery.h | 9 ++ lib/Sensors/src/SensorDhtX.h | 43 +++++++-- lib/Sensors/src/SensorLdr.h | 9 ++ lib/Sensors/src/SensorSht3X.cpp | 8 ++ lib/Sensors/src/SensorSht3X.h | 34 +++++-- src/Hal/SensorDataProvider.cpp | 105 ++++++++++++++-------- src/Hal/SensorDataProvider.h | 22 +++++ src/StateMachine/ConnectedState.cpp | 1 + src/StateMachine/ConnectingState.cpp | 2 + 13 files changed, 209 insertions(+), 52 deletions(-) diff --git a/lib/Common/src/ISensor.hpp b/lib/Common/src/ISensor.hpp index 55e7e07b..e105cc7b 100644 --- a/lib/Common/src/ISensor.hpp +++ b/lib/Common/src/ISensor.hpp @@ -66,6 +66,12 @@ class ISensor */ virtual void begin() = 0; + /** + * Process the sensor driver. Mainly used to read the sensor value and + * provide its data cached to the sensor channels. + */ + virtual void process() = 0; + /** * Get sensor name. * diff --git a/lib/Common/src/SensorChannelType.hpp b/lib/Common/src/SensorChannelType.hpp index e05d0b5c..5b29f2aa 100644 --- a/lib/Common/src/SensorChannelType.hpp +++ b/lib/Common/src/SensorChannelType.hpp @@ -161,6 +161,7 @@ class SensorChannelType : public ISens /** * Get data value. + * If there is any error, it will return NaN. * * @return Sensor data value */ @@ -182,6 +183,7 @@ class SensorChannelType : public ISens /** * Get value as string. + * If there is any error, it will return "NAN". * * @param[in] precision The precision (ignored for integer values) of the value. * @@ -191,7 +193,7 @@ class SensorChannelType : public ISens { float value = getValue(); String valueStr; - char buffer[20]; + char buffer[20U]; (void)snprintf(buffer, sizeof(buffer), "%.*F", precision, value); valueStr = buffer; diff --git a/lib/Common/src/SensorDataProviderImpl.cpp b/lib/Common/src/SensorDataProviderImpl.cpp index e0793816..d7c6dcdd 100644 --- a/lib/Common/src/SensorDataProviderImpl.cpp +++ b/lib/Common/src/SensorDataProviderImpl.cpp @@ -71,6 +71,19 @@ void SensorDataProviderImpl::begin() } } +void SensorDataProviderImpl::process() +{ + uint8_t index = 0U; + + for(index = 0U; index < m_cnt; ++index) + { + if (nullptr != m_sensors[index]) + { + m_sensors[index]->process(); + } + } +} + ISensor* SensorDataProviderImpl::getSensor(uint8_t index) { ISensor* sensor = nullptr; diff --git a/lib/Common/src/SensorDataProviderImpl.h b/lib/Common/src/SensorDataProviderImpl.h index 835b9bd2..caff7bb9 100644 --- a/lib/Common/src/SensorDataProviderImpl.h +++ b/lib/Common/src/SensorDataProviderImpl.h @@ -85,6 +85,11 @@ class SensorDataProviderImpl */ void begin(); + /** + * Process the sensor drivers. + */ + void process(); + /** * Get number of installed sensor drivers, independed of the physical * sensor availability. diff --git a/lib/Sensors/src/SensorBattery.h b/lib/Sensors/src/SensorBattery.h index 57aeaef3..52ae726d 100644 --- a/lib/Sensors/src/SensorBattery.h +++ b/lib/Sensors/src/SensorBattery.h @@ -169,6 +169,15 @@ class SensorBattery : public ISensor */ void begin() final; + /** + * Process the sensor driver. Mainly used to read the sensor value and + * provide its data cached to the sensor channels. + */ + void process() final + { + /* Nothing to do.*/ + } + /** * Get sensor name. * diff --git a/lib/Sensors/src/SensorDhtX.h b/lib/Sensors/src/SensorDhtX.h index 42879a81..c2caecb2 100644 --- a/lib/Sensors/src/SensorDhtX.h +++ b/lib/Sensors/src/SensorDhtX.h @@ -93,13 +93,24 @@ class DhtXTemperatureChannel : public SensorChannelFloat32 } /** - * Get data value. + * Get the temperature. + * If there is any error, it will return NaN. * - * @return Sensor data value in °C. + * @return Temperature in °C. */ float getValue() final { - return m_driver.readTemperature() + m_offset; + /* readTemperature() will provide the last value from the cache in case + * the request period is lower than 2s. + */ + float temperature = m_driver.readTemperature(); + + if (false == isnan(temperature)) + { + temperature += m_offset; + } + + return temperature; } /** @@ -168,13 +179,24 @@ class DhtXHumidityChannel : public SensorChannelFloat32 } /** - * Get data value. + * Get the humidity. + * If there is any error, it will return NaN. * - * @return Sensor data value in %. + * @return Humidity in %. */ float getValue() final { - return m_driver.readHumidity() + m_offset; + /* readHumidity() will provide the last value from the cache in case + * the request period is lower than 2s. + */ + float humidity = m_driver.readHumidity(); + + if (false == isnan(humidity)) + { + humidity += m_offset; + } + + return humidity; } /** @@ -251,6 +273,15 @@ class SensorDhtX : public ISensor */ void begin() final; + /** + * Process the sensor driver. Mainly used to read the sensor value and + * provide its data cached to the sensor channels. + */ + void process() final + { + /* Nothing to do.*/ + } + /** * Get sensor name. * diff --git a/lib/Sensors/src/SensorLdr.h b/lib/Sensors/src/SensorLdr.h index 03db6d24..624b84af 100644 --- a/lib/Sensors/src/SensorLdr.h +++ b/lib/Sensors/src/SensorLdr.h @@ -189,6 +189,15 @@ class SensorLdr : public ISensor */ void begin() final; + /** + * Process the sensor driver. Mainly used to read the sensor value and + * provide its data cached to the sensor channels. + */ + void process() final + { + /* Nothing to do.*/ + } + /** * Get sensor name. * diff --git a/lib/Sensors/src/SensorSht3X.cpp b/lib/Sensors/src/SensorSht3X.cpp index 1c68fd8b..bfcba8fb 100644 --- a/lib/Sensors/src/SensorSht3X.cpp +++ b/lib/Sensors/src/SensorSht3X.cpp @@ -75,6 +75,14 @@ void SensorSht3X::begin() } } +void SensorSht3X::process() +{ + if (true == m_isAvailable) + { + (void)m_driver.readSample(); + } +} + const char* SensorSht3X::getName() const { /* Model can not be read back and the automatic detection may be enabled, diff --git a/lib/Sensors/src/SensorSht3X.h b/lib/Sensors/src/SensorSht3X.h index b73b5c9c..54d9a025 100644 --- a/lib/Sensors/src/SensorSht3X.h +++ b/lib/Sensors/src/SensorSht3X.h @@ -93,13 +93,21 @@ class Sht3XTemperatureChannel : public SensorChannelFloat32 } /** - * Get data value. + * Get the temperature. + * If there is any error, it will return NaN. * - * @return Sensor data value in °C. + * @return Temperature in °C. */ float getValue() final { - return m_driver.getTemperature() + m_offset; + float temperature = m_driver.getTemperature(); + + if (false == isnan(temperature)) + { + temperature += m_offset; + } + + return temperature; } /** @@ -168,13 +176,21 @@ class Sht3XHumidityChannel : public SensorChannelFloat32 } /** - * Get data value. + * Get the humidity. + * If there is any error, it will return NaN. * - * @return Sensor data value in %. + * @return Humidity in %. */ float getValue() final { - return m_driver.getHumidity() + m_offset; + float humidity = m_driver.getHumidity(); + + if (false == isnan(humidity)) + { + humidity += m_offset; + } + + return humidity; } /** @@ -239,6 +255,12 @@ class SensorSht3X : public ISensor */ void begin() final; + /** + * Process the sensor driver. Mainly used to read the sensor value and + * provide its data cached to the sensor channels. + */ + void process() final; + /** * Get sensor name. * diff --git a/src/Hal/SensorDataProvider.cpp b/src/Hal/SensorDataProvider.cpp index fc531d90..da89dd61 100644 --- a/src/Hal/SensorDataProvider.cpp +++ b/src/Hal/SensorDataProvider.cpp @@ -192,13 +192,28 @@ void SensorDataProvider::begin() logSensorAvailability(); registerSensorTopics(); + + m_timer.start(SENSOR_PROCESS_PERIOD); + m_isInitialized = true; } void SensorDataProvider::end() { + m_isInitialized = false; + m_timer.stop(); unregisterSensorTopics(); } +void SensorDataProvider::process() +{ + if ((true == m_isInitialized) && + (true == m_timer.isTimeout())) + { + m_impl->process(); + m_timer.restart(); + } +} + uint8_t SensorDataProvider::getNumSensors() const { return m_impl->getNumSensors(); @@ -380,7 +395,9 @@ bool SensorDataProvider::save() SensorDataProvider::SensorDataProvider() : m_impl(Sensors::getSensorDataProviderImpl()), - m_deviceId() + m_deviceId(), + m_timer(), + m_isInitialized(false) { } @@ -558,59 +575,69 @@ void SensorDataProvider::registerSensorTopics() { LOG_ERROR("Sensor/Channel %u discovery details error.", index); } - - extra = jsonDoc.as(); - - /* Try to find a sensor channel which provides the required information. */ - if (true == find(sensorIndex, channelIndex, sensorTopic->sensorChannelType)) + else { - ISensor* sensor = this->getSensor(sensorIndex); - ISensorChannel* sensorChannel = sensor->getChannel(channelIndex); - String channelName = "/" + ISensorChannel::channelTypeToName(sensorTopic->sensorChannelType); - String entityId = "sensors/"; - - entityId += index; - - ITopicHandler::GetTopicFunc getTopicFunc = - [sensorTopic, sensorChannel](const String& topic, JsonObject& value) -> bool - { - const uint32_t VALUE_PRECISION = 2U; /* 2 digits after the . */ + extra = jsonDoc.as(); - UTIL_NOT_USED(topic); + /* 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); - value["value"] = sensorChannel->getValueAsString(VALUE_PRECISION); + /* The callback is dedicated to a topic, therefore the + * topic parameter is not used. + */ + UTIL_NOT_USED(topic); - return true; - }; - TopicHandlerService::HasChangedFunc hasChangedFunc = - [sensorTopic, sensorChannel, sensorTopicRunData](const String& topic) -> bool - { - bool hasChanged = false; + /* Floating point channels may provide NaN. */ + if (value != "NAN") + { + jsonValue["value"] = value; - UTIL_NOT_USED(topic); + isSuccessful = true; + } - if ((nullptr != sensorTopic) && - (nullptr != sensorChannel) && - (nullptr != sensorTopicRunData)) + return isSuccessful; + }; + TopicHandlerService::HasChangedFunc hasChangedFunc = + [sensorTopic, sensorChannel, sensorTopicRunData, VALUE_PRECISION](const String& topic) -> bool { - String value = sensorChannel->getValueAsString(2U); - uint32_t timestamp = millis(); - uint32_t delta = timestamp - sensorTopicRunData->lastTimestamp; - - if ((sensorTopicRunData->lastValue != value) && - (sensorTopic->updatePeriod <= delta)) + 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; } - } - return hasChanged; - }; + return hasChanged; + }; - topicHandlerService.registerTopic(m_deviceId, entityId, channelName, extra, getTopicFunc, hasChangedFunc, nullptr, nullptr); + entityId += index; + + topicHandlerService.registerTopic(m_deviceId, entityId, channelName, extra, getTopicFunc, hasChangedFunc, nullptr, nullptr); + } } } } diff --git a/src/Hal/SensorDataProvider.h b/src/Hal/SensorDataProvider.h index 130c68a5..a48388c7 100644 --- a/src/Hal/SensorDataProvider.h +++ b/src/Hal/SensorDataProvider.h @@ -46,6 +46,7 @@ #include #include #include +#include /****************************************************************************** * Macros @@ -95,6 +96,11 @@ class SensorDataProvider */ void end(); + /** + * Process the sensor drivers. + */ + void process(); + /** * Get number of installed sensor drivers, independed of the physical * sensor availability. @@ -158,6 +164,11 @@ class SensorDataProvider */ static const char* SENSOR_CALIB_FILE_NAME; + /** + * Sensor process period in ms. + */ + static const uint32_t SENSOR_PROCESS_PERIOD = SIMPLE_TIMER_SECONDS(10U); + /** * Hidden implementation to avoid to include here all available sensors directly. */ @@ -168,6 +179,17 @@ class SensorDataProvider */ String m_deviceId; + /** + * Timer used for cyclic sensor driver processing. + */ + SimpleTimer m_timer; + + /** + * The flag indicates whether the sensor data provider was initialized + * by begin() or not. Calling end() will reset the flag. + */ + bool m_isInitialized; + /** * Constructs the sensor data provder. */ diff --git a/src/StateMachine/ConnectedState.cpp b/src/StateMachine/ConnectedState.cpp index 8cebadfc..4be97d12 100644 --- a/src/StateMachine/ConnectedState.cpp +++ b/src/StateMachine/ConnectedState.cpp @@ -161,6 +161,7 @@ void ConnectedState::process(StateMachine& sm) } Services::processAll(); + SensorDataProvider::getInstance().process(); } void ConnectedState::exit(StateMachine& sm) diff --git a/src/StateMachine/ConnectingState.cpp b/src/StateMachine/ConnectingState.cpp index 861dd118..4986ba4a 100644 --- a/src/StateMachine/ConnectingState.cpp +++ b/src/StateMachine/ConnectingState.cpp @@ -35,6 +35,7 @@ #include "ConnectingState.h" #include "SysMsg.h" #include "Services.h" +#include "SensorDataProvider.h" #include "IdleState.h" #include "ConnectedState.h" @@ -180,6 +181,7 @@ void ConnectingState::process(StateMachine& sm) } Services::processAll(); + SensorDataProvider::getInstance().process(); } void ConnectingState::exit(StateMachine& sm) From f2731a46d34ad6ee6b12fe06f8668261b81540d3 Mon Sep 17 00:00:00 2001 From: BlueAndi Date: Fri, 29 Dec 2023 13:14:52 +0100 Subject: [PATCH 2/3] Show humidity without '.'. --- lib/TempHumidPlugin/src/TempHumidPlugin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/TempHumidPlugin/src/TempHumidPlugin.cpp b/lib/TempHumidPlugin/src/TempHumidPlugin.cpp index 733ce71c..7182261a 100644 --- a/lib/TempHumidPlugin/src/TempHumidPlugin.cpp +++ b/lib/TempHumidPlugin/src/TempHumidPlugin.cpp @@ -165,7 +165,7 @@ void TempHumidPlugin::process(bool isConnected) { m_humidity = humidity; - LOG_INFO("Humidity: %3.1f %%", m_humidity); + LOG_INFO("Humidity: %3.0f %%", m_humidity); } } } @@ -266,7 +266,7 @@ void TempHumidPlugin::handleTemperature() } else { - char valueReducedPrecison[6] = { 0 }; /* Holds a value in lower precision for display. */ + char valueReducedPrecison[10] = { 0 }; /* Holds a value in lower precision for display. */ String text; /* Generate temperature string with reduced precision and add unit °C. */ @@ -289,10 +289,10 @@ void TempHumidPlugin::handleHumidity() } else { - char valueReducedPrecison[4] = { 0 }; /* Holds a value in lower precision for display. */ + char valueReducedPrecison[10] = { 0 }; /* Holds a value in lower precision for display. */ String text; - (void)snprintf(valueReducedPrecison, sizeof(valueReducedPrecison), "%3f", m_humidity); + (void)snprintf(valueReducedPrecison, sizeof(valueReducedPrecison), "%3.0f", m_humidity); text = "\\calign"; text += valueReducedPrecison; text += ISensorChannel::channelTypeToUnit(m_humiditySensorCh->getType()); From 07d67dc1cd365241f0ae7513948a4423ffade1b4 Mon Sep 17 00:00:00 2001 From: BlueAndi Date: Thu, 11 Jan 2024 00:11:50 +0100 Subject: [PATCH 3/3] Bump version to v7.2.1 --- data/version.json | 2 +- doc/doxygen/Doxyfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/version.json b/data/version.json index 7c559750..72bfcf78 100644 --- a/data/version.json +++ b/data/version.json @@ -1,3 +1,3 @@ { - "version": "v7.2.0" + "version": "v7.2.1" } \ No newline at end of file diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index 77e89fbe..6a8dad52 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = Pixelix # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = v7.2.0 +PROJECT_NUMBER = v7.2.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a