Code cleanup.

This commit is contained in:
Maurice Makaay 2020-07-18 16:58:04 +02:00
parent 4233764120
commit f20ff5a4bb
17 changed files with 109 additions and 114 deletions

View File

@ -14,23 +14,14 @@ namespace Dough
mqtt(&wifi, mqttOnConnectCallback, mqttOnMessageCallback), mqtt(&wifi, mqttOnConnectCallback, mqttOnMessageCallback),
sensorControllerPlugin(&mqtt, &ui), sensorControllerPlugin(&mqtt, &ui),
distanceSensor( distanceSensor(
&sensorControllerPlugin, new DistanceSensor(), &sensorControllerPlugin,
&mqtt, "distance", distanceSensorX, DISTANCE_AVERAGE_STORAGE, DISTANCE_MEASURE_INTERVAL, MINIMUM_PUBLISH_INTERVAL),
DISTANCE_AVERAGE_STORAGE,
DISTANCE_MEASURE_INTERVAL,
MINIMUM_PUBLISH_INTERVAL),
temperatureSensor( temperatureSensor(
&sensorControllerPlugin, new TemperatureSensor(), &sensorControllerPlugin,
&mqtt, "temperature", temperatureSensorX, TEMPERATURE_AVERAGE_STORAGE, TEMPERATURE_MEASURE_INTERVAL, MINIMUM_PUBLISH_INTERVAL),
TEMPERATURE_AVERAGE_STORAGE,
TEMPERATURE_MEASURE_INTERVAL,
MINIMUM_PUBLISH_INTERVAL),
humiditySensor( humiditySensor(
&sensorControllerPlugin, new HumiditySensor(), &sensorControllerPlugin,
&mqtt, "humidity", humiditySensorX, HUMIDITY_AVERAGE_STORAGE, HUMIDITY_MEASURE_INTERVAL, MINIMUM_PUBLISH_INTERVAL),
HUMIDITY_AVERAGE_STORAGE,
HUMIDITY_MEASURE_INTERVAL,
MINIMUM_PUBLISH_INTERVAL),
_logger("APP") {} _logger("APP") {}
void App::setup() void App::setup()
@ -50,14 +41,10 @@ namespace Dough
return; return;
} }
// Get measurements from the sensors. Suspend the user interface // Get measurements from the sensors.
// interrupts in the meanwhile, to not disturb the timing-sensitive
// sensor readings.
ui.suspend();
temperatureSensor.loop(); temperatureSensor.loop();
humiditySensor.loop(); humiditySensor.loop();
distanceSensor.loop(); distanceSensor.loop();
ui.resume();
} }
void App::clearHistory() void App::clearHistory()

View File

@ -23,11 +23,8 @@ namespace Dough
WiFi wifi; WiFi wifi;
MQTT mqtt; MQTT mqtt;
SensorControllerPlugin sensorControllerPlugin; SensorControllerPlugin sensorControllerPlugin;
DistanceSensor distanceSensorX;
SensorController distanceSensor; SensorController distanceSensor;
TemperatureSensor temperatureSensorX;
SensorController temperatureSensor; SensorController temperatureSensor;
HumiditySensor humiditySensorX;
SensorController humiditySensor; SensorController humiditySensor;
void setup(); void setup();

View File

@ -2,21 +2,33 @@
namespace Dough namespace Dough
{ {
SensorControllerPlugin::SensorControllerPlugin(MQTT *mqtt, UI *ui) : _mqtt(mqtt), _ui(ui) SensorControllerPlugin::SensorControllerPlugin(MQTT *mqtt, UI *ui) : _mqtt(mqtt), _ui(ui) {}
{
}
void SensorControllerPlugin::doPublish(SensorController *controller) {
Serial.println(">>>>>>>>>> YO PLUGIN HERE! <<<<<<<<<<<");
}
void SensorControllerPlugin::beforeMeasure(SensorController *controller) void SensorControllerPlugin::beforeMeasure(SensorController *controller)
{ {
_ui->notifySensorActivity(); _ui->notifySensorActivity();
// Suspend the user interface interrupts, to not disturb the timing-sensitive
// sensor readings.
_ui->suspend();
}
void SensorControllerPlugin::afterMeasure(SensorController *controller)
{
_ui->resume();
} }
void SensorControllerPlugin::beforePublish(SensorController *controller) void SensorControllerPlugin::beforePublish(SensorController *controller)
{ {
_ui->notifyNetworkActivity(); _ui->notifyNetworkActivity();
} }
void SensorControllerPlugin::doPublish(SensorController *controller, Measurement last, Measurement average)
{
const char *sensorName = controller->getSensorName();
static char mqttAverageKey[50];
snprintf(mqttAverageKey, 50, "%s/average", sensorName);
_mqtt->publish(sensorName, last);
_mqtt->publish(mqttAverageKey, average);
}
} }

