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 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/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()); 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)