Configuration Reference¶
Py ToloMEO reads deployment configuration from a single TOML file, tolomeo.toml,
loaded once per process. Every key is optional; with no file, the defaults
below apply.
Precedence¶
The first source that exists wins:
| Order | Source |
|---|---|
| 1 | An explicit path given to the loader |
| 2 | The TOLOMEO_CONFIG environment variable |
| 3 | ./tolomeo.toml |
| 4 | ~/.config/tolomeo/tolomeo.toml |
| 5 | /etc/tolomeo/tolomeo.toml |
| 6 | Built-in defaults |
A missing file is not an error. A path named explicitly — as an argument or
through TOLOMEO_CONFIG — that does not exist is an error.
[nats]¶
| Key | Type | Default | Meaning |
|---|---|---|---|
url |
string | nats://localhost:4222 |
Broker to connect to |
user |
string | unset | Username for user/password authentication |
password |
string | unset | Password for user/password authentication |
token |
string | unset | Token authentication |
credentials_file |
string | unset | Path to an nkey/JWT credentials file |
tls_ca_file |
string | unset | Path to a CA bundle |
tls_hostname |
string | unset | Expected certificate hostname |
reconnect_time_wait_s |
number | 2 |
Seconds between reconnection attempts |
max_reconnect_attempts |
integer | unset | Retry ceiling; unset means the client library's own default of 60 |
[service]¶
| Key | Type | Default | Meaning |
|---|---|---|---|
heartbeat_interval_ms |
integer | 10000 |
Heartbeat cadence in milliseconds |
[plugins.<plugin_id>]¶
Keyed by the plugin's own id — the value it assigns to self.id during
connect. A plugin with no declared table reads an empty mapping.
Valid keys are the plugin's own business, declared as a Pydantic model in its
Meta.config_model:
class ThermostatOptions(BaseModel):
model_config = ConfigDict(extra="forbid", frozen=True, hide_input_in_errors=True)
endpoint: str = "http://localhost:9000"
samples: PositiveInt = 4
class ThermostatPlugin(SensorPlugin):
class Meta:
config_model = ThermostatOptions
The plugin then reads self.options.samples instead of parsing a dict.
A plugin id that is not a bare word must be quoted
Unquoted TOML keys allow only letters, digits, underscores and dashes. A BLE plugin's id is the device address, so its table name has to be quoted:
Validation happens in two stages¶
[nats] and [service] are validated when the file loads. Plugin tables are
validated against their config_model at attach time, which setup forces
eagerly:
ConfigError: invalid [plugins.thermostat] table: 1 validation error for ThermostatOptions
samples_count
Extra inputs are not permitted
A plugin that declares no config_model is not validated; reading
self.options on one is a programming error. It can still read the raw table
through self.plugin_config.
Options extend, they do not replace¶
A plugin deriving from another inherits its model and adds options by extending it:
class SWUpdateOptions(OTAOptions):
socket_path: Path = Path("/run/swupdate.sock")
class SWUpdatePlugin(OTAPlugin):
class Meta:
config_model = SWUpdateOptions
An unrelated model raises TypeError at class-definition time: base methods read
fields the base declared, so replacing the model would break them.
[plugins.<id>] keys of the shipped plugins¶
OTAPlugin, and therefore anything deriving from it:
| Key | Type | Default | Meaning |
|---|---|---|---|
download_dir |
string | /data/tolomeo† |
Directory the update package goes to |
download_filename |
string | ota.pkg |
Name the package is saved under |
checkpoint_file |
string | /data/tolomeo/ota-service.yml† |
Where the OTA state snapshot is kept |
† /data/tolomeo when /data exists, otherwise the same path under
the system temp directory. checkpoint_file's default is pinned to that
default download directory, not to a configured download_dir — setting
download_dir alone does not move the checkpoint.
SensorPlugin and PluginBase declare no options. The examples/ directory
ships a commented .toml file per service.
Semantics¶
Unset means "not passed"¶
An omitted key is left out of the client library's connect call entirely, rather than passed as the value the framework believes the library defaults to. A library upgrade that changes a default is therefore picked up, not overridden.
The retry ceiling is not unlimited
The client library's max_reconnect_attempts default is 60 attempts, not
unlimited. Leaving the key unset preserves that; it does not mean "retry
forever".
The one exception is reconnect_time_wait_s, always passed explicitly as 2.
One authentication style at a time¶
user/password, token and credentials_file are mutually exclusive.
Configuring more than one is a configuration error.
TLS is verified at load time¶
The client library takes a prepared SSL context, not a CA path. The bundle named
by tls_ca_file is verified at load and the context prepared on first connect,
so an unreadable or invalid CA file fails at startup, not mid-run.
Errors surface at startup¶
A malformed file, an unknown section, an unknown key, or a wrongly typed value in
[nats] or [service] raises at load, naming the file and every offending key —
all mistakes at once, not one per restart. Plugin tables are checked at attach;
see Validation happens in two stages.
Numeric keys are strict: heartbeat_interval_ms = true is an error, not the
integer 1.
What gets logged¶
At INFO, loading reports the file read and its source — an explicit path,
TOLOMEO_CONFIG, or the search path — or that no file was found. A second line
summarises what is in effect; connecting reports the broker and whether any
setting came from an explicit argument:
INFO tolomeo.config.loader: Configuration loaded from /etc/tolomeo/tolomeo.toml (TOLOMEO_CONFIG)
INFO tolomeo.config.loader: Configuration in effect: broker=nats://broker.prod:4222 auth=user/password
tls=CA /etc/nats/ca.pem reconnect_wait=2s max_reconnect=10 heartbeat=5000ms plugins=[thermostat]
INFO my_service: Connecting to NATS at nats://broker.prod:4222: auth=user/password tls=on ...
INFO my_service: Connected to NATS server at broker.prod:4222
Secrets are never logged
Logs name the authentication style, never its value, and list plugin ids,
never a table's contents — plugin options may hold secrets. Search paths are
logged at DEBUG.
A plugin logs its id and the configured keys, never model or class
names, field names, or values. An empty table logs [].
An options model must set hide_input_in_errors=True, as the shipped models
do; without it a validation failure prints the offending value into the
ConfigError that reaches the startup log.
Python API¶
| Function | Purpose |
|---|---|
get_config() |
The service configuration, loaded on first use and cached thereafter |
load_config(path=None) |
Load a configuration without touching the cache |
reset_config() |
Clear the cache so the next read reloads; intended for tests |
Components read through get_config(), and each accepts an explicit override so
a test can inject instead:
from tolomeo.config import Config, NATSConfig
from tolomeo.messaging.client import NATSClientManager
manager = NATSClientManager(logger, url="nats://explicit:4222")
manager = NATSClientManager(logger, config=Config(nats=NATSConfig(url="nats://injected:4222")))
Pointing a service at its own file
Set TOLOMEO_CONFIG in the service's environment. One process runs one
service with one configuration.
A note on scope¶
This is deployment configuration: read-only, loaded once, never mutated at
runtime. Distinct from ConfigManagerABC in tolomeo.services.configuration, a
mutable manager for state a service persists at runtime — the BLE device list,
for instance, which lives in its own .devices.yml. Override
new_config_manager to point it elsewhere, as the ble_mock example does.
See also
- Configure the NATS Connection — task-oriented recipes