From aa734004141c250f6e59eeb61642eeb9a256b86e Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Thu, 10 Sep 2026 20:12:29 +0200 Subject: [PATCH] =?UTF-8?q?fix(ui):=20community=20v1.27=20feedback=20?= =?UTF-8?q?=E2=80=94=20GPS=20altitude=20field,=20noise=20floor,=20Msg=20wa?= =?UTF-8?q?ke=20location,=20units?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add a separate "Altitude (GPS)" dashboard field (label AltG) alongside the existing barometric one (now labelled "Altitude (Baro)") -- the original single Altitude field only ever read a barometric sensor's CayenneLPP telemetry, showing "--" on any board without one even with a perfectly good GPS fix. - Every altitude reading (baro + GPS, Clock and Lock screen) and the GPS home page's "alt" row now go through a shared fmtAlt() helper and respect Settings > System > Units, same as every other distance in the UI -- none of them checked units_imperial before. Same fix for Locator's Radius row, which always showed metric regardless. - Radio home page's noise floor showed "n/a" whenever Pwr save (RX duty-cycle) was on, on the assumption duty-cycle RX can't sample the floor. That's stale: RadioLibWrapper already periodically recalibrates it (noiseFloorCalibCheck(), every 60s) even under duty-cycle, which is exactly why Diagnostics' unconditional read of the same value was already showing something real. Radio home page now matches. - Moved "Msg wake" from Settings > Sound to Settings > Display -- more logical home for a display-wake toggle than notifications. Menu-order only; NodePrefs storage is unaffected by this enum's ordering. Co-Authored-By: Claude Sonnet 5 --- .../clock_screen/clock_screen.md | 3 +- .../settings_screen/settings_screen.md | 2 +- .../ui-new/DashboardConfigScreen.h | 6 ++- .../companion_radio/ui-new/LocatorScreen.h | 3 +- .../companion_radio/ui-new/SettingsScreen.h | 2 +- examples/companion_radio/ui-new/UITask.cpp | 52 ++++++++++++++----- 6 files changed, 49 insertions(+), 19 deletions(-) diff --git a/docs/solo_features/clock_screen/clock_screen.md b/docs/solo_features/clock_screen/clock_screen.md index 6329204e..f9d62b03 100644 --- a/docs/solo_features/clock_screen/clock_screen.md +++ b/docs/solo_features/clock_screen/clock_screen.md @@ -40,12 +40,13 @@ Up to three data fields are shown below the date separator. Each field displays | Humidity | Hum | % from onboard sensor | | Pressure | Pres | hPa from onboard sensor | | GPS | GPS | `lat lon` decimal degrees, or `no fix` | -| Altitude | Alt | metres from onboard sensor (GPS or barometric) | +| Altitude (Baro) | Alt | metres/feet (per Settings › System › Units) from onboard barometric sensor (`--` without one) | | Luminosity | Lux | lux from onboard sensor | | CO₂ | CO2 | ppm from onboard sensor | | Contacts | Nodes | Total contacts in the mesh | | Messages | Msgs | Total unread message count | | Satellites | Sats | GPS satellite count (or `--` without GPS) | +| Altitude (GPS) | AltG | metres/feet (per Settings › System › Units) from the GPS fix (or `no fix`) | Sensor fields show `--` when the sensor is not connected or has no data. diff --git a/docs/solo_features/settings_screen/settings_screen.md b/docs/solo_features/settings_screen/settings_screen.md index f747e3ef..e1bc8fb9 100644 --- a/docs/solo_features/settings_screen/settings_screen.md +++ b/docs/solo_features/settings_screen/settings_screen.md @@ -27,6 +27,7 @@ Press **Cancel/Back** to save and return to the home screen. | Display rotation _(e-ink only)_ | 0° / 90° / 180° / 270° | Applied immediately | | Joystick rotation _(e-ink only)_ | 0° / 90° / 180° / 270° | Rotates input mapping independently of display rotation; useful for custom enclosures | | Full refresh interval _(e-ink only)_ | OFF / 5 / 10 / 20 / 30 | Partial refreshes between full clears; reduces ghosting on long sessions | +| Msg wake | ON / OFF | Whether an incoming message turns the display back on when it was off and no phone/app is connected (default ON — today's behaviour either way). | --- @@ -40,7 +41,6 @@ Press **Cancel/Back** to save and return to the home screen. | Channel Melody | built-in / Melody 1 / Melody 2 / None | Notification sound for incoming channel messages. `None` disables the sound for this event. | | AD sound | built-in / Melody 1 / Melody 2 / None | Sound played whenever an **advert** is received from *any* node — pairs with Auto-Advert as an audible "in range" heartbeat (see Tools › Auto-Advert). `None` disables the sound for this event. | | AD scope | All / Zero-hop | Filters the AD sound so it plays for every advert or only for local zero-hop adverts. | -| Msg wake | ON / OFF | Whether an incoming message turns the display back on when it was off and no phone/app is connected (default ON — today's behaviour either way). | Melody 1 and Melody 2 are custom sequences editable in **Tools › Ringtone Editor**. diff --git a/examples/companion_radio/ui-new/DashboardConfigScreen.h b/examples/companion_radio/ui-new/DashboardConfigScreen.h index a7099c19..55c4b96a 100644 --- a/examples/companion_radio/ui-new/DashboardConfigScreen.h +++ b/examples/companion_radio/ui-new/DashboardConfigScreen.h @@ -16,7 +16,8 @@ static const uint8_t DASH_NODES = 9; static const uint8_t DASH_MSGS = 10; static const uint8_t DASH_BATT_PCT = 11; static const uint8_t DASH_SATS = 12; -static const uint8_t DASH_COUNT = 13; +static const uint8_t DASH_ALT_GPS = 13; +static const uint8_t DASH_COUNT = 14; class DashboardConfigScreen : public UIScreen { UITask* _task; @@ -81,5 +82,6 @@ public: const char* DashboardConfigScreen::OPTION_NAMES[DASH_COUNT] = { "None", "Batt V", "Temp", "Humidity", "Pressure", - "GPS", "Altitude", "Lux", "CO2", "Contacts", "Messages", "Batt %", "Sats" + "GPS", "Altitude (Baro)", "Lux", "CO2", "Contacts", "Messages", "Batt %", "Sats", + "Altitude (GPS)" }; diff --git a/examples/companion_radio/ui-new/LocatorScreen.h b/examples/companion_radio/ui-new/LocatorScreen.h index 585f63c9..0b8cd891 100644 --- a/examples/companion_radio/ui-new/LocatorScreen.h +++ b/examples/companion_radio/ui-new/LocatorScreen.h @@ -92,8 +92,7 @@ public: break; case K_RADIUS: { uint16_t r = NodePrefs::locatorRadiusMeters(_prefs ? _prefs->locator_radius_idx : 1); - if (r < 1000) snprintf(buf, n, "%um", (unsigned)r); - else snprintf(buf, n, "%.1fkm", r / 1000.0f); + geo::fmtDist(buf, n, r / 1000.0f, _task && _task->useImperial()); break; } case K_MODE: diff --git a/examples/companion_radio/ui-new/SettingsScreen.h b/examples/companion_radio/ui-new/SettingsScreen.h index 39287440..768bd463 100644 --- a/examples/companion_radio/ui-new/SettingsScreen.h +++ b/examples/companion_radio/ui-new/SettingsScreen.h @@ -35,6 +35,7 @@ class SettingsScreen : public UIScreen { #if FEAT_FULL_REFRESH_SETTING EINK_FULL_REFRESH, #endif + MSG_WAKE, // Sound section SECTION_SOUND, BUZZER, @@ -43,7 +44,6 @@ class SettingsScreen : public UIScreen { CH_MELODY, AD_SOUND, AD_SOUND_SCOPE, - MSG_WAKE, // Home pages section SECTION_HOME_PAGES, HOME_CLOCK, HOME_FAVOURITES, HOME_RADIO, HOME_BT, HOME_ADVERT, diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index bdc5c67e..5c64b1a4 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -299,7 +299,15 @@ static int drawClockTime(DisplayDriver& d, int top_y, const struct tm* ti, // ── HomeScreen ──────────────────────────────────────────────────────────────── // Forward declaration to be able to call formatDashVal from HomeScreen::render() static void formatDashVal(uint8_t field, char* val, int val_len, uint16_t batt_mv, - uint16_t low_batt_mv, int unread, CayenneLPP* lpp = nullptr); + uint16_t low_batt_mv, int unread, bool imperial, CayenneLPP* lpp = nullptr); + +// Altitude (baro or GPS) respects Settings > System > Units, same as every +// other distance in the UI -- unlike geo::fmtDist, never switches to km/mi +// regardless of magnitude, since altitude is always discussed in the small unit. +static void fmtAlt(char* buf, int n, float meters, bool imperial) { + if (imperial) snprintf(buf, n, "%.0fft", meters * 3.28084f); + else snprintf(buf, n, "%.0fm", meters); +} class HomeScreen : public UIScreen { enum HomePage { @@ -899,6 +907,17 @@ public: else strcpy(val, "--"); #else strcpy(val, "--"); +#endif + } else if (field == DASH_ALT_GPS) { + strcpy(label, "AltG"); +#if ENV_INCLUDE_GPS == 1 + LocationProvider* loc = sensors.getLocationProvider(); + if (loc && loc->isValid()) + fmtAlt(val, sizeof(val), loc->getAltitude() / 1000.0f, _node_prefs && _node_prefs->units_imperial); + else + strcpy(val, "no fix"); +#else + strcpy(val, "--"); #endif } else if (field == DASH_NODES) { strcpy(label, "Nodes"); @@ -927,7 +946,7 @@ public: case LPP_TEMPERATURE: r.readTemperature(v); snprintf(val, sizeof(val), "%.1f\xf8""C", v); break; case LPP_RELATIVE_HUMIDITY: r.readRelativeHumidity(v); snprintf(val, sizeof(val), "%.0f%%", v); break; case LPP_BAROMETRIC_PRESSURE: r.readPressure(v); snprintf(val, sizeof(val), "%.0fhPa", v); break; - case LPP_ALTITUDE: r.readAltitude(v); snprintf(val, sizeof(val), "%.0fm", v); break; + case LPP_ALTITUDE: r.readAltitude(v); fmtAlt(val, sizeof(val), v, _node_prefs && _node_prefs->units_imperial); break; case LPP_LUMINOSITY: r.readLuminosity(v); snprintf(val, sizeof(val), "%.0flux", v); break; case LPP_CONCENTRATION: r.readConcentration(v); snprintf(val, sizeof(val), "%.0fppm", v); break; } @@ -986,8 +1005,8 @@ public: int unread = (f0 == DASH_MSGS || f1 == DASH_MSGS) ? _task->getDMUnreadTotal() + _task->getChannelUnreadCount() + _task->getRoomUnreadCount() : 0; uint16_t batt_mv = _task->getBattMilliVolts(); - formatDashVal(f0, v0, sizeof(v0), batt_mv, _node_prefs->low_batt_mv, unread, lpp_ptr); - formatDashVal(f1, v1, sizeof(v1), batt_mv, _node_prefs->low_batt_mv, unread, lpp_ptr); + formatDashVal(f0, v0, sizeof(v0), batt_mv, _node_prefs->low_batt_mv, unread, _node_prefs->units_imperial, lpp_ptr); + formatDashVal(f1, v1, sizeof(v1), batt_mv, _node_prefs->low_batt_mv, unread, _node_prefs->units_imperial, lpp_ptr); if (v0[0] || v1[0]) { int sv_y = date_y + step; display.setColor(DisplayDriver::LIGHT); @@ -1039,11 +1058,12 @@ public: snprintf(tmp, sizeof(tmp),"TX: %ddBm", radio_driver.getTxPower()); // live value (reflects APC) display.print(tmp); display.setCursor(0, content_y + step * 3); - if (radio_driver.getPowerSaving()) { // duty-cycle RX doesn't sample the floor - snprintf(tmp, sizeof(tmp),"Noise floor: n/a"); - } else { - snprintf(tmp, sizeof(tmp),"Noise floor: %d", radio_driver.getNoiseFloor()); - } + // Was gated to "n/a" while duty-cycle RX (Pwr save) was active, on the + // assumption that the floor only gets sampled during continuous RX -- + // stale since RadioLibWrapper's periodic recalibration (noiseFloorCalibCheck(), + // NF_CALIB_INTERVAL_MS) started keeping it fresh even under duty-cycle, + // same live value Diagnostics already showed unconditionally. + snprintf(tmp, sizeof(tmp),"Noise floor: %d", radio_driver.getNoiseFloor()); display.print(tmp); } else if (_page == HomePage::BLUETOOTH) { display.setColor(DisplayDriver::LIGHT); @@ -1105,7 +1125,7 @@ public: display.drawTextRightAlign(display.width()-1, y, buf); y += step; display.drawTextLeftAlign(0, y, "alt"); - snprintf(buf, sizeof(buf),"%.2f", nmea->getAltitude()/1000.); + fmtAlt(buf, sizeof(buf), nmea->getAltitude() / 1000.0f, _node_prefs && _node_prefs->units_imperial); display.drawTextRightAlign(display.width()-1, y, buf); y += step; } @@ -2240,7 +2260,7 @@ bool UITask::isButtonPressed() const { } static void formatDashVal(uint8_t field, char* val, int val_len, uint16_t batt_mv, - uint16_t low_batt_mv, int unread, CayenneLPP* lpp) { + uint16_t low_batt_mv, int unread, bool imperial, CayenneLPP* lpp) { val[0] = '\0'; switch (field) { case DASH_NONE: return; @@ -2273,8 +2293,16 @@ static void formatDashVal(uint8_t field, char* val, int val_len, uint16_t batt_m else strcpy(val, "--"); return; } + case DASH_ALT_GPS: { + LocationProvider* loc = sensors.getLocationProvider(); + if (loc && loc->isValid()) + fmtAlt(val, val_len, loc->getAltitude() / 1000.0f, imperial); + else strcpy(val, "no fix"); + return; + } #else case DASH_SATS: + case DASH_ALT_GPS: strcpy(val, "--"); return; #endif @@ -2301,7 +2329,7 @@ static void formatDashVal(uint8_t field, char* val, int val_len, uint16_t batt_m case LPP_TEMPERATURE: r.readTemperature(v); snprintf(val, val_len, "%.1f\xf8""C", v); return; case LPP_RELATIVE_HUMIDITY: r.readRelativeHumidity(v); snprintf(val, val_len, "%.0f%%", v); return; case LPP_BAROMETRIC_PRESSURE: r.readPressure(v); snprintf(val, val_len, "%.0fhPa", v); return; - case LPP_ALTITUDE: r.readAltitude(v); snprintf(val, val_len, "%.0fm", v); return; + case LPP_ALTITUDE: r.readAltitude(v); fmtAlt(val, val_len, v, imperial); return; case LPP_LUMINOSITY: r.readLuminosity(v); snprintf(val, val_len, "%.0flux", v); return; case LPP_CONCENTRATION: r.readConcentration(v); snprintf(val, val_len, "%.0fppm", v); return; }