From ce55ba3cea96f2097d26b0af6dc4de2b814f5d35 Mon Sep 17 00:00:00 2001 From: nomdetom Date: Tue, 2 Jun 2026 21:52:03 +0100 Subject: [PATCH 1/8] feat: add MeshBeacon portnum, wire message, and module config --- meshtastic/mesh_beacon.options | 3 ++ meshtastic/mesh_beacon.proto | 42 ++++++++++++++++++ meshtastic/module_config.options | 6 +++ meshtastic/module_config.proto | 73 ++++++++++++++++++++++++++++++++ meshtastic/portnums.proto | 8 ++++ 5 files changed, 132 insertions(+) create mode 100644 meshtastic/mesh_beacon.options create mode 100644 meshtastic/mesh_beacon.proto diff --git a/meshtastic/mesh_beacon.options b/meshtastic/mesh_beacon.options new file mode 100644 index 000000000..cd4099cde --- /dev/null +++ b/meshtastic/mesh_beacon.options @@ -0,0 +1,3 @@ +*MeshBeacon.message max_size:101 +*MeshBeacon.offer_channel.name max_size:12 +*MeshBeacon.offer_channel.psk max_size:32 diff --git a/meshtastic/mesh_beacon.proto b/meshtastic/mesh_beacon.proto new file mode 100644 index 000000000..3ca59f54e --- /dev/null +++ b/meshtastic/mesh_beacon.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +package meshtastic; + +import "meshtastic/channel.proto"; +import "meshtastic/config.proto"; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "MeshBeaconProtos"; +option java_package = "org.meshtastic.proto"; +option swift_prefix = ""; + +/* + * Payload for MESH_BEACON_APP packets. + * Periodically broadcast by nodes in beacon mode. + * Listeners deliver the text message to the local inbox and cache any offered + * channel/preset for the client app to act on — the firmware never auto-applies them. + */ +message MeshBeacon { + /* + * Human-readable beacon message. Max 100 bytes enforced by firmware on send. + */ + string message = 1; + + /* + * Optional channel (name + PSK) being advertised to listening clients. + * A client app may offer to switch the user to this channel; firmware never applies it automatically. + */ + ChannelSettings offer_channel = 2; + + /* + * Optional region being advertised alongside offer_preset. + */ + Config.LoRaConfig.RegionCode offer_region = 3; + + /* + * Optional modem preset being advertised. + * Combined with offer_region, tells a client "there is a mesh on this preset/region". + */ + Config.LoRaConfig.ModemPreset offer_preset = 4; +} diff --git a/meshtastic/module_config.options b/meshtastic/module_config.options index c6158befa..1a4efaa9a 100644 --- a/meshtastic/module_config.options +++ b/meshtastic/module_config.options @@ -29,3 +29,9 @@ *DetectionSensorConfig.detection_trigger_type max_size:8 *StatusMessageConfig.node_status max_size:80 + +*MeshBeaconConfig.broadcast_message max_size:101 +*MeshBeaconConfig.broadcast_offer_channel.name max_size:12 +*MeshBeaconConfig.broadcast_offer_channel.psk max_size:32 +*MeshBeaconConfig.broadcast_on_channel.name max_size:12 +*MeshBeaconConfig.broadcast_on_channel.psk max_size:32 diff --git a/meshtastic/module_config.proto b/meshtastic/module_config.proto index a134f74c5..987cf42e3 100644 --- a/meshtastic/module_config.proto +++ b/meshtastic/module_config.proto @@ -857,6 +857,74 @@ message ModuleConfig { string node_status = 1; } + /* + * MeshBeacon module config + */ + message MeshBeaconConfig { + /* + * Enable receiving MESH_BEACON_APP packets from other nodes. + * The text portion is delivered to the local message inbox. + * Offered channel/preset are stored for the client app to act on. + */ + bool listen_enabled = 1; + + /* + * Enable periodically broadcasting MESH_BEACON_APP packets from this node. + */ + bool broadcast_enabled = 2; + + /* + * Optional: node ID to send beacon messages AS. + * When set, the `from` field of outgoing beacon packets is set to this node ID, + * making beacons appear to originate from that node. + * When unset (0), beacons are sent as the local node. + * A remote admin can only set this field to their own node ID. + */ + uint32 broadcast_send_as_node = 3; + + /* + * Message to include in each beacon broadcast. Max 100 bytes enforced by firmware. + */ + string broadcast_message = 4; + + /* + * Optional channel (name + PSK) to advertise in the MeshBeacon offer_channel field. + */ + ChannelSettings broadcast_offer_channel = 5; + + /* + * Optional region to advertise in the MeshBeacon offer_region field. + */ + Config.LoRaConfig.RegionCode broadcast_offer_region = 6; + + /* + * Optional modem preset to advertise in the MeshBeacon offer_preset field. + */ + Config.LoRaConfig.ModemPreset broadcast_offer_preset = 7; + + /* + * Channel settings (name + PSK) to use when sending beacons. + * If unset, beacons go out on the primary channel. + */ + ChannelSettings broadcast_on_channel = 8; + + /* + * Region to use when sending beacons on broadcast_on_preset. + */ + Config.LoRaConfig.RegionCode broadcast_on_region = 9; + + /* + * Modem preset to use when sending beacons. + * If different from current config, the radio is temporarily switched for TX. + */ + Config.LoRaConfig.ModemPreset broadcast_on_preset = 10; + + /* + * How often to broadcast, in seconds. Min 3600 (1 h), max 259200 (72 h). Default 3600. + */ + uint32 broadcast_interval_secs = 11; + } + /* * TODO: REPLACE */ @@ -940,6 +1008,11 @@ message ModuleConfig { * TAK team/role configuration for TAK_TRACKER */ TAKConfig tak = 16; + + /* + * MeshBeacon module config + */ + MeshBeaconConfig mesh_beacon = 17; } /* diff --git a/meshtastic/portnums.proto b/meshtastic/portnums.proto index 61412cfe5..5ebe26fb0 100644 --- a/meshtastic/portnums.proto +++ b/meshtastic/portnums.proto @@ -155,6 +155,14 @@ enum PortNum { */ NODE_STATUS_APP = 36; + /* + * Beacon module broadcast packets. + * ENCODING: protobuf (MeshBeacon) + * Periodically broadcast by nodes in beacon mode; received by nodes with listen_enabled. + * Carries a text message plus optional channel/preset offers for client apps. + */ + MESH_BEACON_APP = 37; + /* * Provides a hardware serial interface to send and receive from the Meshtastic network. * Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic From 6546d167d94c715e4d75ad6fbc77d50b2e57854d Mon Sep 17 00:00:00 2001 From: nomdetom Date: Tue, 2 Jun 2026 21:53:57 +0100 Subject: [PATCH 2/8] fix: add missing channel.proto and config.proto imports to module_config --- meshtastic/module_config.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meshtastic/module_config.proto b/meshtastic/module_config.proto index 987cf42e3..001e9c94c 100644 --- a/meshtastic/module_config.proto +++ b/meshtastic/module_config.proto @@ -3,6 +3,8 @@ syntax = "proto3"; package meshtastic; import "meshtastic/atak.proto"; +import "meshtastic/channel.proto"; +import "meshtastic/config.proto"; option csharp_namespace = "Meshtastic.Protobufs"; option go_package = "github.com/meshtastic/go/generated"; From 3d8599d285835996b57f9b931cbc636245624985 Mon Sep 17 00:00:00 2001 From: nomdetom Date: Tue, 2 Jun 2026 22:13:13 +0100 Subject: [PATCH 3/8] feat: add mesh_beacon field to LocalModuleConfig (localonly.proto) --- meshtastic/localonly.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meshtastic/localonly.proto b/meshtastic/localonly.proto index 2a6c7cacd..4f846e538 100644 --- a/meshtastic/localonly.proto +++ b/meshtastic/localonly.proto @@ -146,6 +146,11 @@ message LocalModuleConfig { */ ModuleConfig.TAKConfig tak = 17; + /* + * MeshBeacon Config + */ + ModuleConfig.MeshBeaconConfig mesh_beacon = 18; + /* * A version integer used to invalidate old save files when we make * incompatible changes This integer is set at build time and is private to From 23b869d373b7a46b33adfc081ba2fe52a871200c Mon Sep 17 00:00:00 2001 From: nomdetom Date: Wed, 3 Jun 2026 06:20:37 +0100 Subject: [PATCH 4/8] mmmmm... beacon --- meshtastic/mesh_beacon.proto | 2 +- meshtastic/module_config.proto | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meshtastic/mesh_beacon.proto b/meshtastic/mesh_beacon.proto index 3ca59f54e..c6005ab71 100644 --- a/meshtastic/mesh_beacon.proto +++ b/meshtastic/mesh_beacon.proto @@ -38,5 +38,5 @@ message MeshBeacon { * Optional modem preset being advertised. * Combined with offer_region, tells a client "there is a mesh on this preset/region". */ - Config.LoRaConfig.ModemPreset offer_preset = 4; + optional Config.LoRaConfig.ModemPreset offer_preset = 4; } diff --git a/meshtastic/module_config.proto b/meshtastic/module_config.proto index 001e9c94c..5d4878a17 100644 --- a/meshtastic/module_config.proto +++ b/meshtastic/module_config.proto @@ -902,7 +902,7 @@ message ModuleConfig { /* * Optional modem preset to advertise in the MeshBeacon offer_preset field. */ - Config.LoRaConfig.ModemPreset broadcast_offer_preset = 7; + optional Config.LoRaConfig.ModemPreset broadcast_offer_preset = 7; /* * Channel settings (name + PSK) to use when sending beacons. @@ -919,7 +919,7 @@ message ModuleConfig { * Modem preset to use when sending beacons. * If different from current config, the radio is temporarily switched for TX. */ - Config.LoRaConfig.ModemPreset broadcast_on_preset = 10; + optional Config.LoRaConfig.ModemPreset broadcast_on_preset = 10; /* * How often to broadcast, in seconds. Min 3600 (1 h), max 259200 (72 h). Default 3600. From d682190d03892b6281dd59ae45eca33b00185e26 Mon Sep 17 00:00:00 2001 From: nomdetom Date: Wed, 3 Jun 2026 22:10:54 +0100 Subject: [PATCH 5/8] legacy mode activate --- meshtastic/module_config.proto | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/meshtastic/module_config.proto b/meshtastic/module_config.proto index 5d4878a17..d74de6cab 100644 --- a/meshtastic/module_config.proto +++ b/meshtastic/module_config.proto @@ -925,6 +925,16 @@ message ModuleConfig { * How often to broadcast, in seconds. Min 3600 (1 h), max 259200 (72 h). Default 3600. */ uint32 broadcast_interval_secs = 11; + + /* + * When true and both broadcast_message and offer content (preset/channel/region) are present, + * the broadcaster splits them into two separate packets instead of one combined MESH_BEACON_APP: + * - Packet A: MESH_BEACON_APP carrying only the offer fields (no text) on the beacon radio config. + * - Packet B: TEXT_MESSAGE_APP carrying only the broadcast_message on the normal radio config. + * This ensures nodes that only decode TEXT_MESSAGE_APP can still receive the human-readable text. + */ + bool broadcast_legacy_split = 12; + } /* From d381bbbcb7bca33e5ef087e2fd27a08d42220c92 Mon Sep 17 00:00:00 2001 From: nomdetom Date: Thu, 4 Jun 2026 00:19:34 +0100 Subject: [PATCH 6/8] spaaaaaace --- meshtastic/module_config.proto | 1 - 1 file changed, 1 deletion(-) diff --git a/meshtastic/module_config.proto b/meshtastic/module_config.proto index d74de6cab..0805de4ea 100644 --- a/meshtastic/module_config.proto +++ b/meshtastic/module_config.proto @@ -934,7 +934,6 @@ message ModuleConfig { * This ensures nodes that only decode TEXT_MESSAGE_APP can still receive the human-readable text. */ bool broadcast_legacy_split = 12; - } /* From 15c194d1d64eb0a6c4de49afb9b1f32a2d0a73cc Mon Sep 17 00:00:00 2001 From: nomdetom Date: Thu, 4 Jun 2026 00:48:26 +0100 Subject: [PATCH 7/8] typoo --- meshtastic/module_config.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshtastic/module_config.proto b/meshtastic/module_config.proto index 0805de4ea..bcc89fcfd 100644 --- a/meshtastic/module_config.proto +++ b/meshtastic/module_config.proto @@ -922,7 +922,7 @@ message ModuleConfig { optional Config.LoRaConfig.ModemPreset broadcast_on_preset = 10; /* - * How often to broadcast, in seconds. Min 3600 (1 h), max 259200 (72 h). Default 3600. + * How often to broadcast, in seconds. Min 3600 (1 h), default 3600. */ uint32 broadcast_interval_secs = 11; From d8bef9fa97fbca7616c6fee2c587b006b3c4dbcb Mon Sep 17 00:00:00 2001 From: Tom <116762865+NomDeTom@users.noreply.github.com> Date: Thu, 4 Jun 2026 00:54:45 +0100 Subject: [PATCH 8/8] Develop (#1) * Initial plan * Fix truncated mesh.proto: restore full file, add LockdownAuth.disable and LockdownStatus.State.DISABLED * fix: align Station G3 comment formatting in mesh proto * fix: revert unrelated MeshLink description edit * Add TINY_FAST and TINY_SLOW presets for Amateur Radio compliance (#934) --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Ben Meadors Co-authored-by: Austin --- meshtastic/admin.proto | 25 +++++++++++++++++++++++++ meshtastic/config.proto | 20 ++++++++++++++++++++ meshtastic/mesh.proto | 14 ++++++++++++-- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/meshtastic/admin.proto b/meshtastic/admin.proto index 06dd7e082..27b6f9ebd 100644 --- a/meshtastic/admin.proto +++ b/meshtastic/admin.proto @@ -619,6 +619,31 @@ message LockdownAuth { * from the on-flash, HMAC-bound counter. */ uint32 max_session_seconds = 5; + + /* + * Disable lockdown mode. Requires a valid passphrase in the same + * message (the device must prove the operator owns it before + * reverting at-rest encryption). On success the firmware decrypts + * every stored config / channel / nodedb file back to plaintext, + * removes the wrapped DEK, unlock token, monotonic-counter, and + * backoff files, and reboots out of lockdown. + * + * This is the inverse of the provision/unlock path: it is how the + * client app's "lockdown mode" toggle returns a device to normal + * operation. + * + * NOT reversed by this operation: APPROTECT. Once the debug port + * lockout has been burned (on silicon where it is effective) it is + * permanent — disabling lockdown decrypts your data and removes the + * access gates, but the SWD/JTAG port stays locked for the life of + * the device (recoverable only via a full chip erase over a debug + * probe, which destroys all data). Clients should make this + * irreversibility clear at the moment lockdown is first enabled. + * + * When true the passphrase field is still required; boots_remaining, + * valid_until_epoch, max_session_seconds, and lock_now are ignored. + */ + bool disable = 6; } /* diff --git a/meshtastic/config.proto b/meshtastic/config.proto index 8f554d0fc..528a6d3a4 100644 --- a/meshtastic/config.proto +++ b/meshtastic/config.proto @@ -1073,6 +1073,26 @@ message Config { * Comparable link budget and data rate to LONG_FAST. */ NARROW_SLOW = 13; + + /* + * Tiny Fast + * Preset optimized for compliance with Amateur Radio restrictions with 20kHz bandwidth. + * Many regions limit data transmission bandwidth in lower amateur bands (2 Meter). + * Note: TCXO with tight tolerances (±5 ppm or better) is *absolutely required* at these narrow bandwidths. + * Only compatible with SX127x and SX126x chipsets. + * Comparable link budget and data rate to LONG_FAST. + */ + TINY_FAST = 14; + + /* + * Tiny Slow + * Preset optimized for compliance with Amateur Radio restrictions with 20kHz bandwidth. + * Many regions limit data transmission bandwidth in lower amateur bands (2 Meter). + * Note: TCXO with tight tolerances (±5 ppm or better) is *absolutely required* at these narrow bandwidths. + * Only compatible with SX127x and SX126x chipsets. + * Comparable link budget and data rate to LONG_MODERATE. + */ + TINY_SLOW = 15; } enum FEM_LNA_Mode { diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index fe2304ea1..2c6b784e0 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -899,8 +899,8 @@ enum HardwareModel { HELTEC_MESH_NODE_T1 = 133; /* - * B&Q Consulting Station G3: TBD - */ + * B&Q Consulting Station G3: TBD + */ STATION_G3 = 134; /* @@ -2348,6 +2348,16 @@ message LockdownStatus { * Passphrase rejected. backoff_seconds is non-zero when rate-limited. */ UNLOCK_FAILED = 4; + + /* + * Lockdown is supported by this firmware but not currently active + * (no passphrase has been provisioned, or it was disabled via + * AdminMessage.lockdown_auth.disable). The device is operating in + * normal, non-encrypted mode. Clients render the lockdown-mode + * toggle as OFF on receiving this. Distinct from NEEDS_PROVISION, + * which is only used during an in-progress enable flow. + */ + DISABLED = 5; } /* Current lockdown state being reported. */