Atlas Meshtastic Bridge
Reliable offline access to Atlas Command over Meshtastic radios. The bridge runs in two modes:
- Gateway - connected to Atlas Command over IP. It receives Meshtastic requests, calls the HTTP API, and returns responses over radio.
- Client - runs next to a field asset. It issues Atlas Command requests via the gateway and renders the responses locally.
The protocol and chunking design are described in
docs/SYSTEMS_DESIGN.md. This README focuses on day-to-day setup, usage, and troubleshooting.
Reliability guarantees
- Application-level ACKs are emitted for every reassembled message; senders track pending messages until ACKed.
- Outgoing messages are durably spooled to disk (JSON file) and retried with exponential backoff + jitter until acknowledged.
- Pending messages are replayed automatically after restarts; gateways flush the outbox each poll cycle and clients flush before sending.
- ACK envelopes are filtered from application handlers so existing client/gateway flows remain unchanged.
- Spool location is configurable via
--spool-path(default:~/.atlas_meshtastic_spool.json).
Payload limits
- Chunk: the smallest on-air packet sent over Meshtastic (what the transport already splits and ACKs today).
- Current chunk limit is up to 230 bytes (
MAX_CHUNK_SIZE) before transport-level retries/ack handling. - The hardware harness enforces a 10 KB limit for object uploads. Larger transfers are currently disabled; use the Atlas HTTP API instead.
- Keep request payloads small and metadata-focused when operating over radio links.
Prerequisites
- Python 3.10+
- Atlas Command reachable from the gateway (HTTPS recommended)
- Meshtastic radios flashed with current firmware
atlas-asset-client>=0.3.0(required)meshtastic>=2.3.0(optional for real radios; not needed for--simulate-radio)- Optional: virtual (in-memory) radio for local testing
Install the bridge as a standalone package (and optionally meshtastic-python for real radios):
cd Atlas_Client_SDKs/connection_packages/atlas_meshtastic_bridge
pip install -e .[meshtastic] # includes meshtastic
# or, for simulation-only workflows without hardware drivers:
pip install -e .
Meshtastic hardware setup
- Flash both radios with the same firmware and channel settings. Verify they can message each other using the Meshtastic app.
- Connect the gateway radio to the machine that can reach Atlas Command over IP.
- Note the serial port for each device:
- Linux:
/dev/ttyUSB0,/dev/ttyACM0, ordmesg | grep tty - macOS:
/dev/cu.usbserial-* - Windows:
COM3,COM4, etc.
- Linux:
- Recommended radio config:
- Same channel name/psk on all nodes
hop_limitandpowerappropriate for your mesh size- Unique, meaningful node IDs (set via Meshtastic app)
- Run with
--radio-portpointing at the serial device. Use--simulate-radioto bypass hardware during development.
Configuration
CLI flags (client and gateway):
| Flag | Description |
|---|---|
--mode {gateway,client} |
Run as gateway or client (required). |
--gateway-node-id |
Meshtastic node ID of the gateway (required). |
--api-base-url |
Atlas Command base URL. Required by the CLI; gateway uses it for HTTP calls (clients must still supply because the flag is required). |
--api-token |
Atlas Command bearer token (gateway mode, optional). |
--timeout |
Client request timeout in seconds (default: 5). |
--simulate-radio |
Use in-memory radio instead of hardware. |
--radio-port |
Serial port path (hardware mode). |
--node-id |
Override local node ID (default: gateway or client). |
--command |
Client command to run (client mode). |
--data |
JSON payload for the command (client mode). |
--log-level |
Logging level (default: INFO). |
--metrics-host |
Host interface for metrics/health server (default: 0.0.0.0). |
--metrics-port |
Port for metrics/health server (default: 9700). |
--disable-metrics |
Disable metrics and health endpoints. |
Environment variables (gateway):
| Variable | Purpose |
|---|---|
ATLAS_API_BASE_URL |
Convenience only; the bridge does not read this directly. Export it and pass via --api-base-url \"$ATLAS_API_BASE_URL\". |
ATLAS_API_TOKEN |
Convenience only; the bridge does not read this directly. Export it and pass via --api-token \"$ATLAS_API_TOKEN\". |
Quick start (simulated radios)
Terminal 1 - start gateway:
python -m atlas_meshtastic_bridge.cli \
--mode gateway \
--gateway-node-id gw-1 \
--api-base-url http://localhost:8000 \
--api-token "$ATLAS_API_TOKEN" \
--simulate-radio \
--node-id gw-1
Terminal 2 - run a client request:
python -m atlas_meshtastic_bridge.cli \
--mode client \
--gateway-node-id gw-1 \
--api-base-url http://localhost:8000 \
--simulate-radio \
--node-id field-1 \
--command list_entities \
--data '{"limit":5}'
Usage examples
Entity registration / creation
Entity creation is performed over the HTTP API (the mesh bridge keeps payloads small). Register the asset via HTTP first, then use the bridge for telemetry and tasking:
curl -X POST "$ATLAS_API_BASE_URL/entities" \
-H "Authorization: Bearer $ATLAS_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id":"DRONE-001","entity_type":"asset","subtype":"uav","alias":"DRONE-001"}'
Check-in workflow (over Meshtastic)
- Ensure the entity exists (HTTP as above).
- Send a check-in from the asset:
python -m atlas_meshtastic_bridge.cli \
--mode client \
--gateway-node-id gw-1 \
--simulate-radio \
--command checkin_entity \
--data '{"entity_id":"DRONE-001","latitude":40.0,"longitude":-105.0}'
- Fetch outstanding tasks for the entity:
python -m atlas_meshtastic_bridge.cli \
--mode client \
--gateway-node-id gw-1 \
--simulate-radio \
--command get_tasks_by_entity \
--data '{"entity_id":"DRONE-001","limit":5}'
- Report progress or telemetry:
python -m atlas_meshtastic_bridge.cli \
--mode client \
--gateway-node-id gw-1 \
--simulate-radio \
--command update_telemetry \
--data '{"entity_id":"DRONE-001","altitude_m":1200,"speed_m_s":14}'
Task execution (start / complete / fail)
# Start a task
python -m atlas_meshtastic_bridge.cli --mode client --gateway-node-id gw-1 \
--simulate-radio --command start_task --data '{"task_id":"TASK-123"}'
# Complete a task with result data
python -m atlas_meshtastic_bridge.cli --mode client --gateway-node-id gw-1 \
--simulate-radio --command complete_task --data '{"task_id":"TASK-123","result":{"summary":"scan complete"}}'
Object download
Request object metadata or bytes (small payloads only):
python -m atlas_meshtastic_bridge.cli --mode client --gateway-node-id gw-1 \
--simulate-radio --command get_object \
--data '{"object_id":"OBJ-1","download":true}'
If download is omitted or false, only metadata is returned.
Object upload
Large uploads are intentionally not sent over Meshtastic. Use the Atlas Command HTTP API to obtain a presigned upload URL, upload the file via HTTPS, and then reference the object by ID in subsequent mesh requests.
Change feed / incremental sync
Fetch changes since an RFC3339 timestamp:
python -m atlas_meshtastic_bridge.cli --mode client --gateway-node-id gw-1 \
--simulate-radio --command get_changed_since \
--data '{"since":"2025-01-01T00:00:00Z","limit_per_type":50}'
End-to-end workflow example
- Register entity via HTTP.
- Start gateway (hardware or simulated) pointed at Atlas Command.
- Client check-in over Meshtastic; gateway forwards to Atlas Command.
- Client requests tasks; gateway responds with pending assignments.
- Client downloads any referenced objects (metadata/bytes) as needed.
- Client reports task status (start/complete/fail) and telemetry updates.
Command reference
| Command | Description | Payload keys |
|---|---|---|
list_entities |
List entities with pagination. | limit, offset |
get_entity |
Fetch entity by ID. | entity_id |
get_entity_by_alias |
Fetch entity by alias. | alias |
create_entity |
Create a new entity. | entity_id, entity_type, alias, subtype, optional components |
update_entity |
Update entity metadata/components. | entity_id, optional subtype, components |
delete_entity |
Delete entity by ID. | entity_id |
checkin_entity |
Check in an entity with optional telemetry and task filters. | entity_id, telemetry fields, optional status_filter, limit, since, fields |
update_telemetry |
Update entity telemetry. | entity_id, telemetry fields (latitude, longitude, altitude_m, speed_m_s, heading_deg) |
list_tasks |
List tasks (no server-side status filter). | limit, offset |
get_task |
Fetch task by ID. | task_id |
get_tasks_by_entity |
Tasks scoped to an entity. | entity_id, limit |
create_task |
Create a task. | task_id, optional status, entity_id, components, extra |
update_task |
Update an existing task. | task_id, optional status, entity_id, components, extra |
delete_task |
Delete task by ID. | task_id |
transition_task_status |
Transition task to a new status. | task_id, status |
start_task |
Mark a task as started. | task_id |
complete_task |
Mark task complete. | task_id, optional result |
fail_task |
Mark task failed. | task_id, optional error_message, error_details |
list_objects |
List objects. | limit, offset |
create_object |
Create/upload an object (small payloads only). | object_id, content_b64, content_type, optional file_name, usage_hint, type, referenced_by |
get_object |
Get object metadata or bytes. | object_id, optional download |
update_object |
Update object metadata. | object_id, optional usage_hints, referenced_by |
delete_object |
Delete object by ID. | object_id |
get_objects_by_entity |
Objects linked to an entity. | entity_id, optional limit |
get_objects_by_task |
Objects linked to a task. | task_id, optional limit |
add_object_reference |
Link object to entity/task. | object_id, entity_id or task_id |
remove_object_reference |
Unlink object from entity/task. | object_id, entity_id or task_id |
find_orphaned_objects |
Find objects with no references. | optional limit, offset |
get_object_references |
List current object references. | object_id |
validate_object_references |
Validate object references. | object_id |
cleanup_object_references |
Cleanup invalid object references. | object_id |
get_changed_since |
Incremental change feed (includes deleted_entities/deleted_tasks/deleted_objects as {id,type,deleted_at}; ~1h in-memory TTL). |
since, limit_per_type |
get_full_dataset |
Fetch complete dataset snapshot. | optional entity_limit, task_limit, object_limit |
health_check |
Check Atlas Command health. | none |
test_echo |
Echo payload for connectivity testing. | free-form |
Troubleshooting
- No response from gateway: Confirm the gateway process is running, radio IDs match
--gateway-node-id, and Atlas Command is reachable at--api-base-url(check/health). - Serial port errors: Verify the port path and permissions (
sudo usermod -a -G dialout $USERon Linux). Try--simulate-radioto isolate radio issues. - Large payloads dropped: Messages are chunked to fit Meshtastic limits (up to 230 bytes per chunk). Avoid sending large JSON or binary content; use HTTP uploads instead.
- Duplicate or missing responses: Ensure both radios share the same channel/PSK and that clocks are roughly in sync. The CLI generates a fresh UUID for every request; custom integrations should do the same and reuse that UUID when retrying so deduplication works as expected.
- Timeouts: Increase
--timeoutfor slow links. Poor RF conditions may require retries on the client side. - Observability checks: Metrics and health endpoints are available by default on
http://<metrics-host>:<metrics-port>/metrics,/health,/ready, and/statusunless--disable-metricsis set.
Where to go next
- Protocol details:
docs/SYSTEMS_DESIGN.md - Code reference:
atlas_meshtastic_bridge.gatewayandatlas_meshtastic_bridge.transport - Atlas Command HTTP client:
connection_packages/atlas_asset_http_client_python
Metadata
Release files for atlas-meshtastic-bridge 0.1.26
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| atlas_meshtastic_bridge-0.1.26.tar.gz | 71.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| atlas_meshtastic_bridge-0.1.26-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 139.6 kB
Release files / atlas_meshtastic_bridge-0.1.26.tar.gz
| Download URL | atlas_meshtastic_bridge-0.1.26.tar.gz |
|---|---|
| Size | 71.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1a1fa4ee05bdccfe487b7f05485e13f5a85695d9c8e6351fd547dc92d4fee609
|
|
BLAKE2b-256 checksum How to use checksums |
297a14a7f902d4380fc6779c0cc782fc71b48caf9d711f6f46c539763479f14c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Release files / atlas_meshtastic_bridge-0.1.26-py3-none-any.whl
| Download URL | atlas_meshtastic_bridge-0.1.26-py3-none-any.whl |
|---|---|
| Size | 68.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d8fec74dcd86e9ed16c151d3ab3dcdf713d9e499f7ae3e35f6219ed0504f6130
|
|
BLAKE2b-256 checksum How to use checksums |
926ec7b1614c9a7e1d7afc3854a9180a1921b449b999234266cf25db7c5a2f99
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|