mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-09-14 23:26:38 +00:00
feat(admin): add confirmed "Start OTA" action for remote nodes
start ota was already sendable via Admin's Custom-command row (and CLI-reachable directly), but had no dedicated menu entry. Adds a row to the Actions tab that confirms first (Start/Cancel, defaulting to Cancel) before sending -- unlike Reboot, OTA parks the remote in BLE DFU mode for the duration of the update, disruptive enough to warrant the extra step. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -568,13 +568,13 @@ Send commands to a **repeater/room server you have admin permission on** — the
|
||||
| **System** | Name, Owner info, Admin password |
|
||||
| **Radio** | Frequency, Bandwidth, Spreading factor, Coding rate, TX power |
|
||||
| **Routing** | Repeat, Advert interval, Flood advert interval, Max hops |
|
||||
| **Actions** | Send advert, Send zero-hop advert, Sync clock, Reboot, **Custom command...** |
|
||||
| **Actions** | Send advert, Send zero-hop advert, Sync clock, Reboot, Start OTA, **Custom command...** |
|
||||
|
||||
**Enter** on a row does one of four things, depending on the field:
|
||||
- **Name / Owner info** first **fetch** the node's current value, then open the keyboard **pre-filled** with it to edit — submitting sends the change. If the fetch fails or times out, the keyboard still opens (blank), so the value can be set blind.
|
||||
- **Radio and Routing rows** are typed, not free text: **Repeat** is an ON/OFF toggle; **Advert interval / Flood advert interval / Max hops / TX power** are number steppers (**LEFT/RIGHT** to adjust, within that field's valid range); **Frequency** uses the same digit-by-digit cursor editor as Settings' own Radio screen (**LEFT/RIGHT** moves between digits, **UP/DOWN** changes the selected one); **Bandwidth / Spreading factor / Coding rate** step through their valid discrete LoRa values with **LEFT/RIGHT**. All four Radio-tuple fields (Frequency/Bandwidth/SF/Coding rate) fetch and re-send the same underlying `radio` value together — editing any one of them still only overwrites that one, the other three round-trip unchanged. **Enter** sends the change; **Cancel** discards it and returns to the row list without sending anything.
|
||||
- **Admin password** has no fetch (there's no way to read a password back) — it opens straight to a blank keyboard.
|
||||
- **Actions** (Reboot, Send advert, …) send immediately, no editing step.
|
||||
- **Actions** (Reboot, Send advert, …) send immediately, no editing step — except **Start OTA**, which asks **Start / Cancel** first (defaulting to Cancel): it puts the remote into BLE DFU mode for the duration of the update, far more disruptive than a quick reboot.
|
||||
- **Custom command...** (last row of Actions) opens the same free-text entry for anything not covered above — up to 160 characters, see the linked reference for the full grammar. The keyboard's **{}** key doubles as command completion here: it lists commands matching whatever's typed since the last space (narrowing as you type), and picking one completes that word instead of just inserting after it.
|
||||
4. **Read the reply** — the text reply opens in a scrollable view (**UP/DOWN** to scroll, **Cancel/Enter** to go back to the category tabs).
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "FullscreenMsgView.h"
|
||||
#include "TabBar.h"
|
||||
#include "PopupMenu.h" // "Start OTA" confirmation
|
||||
#include "RadioParamsEditor.h" // DigitEditor + stepSF/stepBW/stepCR -- same widgets Settings/Repeater use locally
|
||||
#include <helpers/ClientACL.h> // PERM_ACL_ADMIN / PERM_ACL_ROLE_MASK
|
||||
|
||||
@@ -137,6 +138,15 @@ class AdminScreen : public UIScreen {
|
||||
FullscreenMsgView _reply_view;
|
||||
char _reply_text[200] = "";
|
||||
|
||||
// "Start OTA" confirmation -- pulls the remote out of the mesh into BLE DFU
|
||||
// mode for the duration of the update, far more disruptive than the other
|
||||
// one-shot actions on this tab, so unlike Reboot it doesn't fire on a bare
|
||||
// Enter. Only this one action needs a confirm today, so it's special-cased
|
||||
// in activateField() by command string rather than adding a generic
|
||||
// needs_confirm flag to every AdminField literal below.
|
||||
PopupMenu _confirm;
|
||||
const AdminField* _pending_confirm_field = nullptr;
|
||||
|
||||
KeyboardWidget& kb() { return _task->keyboard(); }
|
||||
|
||||
bool isAdminOk(const uint8_t* pub_key) const {
|
||||
@@ -226,6 +236,14 @@ class AdminScreen : public UIScreen {
|
||||
if (f.get_cmd == nullptr && f.set_prefix == nullptr) { // Custom command...
|
||||
openValueKb(_cmd_text, true);
|
||||
} else if (f.set_prefix == nullptr) { // Action
|
||||
if (!strcmp(f.get_cmd, "start ota")) { // see _confirm's comment
|
||||
_pending_confirm_field = &f;
|
||||
_confirm.begin("Start OTA update?", 2);
|
||||
_confirm.addItem("Start");
|
||||
_confirm.addItem("Cancel");
|
||||
_confirm.setSelected(1); // default highlight = Cancel
|
||||
return;
|
||||
}
|
||||
strncpy(_cmd_text, f.get_cmd, sizeof(_cmd_text) - 1);
|
||||
_cmd_text[sizeof(_cmd_text) - 1] = '\0';
|
||||
sendCommand();
|
||||
@@ -333,6 +351,8 @@ public:
|
||||
_value_editing = false;
|
||||
_login_waiting = false;
|
||||
_admin_ok = false;
|
||||
_confirm.active = false;
|
||||
_pending_confirm_field = nullptr;
|
||||
}
|
||||
|
||||
// Canonical entry for a specific target -- called by UITask::openAdminFor(),
|
||||
@@ -519,6 +539,7 @@ public:
|
||||
}
|
||||
}
|
||||
});
|
||||
if (_confirm.active) { _confirm.render(display); return 50; }
|
||||
return _value_editing ? 50 : 2000;
|
||||
}
|
||||
|
||||
@@ -552,6 +573,20 @@ public:
|
||||
}
|
||||
|
||||
if (_phase == COMMAND) {
|
||||
if (_confirm.active) {
|
||||
auto res = _confirm.handleInput(c);
|
||||
if (res == PopupMenu::SELECTED) {
|
||||
if (_confirm.selectedIndex() == 0 && _pending_confirm_field) {
|
||||
strncpy(_cmd_text, _pending_confirm_field->get_cmd, sizeof(_cmd_text) - 1);
|
||||
_cmd_text[sizeof(_cmd_text) - 1] = '\0';
|
||||
sendCommand();
|
||||
}
|
||||
_pending_confirm_field = nullptr;
|
||||
} else if (res == PopupMenu::CANCELLED) {
|
||||
_pending_confirm_field = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (_kb_active) {
|
||||
auto r = kb().handleInput(c);
|
||||
if (r == KeyboardWidget::DONE) {
|
||||
@@ -670,6 +705,7 @@ const AdminScreen::AdminField AdminScreen::ACTION_FIELDS[] = {
|
||||
{ "Send zero-hop advert", "advert.zerohop", nullptr },
|
||||
{ "Sync clock", "clock sync", nullptr },
|
||||
{ "Reboot", "reboot", nullptr }, // disruptive + no confirm: keep off the default row
|
||||
{ "Start OTA", "start ota", nullptr }, // confirmed first -- see _confirm's comment
|
||||
{ "Custom command...", nullptr, nullptr },
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
- **Optional magnetic "flip cover" screen lock**, for anyone who wants to wire a Hall-effect or reed sensor to a free GPIO — no board ships one built in. Set `PIN_HALL_SENSOR` as a build flag on your own env and closing the cover locks and blanks the screen instantly, opening it unlocks and wakes it — no combo, independent of Auto-lock. See [Screen Lock](docs/solo_features/screen_lock/screen_lock.md#magnetic-cover-hall-sensor).
|
||||
- **Experimental: solo build for ProMicro (nRF52840)**, with CardKB support sharing the board's primary I2C bus (no free pins for a second one on this board). Contributed by @tchellow — thanks!
|
||||
- **New [Build Flags](docs/solo_features/build_flags.md) reference** — every optional `-D` flag a solo build understands (GPIO, CardKB/joystick, Hall-sensor cover lock, buzzer/vibration, GPS switch, display/battery tuning) in one place.
|
||||
- **Tools › Admin gains a "Start OTA" action** for a repeater/room server you're logged into — sends the same `start ota` CLI command the Custom-command row already reached, now with its own menu row and a confirm ("Start" defaulting to "Cancel" first) since it puts the remote into BLE DFU mode for the duration of the update.
|
||||
|
||||
### Fixes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user