View File

@ -11,13 +11,15 @@ namespace Dough
{ {
// This class is a plugin for the Dough::SensorController. It takes care // This class is a plugin for the Dough::SensorController. It takes care
// of notifying events via the device UI and publishing data via the MQTT broker. // of notifying events via the device UI and publishing data via the MQTT broker.
// This decouples the sensor controller for the network and user interface specifics.
class SensorControllerPlugin : public SensorControllerPluginBase class SensorControllerPlugin : public SensorControllerPluginBase
{ {
public: public:
SensorControllerPlugin(MQTT *mqtt, UI *ui); SensorControllerPlugin(MQTT *mqtt, UI *ui);
virtual void beforeMeasure(SensorController *controller); virtual void beforeMeasure(SensorController *controller);
virtual void afterMeasure(SensorController *controller);
virtual void beforePublish(SensorController *controller); virtual void beforePublish(SensorController *controller);
virtual void doPublish(SensorController *controller); virtual void doPublish(SensorController *controller, Measurement last, Measurement average);
private: private:
MQTT *_mqtt; MQTT *_mqtt;

View File

@ -39,7 +39,7 @@ void setupButtonInterruptCallback()
// This callback is called when the TC4 timer from the UI code hits an overflow // This callback is called when the TC4 timer from the UI code hits an overflow
// interrupt. It is defined outside the Dough namespace, because TC4_Handler is // interrupt. It is defined outside the Dough namespace, because TC4_Handler is
// a hard-coded root namespace function name. // a hard-coded, root namespace function name.
void TC4_Handler() void TC4_Handler()
{ {
Dough::App::Instance()->ui.updateLEDs(); Dough::App::Instance()->ui.updateLEDs();

View File

@ -2,16 +2,19 @@
namespace Dough namespace Dough
{ {
DistanceSensor::DistanceSensor() : _logger("DISTANCE") DistanceSensor::DistanceSensor() : _logger(getName()),
{ _hcsr04(new SensorHCSR04(HCSR04_TRIG_PIN, HCSR04_ECHO_PIN)) {}
_hcsr04 = new SensorHCSR04(HCSR04_TRIG_PIN, HCSR04_ECHO_PIN);
}
void DistanceSensor::setup() void DistanceSensor::setup()
{ {
_hcsr04->setup(); _hcsr04->setup();
} }
const char* DistanceSensor::getName()
{
return "distance";
}
void DistanceSensor::setTemperature(int temperature) void DistanceSensor::setTemperature(int temperature)
{ {
_hcsr04->setTemperature(temperature); _hcsr04->setTemperature(temperature);

View File

@ -14,9 +14,10 @@ namespace Dough
{ {
public: public:
DistanceSensor(); DistanceSensor();
virtual void setup();
virtual const char* getName();
void setTemperature(int temperature); void setTemperature(int temperature);
void setHumidity(int humidity); void setHumidity(int humidity);
virtual void setup();
virtual Measurement read(); virtual Measurement read();
virtual unsigned int getPrecision(); virtual unsigned int getPrecision();

View File

@ -2,13 +2,18 @@
namespace Dough namespace Dough
{ {
HumiditySensor::HumiditySensor() : _logger("HUMIDITY") {} HumiditySensor::HumiditySensor() : _logger(getName()) {}
void HumiditySensor::setup() void HumiditySensor::setup()
{ {
SensorDHT11::Instance()->begin(); SensorDHT11::Instance()->begin();
} }
const char* HumiditySensor::getName()
{
return "humidity";
}
Measurement HumiditySensor::read() Measurement HumiditySensor::read()
{ {
float t = SensorDHT11::Instance()->readHumidity(); float t = SensorDHT11::Instance()->readHumidity();

View File

@ -15,6 +15,7 @@ namespace Dough
public: public:
HumiditySensor(); HumiditySensor();
virtual void setup(); virtual void setup();
virtual const char* getName();
virtual Measurement read(); virtual Measurement read();
virtual unsigned int getPrecision(); virtual unsigned int getPrecision();

View File

@ -10,6 +10,7 @@ namespace Dough
{ {
public: public:
virtual void setup(); virtual void setup();
virtual const char* getName();
virtual Measurement read(); virtual Measurement read();
virtual unsigned int getPrecision(); virtual unsigned int getPrecision();
}; };

View File

@ -2,13 +2,18 @@
namespace Dough namespace Dough
{ {
TemperatureSensor::TemperatureSensor() : _logger("TEMPERATURE") {} TemperatureSensor::TemperatureSensor() : _logger(getName()) {}
void TemperatureSensor::setup() void TemperatureSensor::setup()
{ {
SensorDHT11::Instance()->begin(); SensorDHT11::Instance()->begin();
} }
const char* TemperatureSensor::getName()
{
return "temperature";
}
Measurement TemperatureSensor::read() Measurement TemperatureSensor::read()
{ {
float t = SensorDHT11::Instance()->readTemperature(); float t = SensorDHT11::Instance()->readTemperature();

View File

@ -15,6 +15,7 @@ namespace Dough
public: public:
TemperatureSensor(); TemperatureSensor();
virtual void setup(); virtual void setup();
virtual const char* getName();
virtual Measurement read(); virtual Measurement read();
virtual unsigned int getPrecision(); virtual unsigned int getPrecision();

View File

@ -4,32 +4,29 @@
namespace Dough namespace Dough
{ {
SensorController::SensorController( SensorController::SensorController(
SensorBase *sensor,
SensorControllerPluginBase *plugin, SensorControllerPluginBase *plugin,
MQTT *mqtt,
const char *mqttKey,
SensorBase &sensor,
unsigned int storageSize, unsigned int storageSize,
unsigned int minimumMeasureTime, unsigned int minimumMeasureTime,
unsigned int minimumPublishTime) : _plugin(plugin), unsigned int minimumPublishTime) : _sensor(sensor),
_mqtt(mqtt), _plugin(plugin),
_sensor(sensor) _storageSize(storageSize),
_minimumMeasureTime(minimumMeasureTime),
_minimumPublishTime(minimumPublishTime) {}
const char* SensorController::getSensorName()
{ {
_mqttKey = mqttKey; return _sensor->getName();
_storageSize = storageSize;
_minimumMeasureTime = minimumMeasureTime;
_minimumPublishTime = minimumPublishTime;
} }
void SensorController::setup() void SensorController::setup()
{ {
_sensor.setup(); _sensor->setup();
// Format the key to use for publishing the average (i.e. "<mqttKey>/average"). // Initialize the storage for holding measurements. This storage is used
auto lenAverageKey = strlen(_mqttKey) + 9; // +9 for the "/average\0" suffix // as a circular buffer, and it helps in computing an over time average
_mqttAverageKey = new char[lenAverageKey]; // value for the collected measurements. The bigger the storage size, the
snprintf(_mqttAverageKey, lenAverageKey, "%s/average", _mqttKey); // more values will be included for the average computation.
// Initialize the storage for holding the measurements.
_storage = new Measurement *[_storageSize]; _storage = new Measurement *[_storageSize];
for (unsigned int i = 0; i < _storageSize; i++) for (unsigned int i = 0; i < _storageSize; i++)
{ {
@ -49,10 +46,13 @@ namespace Dough
if (_mustPublish()) if (_mustPublish())
{ {
_plugin->beforePublish(this); _plugin->beforePublish(this);
Serial.println("CALLING doPublish() from plugin"); // DEBUG XXX auto average = _getAverage();
_plugin->doPublish(this); auto last = _getLast();
_lastPublishedAt = millis();
average.copyTo(&_lastPublishedAverage);
last.copyTo(&_lastPublished);
_plugin->doPublish(this, last, average);
_plugin->afterPublish(this); _plugin->afterPublish(this);
_publish();
} }
} }
@ -75,12 +75,12 @@ namespace Dough
{ {
_lastMeasuredAt = millis(); _lastMeasuredAt = millis();
_store(_sensor.read()); _store(_sensor->read());
} }
bool SensorController::_mustPublish() bool SensorController::_mustPublish()
{ {
Measurement lastMeasurement = getLast(); Measurement lastMeasurement = _getLast();
// When the measurement failed, then there's no need to publish it. // When the measurement failed, then there's no need to publish it.
if (lastMeasurement.ok == false) if (lastMeasurement.ok == false)
@ -103,7 +103,7 @@ namespace Dough
return _lastPublishedAt == 0 || delta >= (_minimumPublishTime * 1000); return _lastPublishedAt == 0 || delta >= (_minimumPublishTime * 1000);
} }
auto precision = _sensor.getPrecision(); auto precision = _sensor->getPrecision();
// When there is a significant change in the sensor value, then publish. // When there is a significant change in the sensor value, then publish.
if (abs(_lastPublished.value - lastMeasurement.value) >= precision) if (abs(_lastPublished.value - lastMeasurement.value) >= precision)
@ -111,7 +111,7 @@ namespace Dough
return true; return true;
} }
auto average = getAverage(); auto average = _getAverage();
// When there is a significant change in the average value, then publish. // When there is a significant change in the average value, then publish.
if (average.ok && abs(_lastPublishedAverage.value - average.value) >= precision) if (average.ok && abs(_lastPublishedAverage.value - average.value) >= precision)
@ -131,19 +131,6 @@ namespace Dough
return false; return false;
} }
void SensorController::_publish()
{
auto average = getAverage();
auto last = getLast();
_mqtt->publish(_mqttKey, last);
_mqtt->publish(_mqttAverageKey, average);
_lastPublishedAt = millis();
average.copyTo(&_lastPublishedAverage);
last.copyTo(&_lastPublished);
}
void SensorController::_store(Measurement measurement) void SensorController::_store(Measurement measurement)
{ {
measurement.copyTo(_storage[_next()]); measurement.copyTo(_storage[_next()]);
@ -177,12 +164,12 @@ namespace Dough
return _index; return _index;
} }
Measurement SensorController::getLast() Measurement SensorController::_getLast()
{ {
return *_storage[_index]; return *_storage[_index];
} }
Measurement SensorController::getAverage() Measurement SensorController::_getAverage()
{ {
return _averageCount > 0 return _averageCount > 0
? Measurement::Value(round(_averageSum / _averageCount)) ? Measurement::Value(round(_averageSum / _averageCount))

View File

@ -24,7 +24,7 @@ namespace Dough
virtual void beforeMeasure(SensorController *controller) {}; virtual void beforeMeasure(SensorController *controller) {};
virtual void afterMeasure(SensorController *controller) {}; virtual void afterMeasure(SensorController *controller) {};
virtual void beforePublish(SensorController *controller) {}; virtual void beforePublish(SensorController *controller) {};
virtual void doPublish(SensorController *controller) {}; virtual void doPublish(SensorController *controller, Measurement last, Measurement average) {};
virtual void afterPublish(SensorController *controller) {}; virtual void afterPublish(SensorController *controller) {};
}; };
@ -33,67 +33,59 @@ namespace Dough
public: public:
// Create a new Measurements object. // Create a new Measurements object.
// //
// @param plugin
// The Dough::SensorControllerPluginBase to use.
// @param mqtt
// The Dough::MQTT object, which is connected to the MQTT broker.
// @param mqttKey
// The key to use when publishing sensor values to MQTT.
// The full key will be "<prefix>/<mqttKey>" for measurement values
// and "<prefix>/<mqttKey>/average" for average values.
// @param sensor // @param sensor
// The sensor to read, implements SensorBase. // The Dough::SensorBase implementation to wrap in this controller.
// @param plugin
// The Dough::SensorControllerPluginBase implementation to use.
// This plugin is used to decouple network / user interface functionality
// from the sensor controller code.
// @param storageSize // @param storageSize
// Number of measurements to keep track of for computing an average. // Number of measurements to keep track of for computing an average.
// @param minimumMeasureTime // @param minimumMeasureTime
// The number of seconds after which to read the next measurement // The number of seconds after which to read the next measurement
// from the sensor. // from the sensor.
// @param onMeasure
// A callback function that is called right before a measurement
// is taken using the contained sensor object.
// @param minimumPublishTime // @param minimumPublishTime
// The number of seconds after which to forcibly publish measurements // The number of seconds after which to forcibly publish measurements
// to MQTT, even when no significant changes to measurements were seen. // to MQTT, even when no significant changes to measurements were seen.
// @param onPublish // "Significant change" is defined by the Dough::SensorBase implementation.
// A callback function that is called right before a measurement
// is published.
SensorController( SensorController(
SensorBase *sensor,
SensorControllerPluginBase *plugin, SensorControllerPluginBase *plugin,
MQTT *mqtt,
const char *mqttKey,
SensorBase &sensor,
unsigned int storageSize, unsigned int storageSize,
unsigned int minimumMeasureTime, unsigned int minimumMeasureTime,
unsigned int minimumPublishTime); unsigned int minimumPublishTime);
const char *getSensorName();
void setup(); void setup();
void loop(); void loop();
Measurement getLast();
Measurement getAverage();
void clearHistory(); void clearHistory();
private: private:
SensorBase *_sensor;
SensorControllerPluginBase *_plugin; SensorControllerPluginBase *_plugin;
MQTT *_mqtt; Measurement _getLast();
const char *_mqttKey; Measurement _getAverage();
char *_mqttAverageKey;
SensorBase &_sensor; // Members related to the measurement storage.
Measurement **_storage; Measurement **_storage;
unsigned int _storageSize; unsigned int _storageSize;
int _averageSum = 0; int _averageSum = 0;
unsigned int _averageCount = 0; unsigned int _averageCount = 0;
unsigned int _index = 0; unsigned int _index = 0;
void _store(Measurement measurement);
unsigned int _next();
// Members used for controlling measurements.
bool _mustMeasure(); bool _mustMeasure();
void _measure(); void _measure();
unsigned int _minimumMeasureTime; unsigned int _minimumMeasureTime;
unsigned long _lastMeasuredAt = 0; unsigned long _lastMeasuredAt = 0;
// Members used for controlling publishing of measurements.
bool _mustPublish(); bool _mustPublish();
void _publish();
unsigned int _minimumPublishTime; unsigned int _minimumPublishTime;
unsigned long _lastPublishedAt = 0; unsigned long _lastPublishedAt = 0;
Measurement _lastPublished; Measurement _lastPublished;
Measurement _lastPublishedAverage; Measurement _lastPublishedAverage;
void _store(Measurement measurement);
unsigned int _next();
}; };
} // namespace Dough } // namespace Dough

View File

@ -2,10 +2,7 @@
namespace Dough namespace Dough
{ {
LED::LED(int pin) LED::LED(int pin) : _pin(pin) {}
{
_pin = pin;
}
void LED::setup() void LED::setup()
{ {

View File

@ -4,7 +4,10 @@ namespace Dough
{ {
Logger::Logger(const char *section) Logger::Logger(const char *section)
{ {
_section = section; strncpy(_section, section, sizeof(_section)/sizeof(_section[0]));
for (unsigned int i = 0; i < strlen(_section); i++) {
_section[i] = toupper(_section[i]);
}
} }
void Logger::setup() void Logger::setup()

View File

@ -1,7 +1,8 @@
#ifndef DOUGH_LOGGER_H #ifndef DOUGH_LOGGER_H
#define DOUGH_LOGGER_H #define DOUGH_LOGGER_H
#define LOGGER_PREFIX_BUFLEN 16 #define LOGGER_SECTION_BUFLEN 12
#define LOGGER_PREFIX_BUFLEN LOGGER_SECTION_BUFLEN+3
#define LOGGER_PREFIX_FORMAT "%11s | " #define LOGGER_PREFIX_FORMAT "%11s | "
#include <Arduino.h> #include <Arduino.h>
@ -23,7 +24,7 @@ namespace Dough
void resume(); void resume();
private: private:
const char *_section; char _section[LOGGER_SECTION_BUFLEN];
bool _suspended = false; bool _suspended = false;
}; };