249 lines
7.1 KiB
C++
249 lines
7.1 KiB
C++
#pragma once
|
|
|
|
#include <Adafruit_LEDBackpack.h> // Support for the Backpack FeatherWing
|
|
#include <Adafruit_GFX.h> // Adafruit's graphics library
|
|
#include <Adafruit_I2CDevice.h>
|
|
#include <SPI.h>
|
|
#include "ntp_time.h"
|
|
#include "bme.h"
|
|
#include "timer.h"
|
|
|
|
#define DISPLAY_ADDRESS 0x70
|
|
#define MILLISECONDS(value) value*TASK_MILLISECOND
|
|
#define SECONDS(value) value*TASK_SECOND
|
|
#define MINUTES(value) value*TASK_MINUTE
|
|
#define DISPLAY_SENSOR_ITERATIONS 2+1
|
|
#define DISPLAY_DELAY (SECONDS(2))
|
|
|
|
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 displayDate();
|
|
void displayTemp();
|
|
void displayHumidity();
|
|
void drawTime();
|
|
void drawColon(bool);
|
|
Task tDisplayTime(MILLISECONDS(500), TASK_FOREVER, displayTime, &ts, false,
|
|
[]() {
|
|
drawTime();
|
|
return true;
|
|
},
|
|
[]() {
|
|
drawColon(false);
|
|
});
|
|
Task tDisplaySensor(SECONDS(5), DISPLAY_SENSOR_ITERATIONS, nullptr, &ts, false,
|
|
[]() {
|
|
tDisplaySensor.setCallback(displayTemp);
|
|
return true;
|
|
},
|
|
[]() {
|
|
tDisplaySensor.setIterations(DISPLAY_SENSOR_ITERATIONS);
|
|
displayTask.restorePerm();
|
|
});
|
|
Task tDisplayDate(SECONDS(5), TASK_ONCE + 1, displayDate, &ts, false, nullptr,
|
|
[]() {
|
|
displayTask.restorePerm();
|
|
});
|
|
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;
|
|
},
|
|
[]{
|
|
displayTask.activate(tDisplayTime);
|
|
});
|
|
|
|
struct HourFormat : public CallbackAware<callback_t> {
|
|
|
|
operator bool() {
|
|
return format24;
|
|
}
|
|
|
|
void operator=(bool value) {
|
|
format24 = value;
|
|
if (displayTask.isPerm(tDisplayTime)) drawTime();
|
|
if (callback) callback();
|
|
}
|
|
private:
|
|
bool format24 = false;
|
|
} hourFormat24;
|
|
|
|
struct Brightness : public CallbackAware<callback_t> {
|
|
static constexpr uint8 MIN = 0;
|
|
static constexpr uint8 MAX = 15;
|
|
static constexpr uint8 DAY = 11;
|
|
static constexpr uint8 NIGHT = MIN;
|
|
|
|
void operator=(uint8 value) {
|
|
current = value % (MAX + 1);
|
|
clockDisplay.setBrightness(current);
|
|
if (callback) callback();
|
|
}
|
|
|
|
operator uint8() {
|
|
return current;
|
|
}
|
|
|
|
private:
|
|
uint8 current = NIGHT;
|
|
} brightness;
|
|
|
|
void drawTime() {
|
|
int displayHour = hourFormat24 ? hour() : hourFormat12();
|
|
int displayMinute = minute();
|
|
int displayValue = displayHour * 100 + displayMinute;
|
|
|
|
// Print the time on the display
|
|
clockDisplay.print(displayValue, DEC);
|
|
|
|
// Add zero padding when in 24 hour mode and it's midnight.
|
|
// In this case the print function above won't have leading 0's
|
|
// which can look confusing. Go in and explicitly add these zeros.
|
|
if (displayHour == 0) {
|
|
clockDisplay.writeDigitNum(1, 0);
|
|
if (displayMinute < 10) {
|
|
clockDisplay.writeDigitNum(3, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void drawColon(bool colonOn) {
|
|
if (colonOn) {
|
|
static int currentHour = -1;
|
|
if (currentHour != hour()) {
|
|
currentHour = hour();
|
|
if (currentHour == 4) {
|
|
Ntp::tUpdateTime.restart();
|
|
}
|
|
if (currentHour == 8) {
|
|
brightness = Brightness::DAY;
|
|
Wifi::tConnect.enable();
|
|
}
|
|
if (currentHour == 17) {
|
|
brightness = Brightness::NIGHT;
|
|
}
|
|
}
|
|
static int currentMin = -1;
|
|
if (currentMin != minute()) {
|
|
currentMin = minute();
|
|
drawTime();
|
|
}
|
|
}
|
|
clockDisplay.drawColon(colonOn);
|
|
}
|
|
|
|
void displayTime() {
|
|
static bool colonOn = true;
|
|
|
|
drawColon(colonOn);
|
|
clockDisplay.writeDisplay();
|
|
|
|
colonOn = !colonOn;
|
|
}
|
|
|
|
void displayTemp() {
|
|
clockDisplay.printFloat(Bme::data.temp, 2);
|
|
clockDisplay.writeDigitAscii(4, 'c');
|
|
clockDisplay.writeDisplay();
|
|
tDisplaySensor.setCallback(&displayHumidity);
|
|
}
|
|
|
|
void displayHumidity() {
|
|
clockDisplay.printFloat(Bme::data.humidity, 2);
|
|
clockDisplay.writeDigitAscii(4, '%');
|
|
clockDisplay.writeDisplay();
|
|
tDisplaySensor.setCallback(&displayTemp);
|
|
}
|
|
|
|
void displayValue(uint8 value) {
|
|
tDisplayTime.disable();
|
|
clockDisplay.print(value, HEX);
|
|
clockDisplay.writeDisplay();
|
|
tDisplayTime.enableDelayed(DISPLAY_DELAY);
|
|
}
|
|
|
|
void displayText(const char c[]) {
|
|
tDisplayTime.disable();
|
|
clockDisplay.println(c);
|
|
clockDisplay.writeDisplay();
|
|
tDisplayTime.enableDelayed(DISPLAY_DELAY);
|
|
}
|
|
|
|
unordered_map<char, const char*> daysOfWeek = {
|
|
{1, "So"},
|
|
{2, "Mo"},
|
|
{3, "Di"},
|
|
{4, "Mi"},
|
|
{5, "Do"},
|
|
{6, "Fr"},
|
|
{7, "Sa"},
|
|
};
|
|
void displayDate() {
|
|
char date[5];
|
|
sprintf(date, "%2s%2u", daysOfWeek[weekday()], day());
|
|
clockDisplay.println(date);
|
|
clockDisplay.writeDisplay();
|
|
}
|
|
|
|
void setup() {
|
|
clockDisplay.begin(DISPLAY_ADDRESS);
|
|
clockDisplay.setBrightness(brightness);
|
|
displayTask.activate(tDisplayTime);
|
|
}
|
|
}
|