Skip to content

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.transport are 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 in BeeboBasePrefs (radio params, transport enables, WiFi credentials, monitor flags, identity/behavior), addressed explicitly per role rather than "whichever role happens to be live" — asking for repeater.radio.lora.freq while companion is live still reads repeater's own stored value, not companion's. companion.*/repeater.* each nest further into radio.*, fem.*, monitor.*, routing.*, and node.* (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/writing console.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.role is multi_role firmware's companion/repeater role (companion or repeater). A change is persisted and the node reboots into the new role, so the connection drops; it has no -r/--raw equivalent — plain-text simple_repeater/companion_radio firmware 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.quiet cover 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/usb are 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.password hold 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, ...), plus repeater.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 outside repeater.routing.*. -r/--raw is only needed to reach a legacy simple_repeater node over CommonLink; a multi_role node exposes every repeater.* leaf over its normal binary connection regardless of which role it's currently running as, since the dedicated CMD_BEEBO sub-ids work independently of board.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, and beebo cw is refused. Stricter than node.repeat, which only stops relaying. Per role and persisted; the repeater text CLI has get/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).