Configure the NATS Connection¶
This guide shows how to point a Py ToloMEO service at a broker, give it credentials, and secure the connection with TLS — all from a configuration file, with no code changes.
Where Configuration Comes From¶
Py ToloMEO reads a single TOML file, tolomeo.toml, once per process. The first
source that exists wins:
- An explicit path passed to
load_config() - The
TOLOMEO_CONFIGenvironment variable ./tolomeo.toml~/.config/tolomeo/tolomeo.toml/etc/tolomeo/tolomeo.toml- Built-in defaults
No file is a valid deployment
A missing configuration file is not an error — the built-in defaults apply and the service behaves exactly as it did before this feature existed.
A file that does exist but is malformed, names an unknown key, or gives a key the wrong type is an error, raised at startup and naming the file and the key. Configuration mistakes surface when the service starts, never as a surprise mid-run.
Change the Broker URL¶
Create tolomeo.toml next to your service:
That is the whole change. No subclassing, no code edit, no rebuild.
Add Credentials¶
Choose exactly one authentication style.
One style at a time
Configuring two authentication styles at once is a configuration error. Silently preferring one over another would hide a deployment mistake.
Enable TLS¶
Point at a CA bundle, and optionally at the hostname the certificate is expected to present:
[nats]
url = "tls://my-server:4222"
tls_ca_file = "/etc/nats/ca.pem"
tls_hostname = "broker.example"
The framework builds the SSL context from that file at startup — the client library takes a prepared context, not a CA path. An unreadable or invalid CA file is a configuration error at startup, not a connection failure later.
Tune Reconnection¶
[nats]
reconnect_time_wait_s = 2 # seconds between attempts; this is the default
max_reconnect_attempts = 10 # omit to use the client library's own default (60)
Omitted means not passed
A key you leave out is omitted from the connect call entirely rather than passed as a value the framework guessed. That keeps the default deployment identical to the library's own behaviour, even across a library upgrade.
Set the Heartbeat Cadence¶
Pass Options to a Plugin¶
Each plugin reads its own table, keyed by its plugin id:
The plugin declares which keys are valid as a Pydantic model, and reads the
validated result through self.options:
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
A mistyped key stops the plugin as it attaches and names the offender, instead of sitting inert in a deployed file. See Implement a Custom Plugin and the Configuration Reference.
Shipped examples
The example services each ship a commented .toml beside them —
temperature.toml, ota_mock.toml, ble_mock.toml — showing every table
that service reads. Pass one with TOLOMEO_CONFIG.
Environment Variables¶
| Variable | Default | Description |
|---|---|---|
TOLOMEO_CONFIG |
unset | Path to a configuration file |
DEVICE_SERIAL_NUMBER |
1122334455667788 |
Device identifier used in the SenML base name |
TOLOMEO_CONFIG=/opt/myservice/tolomeo.toml \
DEVICE_SERIAL_NUMBER=abc123 \
python -m my_service.main
Pointing a Service at Its Own File¶
One process runs one service with one configuration. Name the file in the service's environment and it is read once at startup:
Advanced: Subclassing¶
Configuration covers the broker address, credentials, TLS and reconnection. For anything it cannot express — a bespoke connect sequence, a custom transport, a value computed at runtime — subclass the client manager and wire it in through a strategy.
Prefer passing settings explicitly, which take precedence over the configuration file:
from tolomeo.messaging.client import NATSClientManager
class CustomNATSClientManager(NATSClientManager):
def __init__(self, logger):
super().__init__(logger, url=discover_broker_url())
Or override connect outright when the sequence itself must change:
import nats
from tolomeo.messaging.client import NATSClientManager
class CustomNATSClientManager(NATSClientManager):
async def connect(self) -> None:
self.client = await nats.connect(**self._connect_options())
await self.do_something_bespoke()
Then pass your manager to a custom strategy and wire it into the service:
from tolomeo.messaging import NATSMessageStrategy
from tolomeo.services import NATSService
class CustomStrategy(NATSMessageStrategy):
def __init__(self, logger=None):
super().__init__(
logger=logger,
client_manager=CustomNATSClientManager(logger),
)
class MyService(NATSService):
class Meta:
plugin_class = MyPlugin
strategy_class = CustomStrategy
Publishing Cadence¶
Note
Py ToloMEO publishes sensor data as soon as a plugin pushes it via
push_reading — the service reacts to data as it arrives. There is no
polling interval to configure.
See also
- Configuration Reference — every section, key and default
- NATS Messaging
- SenML Message Format