Another round of code cleanup.

This commit is contained in:
Maurice Makaay 2020-07-12 01:35:07 +02:00
parent f1b941d964
commit 9db52bad08
21 changed files with 407 additions and 179 deletions

View File

@ -17,26 +17,25 @@ DataController *DataController::Instance()
DataController::DataController() : _temperatureMeasurements(
"temperature",
readTemperature,
TemperatureSensor::Instance(),
TEMPERATURE_AVG_LOOKBACK,
TEMPERATURE_SIGNIFICANT_CHANGE,
PUBLISH_INTERVAL),
_humidityMeasurements(
"humidity",
readHumidity,
HumiditySensor::Instance(),
HUMIDITY_AVG_LOOKBACK,
HUMIDITY_SIGNIFICANT_CHANGE,
PUBLISH_INTERVAL),
_distanceMeasurements(
"distance",
readDistance,
DistanceSensor::Instance(),
DISTANCE_AVG_LOOKBACK,
DISTANCE_SIGNIFICANT_CHANGE,
PUBLISH_INTERVAL),
_logger("DATA")
{
_ui = DoughUI::Instance();
_sensors = DoughSensors::Instance();
_mqtt = DoughMQTT::Instance();
}
@ -52,6 +51,10 @@ void DataController::setup()
DoughMQTT *mqtt = DoughMQTT::Instance();
mqtt->onConnect(DataController::handleMqttConnect);
mqtt->onMessage(DataController::handleMqttMessage);
_temperatureMeasurements.setup();
_humidityMeasurements.setup();
_distanceMeasurements.setup();
}
void DataController::handleMqttConnect(DoughMQTT *mqtt)

View File

@ -29,7 +29,9 @@
#include <Arduino.h>
#include "Data/Measurements.h"
#include "Sensors/DoughSensors.h"
#include "Sensors/TemperatureSensor.h"
#include "Sensors/HumiditySensor.h"
#include "Sensors/DistanceSensor.h"
#include "Network/DoughWiFi.h"
#include "Network/DoughMQTT.h"
#include "UI/DoughUI.h"
@ -64,7 +66,6 @@ private:
static DataController *_instance;
DoughUI *_ui;
DoughMQTT *_mqtt;
DoughSensors *_sensors;
Measurements _temperatureMeasurements;
Measurements _humidityMeasurements;
Measurements _distanceMeasurements;

View File

