diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 976625594..753283e34 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -31,6 +31,7 @@ along with this program. If not, see .
#include "draw/DebugRenderer.h"
#include "draw/MessageRenderer.h"
#include "draw/NodeListRenderer.h"
+#include "draw/NotificationRenderer.h"
#include "draw/UIRenderer.h"
#if !MESHTASTIC_EXCLUDE_GPS
#include "GPS.h"
@@ -76,8 +77,6 @@ using graphics::NodeListRenderer::drawScaledXBitmap16x16;
#endif
#ifdef ARCH_ESP32
-#include "esp_task_wdt.h"
-#include "modules/StoreForwardModule.h"
#endif
#if ARCH_PORTDUINO
@@ -141,61 +140,6 @@ static bool heartbeat = false;
#include "graphics/ScreenFonts.h"
#include
-// Start Functions to write date/time to the screen
-#include // Only needed if you're using std::string elsewhere
-
-bool isLeapYear(int year)
-{
- return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
-}
-
-const int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-// Fills the buffer with a formatted date/time string and returns pixel width
-int formatDateTime(char *buf, size_t bufSize, uint32_t rtc_sec, OLEDDisplay *display, bool includeTime)
-{
- int sec = rtc_sec % 60;
- rtc_sec /= 60;
- int min = rtc_sec % 60;
- rtc_sec /= 60;
- int hour = rtc_sec % 24;
- rtc_sec /= 24;
-
- int year = 1970;
- while (true) {
- int daysInYear = isLeapYear(year) ? 366 : 365;
- if (rtc_sec >= (uint32_t)daysInYear) {
- rtc_sec -= daysInYear;
- year++;
- } else {
- break;
- }
- }
-
- int month = 0;
- while (month < 12) {
- int dim = daysInMonth[month];
- if (month == 1 && isLeapYear(year))
- dim++;
- if (rtc_sec >= (uint32_t)dim) {
- rtc_sec -= dim;
- month++;
- } else {
- break;
- }
- }
-
- int day = rtc_sec + 1;
-
- if (includeTime) {
- snprintf(buf, bufSize, "%04d-%02d-%02d %02d:%02d:%02d", year, month + 1, day, hour, min, sec);
- } else {
- snprintf(buf, bufSize, "%04d-%02d-%02d", year, month + 1, day);
- }
-
- return display->getStringWidth(buf);
-}
-
// Usage: int stringWidth = formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display);
// End Functions to write date/time to the screen
@@ -367,51 +311,6 @@ void Screen::drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int1
display->setFont(FONT_MEDIUM);
display->drawString(x_offset + x, 26 + y, message);
}
-
-// Used on boot when a certificate is being created
-static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
-{
- display->setTextAlignment(TEXT_ALIGN_CENTER);
- display->setFont(FONT_SMALL);
- display->drawString(64 + x, y, "Creating SSL certificate");
-
-#ifdef ARCH_ESP32
- yield();
- esp_task_wdt_reset();
-#endif
-
- display->setFont(FONT_SMALL);
- if ((millis() / 1000) % 2) {
- display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . .");
- } else {
- display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ");
- }
-}
-
-// Used when booting without a region set
-static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
-{
- display->setFont(FONT_SMALL);
- display->setTextAlignment(TEXT_ALIGN_CENTER);
- display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
- display->drawString(64 + x, y + FONT_HEIGHT_SMALL, getDeviceName());
- display->setTextAlignment(TEXT_ALIGN_LEFT);
-
- if ((millis() / 10000) % 2) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the");
- display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,");
- display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Web or CLI clients.");
- } else {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Visit meshtastic.org");
- display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "for more information.");
- display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "");
- }
-
-#ifdef ARCH_ESP32
- yield();
- esp_task_wdt_reset();
-#endif
-}
// ==============================
// Overlay Alert Banner Renderer
// ==============================
@@ -426,79 +325,6 @@ void Screen::showOverlayBanner(const String &message, uint32_t durationMs)
alertBannerUntil = (durationMs == 0) ? 0 : 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 || (alertBannerUntil != 0 && millis() > alertBannerUntil))
- return;
-
- // === Layout Configuration ===
- constexpr uint16_t padding = 5; // Padding around text inside the box
- constexpr uint8_t lineSpacing = 1; // Extra space between lines
-
- // Search the mesage to determine if we need the bell added
- bool needs_bell = (alertBannerMessage.indexOf("Alert Received") != -1);
-
- // Setup font and alignment
- display->setFont(FONT_SMALL);
- display->setTextAlignment(TEXT_ALIGN_LEFT); // We will manually center per line
-
- // === Split the message into lines (supports multi-line banners) ===
- std::vector lines;
- int start = 0, newlineIdx;
- while ((newlineIdx = alertBannerMessage.indexOf('\n', start)) != -1) {
- lines.push_back(alertBannerMessage.substring(start, newlineIdx));
- start = newlineIdx + 1;
- }
- lines.push_back(alertBannerMessage.substring(start));
-
- // === Measure text dimensions ===
- uint16_t minWidth = (SCREEN_WIDTH > 128) ? 106 : 78;
- uint16_t maxWidth = 0;
- std::vector lineWidths;
- for (const auto &line : lines) {
- uint16_t w = display->getStringWidth(line.c_str(), line.length(), true);
- lineWidths.push_back(w);
- if (w > maxWidth)
- maxWidth = w;
- }
-
- uint16_t boxWidth = padding * 2 + maxWidth;
- if (needs_bell && boxWidth < minWidth)
- boxWidth += (SCREEN_WIDTH > 128) ? 26 : 20;
-
- uint16_t boxHeight = padding * 2 + lines.size() * FONT_HEIGHT_SMALL + (lines.size() - 1) * lineSpacing;
-
- int16_t boxLeft = (display->width() / 2) - (boxWidth / 2);
- int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
-
- // === 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 each line centered in the box ===
- int16_t lineY = boxTop + padding;
- for (size_t i = 0; i < lines.size(); ++i) {
- int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2;
- uint16_t line_width = display->getStringWidth(lines[i].c_str(), lines[i].length(), true);
-
- if (needs_bell && i == 0) {
- int bellY = lineY + (FONT_HEIGHT_SMALL - 8) / 2;
- display->drawXbm(textX - 10, bellY, 8, 8, bell_alert);
- display->drawXbm(textX + line_width + 2, bellY, 8, 8, bell_alert);
- }
-
- display->drawString(textX, lineY, lines[i]);
- if (SCREEN_WIDTH > 128)
- display->drawString(textX + 1, lineY, lines[i]); // Faux bold
-
- lineY += FONT_HEIGHT_SMALL + lineSpacing;
- }
-}
-
// 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)
{
@@ -602,32 +428,6 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
pi.drawFrame(display, state, x, y);
}
-static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
-{
- display->setTextAlignment(TEXT_ALIGN_CENTER);
- display->setFont(FONT_MEDIUM);
- display->drawString(64 + x, y, "Updating");
-
- display->setFont(FONT_SMALL);
- display->setTextAlignment(TEXT_ALIGN_LEFT);
- display->drawStringMaxWidth(0 + x, 2 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(),
- "Please be patient and do not power off.");
-}
-
-/// Draw the last text message we received
-static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
-{
- display->setTextAlignment(TEXT_ALIGN_LEFT);
- display->setFont(FONT_MEDIUM);
-
- char tempBuf[24];
- snprintf(tempBuf, sizeof(tempBuf), "Critical fault #%d", error_code);
- display->drawString(0 + x, 0 + y, tempBuf);
- display->setTextAlignment(TEXT_ALIGN_LEFT);
- display->setFont(FONT_SMALL);
- display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please visit \nmeshtastic.org");
-}
-
// Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled
static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
{
@@ -2107,7 +1907,7 @@ static void drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayUiStat
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
char datetimeStr[25];
bool showTime = false; // set to true for full datetime
- formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display, showTime);
+ graphics::UIRenderer::formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display, showTime);
char fullLine[40];
snprintf(fullLine, sizeof(fullLine), " Date: %s", datetimeStr);
display->drawString(0, ((SCREEN_HEIGHT > 64) ? compactFifthLine : moreCompactFifthLine), fullLine);
@@ -2926,7 +2726,7 @@ void Screen::setSSLFrames()
{
if (address_found.address) {
// LOG_DEBUG("Show SSL frames");
- static FrameCallback sslFrames[] = {drawSSLScreen};
+ static FrameCallback sslFrames[] = {NotificationRenderer::drawSSLScreen};
ui->setFrames(sslFrames, 1);
ui->update();
}
@@ -2938,7 +2738,7 @@ void Screen::setWelcomeFrames()
{
if (address_found.address) {
// LOG_DEBUG("Show Welcome frames");
- static FrameCallback frames[] = {drawWelcomeScreen};
+ static FrameCallback frames[] = {NotificationRenderer::drawWelcomeScreen};
setFrameImmediateDraw(frames);
}
}
@@ -3057,7 +2857,7 @@ void Screen::setFrames(FrameFocus focus)
// If we have a critical fault, show it first
fsi.positions.fault = numframes;
if (error_code) {
- normalFrames[numframes++] = drawCriticalFaultFrame;
+ normalFrames[numframes++] = NotificationRenderer::drawCriticalFaultFrame;
indicatorIcons.push_back(icon_error);
focus = FOCUS_FAULT; // Change our "focus" parameter, to ensure we show the fault frame
}
@@ -3145,7 +2945,7 @@ void Screen::setFrames(FrameFocus focus)
ui->disableAllIndicators();
// Add overlays: frame icons and alert banner)
- static OverlayCallback overlays[] = {NavigationBar, drawAlertBannerOverlay};
+ static OverlayCallback overlays[] = {NavigationBar, NotificationRenderer::drawAlertBannerOverlay};
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
@@ -3231,7 +3031,7 @@ void Screen::handleStartFirmwareUpdateScreen()
showingNormalScreen = false;
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame
- static FrameCallback frames[] = {drawFrameFirmware};
+ static FrameCallback frames[] = {NotificationRenderer::drawFrameFirmware};
setFrameImmediateDraw(frames);
}
diff --git a/src/graphics/draw/NotificationRenderer.cpp b/src/graphics/draw/NotificationRenderer.cpp
new file mode 100644
index 000000000..d72d6c907
--- /dev/null
+++ b/src/graphics/draw/NotificationRenderer.cpp
@@ -0,0 +1,167 @@
+#include "NotificationRenderer.h"
+#include "DisplayFormatters.h"
+#include "NodeDB.h"
+#include "configuration.h"
+#include "graphics/ScreenFonts.h"
+#include "graphics/SharedUIDisplay.h"
+#include "graphics/images.h"
+#include "main.h"
+#include
+#include
+#include
+
+#ifdef ARCH_ESP32
+#include "esp_task_wdt.h"
+#endif
+
+using namespace meshtastic;
+
+// External references to global variables from Screen.cpp
+extern String alertBannerMessage;
+extern uint32_t alertBannerUntil;
+extern std::vector functionSymbol;
+extern std::string functionSymbolString;
+extern bool hasUnreadMessage;
+
+// Used on boot when a certificate is being created
+void NotificationRenderer::drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
+{
+ display->setTextAlignment(TEXT_ALIGN_CENTER);
+ display->setFont(FONT_SMALL);
+ display->drawString(64 + x, y, "Creating SSL certificate");
+
+#ifdef ARCH_ESP32
+ yield();
+ esp_task_wdt_reset();
+#endif
+
+ display->setFont(FONT_SMALL);
+ if ((millis() / 1000) % 2) {
+ display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . .");
+ } else {
+ display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ");
+ }
+}
+
+// Used when booting without a region set
+void NotificationRenderer::drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
+{
+ display->setFont(FONT_SMALL);
+ display->setTextAlignment(TEXT_ALIGN_CENTER);
+ display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
+ display->drawString(64 + x, y + FONT_HEIGHT_SMALL, getDeviceName());
+ display->setTextAlignment(TEXT_ALIGN_LEFT);
+
+ if ((millis() / 10000) % 2) {
+ display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the");
+ display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,");
+ display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Web or CLI clients.");
+ } else {
+ display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Visit meshtastic.org");
+ display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "for more information.");
+ display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "");
+ }
+
+#ifdef ARCH_ESP32
+ yield();
+ esp_task_wdt_reset();
+#endif
+}
+
+void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
+{
+ // Exit if no message is active or duration has passed
+ if (alertBannerMessage.length() == 0 || (alertBannerUntil != 0 && millis() > alertBannerUntil))
+ return;
+
+ // === Layout Configuration ===
+ constexpr uint16_t padding = 5; // Padding around text inside the box
+ constexpr uint8_t lineSpacing = 1; // Extra space between lines
+
+ // Search the mesage to determine if we need the bell added
+ bool needs_bell = (alertBannerMessage.indexOf("Alert Received") != -1);
+
+ // Setup font and alignment
+ display->setFont(FONT_SMALL);
+ display->setTextAlignment(TEXT_ALIGN_LEFT); // We will manually center per line
+
+ // === Split the message into lines (supports multi-line banners) ===
+ std::vector lines;
+ int start = 0, newlineIdx;
+ while ((newlineIdx = alertBannerMessage.indexOf('\n', start)) != -1) {
+ lines.push_back(alertBannerMessage.substring(start, newlineIdx));
+ start = newlineIdx + 1;
+ }
+ lines.push_back(alertBannerMessage.substring(start));
+
+ // === Measure text dimensions ===
+ uint16_t minWidth = (SCREEN_WIDTH > 128) ? 106 : 78;
+ uint16_t maxWidth = 0;
+ std::vector lineWidths;
+ for (const auto &line : lines) {
+ uint16_t w = display->getStringWidth(line.c_str(), line.length(), true);
+ lineWidths.push_back(w);
+ if (w > maxWidth)
+ maxWidth = w;
+ }
+
+ uint16_t boxWidth = padding * 2 + maxWidth;
+ if (needs_bell && boxWidth < minWidth)
+ boxWidth += (SCREEN_WIDTH > 128) ? 26 : 20;
+
+ uint16_t boxHeight = padding * 2 + lines.size() * FONT_HEIGHT_SMALL + (lines.size() - 1) * lineSpacing;
+
+ int16_t boxLeft = (display->width() / 2) - (boxWidth / 2);
+ int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
+
+ // === 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 each line centered in the box ===
+ int16_t lineY = boxTop + padding;
+ for (size_t i = 0; i < lines.size(); ++i) {
+ int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2;
+ uint16_t line_width = display->getStringWidth(lines[i].c_str(), lines[i].length(), true);
+
+ if (needs_bell && i == 0) {
+ int bellY = lineY + (FONT_HEIGHT_SMALL - 8) / 2;
+ display->drawXbm(textX - 10, bellY, 8, 8, bell_alert);
+ display->drawXbm(textX + line_width + 2, bellY, 8, 8, bell_alert);
+ }
+
+ display->drawString(textX, lineY, lines[i]);
+ if (SCREEN_WIDTH > 128)
+ display->drawString(textX + 1, lineY, lines[i]); // Faux bold
+
+ lineY += FONT_HEIGHT_SMALL + lineSpacing;
+ }
+}
+
+/// Draw the last text message we received
+void NotificationRenderer::drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
+{
+ display->setTextAlignment(TEXT_ALIGN_LEFT);
+ display->setFont(FONT_MEDIUM);
+
+ char tempBuf[24];
+ snprintf(tempBuf, sizeof(tempBuf), "Critical fault #%d", error_code);
+ display->drawString(0 + x, 0 + y, tempBuf);
+ display->setTextAlignment(TEXT_ALIGN_LEFT);
+ display->setFont(FONT_SMALL);
+ display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please visit \nmeshtastic.org");
+}
+
+void NotificationRenderer::drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
+{
+ display->setTextAlignment(TEXT_ALIGN_CENTER);
+ display->setFont(FONT_MEDIUM);
+ display->drawString(64 + x, y, "Updating");
+
+ display->setFont(FONT_SMALL);
+ display->setTextAlignment(TEXT_ALIGN_LEFT);
+ display->drawStringMaxWidth(0 + x, 2 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(),
+ "Please be patient and do not power off.");
+}
diff --git a/src/graphics/draw/NotificationRenderer.h b/src/graphics/draw/NotificationRenderer.h
new file mode 100644
index 000000000..0b90979e2
--- /dev/null
+++ b/src/graphics/draw/NotificationRenderer.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "OLEDDisplay.h"
+#include "OLEDDisplayUi.h"
+
+class NotificationRenderer
+{
+ public:
+ static void drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state);
+ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
+ static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
+ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
+ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
+};
diff --git a/src/graphics/draw/UIRenderer.cpp b/src/graphics/draw/UIRenderer.cpp
index 5210b53b9..4789bd92c 100644
--- a/src/graphics/draw/UIRenderer.cpp
+++ b/src/graphics/draw/UIRenderer.cpp
@@ -183,8 +183,62 @@ void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshta
}
}
-} // namespace UIRenderer
+// Start Functions to write date/time to the screen
+// Helper function to check if a year is a leap year
+bool isLeapYear(int year)
+{
+ return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
+}
+// Array of days in each month (non-leap year)
+const int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+// Fills the buffer with a formatted date/time string and returns pixel width
+int formatDateTime(char *buf, size_t bufSize, uint32_t rtc_sec, OLEDDisplay *display, bool includeTime)
+{
+ int sec = rtc_sec % 60;
+ rtc_sec /= 60;
+ int min = rtc_sec % 60;
+ rtc_sec /= 60;
+ int hour = rtc_sec % 24;
+ rtc_sec /= 24;
+
+ int year = 1970;
+ while (true) {
+ int daysInYear = isLeapYear(year) ? 366 : 365;
+ if (rtc_sec >= (uint32_t)daysInYear) {
+ rtc_sec -= daysInYear;
+ year++;
+ } else {
+ break;
+ }
+ }
+
+ int month = 0;
+ while (month < 12) {
+ int dim = daysInMonth[month];
+ if (month == 1 && isLeapYear(year))
+ dim++;
+ if (rtc_sec >= (uint32_t)dim) {
+ rtc_sec -= dim;
+ month++;
+ } else {
+ break;
+ }
+ }
+
+ int day = rtc_sec + 1;
+
+ if (includeTime) {
+ snprintf(buf, bufSize, "%04d-%02d-%02d %02d:%02d:%02d", year, month + 1, day, hour, min, sec);
+ } else {
+ snprintf(buf, bufSize, "%04d-%02d-%02d", year, month + 1, day);
+ }
+
+ return display->getStringWidth(buf);
+}
+
+} // namespace UIRenderer
} // namespace graphics
#endif // !MESHTASTIC_EXCLUDE_GPS
diff --git a/src/graphics/draw/UIRenderer.h b/src/graphics/draw/UIRenderer.h
index 770e5010d..e1675bc71 100644
--- a/src/graphics/draw/UIRenderer.h
+++ b/src/graphics/draw/UIRenderer.h
@@ -55,7 +55,7 @@ void drawStringWithEmotes(OLEDDisplay *display, int x, int y, const std::string
// Time and date utilities
void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength);
std::string drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds);
-void formatDateTime(char *buffer, size_t bufferSize, uint32_t rtc_sec, OLEDDisplay *display, bool showTime);
+int formatDateTime(char *buffer, size_t bufferSize, uint32_t rtc_sec, OLEDDisplay *display, bool showTime);
// Message filtering
bool shouldDrawMessage(const meshtastic_MeshPacket *packet);