Review follow-up. With * listed, an uncorrelated message is still answered globally when no scoped packet was heard around it; the radio's default scope does apply to sends the bot leaves unscoped; [Scheduled_Messages] needs the leading #; and the outbound log lines are quoted as they are actually printed, including that the global one is DEBUG.
6.9 KiB
Region scopes
MeshCore lets a client confine a channel message to one region of the mesh. The setting is called a region, a region code, or a flood scope depending on where you look; this page calls it a scope. The bot can answer inside the sender's region, post its own messages inside a region, and ignore traffic from regions it should not answer. All of it needs the bot to be told the region names, because they cannot be read off the air.
How a region works on the air
A client with no region sends each channel message as an ordinary FLOOD, and every repeater that hears it rebroadcasts it.
A client with a region set sends a TC_FLOOD instead: the same packet plus a 16-bit transport code. The code is an HMAC of the packet's payload type and payload, keyed by a hash of the region name (#home, say). A repeater configured for that region computes the same HMAC, sees a match, and forwards the packet. A repeater that denies the region, or does not know it, drops it. That is what keeps a scoped message inside its region.
Two consequences follow:
- The code changes on every packet. It is computed over the payload, so two messages scoped to
#homecarry different codes. There is no fixed number that means "home". - The code cannot be turned back into a name. Given a packet and a candidate name, anyone can check whether the code matches. Given only the code, there is nothing to look up. The bot therefore checks the inbound code against each region name it has been given, and a name it was not given can never match.
Scopes only limit forwarding. A companion radio accepts a scoped message whatever region it has set itself, so someone with no region still hears a scoped reply, as long as the repeaters between you carry that region.
Answering in the sender's region
By default flood_scopes is empty. The bot answers channel commands regardless of how they arrived, and the replies go out as ordinary global FLOOD, even when the command came in scoped. A repeater that denies #home then forwards the reply to a #home command, because the reply has no region on it.
To mirror the sender's region, list it:
[Channels]
flood_scopes = *, #home
With that set, a command that arrives scoped to #home matches the #home entry and the reply is sent scoped to #home too. The * entry keeps the bot answering people with no region set; leave it out and unscoped commands are ignored.
flood_scopes is an allowlist as well as a mirror list. Once it has any entry, the bot only answers messages whose scope it can match against the list. A command scoped to a region you did not list is ignored, not answered globally.
flood_scopes |
Command scoped to #home |
Command with no region |
|---|---|---|
| empty (default) | answered, reply is global FLOOD |
answered, reply is global FLOOD |
*, #home |
answered, reply scoped to #home |
answered, reply is global FLOOD |
#home |
answered, reply scoped to #home |
ignored |
* |
ignored | answered, reply is global FLOOD |
Mirroring depends on RF correlation. The bot matches the code on the packet it actually heard for that message. When it cannot tie the message to a packet, it does not borrow the scope of some other recent packet. With * listed, such a message is still answered globally if no scoped packet was heard around it, since it was then almost certainly an ordinary FLOOD; if a scoped packet was heard, the scope is unknown and the message is ignored. Without *, an unmatched message is always ignored.
Scoping the bot's own messages
Messages the bot starts itself (scheduled messages, webhooks, feeds, alerts, service plugins) have no inbound packet to mirror. They use the first of these that is set:
- A scope given for that one send: a webhook request's
flood_scope, orchannel:#scope:messagein[Scheduled_Messages]. flood_scopein the plugin or service's own config section.[Channels] flood_scope.<channel>for the channel being posted to.[Channels] outgoing_flood_scope_override.- Global flood.
outgoing_flood_scope_override also applies to replies that have no mirrored scope, so a bot with an empty flood_scopes and the override set to #home answers everything in #home. A reply that did mirror a scope keeps it; the override never replaces a matched scope.
[Channels]
flood_scopes = *, #home
outgoing_flood_scope_override = #home
flood_scope.weather = #sea
The config keys accept region or #region; the # is added if missing. The [Scheduled_Messages] form is the exception: its middle field must start with #, or it is read as part of the message. *, 0, None or an empty value mean global flood.
A regional send costs 10 bytes of message length, so scoped channel messages are split a little sooner.
The Radio page
The web viewer's Radio page edits flood_scopes and outgoing_flood_scope_override in its Region Scopes card and reloads the bot, so you do not need to restart. Per-channel flood_scope.<channel> entries are listed there read-only; edit those in config.ini.
The Default Region Scope card on the same page is a different setting: the radio's own default, stored in firmware. It plays no part in mirroring or in deciding which messages the bot answers, but a send the bot does not scope itself goes out under it, because the bot only sets a scope on the radio when it has one of its own.
Checking it works
Send a command from a client with the region set, then look for these lines in the bot log:
Flood scope allowlist active: ['#home'] (global/unscoped permitted: True)at startup or reload confirms whatflood_scopeswas parsed to.Incoming TC_FLOOD matched scope '#home'means the inbound code matched a listed name.Outbound channel flood scope: #home (<source>; set_flood_scope)means the bot set that scope for the send.<source>says where it came from:explicit argumentfor a mirrored reply or a per-send scope,outgoing_flood_scope_override, orreply_scope or config. If a warning follows saying the radio rejectedset_flood_scopeor the message will use the device default, the send went out at whatever scope the radio held instead.Outbound channel flood scope: globalmeans the bot set no scope. It is logged at DEBUG, so it only shows withlog_level = DEBUG, except whenoutgoing_flood_scope_overrideis set and something else decided on global: that case is a WARNING saying the override was not applied.Ignoring TC_FLOOD: scope not in flood_scopes allowlistmeans the message was scoped to a region you have not listed.
On the air, a scoped reply is a TC_FLOOD (route type 0) with a nonzero first transport code; a global reply is a FLOOD (route type 1) with no transport codes.
Related
- Configuration covers every
[Channels]key. - Region warnings counts how much unscoped traffic your mesh carries and can tell senders to set a region.