Further cleanup. Most noticably is moving all physical LED logic into the Dough::UI class, providing app-state-dependent logical functions for letting the LEDs represent a given application state.
This commit is contained in:
parent
52b33de7aa
commit
fd1363dd45
|
@ -9,6 +9,7 @@ namespace Dough
|
||||||
}
|
}
|
||||||
|
|
||||||
App::App() : config(),
|
App::App() : config(),
|
||||||
|
ui(),
|
||||||
wifi(),
|
wifi(),
|
||||||
mqtt(
|
mqtt(
|
||||||
&wifi,
|
&wifi,
|
||||||
|
@ -19,26 +20,30 @@ namespace Dough
|
||||||
"temperature",
|
"temperature",
|
||||||
TemperatureSensor::Instance(),
|
TemperatureSensor::Instance(),
|
||||||
TEMPERATURE_AVERAGE_STORAGE,
|
TEMPERATURE_AVERAGE_STORAGE,
|
||||||
TEMPERATURE_MEASURE_INTERVAL,
|
TEMPERATURE_MEASURE_INTERVAL, sensorOnMeasureCallback,
|
||||||
MINIMUM_PUBLISH_INTERVAL),
|
MINIMUM_PUBLISH_INTERVAL, sensorOnPublishCallback),
|
||||||
humiditySensor(
|
humiditySensor(
|
||||||
&mqtt,
|
&mqtt,
|
||||||
"humidity",
|
"humidity",
|
||||||
HumiditySensor::Instance(),
|
HumiditySensor::Instance(),
|
||||||
HUMIDITY_AVERAGE_STORAGE,
|
HUMIDITY_AVERAGE_STORAGE,
|
||||||
HUMIDITY_MEASURE_INTERVAL,
|
HUMIDITY_MEASURE_INTERVAL, sensorOnMeasureCallback,
|
||||||
MINIMUM_PUBLISH_INTERVAL),
|
MINIMUM_PUBLISH_INTERVAL, sensorOnPublishCallback),
|
||||||
distanceSensor(
|
distanceSensor(
|
||||||
&mqtt,
|
&mqtt,
|
||||||
"distance",
|
"distance",
|
||||||
DistanceSensor::Instance(),
|
DistanceSensor::Instance(),
|
||||||
DISTANCE_AVERAGE_STORAGE,
|
DISTANCE_AVERAGE_STORAGE,
|
||||||
DISTANCE_MEASURE_INTERVAL,
|
DISTANCE_MEASURE_INTERVAL, sensorOnMeasureCallback,
|
||||||
MINIMUM_PUBLISH_INTERVAL),
|
MINIMUM_PUBLISH_INTERVAL, sensorOnPublishCallback),
|
||||||
_logger("APP") {}
|
_logger("APP") {}
|
||||||
|
|
||||||
void App::setup()
|
void App::setup()
|
||||||
{
|
{
|
||||||
|
ui.setup();
|
||||||
|
ui.onoffButton.onInterrupt(::onoffButtonInterruptCallback);
|
||||||
|
ui.setupButton.onInterrupt(::setupButtonInterruptCallback);
|
||||||
|
|
||||||
wifi.setup();
|
wifi.setup();
|
||||||
mqtt.setup();
|
mqtt.setup();
|
||||||
temperatureSensor.setup();
|
temperatureSensor.setup();
|
||||||
|
@ -50,9 +55,14 @@ namespace Dough
|
||||||
{
|
{
|
||||||
if (config.isOk())
|
if (config.isOk())
|
||||||
{
|
{
|
||||||
|
// Get measurements from the sensors. Suspend the user interface
|
||||||
|
// 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,4 +99,33 @@ void mqttOnMessageCallback(String &topic, String &payload)
|
||||||
{
|
{
|
||||||
callbackLogger.log("ss", "ERROR - Unhandled MQTT message, topic = ", topic.c_str());
|
callbackLogger.log("ss", "ERROR - Unhandled MQTT message, topic = ", topic.c_str());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onoffButtonInterruptCallback()
|
||||||
|
{
|
||||||
|
Dough::App::Instance()->ui.onoffButton.handleButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupButtonInterruptCallback()
|
||||||
|
{
|
||||||
|
Dough::App::Instance()->ui.setupButton.handleButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sensorOnMeasureCallback()
|
||||||
|
{
|
||||||
|
Dough::App::Instance()->ui.notifySensorActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sensorOnPublishCallback()
|
||||||
|
{
|
||||||
|
Dough::App::Instance()->ui.notifyNetworkActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
void TC4_Handler()
|
||||||
|
{
|
||||||
|
Dough::App::Instance()->ui.updateLEDs();
|
||||||
|
REG_TC4_INTFLAG = TC_INTFLAG_OVF; // Clear the OVF interrupt flag.
|
||||||
}
|
}
|
|
@ -16,6 +16,7 @@ namespace Dough
|
||||||
public:
|
public:
|
||||||
static App *Instance();
|
static App *Instance();
|
||||||
Configuration config;
|
Configuration config;
|
||||||
|
UI ui;
|
||||||
WiFi wifi;
|
WiFi wifi;
|
||||||
MQTT mqtt;
|
MQTT mqtt;
|
||||||
SensorController temperatureSensor;
|
SensorController temperatureSensor;
|
||||||
|
@ -33,7 +34,11 @@ namespace Dough
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback functions that need to live in the global namespace.
|
// Callback functions that need to live in the global namespace.
|
||||||
void mqttOnConnectCallback(Dough::MQTT* mqtt);
|
void mqttOnConnectCallback(Dough::MQTT *mqtt);
|
||||||
void mqttOnMessageCallback(String &topic, String &payload);
|
void mqttOnMessageCallback(String &topic, String &payload);
|
||||||
|
void onoffButtonInterruptCallback();
|
||||||
|
void setupButtonInterruptCallback();
|
||||||
|
void sensorOnMeasureCallback();
|
||||||
|
void sensorOnPublishCallback();
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -2,10 +2,7 @@
|
||||||
|
|
||||||
namespace Dough
|
namespace Dough
|
||||||
{
|
{
|
||||||
Configuration::Configuration() : _logger("CONFIG")
|
Configuration::Configuration() : _logger("CONFIG") {}
|
||||||
{
|
|
||||||
// _mqtt = MQTT::Instance();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Configuration::setup()
|
void Configuration::setup()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
#define DOUGH_CONFIG_H
|
#define DOUGH_CONFIG_H
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
//#include "App/App.h"
|
|
||||||
#include "Network/MQTT.h"
|
|
||||||
#include "UI/Logger.h"
|
#include "UI/Logger.h"
|
||||||
#include "Sensors/LowLevel/SensorHCSR04.h"
|
#include "Sensors/LowLevel/SensorHCSR04.h"
|
||||||
|
|
||||||
|
@ -18,8 +16,6 @@ namespace Dough
|
||||||
public:
|
public:
|
||||||
Configuration();
|
Configuration();
|
||||||
void setup();
|
void setup();
|
||||||
static void handleMqttConnect(MQTT *mqtt);
|
|
||||||
static void handleMqttMessage(String &key, String &value);
|
|
||||||
void setContainerHeight(int height);
|
void setContainerHeight(int height);
|
||||||
unsigned int getContainerHeight();
|
unsigned int getContainerHeight();
|
||||||
void setTemperatureOffset(int offset);
|
void setTemperatureOffset(int offset);
|
||||||
|
@ -27,7 +23,6 @@ namespace Dough
|
||||||
bool isOk();
|
bool isOk();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MQTT *_mqtt;
|
|
||||||
Logger _logger;
|
Logger _logger;
|
||||||
unsigned int _containerHeight;
|
unsigned int _containerHeight;
|
||||||
bool _containerHeightSet;
|
bool _containerHeightSet;
|
||||||
|
|
|
@ -9,15 +9,18 @@ namespace Dough
|
||||||
SensorBase *sensor,
|
SensorBase *sensor,
|
||||||
unsigned int storageSize,
|
unsigned int storageSize,
|
||||||
unsigned int minimumMeasureTime,
|
unsigned int minimumMeasureTime,
|
||||||
unsigned int minimumPublishTime)
|
SensorControllerCallback onMeasure,
|
||||||
|
unsigned int minimumPublishTime,
|
||||||
|
SensorControllerCallback onPublish)
|
||||||
{
|
{
|
||||||
_mqtt = mqtt;
|
_mqtt = mqtt;
|
||||||
_mqttKey = mqttKey;
|
_mqttKey = mqttKey;
|
||||||
_sensor = sensor;
|
_sensor = sensor;
|
||||||
_storageSize = storageSize;
|
_storageSize = storageSize;
|
||||||
_minimumMeasureTime = minimumMeasureTime;
|
_minimumMeasureTime = minimumMeasureTime;
|
||||||
|
_onMeasure = onMeasure;
|
||||||
_minimumPublishTime = minimumPublishTime;
|
_minimumPublishTime = minimumPublishTime;
|
||||||
_ui = UI::Instance();
|
_onPublish = onPublish;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SensorController::setup()
|
void SensorController::setup()
|
||||||
|
@ -42,10 +45,12 @@ namespace Dough
|
||||||
{
|
{
|
||||||
if (_mustMeasure())
|
if (_mustMeasure())
|
||||||
{
|
{
|
||||||
|
_onMeasure();
|
||||||
_measure();
|
_measure();
|
||||||
}
|
}
|
||||||
if (_mustPublish())
|
if (_mustPublish())
|
||||||
{
|
{
|
||||||
|
_onPublish();
|
||||||
_publish();
|
_publish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,19 +74,7 @@ namespace Dough
|
||||||
{
|
{
|
||||||
_lastMeasuredAt = millis();
|
_lastMeasuredAt = millis();
|
||||||
|
|
||||||
// Quickly dip the LED to indicate that a measurement has started.
|
|
||||||
// This is done synchroneously, because we suspend the timer interrupts
|
|
||||||
// in the upcoming code.
|
|
||||||
_ui->led3.off();
|
|
||||||
delay(50);
|
|
||||||
_ui->led3.on();
|
|
||||||
|
|
||||||
// Read a measurement from the sensor. Suspend the user interface
|
|
||||||
// interrupts in the meanwhile, to not disturb the timing-sensitive
|
|
||||||
// sensor readings.
|
|
||||||
_ui->suspend();
|
|
||||||
_store(_sensor->read());
|
_store(_sensor->read());
|
||||||
_ui->resume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SensorController::_mustPublish()
|
bool SensorController::_mustPublish()
|
||||||
|
@ -139,14 +132,6 @@ namespace Dough
|
||||||
|
|
||||||
void SensorController::_publish()
|
void SensorController::_publish()
|
||||||
{
|
{
|
||||||
// Quickly dip the LED to indicate that a publish has started.
|
|
||||||
// This is done synchroneously, because the upcoming code is too
|
|
||||||
// fast normally to register a LED going off and on again during
|
|
||||||
// the operation.
|
|
||||||
_ui->led1.off();
|
|
||||||
delay(50);
|
|
||||||
_ui->led1.on();
|
|
||||||
|
|
||||||
auto average = getAverage();
|
auto average = getAverage();
|
||||||
auto last = getLast();
|
auto last = getLast();
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
namespace Dough
|
namespace Dough
|
||||||
{
|
{
|
||||||
|
typedef void (*SensorControllerCallback)();
|
||||||
|
|
||||||
// This class is used to store measurements for a sensor and to keep
|
// This class is used to store measurements for a sensor and to keep
|
||||||
// track of running totals for handling average computations.
|
// track of running totals for handling average computations.
|
||||||
// It also provides functionality to decide when to read a measurement
|
// It also provides functionality to decide when to read a measurement
|
||||||
|
@ -32,16 +34,24 @@ namespace Dough
|
||||||
// @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.
|
||||||
// @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
|
||||||
|
// A callback function that is called right before a measurement
|
||||||
|
// is published.
|
||||||
SensorController(
|
SensorController(
|
||||||
MQTT *mqtt,
|
MQTT *mqtt,
|
||||||
const char *mqttKey,
|
const char *mqttKey,
|
||||||
SensorBase *sensor,
|
SensorBase *sensor,
|
||||||
unsigned int storageSize,
|
unsigned int storageSize,
|
||||||
unsigned int minimumMeasureTime,
|
unsigned int minimumMeasureTime,
|
||||||
unsigned int minimumPublishTime);
|
SensorControllerCallback onMeasure,
|
||||||
|
unsigned int minimumPublishTime,
|
||||||
|
SensorControllerCallback onPublish);
|
||||||
void setup();
|
void setup();
|
||||||
void loop();
|
void loop();
|
||||||
Measurement getLast();
|
Measurement getLast();
|
||||||
|
@ -50,7 +60,6 @@ namespace Dough
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MQTT *_mqtt;
|
MQTT *_mqtt;
|
||||||
UI *_ui;
|
|
||||||
const char *_mqttKey;
|
const char *_mqttKey;
|
||||||
char *_mqttAverageKey;
|
char *_mqttAverageKey;
|
||||||
SensorBase *_sensor;
|
SensorBase *_sensor;
|
||||||
|
@ -60,10 +69,12 @@ namespace Dough
|
||||||
unsigned int _averageCount = 0;
|
unsigned int _averageCount = 0;
|
||||||
unsigned int _index = 0;
|
unsigned int _index = 0;
|
||||||
bool _mustMeasure();
|
bool _mustMeasure();
|
||||||
|
SensorControllerCallback _onMeasure;
|
||||||
void _measure();
|
void _measure();
|
||||||
unsigned int _minimumMeasureTime;
|
unsigned int _minimumMeasureTime;
|
||||||
unsigned long _lastMeasuredAt = 0;
|
unsigned long _lastMeasuredAt = 0;
|
||||||
bool _mustPublish();
|
bool _mustPublish();
|
||||||
|
SensorControllerCallback _onPublish ;
|
||||||
void _publish();
|
void _publish();
|
||||||
unsigned int _minimumPublishTime;
|
unsigned int _minimumPublishTime;
|
||||||
unsigned long _lastPublishedAt = 0;
|
unsigned long _lastPublishedAt = 0;
|
||||||
|
|
110
src/UI/UI.cpp
110
src/UI/UI.cpp
|
@ -2,17 +2,6 @@
|
||||||
|
|
||||||
namespace Dough
|
namespace Dough
|
||||||
{
|
{
|
||||||
UI *UI::_instance = nullptr;
|
|
||||||
|
|
||||||
UI *UI::Instance()
|
|
||||||
{
|
|
||||||
if (UI::_instance == nullptr)
|
|
||||||
{
|
|
||||||
UI::_instance = new UI();
|
|
||||||
}
|
|
||||||
return UI::_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
UI::UI() : onoffButton(ONOFF_BUTTON_PIN),
|
UI::UI() : onoffButton(ONOFF_BUTTON_PIN),
|
||||||
setupButton(SETUP_BUTTON_PIN),
|
setupButton(SETUP_BUTTON_PIN),
|
||||||
ledBuiltin(LED_BUILTIN),
|
ledBuiltin(LED_BUILTIN),
|
||||||
|
@ -24,9 +13,7 @@ namespace Dough
|
||||||
{
|
{
|
||||||
// Setup the buttons.
|
// Setup the buttons.
|
||||||
onoffButton.setup();
|
onoffButton.setup();
|
||||||
onoffButton.onInterrupt(UI::onoffButtonISR);
|
|
||||||
setupButton.setup();
|
setupButton.setup();
|
||||||
setupButton.onInterrupt(UI::setupButtonISR);
|
|
||||||
|
|
||||||
// Setup the LEDs.
|
// Setup the LEDs.
|
||||||
ledBuiltin.setup();
|
ledBuiltin.setup();
|
||||||
|
@ -47,16 +34,6 @@ namespace Dough
|
||||||
resume();
|
resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI::onoffButtonISR()
|
|
||||||
{
|
|
||||||
UI::Instance()->onoffButton.handleButtonState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UI::setupButtonISR()
|
|
||||||
{
|
|
||||||
UI::Instance()->setupButton.handleButtonState();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup a timer interrupt for updating the GUI. Unfortunately, the standard
|
// Setup a timer interrupt for updating the GUI. Unfortunately, the standard
|
||||||
// libraries that I can find for this, are not equipped to work for the
|
// libraries that I can find for this, are not equipped to work for the
|
||||||
// Arduino Nano 33 IOT architecture. Luckily, documentation and various
|
// Arduino Nano 33 IOT architecture. Luckily, documentation and various
|
||||||
|
@ -91,13 +68,6 @@ namespace Dough
|
||||||
; // Wait for synchronization
|
; // Wait for synchronization
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disables the TC4 interrupts, suspending timed async updates to
|
|
||||||
// the user interface.
|
|
||||||
void UI::suspend()
|
|
||||||
{
|
|
||||||
NVIC_DisableIRQ(TC4_IRQn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enables the TC4 interrupts in the Nested Vector InterruptController (NVIC),
|
// Enables the TC4 interrupts in the Nested Vector InterruptController (NVIC),
|
||||||
// starting timed async updates for the user interface.
|
// starting timed async updates for the user interface.
|
||||||
void UI::resume()
|
void UI::resume()
|
||||||
|
@ -106,6 +76,13 @@ namespace Dough
|
||||||
NVIC_EnableIRQ(TC4_IRQn); // Enable TC4 interrupts
|
NVIC_EnableIRQ(TC4_IRQn); // Enable TC4 interrupts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disables the TC4 interrupts, suspending timed async updates to
|
||||||
|
// the user interface.
|
||||||
|
void UI::suspend()
|
||||||
|
{
|
||||||
|
NVIC_DisableIRQ(TC4_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
// Fire pending button events.
|
// Fire pending button events.
|
||||||
void UI::processButtonEvents()
|
void UI::processButtonEvents()
|
||||||
{
|
{
|
||||||
|
@ -125,7 +102,7 @@ namespace Dough
|
||||||
// the timer interrupt code from above. The timer interrupt based invocation
|
// the timer interrupt code from above. The timer interrupt based invocation
|
||||||
// makes it possible to do LED updates, while the device is busy doing
|
// makes it possible to do LED updates, while the device is busy doing
|
||||||
// something else.
|
// something else.
|
||||||
void UI::updatedLEDs()
|
void UI::updateLEDs()
|
||||||
{
|
{
|
||||||
ledBuiltin.loop();
|
ledBuiltin.loop();
|
||||||
led1.loop();
|
led1.loop();
|
||||||
|
@ -133,7 +110,65 @@ namespace Dough
|
||||||
led3.loop();
|
led3.loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flash all LEDs, one at a time.
|
void UI::notifyConnectingToWifi()
|
||||||
|
{
|
||||||
|
led1.blink()->slow();
|
||||||
|
led2.off();
|
||||||
|
led3.off();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::notifyConnectingToMQTT()
|
||||||
|
{
|
||||||
|
led1.blink()->fast();
|
||||||
|
led2.off();
|
||||||
|
led3.off();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::notifyWaitingForConfiguration()
|
||||||
|
{
|
||||||
|
led1.on();
|
||||||
|
led2.blink()->slow();
|
||||||
|
led3.off();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::notifyCalibrating()
|
||||||
|
{
|
||||||
|
led1.on();
|
||||||
|
led2.blink()->fast();
|
||||||
|
led3.off();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::notifyMeasurementsActive()
|
||||||
|
{
|
||||||
|
led1.on();
|
||||||
|
led2.on();
|
||||||
|
led3.on();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::notifyMeasurementsPaused()
|
||||||
|
{
|
||||||
|
led1.on();
|
||||||
|
led2.on();
|
||||||
|
led3.pulse();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::notifySensorActivity()
|
||||||
|
{
|
||||||
|
led3.off();
|
||||||
|
delay(50);
|
||||||
|
led3.on();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::notifyNetworkActivity()
|
||||||
|
{
|
||||||
|
led1.off();
|
||||||
|
delay(50);
|
||||||
|
led1.on();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flash all LEDs, one at a time in a synchroneous manner, making
|
||||||
|
// this work when the UI timer interrupt is inactive. This is used
|
||||||
|
// as a "Hey, I'm awake!" signal from the device after booting up.
|
||||||
void UI::_flash_all_leds()
|
void UI::_flash_all_leds()
|
||||||
{
|
{
|
||||||
ledBuiltin.on();
|
ledBuiltin.on();
|
||||||
|
@ -149,13 +184,4 @@ namespace Dough
|
||||||
delay(100);
|
delay(100);
|
||||||
led3.off();
|
led3.off();
|
||||||
}
|
}
|
||||||
} // namespace Dough
|
} // namespace Dough
|
||||||
|
|
||||||
// This callback is called when the TC4 timer hits an overflow interrupt.
|
|
||||||
// Defined outside the Dough namespace, because TC4_Handler is a hard-coded
|
|
||||||
// root namespace function name.
|
|
||||||
void TC4_Handler()
|
|
||||||
{
|
|
||||||
Dough::UI::Instance()->updatedLEDs();
|
|
||||||
REG_TC4_INTFLAG = TC_INTFLAG_OVF; // Clear the OVF interrupt flag.
|
|
||||||
}
|
|
61
src/UI/UI.h
61
src/UI/UI.h
|
@ -9,33 +9,40 @@
|
||||||
|
|
||||||
namespace Dough
|
namespace Dough
|
||||||
{
|
{
|
||||||
// This class groups all user interface functionality: serial logging,
|
// This class groups all user interface functionality: serial logging,
|
||||||
// LEDs and buttons.
|
// LEDs and buttons.
|
||||||
class UI
|
class UI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static UI *Instance();
|
UI();
|
||||||
void setup();
|
void setup();
|
||||||
static void onoffButtonISR();
|
static void onoffButtonISR();
|
||||||
static void setupButtonISR();
|
static void setupButtonISR();
|
||||||
Button onoffButton;
|
Button onoffButton;
|
||||||
Button setupButton;
|
Button setupButton;
|
||||||
LED ledBuiltin;
|
LED ledBuiltin;
|
||||||
LED led1;
|
LED led1;
|
||||||
LED led2;
|
LED led2;
|
||||||
LED led3;
|
LED led3;
|
||||||
void processButtonEvents();
|
void processButtonEvents();
|
||||||
void clearButtonEvents();
|
void clearButtonEvents();
|
||||||
void updatedLEDs();
|
void updateLEDs();
|
||||||
void resume();
|
void resume();
|
||||||
void suspend();
|
void suspend();
|
||||||
|
void notifyConnectingToWifi();
|
||||||
|
void notifyConnectingToMQTT();
|
||||||
|
void notifyWaitingForConfiguration();
|
||||||
|
void notifyCalibrating();
|
||||||
|
void notifyMeasurementsActive();
|
||||||
|
void notifyMeasurementsPaused();
|
||||||
|
void notifySensorActivity();
|
||||||
|
void notifyNetworkActivity();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UI();
|
void _setupTimerInterrupt();
|
||||||
void _setupTimerInterrupt();
|
static UI *_instance;
|
||||||
static UI *_instance;
|
void _flash_all_leds();
|
||||||
void _flash_all_leds();
|
};
|
||||||
};
|
} // namespace Dough
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
60
src/main.cpp
60
src/main.cpp
|
@ -1,6 +1,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
// TOOD: implement the calibration logic
|
// TOOD: implement the calibration logic
|
||||||
|
// TODO: don't make sensors instances
|
||||||
// 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: see what more stuff can be moved to the UI code. Maybe state to UI state translation ought to be there as well
|
||||||
|
|
||||||
DoughBoyState state = CONFIGURING;
|
DoughBoyState state = CONFIGURING;
|
||||||
|
@ -10,20 +11,18 @@ void setup()
|
||||||
{
|
{
|
||||||
Dough::Logger::setup();
|
Dough::Logger::setup();
|
||||||
logger.log("s", "Initializing device");
|
logger.log("s", "Initializing device");
|
||||||
Dough::App::Instance()->setup();
|
auto app = Dough::App::Instance();
|
||||||
auto ui = Dough::UI::Instance();
|
app->setup();
|
||||||
ui->setup();
|
app->ui.onoffButton.onPress(handleOnoffButtonPress);
|
||||||
ui->onoffButton.onPress(handleOnoffButtonPress);
|
app->ui.setupButton.onPress(handleSetupButtonPress);
|
||||||
ui->setupButton.onPress(handleSetupButtonPress);
|
|
||||||
logger.log("s", "Initialization completed, starting device");
|
logger.log("s", "Initialization completed, starting device");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
auto app = Dough::App::Instance();
|
auto app = Dough::App::Instance();
|
||||||
auto ui = Dough::UI::Instance();
|
|
||||||
|
|
||||||
ui->processButtonEvents();
|
app->ui.processButtonEvents();
|
||||||
|
|
||||||
if (!setupNetworkConnection())
|
if (!setupNetworkConnection())
|
||||||
{
|
{
|
||||||
|
@ -66,7 +65,6 @@ bool setupNetworkConnection()
|
||||||
static auto connectionState = CONNECTING_WIFI;
|
static auto connectionState = CONNECTING_WIFI;
|
||||||
|
|
||||||
auto app = Dough::App::Instance();
|
auto app = Dough::App::Instance();
|
||||||
auto ui = Dough::UI::Instance();
|
|
||||||
|
|
||||||
if (!app->wifi.isConnected())
|
if (!app->wifi.isConnected())
|
||||||
{
|
{
|
||||||
|
@ -79,9 +77,7 @@ bool setupNetworkConnection()
|
||||||
logger.log("s", "Connecting to the WiFi network ...");
|
logger.log("s", "Connecting to the WiFi network ...");
|
||||||
}
|
}
|
||||||
connectionState = CONNECTING_WIFI;
|
connectionState = CONNECTING_WIFI;
|
||||||
ui->led1.blink()->slow();
|
app->ui.notifyConnectingToWifi();
|
||||||
ui->led2.off();
|
|
||||||
ui->led3.off();
|
|
||||||
app->wifi.connect();
|
app->wifi.connect();
|
||||||
}
|
}
|
||||||
if (app->wifi.isConnected() && !app->mqtt.isConnected())
|
if (app->wifi.isConnected() && !app->mqtt.isConnected())
|
||||||
|
@ -95,9 +91,7 @@ bool setupNetworkConnection()
|
||||||
logger.log("s", "Connecting to the MQTT broker ...");
|
logger.log("s", "Connecting to the MQTT broker ...");
|
||||||
}
|
}
|
||||||
connectionState = CONNECTING_MQTT;
|
connectionState = CONNECTING_MQTT;
|
||||||
ui->led1.blink()->fast();
|
app->ui.notifyConnectingToMQTT();
|
||||||
ui->led2.off();
|
|
||||||
ui->led3.off();
|
|
||||||
app->mqtt.connect();
|
app->mqtt.connect();
|
||||||
delay(1000); // purely costmetic, to make the faster LED blinking noticable
|
delay(1000); // purely costmetic, to make the faster LED blinking noticable
|
||||||
}
|
}
|
||||||
|
@ -106,10 +100,8 @@ bool setupNetworkConnection()
|
||||||
if (connectionState != CONNECTED)
|
if (connectionState != CONNECTED)
|
||||||
{
|
{
|
||||||
logger.log("s", "Connection to MQTT broker established");
|
logger.log("s", "Connection to MQTT broker established");
|
||||||
ui->led1.on();
|
app->ui.notifyConnected();
|
||||||
ui->led2.off();
|
app->ui.clearButtonEvents();
|
||||||
ui->led3.off();
|
|
||||||
ui->clearButtonEvents();
|
|
||||||
connectionState = CONNECTED;
|
connectionState = CONNECTED;
|
||||||
setStateToConfiguring();
|
setStateToConfiguring();
|
||||||
}
|
}
|
||||||
|
@ -137,44 +129,36 @@ void handleSetupButtonPress()
|
||||||
|
|
||||||
void setStateToConfiguring()
|
void setStateToConfiguring()
|
||||||
{
|
{
|
||||||
auto ui = Dough::UI::Instance();
|
auto app = Dough::App::Instance();
|
||||||
logger.log("s", "Waiting for configuration ...");
|
logger.log("s", "Waiting for configuration ...");
|
||||||
state = CONFIGURING;
|
state = CONFIGURING;
|
||||||
ui->led1.on();
|
app->ui.notifyWaitingForConfiguration();
|
||||||
ui->led2.blink()->fast();
|
app->mqtt.publish("state", "configuring");
|
||||||
ui->led3.off();
|
|
||||||
Dough::App::Instance()->mqtt.publish("state", "configuring");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStateToMeasuring()
|
void setStateToMeasuring()
|
||||||
{
|
{
|
||||||
auto ui = Dough::UI::Instance();
|
auto app = Dough::App::Instance();
|
||||||
logger.log("s", "Starting measurements");
|
logger.log("s", "Starting measurements");
|
||||||
state = MEASURING;
|
state = MEASURING;
|
||||||
ui->led1.on();
|
app->ui.notifyMeasurementsActive();
|
||||||
ui->led2.on();
|
app->mqtt.publish("state", "measuring");
|
||||||
ui->led3.on();
|
|
||||||
Dough::App::Instance()->mqtt.publish("state", "measuring");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStateToPaused()
|
void setStateToPaused()
|
||||||
{
|
{
|
||||||
auto ui = Dough::UI::Instance();
|
auto app = Dough::App::Instance();
|
||||||
logger.log("s", "Pausing measurements");
|
logger.log("s", "Pausing measurements");
|
||||||
state = PAUSED;
|
state = PAUSED;
|
||||||
ui->led1.on();
|
app->ui.notifyMeasurementsPaused();
|
||||||
ui->led2.on();
|
app->mqtt.publish("state", "paused");
|
||||||
ui->led3.pulse();
|
|
||||||
Dough::App::Instance()->mqtt.publish("state", "paused");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStateToCalibrating()
|
void setStateToCalibrating()
|
||||||
{
|
{
|
||||||
auto ui = Dough::UI::Instance();
|
auto app = Dough::App::Instance();
|
||||||
logger.log("s", "Requested device calibration");
|
logger.log("s", "Requested device calibration");
|
||||||
state = CALIBRATING;
|
state = CALIBRATING;
|
||||||
ui->led1.on();
|
app->ui.notifyCalibrating();
|
||||||
ui->led2.blink()->slow();
|
app->mqtt.publish("state", "calibrating");
|
||||||
ui->led3.off();
|
|
||||||
Dough::App::Instance()->mqtt.publish("state", "calibrating");
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue