Merge branch 'display-task-improvements'

This commit is contained in:
Nicu Hodos 2025-02-12 18:12:39 +01:00
commit 71a5e96994
5 changed files with 126 additions and 116 deletions

View File

@ -49,7 +49,7 @@ namespace Devices {
Number* displayTimerMqtt = Builder<Number>::instance(new Number{ "Timer duration", "timer_duration", Number* displayTimerMqtt = Builder<Number>::instance(new Number{ "Timer duration", "timer_duration",
[](const char* msg) { [](const char* msg) {
auto value = String{ msg }.toInt(); auto value = String{ msg }.toInt();
Display::Timer::timer = value; timer = value;
displayTimerMqtt->updateState(value); displayTimerMqtt->updateState(value);
} }
}).withMin(0).withMax(90).withStep(5).restoreStateFromCommand().build(); }).withMin(0).withMax(90).withStep(5).restoreStateFromCommand().build();
@ -58,10 +58,10 @@ namespace Devices {
Switch* timerMqtt = Builder<Switch>::instance(new Switch{"Timer", "timer", Switch* timerMqtt = Builder<Switch>::instance(new Switch{"Timer", "timer",
[](const char* msg) { [](const char* msg) {
if (strcmp("ON", msg) == 0) { if (strcmp("ON", msg) == 0) {
Display::Timer::start(); Display::tTimer.restart();
timerMqtt->updateState(true); timerMqtt->updateState(true);
} else { } else {
Display::Timer::stop(); Display::tTimer.disable();
timerMqtt->updateState(false); timerMqtt->updateState(false);
} }
} }
@ -77,10 +77,9 @@ namespace Devices {
.addSecondary( .addSecondary(
Builder<Button>::instance(new Button{"Display sensor data", "display_sensor_data", Builder<Button>::instance(new Button{"Display sensor data", "display_sensor_data",
[](const char* msg) { [](const char* msg) {
if (strcmp("PRESS", msg) == 0 && !Display::tDisplaySensor.isEnabled()) { if (strcmp("PRESS", msg) == 0) {
Bme::data.readAll(); Bme::data.readAll();
Display::tDisplaySensor.setIterations(DISPLAY_SENSOR_ITERATIONS); Display::displayTask.activate(Display::tDisplaySensor);
Display::tDisplaySensor.restart();
}; };
} }
}).build() }).build()
@ -88,8 +87,8 @@ namespace Devices {
.addSecondary( .addSecondary(
Builder<Button>::instance(new Button{"Display date", "display_date", Builder<Button>::instance(new Button{"Display date", "display_date",
[](const char* msg) { [](const char* msg) {
if (strcmp("PRESS", msg) == 0 && !Display::tDisplayDate.isEnabled()) { if (strcmp("PRESS", msg) == 0) {
Display::tDisplayDate.restart(); Display::displayTask.activate(Display::tDisplayDate);
}; };
} }
}).build() }).build()
@ -97,8 +96,8 @@ namespace Devices {
.addSecondary( .addSecondary(
Builder<Button>::instance(new Button{"Display remaining timer", "display_remaining_timer", Builder<Button>::instance(new Button{"Display remaining timer", "display_remaining_timer",
[](const char* msg) { [](const char* msg) {
if (strcmp("PRESS", msg) == 0 && !Display::Timer::tDisplayTimer.isEnabled()) { if (strcmp("PRESS", msg) == 0) {
Display::Timer::tDisplayTimer.restart(); Display::displayTask.activate(Display::tDisplayTimer);
} }
} }
}).build() }).build()
@ -137,7 +136,7 @@ namespace Devices {
Display::brightness.registerCallback([]{ Display::brightness.registerCallback([]{
brightnessMqtt->updateState(Display::brightness); brightnessMqtt->updateState(Display::brightness);
}); });
Display::Timer::timer.registerCallback([](int8 current){ timer.registerCallback([](int8 current){
timerRemainingMqtt->updateState(to_string(current).c_str()); timerRemainingMqtt->updateState(to_string(current).c_str());
}); });
} }

View File

@ -6,6 +6,7 @@
#include <SPI.h> #include <SPI.h>
#include "ntp_time.h" #include "ntp_time.h"
#include "bme.h" #include "bme.h"
#include "timer.h"
#define DISPLAY_ADDRESS 0x70 #define DISPLAY_ADDRESS 0x70
#define MILLISECONDS(value) value*TASK_MILLISECOND #define MILLISECONDS(value) value*TASK_MILLISECOND
@ -14,19 +15,41 @@
#define DISPLAY_SENSOR_ITERATIONS 2+1 #define DISPLAY_SENSOR_ITERATIONS 2+1
#define DISPLAY_DELAY (SECONDS(2)) #define DISPLAY_DELAY (SECONDS(2))
typedef void (*callback_t)();
template <typename T>
struct CallbackAware {
void registerCallback(T f) {
callback = f;
}
protected:
T callback;
};
namespace Display { namespace Display {
// Create display object
Adafruit_7segment clockDisplay = Adafruit_7segment();
struct {
operator Task&() {
return *perm;
}
bool activate(Task& task) {
if (task.isEnabled()) return false;
if (temp) temp->cancel();
if (perm) perm->cancel();
if (task.getIterations() == TASK_FOREVER) {
perm = &task;
return task.enable();
} else {
temp = &task;
return task.restart();
}
}
void restorePerm() {
if (temp && temp->isEnabled()) return; // don't enable perm when triggered by another temp on top of exsting temp
if (perm) perm->enable();
}
bool isPerm(Task& task) {
return perm == &task;
}
private:
Task *temp = nullptr, *perm = nullptr;
} displayTask;
void displayTime(); void displayTime();
void displayDate(); void displayDate();
void displayTemp(); void displayTemp();
@ -43,23 +66,46 @@ namespace Display {
}); });
Task tDisplaySensor(SECONDS(5), DISPLAY_SENSOR_ITERATIONS, nullptr, &ts, false, Task tDisplaySensor(SECONDS(5), DISPLAY_SENSOR_ITERATIONS, nullptr, &ts, false,
[]() { []() {
if (!tDisplayTime.isEnabled()) return false;
tDisplayTime.disable();
tDisplaySensor.setCallback(displayTemp); tDisplaySensor.setCallback(displayTemp);
return true; return true;
}, },
[]() { []() {
tDisplaySensor.setIterations((DISPLAY_SENSOR_ITERATIONS - 1) * 2 + 1); tDisplaySensor.setIterations(DISPLAY_SENSOR_ITERATIONS);
tDisplayTime.enable(); displayTask.restorePerm();
}); });
Task tDisplayDate(SECONDS(5), TASK_ONCE + 1, displayDate, &ts, false, Task tDisplayDate(SECONDS(5), TASK_ONCE + 1, displayDate, &ts, false, nullptr,
[]() { []() {
if (!tDisplayTime.isEnabled()) return false; displayTask.restorePerm();
tDisplayTime.disable(); });
Task tDisplayTimer(SECONDS(10), TASK_ONCE + 1,
[]{
if (timer >= 0) {
clockDisplay.print(timer, DEC);
clockDisplay.writeDisplay();
}
}, &ts, false, nullptr,
[]{
tDisplayTimer.setIterations(TASK_ONCE + 1);
if (!displayTask.isPerm(tDisplayTimer)) displayTask.restorePerm();
});
Task tTimer(MINUTES(1), TASK_FOREVER,
[]{
static constexpr uint8 threshold = 16;
timer.decrease();
if (timer.atBeginning()) {
if (timer <= threshold) tDisplayTimer.setIterations(TASK_FOREVER);
displayTask.activate(tDisplayTimer);
} else if (timer == threshold) {
tDisplayTimer.setIterations(TASK_FOREVER);
displayTask.activate(tDisplayTimer);
}
}, &ts, false,
[]{
timer.start();
return true; return true;
}, },
[]() { []{
tDisplayTime.enable(); displayTask.activate(tDisplayTime);
}); });
struct HourFormat : public CallbackAware<callback_t> { struct HourFormat : public CallbackAware<callback_t> {
@ -70,16 +116,13 @@ namespace Display {
void operator=(bool value) { void operator=(bool value) {
format24 = value; format24 = value;
tDisplayTime.restart(); if (displayTask.isPerm(tDisplayTime)) drawTime();
if (callback) callback(); if (callback) callback();
} }
private: private:
bool format24 = false; bool format24 = false;
} hourFormat24; } hourFormat24;
// Create display object
Adafruit_7segment clockDisplay = Adafruit_7segment();
struct Brightness : public CallbackAware<callback_t> { struct Brightness : public CallbackAware<callback_t> {
static constexpr uint8 MIN = 0; static constexpr uint8 MIN = 0;
static constexpr uint8 MAX = 15; static constexpr uint8 MAX = 15;
@ -100,80 +143,6 @@ namespace Display {
uint8 current = NIGHT; uint8 current = NIGHT;
} brightness; } brightness;
namespace Timer {
typedef void (*remaining_callback_t)(int8);
struct : public CallbackAware<remaining_callback_t> {
void operator=(int8 value) {
initial = remaining = value;
}
operator int8() {
return remaining;
}
void start() {
remaining = initial + 1;
}
void decrease() {
remaining--;
if (callback) callback(remaining);
}
bool atBeginning() {
return initial == remaining;
}
private:
int8 initial = 0, remaining = 0;
} timer;
Task tDisplayTimer(SECONDS(10), TASK_ONCE + 1,
[]{
if (timer >= 0) {
clockDisplay.print(timer, DEC);
clockDisplay.writeDisplay();
}
}, &ts, false,
[]{
if (!tDisplayTime.isEnabled()) return false;
tDisplayTime.disable();
return true;
},
[]{
tDisplayTimer.setIterations(TASK_ONCE + 1);
tDisplayTime.enable();
});
Task tTimer(MINUTES(1), TASK_FOREVER,
[]{
static constexpr uint8 threshold = 16;
timer.decrease();
if (timer.atBeginning()) {
if (timer <= threshold) tDisplayTimer.setIterations(TASK_FOREVER);
tDisplayTimer.restart();
} else if (timer == threshold) {
tDisplayTimer.setIterations(TASK_FOREVER);
tDisplayTimer.restart();
}
}, &ts, false,
[]{
timer.start();
return true;
},
[]{
tDisplayTimer.disable();
});
void start() {
tTimer.restart();
}
void stop() {
tTimer.disable();
}
}
void drawTime() { void drawTime() {
int displayHour = hourFormat24 ? hour() : hourFormat12(); int displayHour = hourFormat24 ? hour() : hourFormat12();
int displayMinute = minute(); int displayMinute = minute();
@ -274,6 +243,6 @@ namespace Display {
void setup() { void setup() {
clockDisplay.begin(DISPLAY_ADDRESS); clockDisplay.begin(DISPLAY_ADDRESS);
clockDisplay.setBrightness(brightness); clockDisplay.setBrightness(brightness);
tDisplayTime.enable(); displayTask.activate(tDisplayTime);
} }
} }

12
include/helper.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
typedef void (*callback_t)();
template <typename T>
struct CallbackAware {
void registerCallback(T f) {
callback = f;
}
protected:
T callback;
};

31
include/timer.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include "helper.h"
typedef void (*remaining_callback_t)(int8);
struct : public CallbackAware<remaining_callback_t> {
void operator=(int8 value) {
initial = remaining = value;
}
operator int8() {
return remaining;
}
void start() {
remaining = initial + 1;
}
void decrease() {
remaining--;
if (callback) callback(remaining);
}
bool atBeginning() {
return initial == remaining;
}
private:
int8 initial = 0, remaining = 0;
} timer;

View File

@ -28,10 +28,7 @@ void turnLed(bool on = true) {
Task tButton(TASK_IMMEDIATE, TASK_ONCE, Task tButton(TASK_IMMEDIATE, TASK_ONCE,
[]() { []() {
if (Display::tDisplaySensor.isEnabled()) return; if (Display::displayTask.activate(Display::tDisplaySensor)) Bme::data.readAll();
Bme::data.readAll();
Display::tDisplaySensor.setIterations(DISPLAY_SENSOR_ITERATIONS);
Display::tDisplaySensor.restart();
}, &ts); }, &ts);
Task tLed(TASK_IMMEDIATE, TASK_ONCE, Task tLed(TASK_IMMEDIATE, TASK_ONCE,
[]() { []() {
@ -46,7 +43,8 @@ Task tReadBme(TASK_MINUTE, TASK_FOREVER, []() {
Devices::publishBme280(); Devices::publishBme280();
if (abs(lastTemp - Bme::data.temp) > 0.2) { if (abs(lastTemp - Bme::data.temp) > 0.2) {
lastTemp = Bme::data.temp; lastTemp = Bme::data.temp;
Display::tDisplaySensor.restart(); Display::tDisplaySensor.setIterations((DISPLAY_SENSOR_ITERATIONS - 1) * 2 + 1);
Display::displayTask.activate(Display::tDisplaySensor);
} }
}, &ts); }, &ts);
@ -89,7 +87,8 @@ void setup() {
attachInterrupt(digitalPinToInterrupt(BUTTON), onButtonPressed, FALLING); attachInterrupt(digitalPinToInterrupt(BUTTON), onButtonPressed, FALLING);
attachInterrupt(digitalPinToInterrupt(LED_BUILTIN), onLed, CHANGE); attachInterrupt(digitalPinToInterrupt(LED_BUILTIN), onLed, CHANGE);
tReadBme.enable(); tReadBme.enableDelayed();
tButton.restart();
} }
void loop() { void loop() {