mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-16 18:12:07 +00:00
Screen changes from time deltas to timestamps after 15 minutes (#3935)
* E-Ink displays sometimes use timestamp instead of delta * Allow users to disable E-Ink screensaver * Clarify variable's purpose * Operator order oopsie * Picky print problem * Implement for all display, not just E-Ink * Align "unknown age" behavior with existing code * One more use of timestamp, if screen is wide enough
This commit is contained in:
parent
cdf86f4166
commit
a12b9922ed
@ -348,12 +348,18 @@ void PowerFSM_setup()
|
|||||||
|
|
||||||
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
|
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
|
||||||
|
|
||||||
powerFSM.add_timed_transition(&stateON, &stateDARK,
|
#ifdef USE_EINK
|
||||||
Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
// Allow E-Ink devices to suppress the screensaver, if screen timeout set to 0
|
||||||
"Screen-on timeout");
|
if (config.display.screen_on_secs > 0)
|
||||||
powerFSM.add_timed_transition(&statePOWER, &stateDARK,
|
#endif
|
||||||
Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
{
|
||||||
"Screen-on timeout");
|
powerFSM.add_timed_transition(&stateON, &stateDARK,
|
||||||
|
Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs),
|
||||||
|
NULL, "Screen-on timeout");
|
||||||
|
powerFSM.add_timed_transition(&statePOWER, &stateDARK,
|
||||||
|
Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs),
|
||||||
|
NULL, "Screen-on timeout");
|
||||||
|
}
|
||||||
|
|
||||||
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
|
@ -419,6 +419,76 @@ static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
|
|||||||
return packet->from != 0 && !moduleConfig.store_forward.enabled;
|
return packet->from != 0 && !moduleConfig.store_forward.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get an absolute time from "seconds ago" info. Returns false if no valid timestamp possible
|
||||||
|
bool deltaToTimestamp(uint32_t secondsAgo, uint8_t *hours, uint8_t *minutes, int32_t *daysAgo)
|
||||||
|
{
|
||||||
|
// Cache the result - avoid frequent recalculation
|
||||||
|
static uint8_t hoursCached = 0, minutesCached = 0;
|
||||||
|
static uint32_t daysAgoCached = 0;
|
||||||
|
static uint32_t secondsAgoCached = 0;
|
||||||
|
static bool validCached = false;
|
||||||
|
|
||||||
|
// Abort: if timezone not set
|
||||||
|
if (strlen(config.device.tzdef) == 0) {
|
||||||
|
validCached = false;
|
||||||
|
return validCached;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abort: if invalid pointers passed
|
||||||
|
if (hours == nullptr || minutes == nullptr || daysAgo == nullptr) {
|
||||||
|
validCached = false;
|
||||||
|
return validCached;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abort: if time seems invalid.. (> 6 months ago, probably seen before RTC set)
|
||||||
|
if (secondsAgo > SEC_PER_DAY * 30UL * 6) {
|
||||||
|
validCached = false;
|
||||||
|
return validCached;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If repeated request, don't bother recalculating
|
||||||
|
if (secondsAgo - secondsAgoCached < 60 && secondsAgoCached != 0) {
|
||||||
|
if (validCached) {
|
||||||
|
*hours = hoursCached;
|
||||||
|
*minutes = minutesCached;
|
||||||
|
*daysAgo = daysAgoCached;
|
||||||
|
}
|
||||||
|
return validCached;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get local time
|
||||||
|
uint32_t secondsRTC = getValidTime(RTCQuality::RTCQualityDevice, true); // Get local time
|
||||||
|
|
||||||
|
// Abort: if RTC not set
|
||||||
|
if (!secondsRTC) {
|
||||||
|
validCached = false;
|
||||||
|
return validCached;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get absolute time when last seen
|
||||||
|
uint32_t secondsSeenAt = secondsRTC - secondsAgo;
|
||||||
|
|
||||||
|
// Calculate daysAgo
|
||||||
|
*daysAgo = (secondsRTC / SEC_PER_DAY) - (secondsSeenAt / SEC_PER_DAY); // How many "midnights" have passed
|
||||||
|
|
||||||
|
// Get seconds since midnight
|
||||||
|
uint32_t hms = (secondsRTC - secondsAgo) % SEC_PER_DAY;
|
||||||
|
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
||||||
|
|
||||||
|
// Tear apart hms into hours and minutes
|
||||||
|
*hours = hms / SEC_PER_HOUR;
|
||||||
|
*minutes = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||||||
|
|
||||||
|
// Cache the result
|
||||||
|
daysAgoCached = *daysAgo;
|
||||||
|
hoursCached = *hours;
|
||||||
|
minutesCached = *minutes;
|
||||||
|
secondsAgoCached = secondsAgo;
|
||||||
|
|
||||||
|
validCached = true;
|
||||||
|
return validCached;
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw the last text message we received
|
/// Draw the last text message we received
|
||||||
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
@ -440,18 +510,36 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
|||||||
display->setColor(BLACK);
|
display->setColor(BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For time delta
|
||||||
uint32_t seconds = sinceReceived(&mp);
|
uint32_t seconds = sinceReceived(&mp);
|
||||||
uint32_t minutes = seconds / 60;
|
uint32_t minutes = seconds / 60;
|
||||||
uint32_t hours = minutes / 60;
|
uint32_t hours = minutes / 60;
|
||||||
uint32_t days = hours / 24;
|
uint32_t days = hours / 24;
|
||||||
|
|
||||||
if (config.display.heading_bold) {
|
// For timestamp
|
||||||
display->drawStringf(1 + x, 0 + y, tempBuf, "%s ago from %s",
|
uint8_t timestampHours, timestampMinutes;
|
||||||
screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
int32_t daysAgo;
|
||||||
(node && node->has_user) ? node->user.short_name : "???");
|
bool useTimestamp = deltaToTimestamp(seconds, ×tampHours, ×tampMinutes, &daysAgo);
|
||||||
|
|
||||||
|
// If bold, draw twice, shifting right by one pixel
|
||||||
|
for (uint8_t xOff = 0; xOff <= (config.display.heading_bold ? 1 : 0); xOff++) {
|
||||||
|
// Show a timestamp if received today, but longer than 15 minutes ago
|
||||||
|
if (useTimestamp && minutes >= 15 && daysAgo == 0) {
|
||||||
|
display->drawStringf(xOff + x, 0 + y, tempBuf, "At %02hu:%02hu from %s", timestampHours, timestampMinutes,
|
||||||
|
(node && node->has_user) ? node->user.short_name : "???");
|
||||||
|
}
|
||||||
|
// Timestamp yesterday (if display is wide enough)
|
||||||
|
else if (useTimestamp && daysAgo == 1 && display->width() >= 200) {
|
||||||
|
display->drawStringf(xOff + x, 0 + y, tempBuf, "Yesterday %02hu:%02hu from %s", timestampHours, timestampMinutes,
|
||||||
|
(node && node->has_user) ? node->user.short_name : "???");
|
||||||
|
}
|
||||||
|
// Otherwise, show a time delta
|
||||||
|
else {
|
||||||
|
display->drawStringf(xOff + x, 0 + y, tempBuf, "%s ago from %s",
|
||||||
|
screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||||
|
(node && node->has_user) ? node->user.short_name : "???");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
display->drawStringf(0 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
|
||||||
(node && node->has_user) ? node->user.short_name : "???");
|
|
||||||
|
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes);
|
snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes);
|
||||||
@ -879,19 +967,32 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
|
|
||||||
uint32_t agoSecs = sinceLastSeen(node);
|
uint32_t agoSecs = sinceLastSeen(node);
|
||||||
static char lastStr[20];
|
static char lastStr[20];
|
||||||
|
|
||||||
|
// Use an absolute timestamp in some cases.
|
||||||
|
// Particularly useful with E-Ink displays. Static UI, fewer refreshes.
|
||||||
|
uint8_t timestampHours, timestampMinutes;
|
||||||
|
int32_t daysAgo;
|
||||||
|
bool useTimestamp = deltaToTimestamp(agoSecs, ×tampHours, ×tampMinutes, &daysAgo);
|
||||||
|
|
||||||
if (agoSecs < 120) // last 2 mins?
|
if (agoSecs < 120) // last 2 mins?
|
||||||
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs);
|
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs);
|
||||||
|
// -- if suitable for timestamp --
|
||||||
|
else if (useTimestamp && agoSecs < 15 * SECONDS_IN_MINUTE) // Last 15 minutes
|
||||||
|
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / SECONDS_IN_MINUTE);
|
||||||
|
else if (useTimestamp && daysAgo == 0) // Today
|
||||||
|
snprintf(lastStr, sizeof(lastStr), "Last seen: %02u:%02u", (unsigned int)timestampHours, (unsigned int)timestampMinutes);
|
||||||
|
else if (useTimestamp && daysAgo == 1) // Yesterday
|
||||||
|
snprintf(lastStr, sizeof(lastStr), "Seen yesterday");
|
||||||
|
else if (useTimestamp && daysAgo > 1) // Last six months (capped by deltaToTimestamp method)
|
||||||
|
snprintf(lastStr, sizeof(lastStr), "%li days ago", (long)daysAgo);
|
||||||
|
// -- if using time delta instead --
|
||||||
else if (agoSecs < 120 * 60) // last 2 hrs
|
else if (agoSecs < 120 * 60) // last 2 hrs
|
||||||
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
|
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
|
||||||
else {
|
// Only show hours ago if it's been less than 6 months. Otherwise, we may have bad data.
|
||||||
// Only show hours ago if it's been less than 6 months. Otherwise, we may have bad
|
else if ((agoSecs / 60 / 60) < (hours_in_month * 6))
|
||||||
// data.
|
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
|
||||||
if ((agoSecs / 60 / 60) < (hours_in_month * 6)) {
|
else
|
||||||
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
|
snprintf(lastStr, sizeof(lastStr), "unknown age");
|
||||||
} else {
|
|
||||||
snprintf(lastStr, sizeof(lastStr), "unknown age");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static char distStr[20];
|
static char distStr[20];
|
||||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||||
@ -900,7 +1001,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
strncpy(distStr, "? km", sizeof(distStr));
|
strncpy(distStr, "? km", sizeof(distStr));
|
||||||
}
|
}
|
||||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
const char *fields[] = {username, lastStr, signalStr, distStr, NULL};
|
||||||
int16_t compassX = 0, compassY = 0;
|
int16_t compassX = 0, compassY = 0;
|
||||||
|
|
||||||
// coordinates for the center of the compass/circle
|
// coordinates for the center of the compass/circle
|
||||||
@ -1448,6 +1549,15 @@ void Screen::setFrames()
|
|||||||
LOG_DEBUG("showing standard frames\n");
|
LOG_DEBUG("showing standard frames\n");
|
||||||
showingNormalScreen = true;
|
showingNormalScreen = true;
|
||||||
|
|
||||||
|
#ifdef USE_EINK
|
||||||
|
// If user has disabled the screensaver, warn them after boot
|
||||||
|
static bool warnedScreensaverDisabled = false;
|
||||||
|
if (config.display.screen_on_secs == 0 && !warnedScreensaverDisabled) {
|
||||||
|
screen->print("Screensaver disabled\n");
|
||||||
|
warnedScreensaverDisabled = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
moduleFrames = MeshModule::GetMeshModulesWithUIFrames();
|
moduleFrames = MeshModule::GetMeshModulesWithUIFrames();
|
||||||
LOG_DEBUG("Showing %d module frames\n", moduleFrames.size());
|
LOG_DEBUG("Showing %d module frames\n", moduleFrames.size());
|
||||||
#ifdef DEBUG_PORT
|
#ifdef DEBUG_PORT
|
||||||
|
Loading…
Reference in New Issue
Block a user