feat: per-contact actions, device settings, a companion CLI and your contact's QR code

- Nodes: telemetry permissions per contact, reset path, share nearby
  (L1 options menu; L2 node card with "Can ask for" switches)
- Settings > Privacy: fixed position (typed in, from a waypoint, cleared)
  and the Bluetooth PIN; Settings > System: factory reset, asked twice
- Companion CLI (CMD_RUN_CLI_COMMAND 66 / RESP_CODE_CLI_REPLY 29, as
  upstream; FIRMWARE_VER_CODE 14): upstream's command names plus a key for
  every schema setting (get / set / keys)
- Screenshots move to 0x7E; tools/screenshot.py falls back to 66 / 29
- Your contact as a QR code (meshcore://contact/add): Status > System on
  ui-new, Settings > About on the L2; Nayuki's qrcodegen made header-only

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-10-10 09:59:35 +02:00
co-authored by Claude Opus 5.5
parent 6fba3dfca7
commit c5bb4752d0
22 changed files with 2521 additions and 86 deletions
+21 -1
View File
@@ -9,7 +9,7 @@
class UITask;
/*------------ Frame Protocol --------------*/
#define FIRMWARE_VER_CODE 13
#define FIRMWARE_VER_CODE 14 // 14: CMD_RUN_CLI_COMMAND, as upstream
// Fallback only -- every real build (local or CI) goes through build.sh, which
// always injects its own FIRMWARE_BUILD_DATE (today's date at build time).
@@ -188,6 +188,9 @@ public:
// its state and restarts. Returns false if it doesn't handle it, and
// MyMesh then flushes and reboots by itself.
virtual bool requestShutdown(bool restart) { return false; }
// A companion CLI command MyMesh has no answer for (its settings keys):
// the reply into `reply` (n bytes), false when unknown.
virtual bool onCliCommand(const char* command, char* reply, int n) { return false; }
};
MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store);
@@ -402,6 +405,22 @@ public:
// "fav" list filters no longer depend on the app having starred anything.
bool setContactFavourite(const uint8_t* pub_key, bool fav);
// On-device per-contact telemetry permissions (Nodes): ContactInfo::flags
// bits 1-3 = status / location / sensors, read where Settings > Privacy says
// "Allowed" (onContactRequest). The same bits the app's per-contact toggles write.
bool setContactTelemetry(const uint8_t* pub_key, uint8_t perms);
// On-device path reset (Nodes): forget the learned route; the next message
// floods and learns a new one, as CMD_RESET_PATH does.
bool resetContactPath(const uint8_t* pub_key);
// Factory reset (CMD_FACTORY_RESET, Settings on the device): the serial link
// off, then every file and setting erased, keys too. The caller reboots.
bool factoryReset();
// Companion CLI (MyMeshCli.h): CMD_RUN_CLI_COMMAND's text in, the reply out.
bool handleCliCommand(const char* command, char* reply, int n);
// On-device "remote admin" (Tools > Admin): send a CLI command to a node
// you're logged into with admin permission (see ClientACL::isAdmin()). The
// reply is a text frame (TXT_TYPE_CLI_DATA) delivered via onCommandDataRecv();
@@ -592,6 +611,7 @@ private:
}
void checkCLIRescueCmd();
bool cliRadioCommand(const char* command, char* reply, int n);
void checkSerialInterface();
bool isValidClientRepeatFreq(uint32_t f) const;
#ifdef ENABLE_SCREENSHOT