t-watch - initial step counter implementation

This commit is contained in:
Pelgraine
2026-07-08 21:03:24 +10:00
parent c570cc41c4
commit 51fcf6de83
6 changed files with 137 additions and 17 deletions
+1 -1
View File
@@ -1787,7 +1787,7 @@ static void lastHeardToggleContact() {
if (row == 2 && col == 0) { ui_task.gotoTraceScreen(); return 0; }
// row 2 col 1 = Maps -- TODO subscreen not yet built; no-op for now.
if (row == 3 && col == 0) { ui_task.gotoNotesScreen(); return 0; }
// row 3 col 1 = Games -- placeholder, no target yet; no-op for now.
if (row == 3 && col == 1) { ui_task.gotoStepsScreen(); return 0; }
}
return 0; // consume long-press on the tile page
}
@@ -81,6 +81,12 @@ static const uint8_t icon_gamepad[] PROGMEM = {
0x40,0x20, 0x30,0xC0, 0x10,0x80, 0x1F,0x80, 0x00,0x00, 0x00,0x00,
};
// Star -- 12x12 home tile icon (Steps). MSB-first, 2 bytes per row.
static const uint8_t icon_star[] PROGMEM = {
0x06,0x00, 0x06,0x00, 0x0F,0x00, 0xFF,0xF0, 0x7F,0xE0, 0x3F,0xC0,
0x1F,0x80, 0x3F,0xC0, 0x39,0xC0, 0x70,0xE0, 0x60,0x60, 0x00,0x00,
};
// 🔔 Bell -- 7x8 status bar indicator (alarm enabled)
// MSB-first, 1 byte per row
#define BELL_ICON_W 7
+51 -16
View File
@@ -34,7 +34,7 @@
#endif
#ifndef AUTO_OFF_MILLIS
#define AUTO_OFF_MILLIS 45000 // 45 seconds
#define AUTO_OFF_MILLIS 15000 // 15 seconds
#endif
// Right-aligned values on the dense home pages compensate for the e-ink X
// origin offset so they are not clipped at the right edge. Default 0 for
@@ -686,7 +686,7 @@ public:
{ {icon_envelope, "Messages", 0x0CB1}, {icon_people, "Contacts", 0xCAA0} },
{ {icon_gear, "Settings", 0x0560}, {icon_search, "Discover", 0xF81F} },
{ {icon_trace, "Trace", 0xF800}, {icon_map, "Maps", 0x231D} },
{ {icon_notepad, "Notes", 0x07FF}, {icon_gamepad, "Games", 0xFFE0} },
{ {icon_notepad, "Notes", 0x07FF}, {icon_star, "Steps", 0xFFE0} },
};
const uint16_t TILE_FILL = 0x18C5; // dark navy
@@ -1485,6 +1485,27 @@ public:
return true;
}
};
// Steps screen: big daily step count in the clock font. Opened by long-pressing
// the Steps home tile; any tap dismisses back to the tiles.
class StepsScreen : public UIScreen {
UITask* _task;
public:
StepsScreen(UITask* task) : _task(task) { }
int render(DisplayDriver& display) override {
display.setColor(DisplayDriver::LIGHT);
char buf[16];
snprintf(buf, sizeof(buf), "%u", (unsigned)_task->getTodaySteps());
((LGFXDisplay*)&display)->printClockFont(display.width() / 2, display.height() / 2 - 18, buf);
return 1000;
}
bool handleInput(char c) override {
_task->gotoHomeScreen();
return true;
}
};
#endif
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
@@ -1658,6 +1679,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
#endif
#if defined(LILYGO_TWATCH_S3_PLUS)
lock_screen = new ClockScreen(this, &rtc_clock, node_prefs);
steps_screen = new StepsScreen(this);
#endif
#ifdef TWATCH_COMPOSE_ENABLED
tw_picker = new TWatchChannelPicker(_display);
@@ -2223,20 +2245,6 @@ void UITask::loop() {
} else {
c = checkDisplayOn(KEY_NEXT);
}
#elif defined(LILYGO_TWATCH_S3_PLUS)
// Watch: on the contacts screen a button click opens the path editor for
// the selected contact; elsewhere it wakes the display / emits KEY_NEXT.
if (isOnContactsScreen()) {
int idx = ((ContactsScreen*)contacts_screen)->getSelectedContactIdx();
if (idx >= 0) {
gotoPathEditor(idx);
c = 0;
} else {
c = checkDisplayOn(KEY_NEXT);
}
} else {
c = checkDisplayOn(KEY_NEXT);
}
#else
c = checkDisplayOn(KEY_NEXT);
#endif
@@ -2635,6 +2643,17 @@ if (curr) curr->poll();
setCurrScreen(lock_screen);
_auto_off = millis() + AUTO_OFF_MILLIS;
}
// Roll the daily step baseline over at local midnight (12am-to-12am total).
// No hardware reset -- the displayed count is raw_count - baseline.
{
uint32_t now = rtc_clock.getCurrentTime();
if (now > 1700000000) { // valid timestamp
int32_t localDay = ((int32_t)now + ((int32_t)the_mesh.getNodePrefs()->utc_offset_hours * 3600)) / 86400;
if (_lastStepDay == 0) _lastStepDay = localDay; // seed on first valid read
else if (localDay != _lastStepDay) { _stepBaseline = board.getStepCount(); _lastStepDay = localDay; }
}
}
#endif
// Auto-lock idle timer — runs regardless of display on/off state
@@ -3617,6 +3636,22 @@ void UITask::gotoTraceScreen() {
_next_refresh = 100;
}
#if defined(LILYGO_TWATCH_S3_PLUS)
uint32_t UITask::getTodaySteps() {
uint32_t raw = board.getStepCount();
return (raw >= _stepBaseline) ? (raw - _stepBaseline) : raw;
}
void UITask::gotoStepsScreen() {
setCurrScreen(steps_screen);
if (_display != NULL && !_display->isOn()) {
_display->turnOn();
}
_auto_off = millis() + AUTO_OFF_MILLIS;
_next_refresh = 100;
}
#endif
void UITask::gotoGamesMenu() {
GamesMenuScreen* gm = (GamesMenuScreen*)games_menu_screen;
gm->enter();
+15
View File
@@ -119,6 +119,11 @@ class UITask : public AbstractUITask {
int _tileGridVY = 44; // Virtual Y of tile grid top (updated each render)
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LILYGO_TWATCH_S3_PLUS)
UIScreen* lock_screen; // Lock screen (big clock + battery + unread)
#if defined(LILYGO_TWATCH_S3_PLUS)
UIScreen* steps_screen; // Steps screen (big daily step count)
int32_t _lastStepDay = 0; // local day-of-epoch, for the midnight step reset
uint32_t _stepBaseline = 0; // raw step count at the start of the local day
#endif
UIScreen* _screenBeforeLock = nullptr;
bool _locked = false;
unsigned long _lastInputMillis = 0; // Auto-lock idle tracking
@@ -220,6 +225,10 @@ public:
void gotoGamesMenu(); // Navigate to games launcher menu
void gotoSnakeScreen(); // Navigate to snake game
void gotoMinesweeperScreen(); // Navigate to minesweeper game
#if defined(LILYGO_TWATCH_S3_PLUS)
void gotoStepsScreen(); // Navigate to the step counter screen
uint32_t getTodaySteps(); // Daily step count (raw - baseline)
#endif
#if HAS_GPS
void gotoMapScreen(); // Navigate to map tile screen
#endif
@@ -281,6 +290,9 @@ public:
bool isOnTraceScreen() const { return curr == trace_screen; }
bool isOnGamesMenu() const { return curr == games_menu_screen; }
bool isOnSnakeScreen() const { return curr == snake_screen; }
#if defined(LILYGO_TWATCH_S3_PLUS)
bool isOnStepsScreen() const { return curr == steps_screen; }
#endif
bool isOnMinesweeperScreen() const { return curr == minesweeper_screen; }
bool isOnMapScreen() const { return curr == map_screen; }
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro) || defined(LILYGO_TWATCH_S3_PLUS)
@@ -370,6 +382,9 @@ public:
UIScreen* getTraceScreen() const { return trace_screen; }
UIScreen* getGamesMenuScreen() const { return games_menu_screen; }
UIScreen* getSnakeScreen() const { return snake_screen; }
#if defined(LILYGO_TWATCH_S3_PLUS)
UIScreen* getStepsScreen() const { return steps_screen; }
#endif
UIScreen* getMinesweeperScreen() const { return minesweeper_screen; }
UIScreen* getMapScreen() const { return map_screen; }
#ifdef MECK_WEB_READER