Settings¶
Everything configurable on a beebo node — radio parameters, board tuning, transport enables, WiFi credentials, monitor capture flags, node identity, the tuning optimizer and trial, even the CLI's own defaults — lives in one place: a single settings tree, addressed by dotted path. There's no separate wifi command, no separate transport command, no scattered one-off flags to remember; it's all just beebo settings <path> [value].
Run it with no arguments and you get the whole tree. Point it at a category and you get that subtree. Point it at a leaf and you get (or set) just that value:
$ beebo settings
settings
├── board
│ ├── adc
│ │ ├── multiplier: 5.464
│ │ └── resolution: 12 bits [10, 12]
│ ├── battery
│ │ ├── present: yes {yes|no}
│ │ ├── sample_period: 300 s [30 to 3600]
│ │ └── sample_window: 30 s [1 to 300]
│ ├── node
│ │ ├── id: 5552594e5230
│ │ ├── name: Beebo
│ │ ├── password: (set)
│ │ └── role: companion ['companion', 'repeater']
│ └── state.quiet: off
├── companion
│ ├── fem
│ │ ├── rxgain: off
│ │ └── txgain: on
│ ├── monitor
│ │ ├── batt: on
│ │ ├── command: on
│ │ ├── debug: on
│ │ ├── enabled: on
│ │ ├── env: off
│ │ ├── event: on
│ │ ├── radio: on
│ │ ├── route: on
│ │ ├── rx: on
│ │ ├── setting: on
│ │ ├── tuning: off
│ │ └── tx: on
│ ├── node
│ │ ├── adv_loc_policy: 1 (share) [0=none, 1=share, 2=prefs]
│ │ ├── autoadd_config: 0x01
│ │ ├── ble.pin: 123456
│ │ ├── coords: 0.0, 0.0 deg
│ │ ├── manual_add_contacts: off
│ │ ├── multi_acks: 1
│ │ ├── name: Beebo
│ │ ├── path_hash_mode: 1 [0=1 byte, 1=2 bytes, 2=3 bytes]
│ │ ├── public_key: 5552594e…
│ │ ├── region.scope: (none)
│ │ ├── repeat: off
│ │ ├── telemetry
│ │ │ ├── base: 0 [0 to 3]
│ │ │ ├── env: 0 [0 to 3]
│ │ │ └── loc: 0 [0 to 3]
│ │ ├── transport
│ │ │ ├── ble: off
│ │ │ ├── tcp: on
│ │ │ └── usb: on
│ │ └── wifi
│ │ ├── password: (set)
│ │ └── ssid: myssid
│ ├── radio
│ │ ├── allowed_repeat_freq: 433.0-433.0 MHz, 869.495-869.495 MHz, 918.0-918.0
│ │ │ MHz
│ │ ├── lora
│ │ │ ├── bw: 62.5 kHz [7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250,
│ │ │ │ 500]
│ │ │ ├── cr: 5 [5 to 8]
│ │ │ ├── freq: 910.525 MHz [137 to 1020]
│ │ │ └── sf: 7 [7 to 12]
│ │ ├── rxgain: on
│ │ └── txpower: 18 dBm [-9 to 22]
│ ├── profile.enabled: off
│ └── routing
│ ├── airtime: 0 [0 to 9]
│ ├── seen_window: 0 s
│ ├── dutycycle: 100 % [1 to 100]
│ └── rxdelay: 0 s [0 to 20]
└── console
├── autosave: on
├── ble.address: scan
├── dbg_level: L {H|M|L}
├── log_level: WARNING {DEBUG|INFO|WARNING|ERROR|CRITICAL}
├── tcp.host: beebo
├── transport: tcp {ble|tcp|usb}
└── usb.port: /dev/ttyACM0
repeater.* hidden (board.node.role) — 'beebo settings repeater' shows it anyway.
A few things worth knowing about how the tree is organized:
- Only leaves hold a value — categories like
board,companion.radio,companion.node.transportare just groupings, and asking for one prints the subtree rather than a value. - The top-level namespace is the firmware struct that actually backs the value —
board.*is genuinely single-instance, board-wide state (one physical board, not one per role);companion.*/repeater.*are each role's own fully independent, resident copy of everything inBeeboBasePrefs(radio params, transport enables, WiFi credentials, monitor flags, identity/behavior), addressed explicitly per role rather than "whichever role happens to be live" — asking forrepeater.radio.lora.freqwhile companion is live still reads repeater's own stored value, not companion's.companion.*/repeater.*each nest further intoradio.*,fem.*,monitor.*,routing.*, andnode.*(identity/behavior leaves that aren't their own subsystem).console.*is the odd one out: it covers the CLI's own local config (the node alias's~/.beebo/nodes/<alias>/profile.toml) plus the connected node's autosave flag, so reading/writingconsole.transport,console.tcp.host, etc. never opens a connection at all. - The whole-tree view hides the branch the live role can't use — a companion node hides
repeater.*and vice versa; naming it explicitly (beebo settings repeater) still shows it. board.node.roleismulti_rolefirmware's companion/repeater role (companionorrepeater). A change is persisted and the node reboots into the new role, so the connection drops; it has no-r/--rawequivalent — plain-textsimple_repeater/companion_radiofirmware predates the concept entirely, so this leaf is only reachable without-r; see Multi-Role: Switching Companion/Repeater for the details.board.battery.*/board.state.quietcover the battery-trend sample cadence (sample_period/sample_window, see Battery State of Charge) and a bench-only IR-drop test toggle (quiet) — shared identically between companion and repeater roles, since there's one physical VBAT ADC/battery per board, not one per role.companion.node.transport.ble/tcp/usb/repeater.node.transport.ble/tcp/usbare each role's own persisted enables that decide which radios come up at boot when that role is live — the tree is where transports are switched.companion.node.wifi.ssid/.wifi.passwordhold the WiFi credentials. They're independent leaves, and the password one is write-only — it never reads back, for obvious reasons.repeater.*mirrors CommonCLI's own dotted keys for repeater-only preferences that have no companion-radio equivalent (repeater.node.repeat,repeater.node.name,repeater.admin.password, ...), plusrepeater.routing.*for everything that shapes forwarding/routing behavior: the timing/collision-avoidance/duty-cycle knobs (rxdelay,airtime,dutycycle,txdelay,direct.txdelay,agc.reset.interval,interference.threshold) and the tuning settings listed below), plus flood-routing behavior (loop.detect,flood.max/.max_advert/.max_unscoped— see How a Repeater Routes).repeater.node.advert.interval/.advert.flood_interval(local vs flood advert timing) are presence/broadcast policy, not routing, so they stay outsiderepeater.routing.*.-r/--rawis only needed to reach a legacysimple_repeaternode overCommonLink; amulti_rolenode exposes everyrepeater.*leaf over its normal binary connection regardless of which role it's currently running as, since the dedicatedCMD_BEEBOsub-ids work independently ofboard.node.role.companion.node.transmit/repeater.node.transmit{on|off}, default on: off makes the radio receive-only, with no forwards, adverts, ACKs or replies, andbeebo cwis refused. Stricter thannode.repeat, which only stops relaying. Per role and persisted; the repeater text CLI hasget/set transmit. Setting it off over the mesh also silences the node's replies to that admin session, so use USB to turn it back on.
Setting a leaf is the same pattern everywhere — path, then new value:
$ beebo settings companion.radio.txpower 18
companion.radio.txpower = 18 dBm
$ beebo settings companion.node.transport.tcp off
companion.node.transport.tcp = off
The console.autosave option is special and is used to quickly change radio settings during experiment commands without continuously writing to flash avoiding unnecessary stress. Since console.autosave can hold changes in RAM before they hit flash, commit and restore are settings subcommands too — flush what's pending, or throw it away and reload from flash:
$ beebo settings commit
committed
$ beebo settings restore
restored
On the node console¶
The same command runs on the node itself, from the app's CLI screen or the beebo-cli channel: settings <path> reads, settings <path> <value> writes, and settings or settings <branch> lists the names below it. The console reaches the settings with a plain value (trial, routing, radio, FEM, battery, node and board settings); the role prefix is optional. Secrets, the composite settings and console.* need the beebo command line. Commands has the full list of what runs where.
Tuning settings¶
Everything under repeater.routing.tuning.* belongs to the repeater role. On the CLI screen the repeater. prefix is optional. Trial settings are RAM-only and return to their defaults after a reboot.
| Leaf | What it sets | Details |
|---|---|---|
trial.enabled |
Runs the trial sequence (on/off) |
Setting Trials |
trial.profile |
main (default, four switches) or exhaustive (twelve) |
Trial Reference |
trial.switches.<name>.enable and .values |
Whether a switch runs, and the values it tries (A first) | Trial Reference |
trial.start |
stored (default) or list: where the sequence starts |
Trial Reference |
trial.combined |
One combined trial instead of one per switch | Trial Reference |
trial.block_size_s, trial.block_count |
Block length and count (0 = planned by the node) | Trial Reference |
trial.block_spread_pct |
Advanced: the block spread the first plan starts from | Trial Reference |
trial.confidence_pct, trial.min_gain_pct |
How sure the node must be (90, 95 or 99), and the smallest gain worth taking | Trial Reference |
trial.min_pkt_rate |
Events a minute a fixed schedule needs to start | Trial Reference |
score.routed, score.delivered, score.received |
The weights of the score both tuners judge | Scoring |
adaptive.enabled, adaptive.applied |
The adaptive tuner on/off, and which parameters it may change | The Adaptive Tuner |
adaptive.window.min_s, adaptive.window.max_s |
Shortest and longest evaluation window, in seconds | The Adaptive Tuner |
beebo settings repeater.routing.tuning prints the live values with their ranges.
Console Configuration¶
The console.* settings leaves cover the CLI's own local config, the node alias's ~/.beebo/nodes/<alias>/profile.toml (override the directory with $BEEBO_NODES_DIR; a bare beebo uses the alias beebo), separate from anything stored on the node. It's created with a commented template on first use:
default_transport = "tcp" # ble | tcp | usb — used when none is given
log_level = "WARNING" # DEBUG | INFO | WARNING | ERROR | CRITICAL
dbg_level = "L" # minimum firmware debug severity `monitor debug` streams: H | M | L
[ble]
address = "scan" # BLE MAC/name; "scan" discovers and picks a device
[tcp]
host = "beebo" # host[:port]; default port is 5000
[usb]
port = "/dev/ttyACM0" # COM6 on Windows
Every command shares one set of --ble/--tcp/--usb options, each pre-filled from this file as its default value. default_transport decides which one actually gets used when none of the three flags is typed on the command line — typing exactly one flag overrides it for that invocation, and typing more than one is an error. The chosen transport's own address/host/port then comes from its matching [ble]/[tcp]/[usb] entry unless overridden inline (e.g. --tcp other-node).
Because these values never touch the device, console.transport, console.ble.address, console.tcp.host, console.usb.port, console.log_level and console.dbg_level all read and write the toml file directly — get/set never open a connection:
$ beebo settings console.transport
console.transport = tcp {ble|tcp|usb}
$ beebo settings console.transport tcp
console.transport = tcp
$ beebo settings console.tcp.host other-node
console.tcp.host = other-node
Note that console.autosave is the one console.* leaf that isn't local — it's the connected node's own autosave flag, round-tripped like any node.* setting (see commit/restore above).