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

View File

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

View File

@ -2,21 +2,33 @@
namespace Dough
{
SensorControllerPlugin::SensorControllerPlugin(MQTT *mqtt, UI *ui) : _mqtt(mqtt), _ui(ui)
{
}
void SensorControllerPlugin::doPublish(SensorController *controller) {
Serial.println(">>>>>>>>>> YO PLUGIN HERE! <<<<<<<<<<<");
}
SensorControllerPlugin::SensorControllerPlugin(MQTT *mqtt, UI *ui) : _mqtt(mqtt), _ui(ui) {}
void SensorControllerPlugin::beforeMeasure(SensorController *controller)
{
_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)
{
_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
// 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
{
public:
SensorControllerPlugin(MQTT *mqtt, UI *ui);
virtual void beforeMeasure(SensorController *controller);
virtual void afterMeasure(SensorController *controller);
virtual void beforePublish(SensorController *controller);
virtual void doPublish(SensorController *controller);
virtual void doPublish(SensorController *controller, Measurement last, Measurement average);
private:
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
// 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()
{
Dough::App::Instance()->ui.updateLEDs();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,7 +4,10 @@ namespace Dough
{
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()

View File

@ -1,7 +1,8 @@
#ifndef 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 | "
#include <Arduino.h>
@ -23,7 +24,7 @@ namespace Dough
void resume();
private:
const char *_section;
char _section[LOGGER_SECTION_BUFLEN];
bool _suspended = false;
};