Docs / Contact / sdks/micropython/configuration
MicroPython Client Configuration
The MicroPython client is configured through a combination of the config.json file on the device and constructor parameters.
Config File
Create /config.json on the board's filesystem:
{
"api_key": "your_entity_api_key",
"wifi_ssid": "YourNetwork",
"wifi_pw": "YourPassword",
"app_url": "https://app.tendrl.com",
"mqtt_ssl": true
}
The SDK also checks /lib/tendrl/config.json for built-in defaults. User config overrides built-in values.
Config File Fields
| Field | Type | Default | Description |
|---|---|---|---|
api_key |
string | "" |
Entity API key for authentication |
wifi_ssid |
string | "" |
WiFi network name |
wifi_pw |
string | "" |
WiFi password |
app_url |
string | "https://app.tendrl.com" |
Tendrl server URL |
mqtt_host |
string | Auto | MQTT broker hostname (fetched from API if not set) |
mqtt_port |
int | Auto | MQTT broker port |
mqtt_ssl |
bool | true |
Enable SSL/TLS for MQTT |
app_entry |
string | "main" |
Module a remote deployment imports to start your app (no .py). The device's standing default when a deployment doesn't set its own Entry; set once if your program isn't main.py (e.g. "app" runs /app/app.py). |
serial_metrics |
bool | false |
Emit the TDLMETRIC: serial line (every 10 s by default) that feeds the live-metrics rail while your app runs. Off by default because it prints from the client timer even during an over-serial transfer. The provisioning tools pause it around their own transfers (SDK ≥ 0.2.6), but turn it on for a dev board only; deployed devices report RAM/storage via the heartbeat regardless. |
serial_metrics_interval |
int | 10000 |
Cadence in milliseconds for the serial_metrics heap push (disk is refreshed at most every 15 s regardless). Raise it to cut serial noise, lower it for a snappier rail. Only applies when serial_metrics is on. |
Constructor Parameters
client = Client(**kwargs)
Core
| Parameter | Type | Default | Description |
|---|---|---|---|
mode |
str | "sync" |
"sync" (hardware timer) or "async" (asyncio) |
debug |
bool | False |
Enable verbose debug logging |
net |
str | "wifi" |
Network type: "wifi" or "eth" |
Callbacks
| Parameter | Type | Default | Description |
|---|---|---|---|
callback |
function | None |
Catch-all handler when no @client.on() route matches |
state_callback |
function | None |
Fallback handler when @client.on_state is not used |
Inbound routing (@client.on())
Register handlers on the client instance after construction. Routes are checked in registration order; first match wins.
| Decorator | Description |
|---|---|
@client.on(msg_type=...) |
Match a specific message type |
@client.on(tag=...) |
Match a single tag |
@client.on(tags=[...]) |
Match if message has any listed tag |
@client.on(tags_all=[...]) |
Match if message has all listed tags |
@client.on_default |
Catch-all when no route matches |
Combine parameters for AND semantics (e.g. @client.on(msg_type="publish", tag="config-update")). See API Reference.
Use @client.on_state to receive remote state table updates; it pairs with REST state reads/writes. Polled at check_msg_rate on Python, Go, and JavaScript; pushed over MQTT on MicroPython.
Timing & Performance
| Parameter | Type | Default | Description |
|---|---|---|---|
timer |
int | 0 |
Hardware timer ID (0–3, or -1 for virtual) |
freq |
int | 3 |
Timer frequency in Hz |
check_msg_rate |
int | 5 |
Seconds between MQTT message checks |
max_batch_size |
int | 15 |
Maximum messages per batch |
Storage
| Parameter | Type | Default | Description |
|---|---|---|---|
client_db |
bool | True |
Enable local BTree database |
client_db_in_memory |
bool | True |
In-memory database (faster) vs file-based (persists across reboots, best-effort - see durability) |
client_db_max_records |
int | None |
Optional hard cap on the client database (oldest-first eviction). None = unlimited |
db_page_size |
int | auto | BTree page size in bytes; defaults to 1024 for the in-memory store, 4096 for a file-backed one |
offline_storage |
bool | True |
Queue messages when offline |
offline_max_records |
int | 1000 |
Hard cap on buffered offline messages; oldest are evicted first when exceeded, bounding flash use during outages. 0/None = unlimited (not recommended) |
managed |
bool | True |
Auto-manage database lifecycle |
Health
| Parameter | Type | Default | Description |
|---|---|---|---|
send_heartbeat |
bool | True |
Send periodic memory heartbeats |
watchdog |
int | 0 |
Watchdog timeout in seconds (0 = disabled) |
Async Mode
| Parameter | Type | Default | Description |
|---|---|---|---|
event_loop |
asyncio.Loop | None |
User-provided event loop (async mode only) |
Memory Considerations
The client adapts to available RAM:
- Queue size: Max 150 messages, dynamically reduced based on
gc.mem_free() - Batch size: Max 75 messages, adjusted per-send based on available memory
- MQTT payload limit: 4096 bytes per message chunk
- Offline store: Capped at
offline_max_records(default 1000) with oldest-first eviction so a long outage can't exhaust flash. The cap bounds file size, not write volume, and buffered messages are not guaranteed to survive a power cut (durability)
Flash footprint
SDK install size on flash (precompiled .mpy under /lib/tendrl; every install path ships .mpy, not .py source):
| Package | Flash |
|---|---|
| Minimal (MQTT core) | ~55 KB |
| Files add-on | +~6 KB |
| Full (+ MicroTetherDB) | ~74 KB |
OTA add-on (updater) |
+~5 KB |
| Streaming add-on | +~8 KB |
Use minimal for publish/subscribe only. Add the files package for HTTP file transfer. Use full when you need offline message queuing or the client database. Add the OTA package (updater) for remote app-code deployment; it's a standalone add-on, not bundled into Full. Streaming is a separate add-on for camera boards.
For boards with less than 300KB RAM, consider:
- Using the minimal installation (no database)
- Setting
client_db=False - Reducing
max_batch_sizeto 5–10 - Setting
client_db_in_memory=True(default, avoids flash writes)
MQTT Connection Details
The client automatically discovers and configures all MQTT connection parameters from your API key: broker address, credentials, and the topics your entity publishes and subscribes to. You don't configure any of this manually; provide a valid API key and the SDK handles the connection for you.
Example Configurations
Basic Sensor (ESP32)
{
"api_key": "your_key",
"wifi_ssid": "HomeNetwork",
"wifi_pw": "password123"
}
client = Client(debug=True, send_heartbeat=True)
Memory-Constrained (Pico W)
On the Pico W client_db=False is required, not just a memory optimization: stock rp2 firmware has no btree module, so MicroTetherDB cannot load at all. The client detects this and disables storage with a warning rather than failing, but setting it explicitly documents the intent.
Stock rp2 firmware also has no frozen umqtt. You don't need to do anything about that: every Tendrl install path checks whether the board's firmware provides an MQTT client and pushes the vendored umqtt only when it doesn't.
client = Client(
debug=False,
client_db=False,
max_batch_size=5,
send_heartbeat=False
)
Async with Streaming (OpenMV)
client = Client(
mode="async",
debug=True,
send_heartbeat=True,
offline_storage=True
)
Tendrl