[LEGACY] Reliable offline bridge for Atlas Command over Meshtastic radios. Superseded by next_gen_atlas_meshtastic_link.
Project description
Atlas Meshtastic Bridge
[!WARNING] DEPRECATION NOTICE: This package is the older, legacy Meshtastic bridge. While it is still available and actively used in existing deployments, it has been superseded. We highly recommend new projects use the Next Gen Atlas Meshtastic Link package moving forward, which serves as its replacement.
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file atlas_meshtastic_bridge-0.1.26.tar.gz.
File metadata
- Download URL: atlas_meshtastic_bridge-0.1.26.tar.gz
- Upload date:
- Size: 71.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a1fa4ee05bdccfe487b7f05485e13f5a85695d9c8e6351fd547dc92d4fee609
|
|
| MD5 |
eb4dd9982e2581c3991e145c098dadcc
|
|
| BLAKE2b-256 |
297a14a7f902d4380fc6779c0cc782fc71b48caf9d711f6f46c539763479f14c
|
File details
Details for the file atlas_meshtastic_bridge-0.1.26-py3-none-any.whl.
File metadata
- Download URL: atlas_meshtastic_bridge-0.1.26-py3-none-any.whl
- Upload date:
- Size: 68.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d8fec74dcd86e9ed16c151d3ab3dcdf713d9e499f7ae3e35f6219ed0504f6130
|
|
| MD5 |
b249ab7f8927b8c47be3cd74dba40854
|
|
| BLAKE2b-256 |
926ec7b1614c9a7e1d7afc3854a9180a1921b449b999234266cf25db7c5a2f99
|