From 1def29335c7cb0605f6a6ac4fd96ca6cff33e255 Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Mon, 28 Sep 2026 21:59:40 +0200 Subject: [PATCH] feat(companion): quiet hours -- muted on a schedule, the alarm still rings Settings > Sound > Quiet hours (L2: its own group; L1: Quiet hrs / from / until): from quiet_from to quiet_to (local hours, wrapping past midnight) the buzzer is muted and a message doesn't wake the screen; the clock alarm still rings. A manual mute or unmute inside the window stands until the window ends. Off with the clock unset. NodePrefs gains quiet_hours / quiet_from / quiet_to (appended to the file, sentinel 0xC0DE0030; sizeof 2832 on nRF52 and ESP32), off by default, 22:00-07:00. hourInWindow() / localHour() are shared with the bot's quiet hours. soundctl::tick() replaces autoTick() (Auto and quiet hours). Also fixes the L2 side-button mute: it went by the mode, not by whether the buzzer was muted, so with Auto + an app connected (and now quiet hours) the first press muted instead of unmuting. Co-Authored-By: Claude Opus 5.5 --- docs/development/plan-next.md | 8 +++-- examples/companion_radio/DataStore.cpp | 15 ++++++++ examples/companion_radio/MyMesh.cpp | 2 ++ examples/companion_radio/MyMeshBot.h | 11 ++---- examples/companion_radio/NodePrefs.h | 33 +++++++++++++++-- .../companion_radio/ui-core/SettingsSchema.h | 13 +++++-- .../companion_radio/ui-core/SoundControl.h | 36 +++++++++++++------ examples/companion_radio/ui-lvgl/UITask.cpp | 8 ++--- .../companion_radio/ui-new/SettingsScreen.h | 21 +++++++++++ examples/companion_radio/ui-new/UITask.cpp | 6 ++-- 10 files changed, 121 insertions(+), 32 deletions(-) diff --git a/docs/development/plan-next.md b/docs/development/plan-next.md index d6b1f8de..e760b11b 100644 --- a/docs/development/plan-next.md +++ b/docs/development/plan-next.md @@ -52,12 +52,17 @@ for a second radio). They are L2-specific and block the loop for ~90 s. ## D. Quiet hours in the core -- [ ] A start and end time when the device is silent; in ui-core, so L1, L2 +- [x] A start and end time when the device is silent; in ui-core, so L1, L2 and other boards get it. New NodePrefs fields go at the end of the stored layout, so an L1 keeps its settings after the update. To decide: the Clock alarm rings anyway (proposed yes); whether a message wakes the screen during quiet hours; with the clock not set, quiet hours are off (proposed). + Done 2026-09-28: NodePrefs quiet_hours / quiet_from / quiet_to + (sentinel 0x30, sizeof 2832), off by default, 22-7; the alarm rings, a + message doesn't wake the screen, a manual mute / unmute stands until + the window ends. hourInWindow() / localHour() shared with the bot's + quiet hours. L2 tested; L1 built, not flashed yet. ## E. OTA end-to-end test @@ -107,5 +112,4 @@ it; implement the tiers, docs and website after the merge. ## Open decisions -- D: alarm during quiet hours; messages waking the screen. - I: tier spec before stage F, or after the merge. diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index 666bbc82..4c1469f9 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -627,6 +627,15 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no rd(&_prefs.display_brightness_pct, sizeof(_prefs.display_brightness_pct)); if (_prefs.display_brightness_pct > 100) _prefs.display_brightness_pct = 0; + // quiet_hours / quiet_from / quiet_to. Out of range -> off, 22-7; an older + // file's sentinel bytes landing here are reset below on the mismatch. + rd(&_prefs.quiet_hours, sizeof(_prefs.quiet_hours)); + rd(&_prefs.quiet_from, sizeof(_prefs.quiet_from)); + rd(&_prefs.quiet_to, sizeof(_prefs.quiet_to)); + if (_prefs.quiet_hours > 1) _prefs.quiet_hours = 0; + if (_prefs.quiet_from > 23) _prefs.quiet_from = 22; + if (_prefs.quiet_to > 23) _prefs.quiet_to = 7; + // Schema sentinel: bumped on layout changes. Mismatch means an older file // (or a different schema); rd() and the clamps above already keep every // field within its valid range regardless, so we just log it here — @@ -636,6 +645,9 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no if (sentinel != NodePrefs::SCHEMA_SENTINEL) { MESH_DEBUG_PRINTLN("prefs schema sentinel mismatch: got 0x%08X, expected 0x%08X — re-saving on next change", (unsigned)sentinel, (unsigned)NodePrefs::SCHEMA_SENTINEL); + // 0xC0DE002F → 0xC0DE0030: quiet hours appended; from an older file they + // hold its sentinel's bytes, so start off, 22:00-07:00. + if (sentinel < 0xC0DE0030) { _prefs.quiet_hours = 0; _prefs.quiet_from = 22; _prefs.quiet_to = 7; } // 0xC0DE002E → 0xC0DE002F: display_brightness_pct appended; from an older // file it holds a stray sentinel byte (0x2E = "46 %"), so start from the level. _prefs.display_brightness_pct = 0; @@ -828,6 +840,9 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_ file.write((uint8_t *)&_prefs.loc_share_scope, sizeof(_prefs.loc_share_scope)); file.write((uint8_t *)&_prefs.loc_share_duration_idx, sizeof(_prefs.loc_share_duration_idx)); file.write((uint8_t *)&_prefs.display_brightness_pct, sizeof(_prefs.display_brightness_pct)); + file.write((uint8_t *)&_prefs.quiet_hours, sizeof(_prefs.quiet_hours)); + file.write((uint8_t *)&_prefs.quiet_from, sizeof(_prefs.quiet_from)); + file.write((uint8_t *)&_prefs.quiet_to, sizeof(_prefs.quiet_to)); // Tail sentinel — must be last. See NodePrefs::SCHEMA_SENTINEL. Its write is // the one we check: once the flash fills, writes return 0, so a good diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index fd24c413..2ded2d80 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -1846,6 +1846,8 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe _prefs.radio_fem_txgain = 0; _prefs.display_brightness = 2; // medium brightness by default _prefs.buzzer_volume = 4; // max volume by default + _prefs.quiet_from = 22; // quiet hours (off by default) 22:00-07:00 + _prefs.quiet_to = 7; _prefs.ringtone_bpm_idx = 2; // 120 bpm default _prefs.ringtone_len = 0; // no custom ringtone by default _prefs.ringtone2_bpm_idx = 2; // 120 bpm default diff --git a/examples/companion_radio/MyMeshBot.h b/examples/companion_radio/MyMeshBot.h index 10486cec..0bccbe32 100644 --- a/examples/companion_radio/MyMeshBot.h +++ b/examples/companion_radio/MyMeshBot.h @@ -123,14 +123,9 @@ void MyMesh::botDmRecord(const uint8_t* pubkey) { // width window (start == end) disables the feature; a window where start > end // wraps past midnight. bool MyMesh::botInQuietHours() const { - if (_prefs.bot_quiet_start == _prefs.bot_quiet_end) return false; // disabled - uint32_t utc = getRTCClock()->getCurrentTime(); - if (utc < 1000000000UL) return false; // clock not set — don't suppress - uint32_t local = utc + (int32_t)_prefs.tz_offset_hours * 3600; - int h = (int)((local / 3600) % 24); - int s = _prefs.bot_quiet_start, e = _prefs.bot_quiet_end; - return (s < e) ? (h >= s && h < e) // same-day window - : (h >= s || h < e); // overnight window + int h; + if (!localHour(getRTCClock()->getCurrentTime(), _prefs.tz_offset_hours, h)) return false; // clock not set -- don't suppress + return hourInWindow(h, _prefs.bot_quiet_start, _prefs.bot_quiet_end); } void MyMesh::tryBotReplyDM(const ContactInfo& from, const char* text, uint8_t hops) { diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index c9c4e96d..7f029b4a 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -317,6 +317,13 @@ struct NodePrefs { // persisted to file uint8_t buzzer_quiet; uint8_t buzzer_volume; // 0=min..4=max, default 4 uint8_t buzzer_auto; // 0=manual (default), 1=auto-mute when BT connected + // Quiet hours: muted from quiet_from to quiet_to (local hours 0-23, wrapping + // past midnight) while quiet_hours is on; the clock alarm still rings and a + // message doesn't wake the screen (inQuietHours() below). A manual mute / + // unmute during the window stands until it ends (soundctl::tick()). + uint8_t quiet_hours; // 0=off (default), 1=on + uint8_t quiet_from; // default 22 + uint8_t quiet_to; // default 7 // Settings > Display > "Msg wake". Stored inverted (same reason as // fav_sort_off below) so both a fresh memset and an older prefs file (no // bytes here at all) mean "on" -- today's behaviour, where an incoming @@ -627,7 +634,7 @@ struct NodePrefs { // persisted to file // repeat_* fields) instead of at the tail, which shifted every field after // them by 25 bytes when loading an older file. Never released, but a dev // build wrote it, so the number must not be reused for anything else. - static const uint32_t SCHEMA_SENTINEL = 0xC0DE002F; + static const uint32_t SCHEMA_SENTINEL = 0xC0DE0030; // Bit-index for each home page. Used by page_order (entries store bit+1) and // by home_pages_mask. Single source of truth — both HomeScreen::pageBit/bitToPage @@ -704,6 +711,25 @@ struct NodePrefs { // persisted to file } }; +// Local hour `h` inside [start, end): a window with start > end wraps past +// midnight; start == end is no window. Shared by the bot's quiet hours and the +// sound's. +static inline bool hourInWindow(int h, int start, int end) { + if (start == end) return false; + return start < end ? (h >= start && h < end) : (h >= start || h < end); +} +// The local hour from a UTC time; false while the clock isn't set. +static inline bool localHour(uint32_t utc, int8_t tz_hours, int& h) { + if (utc < 1000000000UL) return false; + h = (int)(((int64_t)utc + (int64_t)tz_hours * 3600) / 3600 % 24); + return true; +} +// Settings > Sound > Quiet hours in force at `utc` (never with the clock unset). +static inline bool inQuietHours(const NodePrefs& p, uint32_t utc) { + int h; + return p.quiet_hours && localHour(utc, p.tz_offset_hours, h) && hourInWindow(h, p.quiet_from, p.quiet_to); +} + // ── Serialization tripwire ─────────────────────────────────────────────────── // NodePrefs is written/read field-by-field, in order, by DataStore::savePrefs() // and loadPrefsInt(); the on-disk format IS the struct's field layout. There is @@ -782,7 +808,10 @@ struct NodePrefs { // persisted to file // (ESP32) builds, sizeof unchanged at 2824. loc_share_duration_idx (0xC0DE002E) // likewise (sim build; see the check below). display_brightness_pct (0xC0DE002F) // likewise (L2 ESP32 + L1 nRF52 builds). -static_assert(sizeof(NodePrefs) == 2824, +// quiet_hours / quiet_from / quiet_to (0xC0DE0030) added 8 bytes, not 3 (next +// to buzzer_auto, rounded up to the alignment) -- sizeof 2832, confirmed via real +// WioTrackerL1_companion_solo_dual (nRF52/ARM) and L2 (ESP32) builds. +static_assert(sizeof(NodePrefs) == 2832, "NodePrefs layout changed — sync DataStore save/load + clamp, bump " "SCHEMA_SENTINEL, then update this size (see steps above)."); diff --git a/examples/companion_radio/ui-core/SettingsSchema.h b/examples/companion_radio/ui-core/SettingsSchema.h index a56ef5fc..06310ddd 100644 --- a/examples/companion_radio/ui-core/SettingsSchema.h +++ b/examples/companion_radio/ui-core/SettingsSchema.h @@ -25,7 +25,7 @@ enum Page : uint8_t { PG_NAV, PG_ADVERT, PG_DEVICE, PG_MESSAGES, PG_SOUND, PG_CO enum Section : uint8_t { SEC_TRAIL, SEC_LIVE_SHARE, SEC_LOCATOR, SEC_ADVERT, SEC_DISPLAY, SEC_POWER, SEC_TIME, SEC_UNITS, SEC_MESSAGES, SEC_CONTACTS, - SEC_SOUND, SEC_SOUND_FOR, SEC_COUNT }; + SEC_SOUND, SEC_SOUND_FOR, SEC_QUIET, SEC_COUNT }; static const char* pageTitle(uint8_t p) { static const char* T[PG_COUNT] = { "Map options", "Advert", "Display & power", "Messages & contacts", "Sound" }; @@ -35,14 +35,14 @@ static const char* sectionTitle(uint8_t s) { static const char* T[SEC_COUNT] = { "TRAIL", "LIVE SHARE", "ARRIVAL ALERT", "AUTOMATIC", "DISPLAY", "POWER", "TIME", "UNITS", "MESSAGES", "CONTACTS", - "SOUND", "PLAYS FOR" }; + "SOUND", "PLAYS FOR", "QUIET HOURS" }; return s < SEC_COUNT ? T[s] : ""; } static uint8_t sectionPage(uint8_t s) { static const uint8_t P[SEC_COUNT] = { PG_NAV, PG_NAV, PG_NAV, PG_ADVERT, PG_DEVICE, PG_DEVICE, PG_DEVICE, PG_DEVICE, PG_MESSAGES, PG_MESSAGES, - PG_SOUND, PG_SOUND }; + PG_SOUND, PG_SOUND, PG_SOUND }; return s < SEC_COUNT ? P[s] : PG_DEVICE; } @@ -136,6 +136,10 @@ static void optVolume(uint8_t v, char* b, int n, const NodePrefs&) { static const char* L[5] = { "Quietest", "Quiet", "Medium", "Loud", "Loudest" }; snprintf(b, n, "%s", L[v < 5 ? v : 4]); } +static void optHour(uint8_t v, char* b, int n, const NodePrefs& p) { // "22:00", or "10 PM" with the 12-hour clock + if (!p.clock_12h) snprintf(b, n, "%02u:00", (unsigned)v); + else snprintf(b, n, "%u %s", (unsigned)(v % 12 ? v % 12 : 12), v < 12 ? "AM" : "PM"); +} static void optSound(uint8_t v, char* b, int n, const NodePrefs&) { snprintf(b, n, "%s", soundctl::soundLabel(v)); } static void optAdvertScope(uint8_t v, char* b, int n, const NodePrefs&) { snprintf(b, n, "%s", v == ADVERT_SOUND_SCOPE_ZERO_HOP ? "Direct only" : "All"); @@ -209,6 +213,9 @@ static const Setting ALL[] = { // On / Off / Auto spans two fields (soundctl::setMode): the frontend's own row. IDX("Volume", nullptr, SEC_SOUND, buzzer_volume, 5, optVolume, applySound), + SW("Quiet hours", "Muted, screen dark; alarms ring", SEC_QUIET, quiet_hours, nullptr), + IDX("From", nullptr, SEC_QUIET, quiet_from, 24, optHour, nullptr), + IDX("Until", nullptr, SEC_QUIET, quiet_to, 24, optHour, nullptr), IDX("Direct messages", nullptr, SEC_SOUND_FOR, notif_melody_dm, soundctl::SOUND_COUNT, optSound, nullptr), IDX("Channels", nullptr, SEC_SOUND_FOR, notif_melody_ch, soundctl::SOUND_COUNT, optSound, nullptr), diff --git a/examples/companion_radio/ui-core/SoundControl.h b/examples/companion_radio/ui-core/SoundControl.h index 176b0d3b..4287fa47 100644 --- a/examples/companion_radio/ui-core/SoundControl.h +++ b/examples/companion_radio/ui-core/SoundControl.h @@ -3,7 +3,7 @@ // Ringtone) and ui-lvgl (Settings > Sound, Melodies): the On / Off / Auto mode // (buzzer_quiet + buzzer_auto), the volume, the built-in sounds, the labels of // the notification sound choices, and the two user melodies (ringtone_* / -// ringtone2_*) as an editable note list. Which sound a message plays is +// ringtone2_*) as an editable note list. Quiet hours mute on a schedule. Which sound a message plays is // SoundNotifier.h. #include "../NodePrefs.h" @@ -44,10 +44,21 @@ static const char* soundLabel(uint8_t v) { static const uint8_t OVERRIDE_COUNT = 3; #ifdef PIN_BUZZER -// The mute that goes with the mode; `connected`: an app is connected. -static void applyMode(const NodePrefs* p, genericBuzzer& b, bool connected) { +// Quiet hours (NodePrefs::inQuietHours) mute like the mode does. A mute or +// unmute by hand inside the window stands until the window ends. +static bool s_quiet_now = false; // inside the window, as of the last tick +static bool s_quiet_override = false; // set by hand since the window began + +// The mute that goes with the mode and quiet hours; `connected`: an app is +// connected. +static bool wantQuiet(const NodePrefs* p, bool connected) { uint8_t m = mode(p); - b.quiet(m == MODE_OFF || (m == MODE_AUTO && connected)); + if (m == MODE_OFF || (m == MODE_AUTO && connected)) return true; + return s_quiet_now && !s_quiet_override; +} +static void applyMode(const NodePrefs* p, genericBuzzer& b, bool connected, uint32_t utc) { + s_quiet_now = p && inQuietHours(*p, utc); + b.quiet(wantQuiet(p, connected)); } // Auto keeps buzzer_quiet (the manual choice it goes back to). The caller @@ -56,16 +67,21 @@ static void setMode(NodePrefs* p, genericBuzzer& b, uint8_t m, bool connected) { if (!p || m >= MODE_COUNT) return; p->buzzer_auto = m == MODE_AUTO; if (m != MODE_AUTO) p->buzzer_quiet = m == MODE_OFF; - applyMode(p, b, connected); + s_quiet_override = s_quiet_now; // a choice made during quiet hours wins until they end + b.quiet(wantQuiet(p, connected)); } -// From the loop: Auto follows the app connection. True when the mute changed. -static bool autoTick(const NodePrefs* p, genericBuzzer& b, bool connected) { - if (!p || !p->buzzer_auto || b.isQuiet() == connected) return false; - b.quiet(connected); +// From the loop: Auto follows the app connection, quiet hours the clock. +// True when the mute changed. +static bool tick(const NodePrefs* p, genericBuzzer& b, bool connected, uint32_t utc) { + if (!p) return false; + bool q = inQuietHours(*p, utc); + if (q != s_quiet_now) { s_quiet_now = q; s_quiet_override = false; } + bool want = wantQuiet(p, connected); + if (b.isQuiet() == want) return false; + b.quiet(want); return true; } - // Level 0..4, with a preview beep (through mute: it answers the user's own // change). The caller saves the prefs. static void setVolume(NodePrefs* p, genericBuzzer& b, uint8_t level) { diff --git a/examples/companion_radio/ui-lvgl/UITask.cpp b/examples/companion_radio/ui-lvgl/UITask.cpp index 05681a3a..de0dedbc 100644 --- a/examples/companion_radio/ui-lvgl/UITask.cpp +++ b/examples/companion_radio/ui-lvgl/UITask.cpp @@ -823,7 +823,7 @@ void UITask::begin(DisplayDriver* display_drv, SensorManager* sensors, NodePrefs user_btn.begin(); #endif #ifdef PIN_BUZZER - soundctl::applyMode(_prefs, _buzzer, isClientConnected()); + soundctl::applyMode(_prefs, _buzzer, isClientConnected(), rtc_clock.getCurrentTime()); _buzzer.setVolume(_prefs ? _prefs->buzzer_volume : 4); _buzzer.begin(); // plays the startup sound unless muted #endif @@ -852,7 +852,7 @@ MyMesh::Listener* UITask::meshListener() { return _core; } void UITask::toggleMute() { #ifdef PIN_BUZZER if (!_prefs) return; - bool on = soundctl::mode(_prefs) != soundctl::MODE_ON; + bool on = _buzzer.isQuiet(); // muted now, however (mode, Auto, quiet hours): sound on soundctl::setMode(_prefs, _buzzer, on ? soundctl::MODE_ON : soundctl::MODE_OFF, isClientConnected()); prefsSave(); if (on) _buzzer.playForced(soundctl::MEL_VOLUME); @@ -988,7 +988,7 @@ void UITask::loop() { #endif #ifdef PIN_BUZZER _buzzer.loop(); - if (soundctl::autoTick(_prefs, _buzzer, isClientConnected()) && !_asleep) refreshStatusBar(); + if (soundctl::tick(_prefs, _buzzer, isClientConnected(), rtc_clock.getCurrentTime()) && !_asleep) refreshStatusBar(); // The alarm melody repeats until dismissed or the ring window ends. if (_core->clock.isRinging() && !_buzzer.isPlaying()) playMelody(soundctl::MEL_ALARM); #endif @@ -1289,7 +1289,7 @@ void UITask::onMessageArrived(const UiEvent& ev) { } // Wake for the message unless an app is already showing it, or the user // turned message-wake off. - bool wake_disabled = _prefs && _prefs->msg_wake_screen_off; + bool wake_disabled = _prefs && (_prefs->msg_wake_screen_off || inQuietHours(*_prefs, rtc_clock.getCurrentTime())); // quiet hours: dark too if (_asleep && !wake_disabled && !isClientConnected()) wake(); else if (!_asleep) lv_display_trigger_activity(NULL); bool open_here = _screen == SCR_THREAD && diff --git a/examples/companion_radio/ui-new/SettingsScreen.h b/examples/companion_radio/ui-new/SettingsScreen.h index 9bb7bb14..63b06e74 100644 --- a/examples/companion_radio/ui-new/SettingsScreen.h +++ b/examples/companion_radio/ui-new/SettingsScreen.h @@ -41,6 +41,7 @@ class SettingsScreen : public UIScreen { SECTION_SOUND, BUZZER, BUZZER_VOLUME, + QUIET_HOURS, QUIET_FROM, QUIET_TO, DM_MELODY, CH_MELODY, AD_SOUND, @@ -480,6 +481,17 @@ class SettingsScreen : public UIScreen { display.setCursor(valCol(display), y); display.print("N/A"); #endif + } else if (item == QUIET_HOURS) { + display.print("Quiet hrs"); + display.setCursor(valCol(display), y); + display.print((p && p->quiet_hours) ? "ON" : "OFF"); + } else if (item == QUIET_FROM || item == QUIET_TO) { + display.print(item == QUIET_FROM ? " from" : " until"); + display.setCursor(valCol(display), y); + { char hb[8]; uint8_t h = p ? (item == QUIET_FROM ? p->quiet_from : p->quiet_to) : 0; + if (p && p->clock_12h) snprintf(hb, sizeof(hb), "%u%s", (unsigned)(h % 12 ? h % 12 : 12), h < 12 ? "AM" : "PM"); + else snprintf(hb, sizeof(hb), "%02u:00", (unsigned)h); + display.print(hb); } } else if (item == DM_MELODY) { display.print("DM sound"); display.setCursor(valCol(display), y); @@ -1027,6 +1039,15 @@ public: #endif return right || left; } + if (_selected == QUIET_HOURS && p && (left || right || enter)) { + p->quiet_hours ^= 1; + _dirty = true; return true; + } + if ((_selected == QUIET_FROM || _selected == QUIET_TO) && p && (left || right || enter)) { + uint8_t& h = _selected == QUIET_FROM ? p->quiet_from : p->quiet_to; + h = (h + (left ? 23 : 1)) % 24; + _dirty = true; return true; + } if (_selected == DM_MELODY && p && (left || right || enter)) { p->notif_melody_dm = (p->notif_melody_dm + (left ? SOUND_COUNT - 1 : 1)) % SOUND_COUNT; _dirty = true; return true; diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 58ba1249..6fbbd416 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -1593,7 +1593,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no } #ifdef PIN_BUZZER - soundctl::applyMode(_node_prefs, buzzer, false); + soundctl::applyMode(_node_prefs, buzzer, false, rtc_clock.getCurrentTime()); buzzer.setVolume(_node_prefs->buzzer_volume); buzzer.begin(); #endif @@ -1952,7 +1952,7 @@ void UITask::onMessageArrived(const UiEvent& ev) { showAlert(alert_buf, 3000); if (_display != NULL && !_locked) { - bool wake_disabled = _node_prefs && _node_prefs->msg_wake_screen_off; + bool wake_disabled = _node_prefs && (_node_prefs->msg_wake_screen_off || inQuietHours(*_node_prefs, rtc_clock.getCurrentTime())); if (!wake_disabled && !_display->isOn() && !isClientConnected()) { // wake for the msg unless an app (BLE/USB) is already showing it, or the user disabled msg-wake _display->turnOn(); } @@ -2686,7 +2686,7 @@ void UITask::loop() { userLedHandler(); #ifdef PIN_BUZZER - if (soundctl::autoTick(_node_prefs, buzzer, isClientConnected())) // BLE bonded or an open USB port + if (soundctl::tick(_node_prefs, buzzer, isClientConnected(), rtc_clock.getCurrentTime())) // BLE bonded or an open USB port _next_refresh = 0; if (buzzer.isPlaying()) buzzer.loop(); #endif