mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-08 22:22:05 +00:00
Added IAQ alert and new Overlay Alert Banner function
This commit is contained in:
parent
9a57a774f6
commit
bc1cc0081f
@ -84,6 +84,8 @@ namespace graphics
|
|||||||
// A text message frame + debug frame + all the node infos
|
// A text message frame + debug frame + all the node infos
|
||||||
FrameCallback *normalFrames;
|
FrameCallback *normalFrames;
|
||||||
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
||||||
|
static String alertBannerMessage;
|
||||||
|
static uint32_t alertBannerUntil = 0;
|
||||||
|
|
||||||
uint32_t logo_timeout = 5000; // 4 seconds for EACH logo
|
uint32_t logo_timeout = 5000; // 4 seconds for EACH logo
|
||||||
|
|
||||||
@ -296,6 +298,53 @@ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==============================
|
||||||
|
// Overlay Alert Banner Renderer
|
||||||
|
// ==============================
|
||||||
|
// Displays a temporary centered banner message (e.g., warning, status, etc.)
|
||||||
|
// The banner appears in the center of the screen and disappears after the specified duration
|
||||||
|
|
||||||
|
// Called to trigger a banner with custom message and duration
|
||||||
|
void Screen::showOverlayBanner(const String &message, uint32_t durationMs)
|
||||||
|
{
|
||||||
|
// Store the message and set the expiration timestamp
|
||||||
|
alertBannerMessage = message;
|
||||||
|
alertBannerUntil = millis() + durationMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draws the overlay banner on screen, if still within display duration
|
||||||
|
static void drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||||
|
{
|
||||||
|
// Exit if no message is active or duration has passed
|
||||||
|
if (alertBannerMessage.length() == 0 || millis() > alertBannerUntil) return;
|
||||||
|
|
||||||
|
// === Layout Configuration ===
|
||||||
|
constexpr uint16_t padding = 5; // Padding around the text
|
||||||
|
constexpr uint8_t imprecision = 3; // Pixel jitter to reduce burn-in on E-Ink
|
||||||
|
|
||||||
|
// Setup font and alignment
|
||||||
|
display->setFont(FONT_SMALL);
|
||||||
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
|
||||||
|
// === Measure and position the box ===
|
||||||
|
uint16_t textWidth = display->getStringWidth(alertBannerMessage.c_str(), alertBannerMessage.length(), true);
|
||||||
|
uint16_t boxWidth = padding * 2 + textWidth;
|
||||||
|
uint16_t boxHeight = FONT_HEIGHT_SMALL + padding * 2;
|
||||||
|
|
||||||
|
int16_t boxLeft = (display->width() / 2) - (boxWidth / 2) + random(-imprecision, imprecision + 1);
|
||||||
|
int16_t boxTop = (display->height() / 2) - (boxHeight / 2) + random(-imprecision, imprecision + 1);
|
||||||
|
|
||||||
|
// === Draw background box ===
|
||||||
|
display->setColor(BLACK);
|
||||||
|
display->fillRect(boxLeft - 1, boxTop - 1, boxWidth + 2, boxHeight + 2); // Slightly oversized box
|
||||||
|
display->setColor(WHITE);
|
||||||
|
display->drawRect(boxLeft, boxTop, boxWidth, boxHeight); // Border
|
||||||
|
|
||||||
|
// === Draw the text (twice for faux bold) ===
|
||||||
|
display->drawString(boxLeft + padding, boxTop + padding, alertBannerMessage);
|
||||||
|
display->drawString(boxLeft + padding + 1, boxTop + padding, alertBannerMessage); // Faux bold effect
|
||||||
|
}
|
||||||
|
|
||||||
// draw overlay in bottom right corner of screen to show when notifications are muted or modifier key is active
|
// draw overlay in bottom right corner of screen to show when notifications are muted or modifier key is active
|
||||||
static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||||
{
|
{
|
||||||
@ -3576,7 +3625,7 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
ui->disableAllIndicators();
|
ui->disableAllIndicators();
|
||||||
|
|
||||||
// Add function overlay here. This can show when notifications muted, modifier key is active etc
|
// Add function overlay here. This can show when notifications muted, modifier key is active etc
|
||||||
static OverlayCallback overlays[] = {drawFunctionOverlay, drawCustomFrameIcons};
|
static OverlayCallback overlays[] = {drawFunctionOverlay, drawCustomFrameIcons, drawAlertBannerOverlay};
|
||||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||||
|
|
||||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
||||||
|
@ -261,6 +261,8 @@ class Screen : public concurrency::OSThread
|
|||||||
enqueueCmd(cmd);
|
enqueueCmd(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showOverlayBanner(const String &message, uint32_t durationMs = 3000);
|
||||||
|
|
||||||
void startFirmwareUpdateScreen()
|
void startFirmwareUpdateScreen()
|
||||||
{
|
{
|
||||||
ScreenCmd cmd;
|
ScreenCmd cmd;
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#include <OLEDDisplayUi.h>
|
#include <OLEDDisplayUi.h>
|
||||||
#include "graphics/SharedUIDisplay.h"
|
#include "graphics/SharedUIDisplay.h"
|
||||||
#include "graphics/images.h"
|
#include "graphics/images.h"
|
||||||
|
#include "buzz.h"
|
||||||
|
#include "modules/ExternalNotificationModule.h"
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||||
// Sensors
|
// Sensors
|
||||||
@ -398,19 +400,35 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
|||||||
entries.push_back("Hum: " + String(m.relative_humidity, 0) + "%");
|
entries.push_back("Hum: " + String(m.relative_humidity, 0) + "%");
|
||||||
if (m.barometric_pressure != 0)
|
if (m.barometric_pressure != 0)
|
||||||
entries.push_back("Prss: " + String(m.barometric_pressure, 0) + " hPa");
|
entries.push_back("Prss: " + String(m.barometric_pressure, 0) + " hPa");
|
||||||
if (m.iaq != 0) {
|
if (m.iaq != 0) {
|
||||||
String aqi = "IAQ: " + String(m.iaq);
|
String aqi = "IAQ: " + String(m.iaq);
|
||||||
|
|
||||||
if (m.iaq <= 50) aqi += " (Good)";
|
if (m.iaq <= 50) aqi += " (Good)";
|
||||||
else if (m.iaq <= 100) aqi += " (Moderate)";
|
else if (m.iaq <= 100) aqi += " (Moderate)";
|
||||||
else if (m.iaq <= 150) aqi += " (Poor)";
|
else if (m.iaq <= 150) aqi += " (Poor)";
|
||||||
else if (m.iaq <= 200) aqi += " (Unhealthy)";
|
else if (m.iaq <= 200) aqi += " (Unhealthy)";
|
||||||
else if (m.iaq <= 250) aqi += " (Very Unhealthy)";
|
else if (m.iaq <= 250) aqi += " (Very Unhealthy)";
|
||||||
else if (m.iaq <= 350) aqi += " (Hazardous)";
|
else if (m.iaq <= 350) aqi += " (Hazardous)";
|
||||||
else aqi += " (Extreme)";
|
else aqi += " (Extreme)";
|
||||||
|
|
||||||
entries.push_back(aqi);
|
entries.push_back(aqi);
|
||||||
|
|
||||||
|
// === IAQ alert logic ===
|
||||||
|
static uint32_t lastAlertTime = 0;
|
||||||
|
uint32_t now = millis();
|
||||||
|
|
||||||
|
bool isOwnTelemetry = lastMeasurementPacket->from == nodeDB->getNodeNum();
|
||||||
|
bool isIAQAlert = m.iaq > 100 && (now - lastAlertTime > 60000);
|
||||||
|
|
||||||
|
if (isOwnTelemetry && isIAQAlert) {
|
||||||
|
LOG_INFO("drawFrame: IAQ %d (own) — showing banner", m.iaq);
|
||||||
|
screen->showOverlayBanner("Unhealthy IAQ Levels", 3000); // Always show banner
|
||||||
|
if (moduleConfig.external_notification.enabled && !externalNotificationModule->getMute()) {
|
||||||
|
playLongBeep(); // Only buzz if not muted
|
||||||
|
}
|
||||||
|
lastAlertTime = now;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (m.voltage != 0 || m.current != 0)
|
if (m.voltage != 0 || m.current != 0)
|
||||||
entries.push_back(String(m.voltage, 1) + "V / " + String(m.current, 0) + "mA");
|
entries.push_back(String(m.voltage, 1) + "V / " + String(m.current, 0) + "mA");
|
||||||
if (m.lux != 0)
|
if (m.lux != 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user