From f1b941d964eb1ebb2ef4acd774ff98535feabcdf Mon Sep 17 00:00:00 2001 From: Maurice Makaay Date: Sat, 11 Jul 2020 22:12:59 +0200 Subject: [PATCH] Moved measuring and publish into the Measurements class. Further code cleanup steps will follow on this, but committing since we have a nicely working version now. --- src/Data/DataController.cpp | 104 ++++++---------------------- src/Data/DataController.h | 32 ++++----- src/Data/Measurement.cpp | 12 ++++ src/Data/Measurement.h | 2 + src/Data/Measurements.cpp | 129 +++++++++++++++++++++++++++++------ src/Data/Measurements.h | 41 ++++++++++- src/Network/DoughMQTT.cpp | 27 ++++---- src/Network/DoughMQTT.h | 16 ++--- src/Network/DoughWiFi.cpp | 3 - src/Network/DoughWiFi.h | 6 +- src/Sensors/DoughSensors.cpp | 78 ++++++++++++++------- src/Sensors/DoughSensors.h | 37 +++++----- src/Sensors/HCSR04.cpp | 85 ++++++++++++++--------- src/Sensors/HCSR04.h | 53 +++++++------- src/UI/DoughLogger.cpp | 4 +- src/UI/DoughLogger.h | 2 +- 16 files changed, 379 insertions(+), 252 deletions(-) diff --git a/src/Data/DataController.cpp b/src/Data/DataController.cpp index 4db06f7..1cf5071 100644 --- a/src/Data/DataController.cpp +++ b/src/Data/DataController.cpp @@ -6,9 +6,6 @@ DataController *DataController::_instance = nullptr; -/** - * Fetch the DoughData singleton. - */ DataController *DataController::Instance() { if (DataController::_instance == nullptr) @@ -18,9 +15,24 @@ DataController *DataController::Instance() return DataController::_instance; } -DataController::DataController() : _temperatureMeasurements(TEMPERATURE_AVG_LOOKBACK), - _humidityMeasurements(HUMIDITY_AVG_LOOKBACK), - _distanceMeasurements(DISTANCE_AVG_LOOKBACK), +DataController::DataController() : _temperatureMeasurements( + "temperature", + readTemperature, + TEMPERATURE_AVG_LOOKBACK, + TEMPERATURE_SIGNIFICANT_CHANGE, + PUBLISH_INTERVAL), + _humidityMeasurements( + "humidity", + readHumidity, + HUMIDITY_AVG_LOOKBACK, + HUMIDITY_SIGNIFICANT_CHANGE, + PUBLISH_INTERVAL), + _distanceMeasurements( + "distance", + readDistance, + DISTANCE_AVG_LOOKBACK, + DISTANCE_SIGNIFICANT_CHANGE, + PUBLISH_INTERVAL), _logger("DATA") { _ui = DoughUI::Instance(); @@ -100,7 +112,6 @@ void DataController::loop() if (isConfigured()) { _sample(); - _publish(); } } @@ -135,52 +146,18 @@ void DataController::_sample() _ui->suspend(); // Take a sample. - Measurement m; switch (_sampleType) { case SAMPLE_TEMPERATURE: - m = _sensors->readTemperature(); - _temperatureMeasurements.add(m); - if (_temperatureLastPublished.ok && m.ok && _temperatureLastPublished.value != m.value) - { - if (m.value == _temperatureMeasurements.getAverage().value || - abs(_temperatureLastPublished.value - m.value) > TEMPERATURE_SIGNIFICANT_CHANGE) { - _publishTemperature(); - } - } - else if (_temperatureLastPublished.ok == false && m.ok) { - _publishTemperature(); - } + _temperatureMeasurements.process(); _sampleType = SAMPLE_HUMIDITY; break; case SAMPLE_HUMIDITY: - m = _sensors->readHumidity(); - _humidityMeasurements.add(m); - if (_humidityLastPublished.ok && m.ok && _humidityLastPublished.value != m.value) - { - if (m.value == _humidityMeasurements.getAverage().value || - abs(_humidityLastPublished.value - m.value) > HUMIDITY_SIGNIFICANT_CHANGE) { - _publishHumidity(); - } - } - else if (_humidityLastPublished.ok == false && m.ok) { - _publishHumidity(); - } + _humidityMeasurements.process(); _sampleType = SAMPLE_DISTANCE; break; case SAMPLE_DISTANCE: - m = _sensors->readDistance(); - _distanceMeasurements.add(m); - if (_distanceLastPublished.ok && m.ok && _distanceLastPublished.value != m.value) - { - if (m.value == _distanceMeasurements.getAverage().value || - abs(_distanceLastPublished.value - m.value) > DISTANCE_SIGNIFICANT_CHANGE) { - _publishDistance(); - } - } - else if (_distanceLastPublished.ok == false && m.ok) { - _publishDistance(); - } + _distanceMeasurements.process(); break; } @@ -193,43 +170,4 @@ void DataController::_sample() _sampleType = SAMPLE_TEMPERATURE; } } -} - -void DataController::_publish() -{ - if (_lastPublish == 0 || millis() - _lastPublish > PUBLISH_INTERVAL) - { - _lastPublish = millis(); - _publishTemperature(); - _publishHumidity(); - _publishDistance(); - _ui->led1.dip()->fast(); - } -} - -void DataController::_publishTemperature() -{ - auto m = _temperatureMeasurements.getLast(); - _temperatureLastPublished.ok = m.ok; - _temperatureLastPublished.value = m.value; - _mqtt->publish("temperature", m); - _mqtt->publish("temperature/average", _temperatureMeasurements.getAverage()); -} - -void DataController::_publishHumidity() -{ - auto m = _humidityMeasurements.getLast(); - _humidityLastPublished.ok = m.ok; - _humidityLastPublished.value = m.value; - _mqtt->publish("humidity", _humidityMeasurements.getLast()); - _mqtt->publish("humidity/average", _humidityMeasurements.getAverage()); -} - -void DataController::_publishDistance() -{ - auto m = _distanceMeasurements.getLast(); - _distanceLastPublished.ok = m.ok; - _distanceLastPublished.value = m.value; - _mqtt->publish("distance", _distanceMeasurements.getLast()); - _mqtt->publish("distance/average", _distanceMeasurements.getAverage()); } \ No newline at end of file diff --git a/src/Data/DataController.h b/src/Data/DataController.h index ad78ec9..dac2e6f 100644 --- a/src/Data/DataController.h +++ b/src/Data/DataController.h @@ -14,7 +14,7 @@ // in the average computation. #define TEMPERATURE_AVG_LOOKBACK 6 // making this a 3 minute average #define HUMIDITY_AVG_LOOKBACK 6 // making this a 3 minute average -#define DISTANCE_AVG_LOOKBACK 28 * 2 * 5 // making this a 5 minute average +#define DISTANCE_AVG_LOOKBACK 28 * 2 * 3 // making this a 3 minute average // When significant changes occur in the sensor measurements, they are // published to MQTT. These definitions specify what is considered significant. @@ -22,10 +22,10 @@ #define HUMIDITY_SIGNIFICANT_CHANGE 2 // also to dampen flapping behavior. #define DISTANCE_SIGNIFICANT_CHANGE 3 // based on the sensor specification of 3mm resolution -// The minimal interval at which to forcibly publish measurements to the MQTT broker. -// When significant changes occur in the measurements, then these will be published -// to the MQTT broker at all times, independent from this interval. -#define PUBLISH_INTERVAL 4000 +// The minimal interval in seconds at which to forcibly publish measurements to the +// MQTT broker. When significant changes occur in the measurements, then these will +// be published to the MQTT broker at all times, independent from this interval. +#define PUBLISH_INTERVAL 300 #include #include "Data/Measurements.h" @@ -50,39 +50,31 @@ typedef enum class DataController { public: - static DataController* Instance(); + static DataController *Instance(); void setup(); void loop(); void clearHistory(); void setContainerHeight(int height); - bool isConfigured(); - static void handleMqttConnect(DoughMQTT* mqtt); + bool isConfigured(); + static void handleMqttConnect(DoughMQTT *mqtt); static void handleMqttMessage(String &key, String &value); private: DataController(); - static DataController* _instance; + static DataController *_instance; + DoughUI *_ui; + DoughMQTT *_mqtt; + DoughSensors *_sensors; Measurements _temperatureMeasurements; - Measurement _temperatureLastPublished; - void _publishTemperature(); Measurements _humidityMeasurements; - Measurement _humidityLastPublished; - void _publishHumidity(); Measurements _distanceMeasurements; - Measurement _distanceLastPublished; - void _publishDistance(); DoughLogger _logger; - DoughUI* _ui; - DoughSensors* _sensors; - DoughMQTT* _mqtt; unsigned long _lastSample = 0; - unsigned long _lastPublish = 0; DoughSampleType _sampleType = SAMPLE_TEMPERATURE; int _sampleCounter = 0; int _containerHeight; bool _containerHeightSet; void _sample(); - void _publish(); }; #endif diff --git a/src/Data/Measurement.cpp b/src/Data/Measurement.cpp index 3421b39..24a164b 100644 --- a/src/Data/Measurement.cpp +++ b/src/Data/Measurement.cpp @@ -14,4 +14,16 @@ Measurement Measurement::Value(int value) m.ok = true; m.value = value; return m; +} + +void Measurement::clear() +{ + ok = false; + value = 0; +} + +void Measurement::copyTo(Measurement* target) +{ + target->ok = ok; + target->value = value; } \ No newline at end of file diff --git a/src/Data/Measurement.h b/src/Data/Measurement.h index 0b163cf..b5c3df5 100644 --- a/src/Data/Measurement.h +++ b/src/Data/Measurement.h @@ -13,6 +13,8 @@ public: bool ok = false; static Measurement Failed(); static Measurement Value(int value); + void clear(); + void copyTo(Measurement *target); }; #endif diff --git a/src/Data/Measurements.cpp b/src/Data/Measurements.cpp index 4fe96f6..06d0afd 100644 --- a/src/Data/Measurements.cpp +++ b/src/Data/Measurements.cpp @@ -1,23 +1,112 @@ #include "Data/Measurements.h" #include "UI/DoughUI.h" -Measurements::Measurements(unsigned int avgLookback) +Measurements::Measurements( + const char *mqttKey, + Measurement (*measureFunc)(), + unsigned int storageSize, + unsigned int significantChange, + unsigned int minimumPublishTime) { - _storageSize = avgLookback; + _mqttKey = mqttKey; + _measureFunc = measureFunc; + _storageSize = storageSize; + _significantChange = significantChange; + _minimumPublishTime = minimumPublishTime; + _mqtt = DoughMQTT::Instance(); - _storage = new Measurement*[avgLookback]; - for (unsigned int i = 0; i < avgLookback; i++) { + // Format the key to use for publishing the average (i.e. "/average"). + auto lenAverageKey = strlen(mqttKey) + 8; // +8 for the "/average" suffix + _mqttAverageKey = new char[lenAverageKey + 1]; // +1 for the ending \0 + snprintf(_mqttAverageKey, lenAverageKey, "%s/average", _mqttKey); + + // Initialize the storage for holding the measurements. + _storage = new Measurement *[storageSize]; + for (unsigned int i = 0; i < storageSize; i++) + { _storage[i] = new Measurement; } clearHistory(); } -void Measurements::add(Measurement measurement) +void Measurements::process() { - unsigned int index = _next(); - _storage[index]->ok = measurement.ok; - _storage[index]->value = measurement.value; - + auto m = _measureFunc(); + _add(m); + if (_mustPublish()) + { + _publish(); + } +} + +bool Measurements::_mustPublish() +{ + Measurement lastMeasurement = getLast(); + + // When the measurement failed, then there's no need to publish it. + if (lastMeasurement.ok == false) + { + return false; + } + + // When no data was published before, then this is a great time to do so. + if (_lastPublished.ok == false) + { + return true; + } + + // If the value did not change, only publish when the minimum publishing + // time has passed. + if (_lastPublished.value == lastMeasurement.value) + { + auto now = millis(); + auto delta = now - _lastPublishedAt; + return _lastPublishedAt == 0 || delta >= (_minimumPublishTime * 1000); + } + + // When there is a significant change in the sensor value, then publish. + if (abs(_lastPublished.value - lastMeasurement.value) >= _significantChange) + { + return true; + } + + auto average = getAverage(); + + // When there is a significant change in the average value, then publish. + if (average.ok && abs(_lastPublishedAverage.value - average.value) >= _significantChange) + { + return true; + } + + // When the value changed less than the significant change, but it reached + // the current average value, then publish it, since we might have reached + // a stable value. + if (average.ok && average.value == lastMeasurement.value) + { + return true; + } + + // Well, we're out of options. No reason to publish the data right now. + return false; +} + +void Measurements::_publish() +{ + auto average = getAverage(); + auto last = getLast(); + + _mqtt->publish(_mqttKey, last); + _mqtt->publish(_mqttAverageKey, average); + + _lastPublishedAt = millis(); + average.copyTo(&_lastPublishedAverage); + last.copyTo(&_lastPublished); +} + +void Measurements::_add(Measurement measurement) +{ + measurement.copyTo(_storage[_next()]); + if (measurement.ok) { _averageCount++; @@ -28,17 +117,22 @@ void Measurements::add(Measurement measurement) unsigned int Measurements::_next() { _index++; + + // Wrap around at the end of the circular buffer. if (_index == _storageSize) { _index = 0; } + + // If the new position contains an ok value, update the running totals. if (_storage[_index]->ok) { _averageSum -= _storage[_index]->value; _averageCount--; } - _storage[_index]->ok = false; - _storage[_index]->value = 0; + + _storage[_index]->clear(); + return _index; } @@ -49,13 +143,9 @@ Measurement Measurements::getLast() Measurement Measurements::getAverage() { - Measurement result; - if (_averageCount > 0) - { - result.ok = true; - result.value = round(_averageSum / _averageCount); - } - return result; + return _averageCount > 0 + ? Measurement::Value(round(_averageSum / _averageCount)) + : Measurement::Failed(); } void Measurements::clearHistory() @@ -64,7 +154,6 @@ void Measurements::clearHistory() _averageSum = 0; for (unsigned int i = 0; i < _storageSize; i++) { - _storage[i]->ok = false; - _storage[i]->value = 0; + _storage[i]->clear(); } } diff --git a/src/Data/Measurements.h b/src/Data/Measurements.h index 95e40b6..e4256ff 100644 --- a/src/Data/Measurements.h +++ b/src/Data/Measurements.h @@ -3,26 +3,61 @@ #include #include "Data/Measurement.h" +#include "Network/DoughMQTT.h" /** * This class is used to store measurements for a sensor and to keep * track of running totals for handling average computations. + * It also provides functionality to decide when to publish measurements + * to MQTT (after significant changes occur or when the last publish + * was too long ago). */ class Measurements { public: - Measurements(unsigned int avgLookback); - void add(Measurement measurement); + /** + * Create a new Measurements object. + * + * @param measureFunc + * Function that reads a sensor and returns a Measurement object. + * @param storageSize + * Number of measurements to keep track of for computing an average. + * @param significantChange + * Number that describes how much a measurement value needs to change, + * before it is considered significant and must be published to MQTT. + * @param minimumPublishTime + * The number of seconds after which to forcibly publish measurements + * to MQTT, even when no significant changes to measurements were seen. + */ + Measurements( + const char *mqttKey, + Measurement (*measureFunc)(), + unsigned int storageSize, + unsigned int significantChange, + unsigned int minimumPublishTime); + void process(); Measurement getLast(); Measurement getAverage(); void clearHistory(); private: - Measurement** _storage; + DoughMQTT *_mqtt; + const char *_mqttKey; + char *_mqttAverageKey; + Measurement (*_measureFunc)(); + Measurement **_storage; unsigned int _storageSize; + unsigned int _significantChange; + unsigned int _minimumPublishTime; int _averageSum = 0; unsigned int _averageCount = 0; unsigned int _index = 0; + unsigned long _lastPublishedAt = 0; + Measurement _lastPublished; + Measurement _lastPublishedAverage; + bool _mustPublish(); + void _publish(); + void _add(Measurement measurement); unsigned int _next(); }; diff --git a/src/Network/DoughMQTT.cpp b/src/Network/DoughMQTT.cpp index 0038ff9..ec425e1 100644 --- a/src/Network/DoughMQTT.cpp +++ b/src/Network/DoughMQTT.cpp @@ -4,12 +4,9 @@ // Constructor // ---------------------------------------------------------------------- -DoughMQTT* DoughMQTT::_instance = nullptr; +DoughMQTT *DoughMQTT::_instance = nullptr; -/** - * Fetch the DoughMQTT singleton. - */ -DoughMQTT* DoughMQTT::Instance() +DoughMQTT *DoughMQTT::Instance() { if (DoughMQTT::_instance == nullptr) { @@ -18,7 +15,7 @@ DoughMQTT* DoughMQTT::Instance() return DoughMQTT::_instance; } -DoughMQTT::DoughMQTT() : _logger("MQTT") { } +DoughMQTT::DoughMQTT() : _logger("MQTT") {} // ---------------------------------------------------------------------- // Setup @@ -26,7 +23,7 @@ DoughMQTT::DoughMQTT() : _logger("MQTT") { } void DoughMQTT::setup() { - DoughWiFi* network = DoughWiFi::Instance(); + DoughWiFi *network = DoughWiFi::Instance(); #ifdef MQTT_DEVICE_ID _mqttDeviceId = MQTT_DEVICE_ID; @@ -88,7 +85,7 @@ void DoughMQTT::handleMessage(String &topic, String &payload) { DoughMQTT::Instance()->_logger.log("sSsS", "<<< ", topic, " = ", payload); - DoughMQTT* mqtt = DoughMQTT::Instance(); + DoughMQTT *mqtt = DoughMQTT::Instance(); if (mqtt->_onMessage != nullptr) { int pos = topic.lastIndexOf('/'); @@ -100,7 +97,7 @@ void DoughMQTT::handleMessage(String &topic, String &payload) } } -void DoughMQTT::subscribe(const char* key) +void DoughMQTT::subscribe(const char *key) { char topic[200]; snprintf(topic, sizeof(topic) / sizeof(topic[0]), "%s/%s/%s", MQTT_TOPIC_PREFIX, _mqttDeviceId, key); @@ -108,7 +105,7 @@ void DoughMQTT::subscribe(const char* key) _mqttClient.subscribe(topic); } -void DoughMQTT::publish(const char* key, const char* payload) +void DoughMQTT::publish(const char *key, const char *payload) { char topic[200]; snprintf(topic, sizeof(topic) / sizeof(topic[0]), "%s/%s/%s", MQTT_TOPIC_PREFIX, _mqttDeviceId, key); @@ -123,10 +120,14 @@ void DoughMQTT::publish(const char *key, int payload) publish(key, buf); } -void DoughMQTT::publish(const char *key, Measurement measurement) { - if (measurement.ok) { +void DoughMQTT::publish(const char *key, Measurement measurement) +{ + if (measurement.ok) + { publish(key, measurement.value); - } else { + } + else + { publish(key, "null"); } } \ No newline at end of file diff --git a/src/Network/DoughMQTT.h b/src/Network/DoughMQTT.h index 880de25..0d12edc 100644 --- a/src/Network/DoughMQTT.h +++ b/src/Network/DoughMQTT.h @@ -14,33 +14,33 @@ */ class DoughMQTT; -typedef void (*DoughMQTTConnectHandler)(DoughMQTT* mqtt); +typedef void (*DoughMQTTConnectHandler)(DoughMQTT *mqtt); typedef void (*DoughMQTTMessageHandler)(String &key, String &value); class DoughMQTT { public: - static DoughMQTT* Instance(); + static DoughMQTT *Instance(); void setup(); void onConnect(DoughMQTTConnectHandler callback); void onMessage(DoughMQTTMessageHandler callback); bool isConnected(); bool connect(); - void subscribe(const char* key); + void subscribe(const char *key); void procesIncomingsMessages(); - void publish(const char* key, const char* payload); - void publish(const char* key, int payload); - void publish(const char* key, Measurement measurement); + void publish(const char *key, const char *payload); + void publish(const char *key, int payload); + void publish(const char *key, Measurement measurement); private: DoughMQTT(); - static DoughMQTT* _instance; + static DoughMQTT *_instance; MQTTClient _mqttClient; DoughLogger _logger; DoughMQTTConnectHandler _onConnect = nullptr; MQTTClientCallbackSimple _onMessage = nullptr; static void handleMessage(String &topic, String &payload); - char* _mqttDeviceId; + char *_mqttDeviceId; }; #endif diff --git a/src/Network/DoughWiFi.cpp b/src/Network/DoughWiFi.cpp index c87364c..d6b6a82 100644 --- a/src/Network/DoughWiFi.cpp +++ b/src/Network/DoughWiFi.cpp @@ -6,9 +6,6 @@ DoughWiFi *DoughWiFi::_instance = nullptr; -/** - * Fetch the DoughWiFi singleton. - */ DoughWiFi *DoughWiFi::Instance() { if (DoughWiFi::_instance == nullptr) diff --git a/src/Network/DoughWiFi.h b/src/Network/DoughWiFi.h index e7502e6..2888a0f 100644 --- a/src/Network/DoughWiFi.h +++ b/src/Network/DoughWiFi.h @@ -11,8 +11,8 @@ class DoughWiFi { public: - static DoughWiFi* Instance(); - char* getMacAddress(); + static DoughWiFi *Instance(); + char *getMacAddress(); void setup(); void loop(); bool isConnected(); @@ -21,7 +21,7 @@ public: private: DoughWiFi(); - static DoughWiFi* _instance; + static DoughWiFi *_instance; void _setMacAddress(); char _macAddress[18]; // max MAC address length + 1 DoughLogger _logger; diff --git a/src/Sensors/DoughSensors.cpp b/src/Sensors/DoughSensors.cpp index aed2f8b..e82e09e 100644 --- a/src/Sensors/DoughSensors.cpp +++ b/src/Sensors/DoughSensors.cpp @@ -1,31 +1,32 @@ #include "DoughSensors.h" - + // ---------------------------------------------------------------------- // Constructor // ---------------------------------------------------------------------- -DoughSensors* DoughSensors::_instance = nullptr; +DoughSensors *DoughSensors::_instance = nullptr; -/** - * Fetch the DoughSensors singleton. - */ -DoughSensors* DoughSensors::Instance() { - if (DoughSensors::_instance == nullptr) { +DoughSensors *DoughSensors::Instance() +{ + if (DoughSensors::_instance == nullptr) + { DoughSensors::_instance = new DoughSensors(); } return DoughSensors::_instance; } -DoughSensors::DoughSensors() : _logger("SENSORS") { +DoughSensors::DoughSensors() : _logger("SENSORS") +{ _dht = new DHT(DHT11_DATA_PIN, DHT11); _hcsr04 = new HCSR04(HCSR04_TRIG_PIN, HCSR04_ECHO_PIN); } // ---------------------------------------------------------------------- -// setup +// setup // ---------------------------------------------------------------------- -void DoughSensors::setup() { +void DoughSensors::setup() +{ _dht->begin(); _hcsr04->begin(); } @@ -34,12 +35,16 @@ void DoughSensors::setup() { // loop // ---------------------------------------------------------------------- -Measurement DoughSensors::readTemperature() { +Measurement DoughSensors::readTemperature() +{ float t = _dht->readTemperature(); - if (isnan(t)) { + if (isnan(t)) + { _logger.log("s", "ERROR - Temperature measurement failed"); return Measurement::Failed(); - } else { + } + else + { _logger.log("sis", "Temperature = ", int(t), "°C "); _hcsr04->setTemperature(int(t)); auto m = Measurement::Value(int(t)); @@ -47,25 +52,52 @@ Measurement DoughSensors::readTemperature() { } } -Measurement DoughSensors::readHumidity() { +Measurement DoughSensors::readHumidity() +{ int h = _dht->readHumidity(); - if (h == 0) { + if (h == 0) + { _logger.log("s", "ERROR - Humidity measurement failed"); return Measurement::Failed(); - } else { + } + else + { _logger.log("sis", "Humidity = ", h, "%"); _hcsr04->setHumidity(h); return Measurement::Value(h); } } -Measurement DoughSensors::readDistance() { +Measurement DoughSensors::readDistance() +{ int d = _hcsr04->readDistance(); - if (d == -1) { - _logger.log("s", "ERROR - Distance measurement failed"); + if (d == -1) + { + _logger.log("s", "ERROR - Distance measurement failed"); return Measurement::Failed(); - } else { - _logger.log("sis", "Distance = ", d, "mm"); - return Measurement::Value(d); - } + } + else + { + _logger.log("sis", "Distance = ", d, "mm"); + return Measurement::Value(d); + } } + +// ---------------------------------------------------------------------- +// Function access to the sensor reading. +// ---------------------------------------------------------------------- + +Measurement readTemperature() +{ + return DoughSensors::Instance()->readTemperature(); +} + +Measurement readHumidity() +{ + return DoughSensors::Instance()->readHumidity(); +} + +Measurement readDistance() +{ + return DoughSensors::Instance()->readDistance(); +} \ No newline at end of file diff --git a/src/Sensors/DoughSensors.h b/src/Sensors/DoughSensors.h index 6fd8eb7..24639bf 100644 --- a/src/Sensors/DoughSensors.h +++ b/src/Sensors/DoughSensors.h @@ -1,29 +1,34 @@ -#ifndef DOUGH_SENSORS_H +#ifndef DOUGH_SENSORS_H #define DOUGH_SENSORS_H #include #include "Sensors/HCSR04.h" #include "UI/DoughLogger.h" #include "Data/Measurement.h" -#include "config.h" +#include "config.h" /** * This class provides access to the sensors in the device. */ -class DoughSensors { - public: - static DoughSensors* Instance(); - void setup(); - Measurement readTemperature(); - Measurement readHumidity(); - Measurement readDistance(); +class DoughSensors +{ +public: + static DoughSensors *Instance(); + void setup(); + Measurement readTemperature(); + Measurement readHumidity(); + Measurement readDistance(); - private: - DoughSensors(); - static DoughSensors* _instance; - DoughLogger _logger; - DHT* _dht; - HCSR04* _hcsr04; +private: + DoughSensors(); + static DoughSensors *_instance; + DoughLogger _logger; + DHT *_dht; + HCSR04 *_hcsr04; }; -#endif +Measurement readTemperature(); +Measurement readHumidity(); +Measurement readDistance(); + +#endif diff --git a/src/Sensors/HCSR04.cpp b/src/Sensors/HCSR04.cpp index fe32991..0930464 100644 --- a/src/Sensors/HCSR04.cpp +++ b/src/Sensors/HCSR04.cpp @@ -1,22 +1,26 @@ #include "Sensors/HCSR04.h" -HCSR04::HCSR04(int triggerPin, int echoPin) { +HCSR04::HCSR04(int triggerPin, int echoPin) +{ _triggerPin = triggerPin; _echoPin = echoPin; _temperature = HCSR04_INIT_TEMPERATURE; _humidity = HCSR04_INIT_HUMIDITY; } -void HCSR04::begin() { +void HCSR04::begin() +{ pinMode(_triggerPin, OUTPUT); - pinMode(_echoPin, INPUT); + pinMode(_echoPin, INPUT); } -void HCSR04::setTemperature(int temperature) { +void HCSR04::setTemperature(int temperature) +{ _temperature = temperature; } -void HCSR04::setHumidity(int humidity) { +void HCSR04::setHumidity(int humidity) +{ _humidity = humidity; } @@ -25,11 +29,13 @@ void HCSR04::setHumidity(int humidity) { * When reading the distance fails, -1 is returned. * Otherwise the distance in mm. */ -int HCSR04::readDistance() { +int HCSR04::readDistance() +{ _setSpeedOfSound(); _setEchoTimeout(); _takeSamples(); - if (_haveEnoughSamples()) { + if (_haveEnoughSamples()) + { _sortSamples(); return _computeAverage(); } @@ -41,68 +47,83 @@ int HCSR04::readDistance() { * and relative humidity. I derived this formula from a YouTube * video about the HC-SR04: https://youtu.be/6F1B_N6LuKw?t=1548 */ -void HCSR04::_setSpeedOfSound() { +void HCSR04::_setSpeedOfSound() +{ _speedOfSound = 0.3314 + (0.000606 * _temperature) + - (0.0000124 * _humidity); + (0.0000124 * _humidity); } -void HCSR04::_setEchoTimeout() { +void HCSR04::_setEchoTimeout() +{ _echoTimeout = HCSR04_MAX_MM * 2 / _speedOfSound; } -void HCSR04::_takeSamples() { +void HCSR04::_takeSamples() +{ _successfulSamples = 0; - for (int i = 0; i 0) { + if (i > 0) + { delay(HCSR04_SAMPLE_WAIT + random(HCSR04_SAMPLE_WAIT_SPREAD)); } int distance = _takeSample(); - if (distance != -1) { + if (distance != -1) + { _samples[i] = distance; _successfulSamples++; } } } -bool HCSR04::_haveEnoughSamples() { +bool HCSR04::_haveEnoughSamples() +{ return _successfulSamples >= HCSR04_SAMPLES_USE; } -int HCSR04::_takeSample() { +int HCSR04::_takeSample() +{ // Send 10μs trigger to ask sensor for a measurement. digitalWrite(HCSR04_TRIG_PIN, LOW); delayMicroseconds(2); digitalWrite(HCSR04_TRIG_PIN, HIGH); delayMicroseconds(10); digitalWrite(HCSR04_TRIG_PIN, LOW); - + // Measure the length of echo signal. unsigned long durationMicroSec = pulseIn(HCSR04_ECHO_PIN, HIGH, _echoTimeout); // Compute the distance, based on the echo signal length. double distance = durationMicroSec / 2.0 * _speedOfSound; - if (distance < HCSR04_MIN_MM || distance >= HCSR04_MAX_MM) { + if (distance < HCSR04_MIN_MM || distance >= HCSR04_MAX_MM) + { return -1; - } else { + } + else + { return distance; } } -void HCSR04::_sortSamples() { +void HCSR04::_sortSamples() +{ int holder, x, y; - for(x = 0; x < _successfulSamples; x++) { - for(y = 0; y < _successfulSamples-1; y++) { - if(_samples[y] > _samples[y+1]) { - holder = _samples[y+1]; - _samples[y+1] = _samples[y]; - _samples[y] = holder; - } - } + for (x = 0; x < _successfulSamples; x++) + { + for (y = 0; y < _successfulSamples - 1; y++) + { + if (_samples[y] > _samples[y + 1]) + { + holder = _samples[y + 1]; + _samples[y + 1] = _samples[y]; + _samples[y] = holder; + } + } } } @@ -112,11 +133,13 @@ void HCSR04::_sortSamples() { * When not enough samples were collected in the previous steps, then * NAN is returned. */ -int HCSR04::_computeAverage() { +int HCSR04::_computeAverage() +{ float sum = 0; int offset = (_successfulSamples - HCSR04_SAMPLES_USE) / 2; - for (int i = 0; i