@ -3,26 +3,29 @@
Measurements::Measurements(
const char *mqttKey,
Measurement (*measureFunc)(),
SensorBase *sensor,
unsigned int storageSize,
unsigned int significantChange,
unsigned int minimumPublishTime)
{
_mqttKey = mqttKey;
_measureFunc = measureFunc;
_sensor = sensor;
_storageSize = storageSize;
_significantChange = significantChange;
_minimumPublishTime = minimumPublishTime;
_mqtt = DoughMQTT::Instance();
}
void Measurements::setup()
{
// Format the key to use for publishing the average (i.e. "<mqttKey>/average").
auto lenAverageKey = strlen(mqttKey) + 8; // +8 for the "/average" suffix
_mqttAverageKey = new char[lenAverageKey + 1]; // +1 for the ending \0
auto lenAverageKey = strlen(_mqttKey) + 9; // +9 for the "/average\0" suffix
_mqttAverageKey = new char[lenAverageKey];
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 = new Measurement *[_storageSize];
for (unsigned int i = 0; i < _storageSize; i++)
{
_storage[i] = new Measurement;
}
@ -31,8 +34,8 @@ Measurements::Measurements(
void Measurements::process()
{
auto m = _measureFunc();
_add(m);
auto m = _sensor->read();
_store(m);
if (_mustPublish())
{
_publish();
@ -103,7 +106,7 @@ void Measurements::_publish()
last.copyTo(&_lastPublished);
}
void Measurements::_add(Measurement measurement)
void Measurements::_store(Measurement measurement)
{
measurement.copyTo(_storage[_next()]);

View File

@ -2,6 +2,7 @@
#define DOUGH_DATA_MEASUREMENTS_H
#include <Arduino.h>
#include "Sensors/SensorBase.h"
#include "Data/Measurement.h"
#include "Network/DoughMQTT.h"
@ -18,8 +19,8 @@ public:
/**
* Create a new Measurements object.
*
* @param measureFunc
* Function that reads a sensor and returns a Measurement object.
* @param sensor
* The sensor to read, implements SensorBase.
* @param storageSize
* Number of measurements to keep track of for computing an average.
* @param significantChange
@ -31,10 +32,11 @@ public:
*/
Measurements(
const char *mqttKey,
Measurement (*measureFunc)(),
SensorBase *sensor,
unsigned int storageSize,
unsigned int significantChange,
unsigned int minimumPublishTime);
void setup();
void process();
Measurement getLast();
Measurement getAverage();
@ -44,7 +46,7 @@ private:
DoughMQTT *_mqtt;
const char *_mqttKey;
char *_mqttAverageKey;
Measurement (*_measureFunc)();
SensorBase *_sensor;
Measurement **_storage;
unsigned int _storageSize;
unsigned int _significantChange;
@ -57,7 +59,7 @@ private:
Measurement _lastPublishedAverage;
bool _mustPublish();
void _publish();
void _add(Measurement measurement);
void _store(Measurement measurement);
unsigned int _next();
};

View File

@ -0,0 +1,59 @@
#include "DistanceSensor.h"
// ----------------------------------------------------------------------
// Constructor
// ----------------------------------------------------------------------
DistanceSensor *DistanceSensor::_instance = nullptr;
DistanceSensor *DistanceSensor::Instance()
{
if (DistanceSensor::_instance == nullptr)
{
DistanceSensor::_instance = new DistanceSensor();
}
return DistanceSensor::_instance;
}
DistanceSensor::DistanceSensor() : _logger("DISTANCE")
{
_hcsr04 = new SensorHCSR04(HCSR04_TRIG_PIN, HCSR04_ECHO_PIN);
}
// ----------------------------------------------------------------------
// setup
// ----------------------------------------------------------------------
void DistanceSensor::setup()
{
_hcsr04->setup();
}
void DistanceSensor::setTemperature(int temperature)
{
_hcsr04->setTemperature(temperature);
}
void DistanceSensor::setHumidity(int humidity)
{
_hcsr04->setHumidity(humidity);
}
// ----------------------------------------------------------------------
// loop
// ----------------------------------------------------------------------
Measurement DistanceSensor::read()
{
int d = _hcsr04->readDistance();
if (d == -1)
{
_logger.log("s", "ERROR - Distance measurement failed");
return Measurement::Failed();
}
else
{
_logger.log("sis", "Distance = ", d, "mm");
return Measurement::Value(d);
}
}

View File

@ -0,0 +1,29 @@
#ifndef DOUGH_SENSORS_DISTANCE_H
#define DOUGH_SENSORS_DISTANCE_H
#include "Sensors/SensorBase.h"
#include "Sensors/LowLevel/SensorHCSR04.h"
#include "UI/DoughLogger.h"
#include "Data/Measurement.h"
#include "config.h"
/**
* This class provides access to the distance sensor in the device.
*/
class DistanceSensor : public SensorBase
{
public:
static DistanceSensor *Instance();
void setup();
void setTemperature(int temperature);
void setHumidity(int humidity);
Measurement read();
private:
DistanceSensor();
static DistanceSensor *_instance;
DoughLogger _logger;
SensorHCSR04 *_hcsr04;
};
#endif

View File

@ -1,103 +0,0 @@
#include "DoughSensors.h"
// ----------------------------------------------------------------------
// Constructor
// ----------------------------------------------------------------------
DoughSensors *DoughSensors::_instance = nullptr;
DoughSensors *DoughSensors::Instance()
{
if (DoughSensors::_instance == nullptr)
{
DoughSensors::_instance = new DoughSensors();
}
return DoughSensors::_instance;
}
DoughSensors::DoughSensors() : _logger("SENSORS")
{
_dht = new DHT(DHT11_DATA_PIN, DHT11);
_hcsr04 = new HCSR04(HCSR04_TRIG_PIN, HCSR04_ECHO_PIN);
}
// ----------------------------------------------------------------------
// setup
// ----------------------------------------------------------------------
void DoughSensors::setup()
{
_dht->begin();
_hcsr04->begin();
}
// ----------------------------------------------------------------------
// loop
// ----------------------------------------------------------------------
Measurement DoughSensors::readTemperature()
{
float t = _dht->readTemperature();
if (isnan(t))
{
_logger.log("s", "ERROR - Temperature measurement failed");
return Measurement::Failed();
}
else
{
_logger.log("sis", "Temperature = ", int(t), "°C ");
_hcsr04->setTemperature(int(t));
auto m = Measurement::Value(int(t));
return m;
}
}
Measurement DoughSensors::readHumidity()
{
int h = _dht->readHumidity();
if (h == 0)
{
_logger.log("s", "ERROR - Humidity measurement failed");
return Measurement::Failed();
}
else
{
_logger.log("sis", "Humidity = ", h, "%");
_hcsr04->setHumidity(h);
return Measurement::Value(h);
}
}
Measurement DoughSensors::readDistance()
{
int d = _hcsr04->readDistance();
if (d == -1)
{
_logger.log("s", "ERROR - Distance measurement failed");
return Measurement::Failed();
}
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();
}

View File

@ -1,34 +0,0 @@
#ifndef DOUGH_SENSORS_H
#define DOUGH_SENSORS_H
#include <DHT.h>
#include "Sensors/HCSR04.h"
#include "UI/DoughLogger.h"
#include "Data/Measurement.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();
private:
DoughSensors();
static DoughSensors *_instance;
DoughLogger _logger;
DHT *_dht;
HCSR04 *_hcsr04;
};
Measurement readTemperature();
Measurement readHumidity();
Measurement readDistance();
#endif

View File

@ -0,0 +1,47 @@
#include "HumiditySensor.h"
// ----------------------------------------------------------------------
// Constructor
// ----------------------------------------------------------------------
HumiditySensor *HumiditySensor::_instance = nullptr;
HumiditySensor *HumiditySensor::Instance()
{
if (HumiditySensor::_instance == nullptr)
{
HumiditySensor::_instance = new HumiditySensor();
}
return HumiditySensor::_instance;
}
HumiditySensor::HumiditySensor() : _logger("HUMIDITY") {}
// ----------------------------------------------------------------------
// setup
// ----------------------------------------------------------------------
void HumiditySensor::setup()
{
SensorDHT11::Instance()->begin();
}
// ----------------------------------------------------------------------
// loop
// ----------------------------------------------------------------------
Measurement HumiditySensor::read()
{
float t = SensorDHT11::Instance()->readHumidity();
if (t == -1)
{
_logger.log("s", "ERROR - Humidity measurement failed");
return Measurement::Failed();
}
else
{
_logger.log("sis", "Humidity = ", int(t), "%");
DistanceSensor::Instance()->setHumidity(int(t));
return Measurement::Value(int(t));
}
}

View File

@ -0,0 +1,27 @@
#ifndef DOUGH_SENSORS_HUMIDITY_H
#define DOUGH_SENSORS_HUMIDITY_H
#include "Sensors/SensorBase.h"
#include "Sensors/LowLevel/SensorDHT11.h"
#include "UI/DoughLogger.h"
#include "Data/Measurement.h"
#include "Sensors/DistanceSensor.h"
#include "config.h"
/**
* This class provides access to the humidity sensor in the device.
*/
class HumiditySensor : public SensorBase
{
public:
static HumiditySensor *Instance();
void setup();
Measurement read();
private:
HumiditySensor();
static HumiditySensor *_instance;
DoughLogger _logger;
};
#endif

View File

@ -0,0 +1,44 @@
#include "Sensors/LowLevel/SensorDHT11.h"
// ----------------------------------------------------------------------
// Constructor
// ----------------------------------------------------------------------
SensorDHT11 *SensorDHT11::_instance = nullptr;
SensorDHT11 *SensorDHT11::Instance()
{
if (SensorDHT11::_instance == nullptr)
{
SensorDHT11::_instance = new SensorDHT11();
}
return SensorDHT11::_instance;
}
SensorDHT11::SensorDHT11()
{
_dht = new DHT(DHT11_DATA_PIN, DHT11);
}
// ----------------------------------------------------------------------
// setup
// ----------------------------------------------------------------------
void SensorDHT11::begin()
{
_dht->begin();
}
// ----------------------------------------------------------------------
// loop
// ----------------------------------------------------------------------
float SensorDHT11::readHumidity()
{
return _dht->readHumidity();
}
float SensorDHT11::readTemperature()
{
return _dht->readTemperature();
}

View File

@ -0,0 +1,24 @@
#ifndef DOUGH_SENSORS_DHT11_H
#define DOUGH_SENSORS_DHT11_H
#include <DHT.h>
#include "config.h"
/**
* This class provides access to the DHT11 sensor in the device.
*/
class SensorDHT11
{
public:
static SensorDHT11 *Instance();
void begin();
float readTemperature();
float readHumidity();
private:
SensorDHT11();
static SensorDHT11 *_instance;
DHT *_dht;
};
#endif

View File

@ -1,26 +1,32 @@
#include "Sensors/HCSR04.h"
#include "Sensors/LowLevel/SensorHCSR04.h"
HCSR04::HCSR04(int triggerPin, int echoPin)
SensorHCSR04::SensorHCSR04(int triggerPin, int echoPin) : _logger("HCSR04")
{
_triggerPin = triggerPin;
_echoPin = echoPin;
_temperature = HCSR04_INIT_TEMPERATURE;
_humidity = HCSR04_INIT_HUMIDITY;
#ifndef HCSR04_DEBUG
_logger.suspend();
#endif
}
void HCSR04::begin()
void SensorHCSR04::setup()
{
_logger.log("sisi", "Setup output pin ", _triggerPin, " and input pin ", _echoPin);
pinMode(_triggerPin, OUTPUT);
pinMode(_echoPin, INPUT);
}
void HCSR04::setTemperature(int temperature)
void SensorHCSR04::setTemperature(int temperature)
{
_logger.log("sis", "Set temperature to ", temperature, "°C");
_temperature = temperature;
}
void HCSR04::setHumidity(int humidity)
void SensorHCSR04::setHumidity(int humidity)
{
_logger.log("sis", "Set humidity to ", humidity, "%");
_humidity = humidity;
}
@ -29,7 +35,7 @@ void HCSR04::setHumidity(int humidity)
* When reading the distance fails, -1 is returned.
* Otherwise the distance in mm.
*/
int HCSR04::readDistance()
int SensorHCSR04::readDistance()
{
_setSpeedOfSound();
_setEchoTimeout();
@ -47,20 +53,22 @@ 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 SensorHCSR04::_setSpeedOfSound()
{
_speedOfSound =
0.3314 +
(0.000606 * _temperature) +
(0.0000124 * _humidity);
_logger.log("sfs", "Speed of sound = ", _speedOfSound, "mm/Ms");
}
void HCSR04::_setEchoTimeout()
void SensorHCSR04::_setEchoTimeout()
{
_echoTimeout = HCSR04_MAX_MM * 2 / _speedOfSound;
_logger.log("sfs", "Echo timeout = ", _echoTimeout, "Ms");
}
void HCSR04::_takeSamples()
void SensorHCSR04::_takeSamples()
{
_successfulSamples = 0;
for (int i = 0; i < HCSR04_SAMPLES_TAKE; i++)
@ -81,12 +89,12 @@ void HCSR04::_takeSamples()
}
}
bool HCSR04::_haveEnoughSamples()
bool SensorHCSR04::_haveEnoughSamples()
{
return _successfulSamples >= HCSR04_SAMPLES_USE;
}
int HCSR04::_takeSample()
int SensorHCSR04::_takeSample()
{
// Send 10μs trigger to ask sensor for a measurement.
digitalWrite(HCSR04_TRIG_PIN, LOW);
@ -100,6 +108,7 @@ int HCSR04::_takeSample()
// Compute the distance, based on the echo signal length.
double distance = durationMicroSec / 2.0 * _speedOfSound;
_logger.log("sfs", "Sample result = ", distance, "mm");
if (distance < HCSR04_MIN_MM || distance >= HCSR04_MAX_MM)
{
return -1;
@ -110,7 +119,7 @@ int HCSR04::_takeSample()
}
}
void HCSR04::_sortSamples()
void SensorHCSR04::_sortSamples()
{
int holder, x, y;
for (x = 0; x < _successfulSamples; x++)
@ -133,7 +142,7 @@ void HCSR04::_sortSamples()
* When not enough samples were collected in the previous steps, then
* NAN is returned.
*/
int HCSR04::_computeAverage()
int SensorHCSR04::_computeAverage()
{
float sum = 0;
int offset = (_successfulSamples - HCSR04_SAMPLES_USE) / 2;

View File

@ -25,22 +25,27 @@
#define HCSR04_INIT_TEMPERATURE 19.000
#define HCSR04_INIT_HUMIDITY 50.000
// Define this one to enable HCSR04 debug logging.
#undef HCSR04_DEBUG
#include <Arduino.h>
#include "UI/DoughLogger.h"
#include "config.h"
/**
* This class is used to get a distance reading from an HCSR04 sensor.
*/
class HCSR04
class SensorHCSR04
{
public:
HCSR04(int triggerPin, int echoPin);
void begin();
SensorHCSR04(int triggerPin, int echoPin);
void setup();
void setTemperature(int temperature);
void setHumidity(int humidity);
int readDistance();
private:
DoughLogger _logger;
int _triggerPin;
int _echoPin;
int _humidity;

16
src/Sensors/SensorBase.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef DOUGH_SENSORS_BASE_H
#define DOUGH_SENSORS_BASE_H
#include "Data/Measurement.h"
/**
* This interface is implemented by all sensors.
*/
class SensorBase
{
public:
virtual void setup();
virtual Measurement read();
};
#endif

View File

@ -0,0 +1,47 @@
#include "TemperatureSensor.h"
// ----------------------------------------------------------------------
// Constructor
// ----------------------------------------------------------------------
TemperatureSensor *TemperatureSensor::_instance = nullptr;
TemperatureSensor *TemperatureSensor::Instance()
{
if (TemperatureSensor::_instance == nullptr)
{
TemperatureSensor::_instance = new TemperatureSensor();
}
return TemperatureSensor::_instance;
}
TemperatureSensor::TemperatureSensor() : _logger("TEMPERATURE") {}
// ----------------------------------------------------------------------
// setup
// ----------------------------------------------------------------------
void TemperatureSensor::setup()
{
SensorDHT11::Instance()->begin();
}
// ----------------------------------------------------------------------
// loop
// ----------------------------------------------------------------------
Measurement TemperatureSensor::read()
{
float t = SensorDHT11::Instance()->readTemperature();
if (isnan(t))
{
_logger.log("s", "ERROR - Temperature measurement failed");
return Measurement::Failed();
}
else
{
_logger.log("sis", "Temperature = ", int(t), "°C");
DistanceSensor::Instance()->setTemperature(int(t));
return Measurement::Value(int(t));
}
}

View File

@ -0,0 +1,27 @@
#ifndef DOUGH_SENSORS_TEMPERATURE_H
#define DOUGH_SENSORS_TEMPERATURE_H
#include "Sensors/SensorBase.h"
#include "Sensors/LowLevel/SensorDHT11.h"
#include "UI/DoughLogger.h"
#include "Data/Measurement.h"
#include "Sensors/DistanceSensor.h"
#include "config.h"
/**
* This class provides access to the temperature sensor in the device.
*/
class TemperatureSensor : public SensorBase
{
public:
static TemperatureSensor *Instance();
void setup();
Measurement read();
private:
TemperatureSensor();
static TemperatureSensor *_instance;
DoughLogger _logger;
};
#endif

View File

@ -5,8 +5,23 @@ DoughLogger::DoughLogger(const char *section)
_section = section;
}
void DoughLogger::suspend()
{
_suspended = true;
}
void DoughLogger::resume()
{
_suspended = false;
}
void DoughLogger::log(const char *fmt, ...)
{
if (_suspended)
{
return;
}
char buf[LOGGER_PREFIX_BUFLEN];
snprintf(buf, sizeof(buf) / sizeof(buf[0]), LOGGER_PREFIX_FORMAT, _section);
Serial.print(buf);

View File

@ -2,7 +2,7 @@
#define DOUGH_LOGGER_H
#define LOGGER_PREFIX_BUFLEN 16
#define LOGGER_PREFIX_FORMAT "%10s | "
#define LOGGER_PREFIX_FORMAT "%11s | "
#include <Arduino.h>
#include <stdarg.h>
@ -17,9 +17,12 @@ class DoughLogger
public:
DoughLogger(const char *section);
void log(const char *fmt, ...);
void suspend();
void resume();
private:
const char *_section;
bool _suspended = false;
};
#endif

View File

@ -1,17 +1,19 @@
#include "main.h"
// TODO: move config to a separate class
// TODO: see if I can give each sensor its own built-in loop schedule for sampling, the DoughData class might be overkill in the latest setup.
// TOOD: implement the calibration logic
// TODO: use different timings for temperature, humidity and distance measurements. Temp/Humidity together takes about 500ms, which slows down stuff.
// TODO: make the measuring more loop-y, giving back control to the main loop more often for better UI responsiveness
// TODO: see what more stuff can be moved to the UI code. Maybe state to UI state translation ought to be there as well
// TODO: use longer term averages for data
// TODO: make significantChange part of sensor class?
DoughBoyState state = CONFIGURING;
auto logger = DoughLogger("MAIN");
void setup()
{
DoughSensors::Instance()->setup();
TemperatureSensor::Instance()->setup();
HumiditySensor::Instance()->setup();
DistanceSensor::Instance()->setup();
DoughWiFi::Instance()->setup();
DoughMQTT::Instance()->setup();
DataController::Instance()->setup();

View File

@ -2,9 +2,11 @@
#define DOUGHBOY_H
#include <Arduino.h>
#include "Sensors/TemperatureSensor.h"
#include "Sensors/HumiditySensor.h"
#include "Sensors/DistanceSensor.h"
#include "Network/DoughWiFi.h"
#include "Network/DoughMQTT.h"
#include "Sensors/DoughSensors.h"
#include "Data/DataController.h"
#include "UI/DoughButton.h"
#include "UI/DoughUI.h"