Integration bridge: RTfMC REST/WS API → meshcore-bot-web Dashboard & Bot (Python, aiohttp)
  • Python 79.1%
  • HTML 20.5%
  • Dockerfile 0.4%
Find a file
ppfeiffer 3ea315601a
Some checks failed
ci / lint-and-test (push) Failing after 6s
docs: add English README (README.en.md)
2026-04-29 19:00:01 +00:00
.forgejo/workflows chore: add CI/release workflows, docs, versioning 2026-04-29 18:57:47 +00:00
bot Initial commit: RTfMC bridge with dashboard, bot, and telemetry poller 2026-04-29 18:50:05 +00:00
bridge Initial commit: RTfMC bridge with dashboard, bot, and telemetry poller 2026-04-29 18:50:05 +00:00
dashboard Initial commit: RTfMC bridge with dashboard, bot, and telemetry poller 2026-04-29 18:50:05 +00:00
docs chore: add CI/release workflows, docs, versioning 2026-04-29 18:57:47 +00:00
.gitignore Initial commit: RTfMC bridge with dashboard, bot, and telemetry poller 2026-04-29 18:50:05 +00:00
CHANGELOG.md chore: add CI/release workflows, docs, versioning 2026-04-29 18:57:47 +00:00
config.example.yaml Initial commit: RTfMC bridge with dashboard, bot, and telemetry poller 2026-04-29 18:50:05 +00:00
docker-compose.yml Initial commit: RTfMC bridge with dashboard, bot, and telemetry poller 2026-04-29 18:50:05 +00:00
Dockerfile Initial commit: RTfMC bridge with dashboard, bot, and telemetry poller 2026-04-29 18:50:05 +00:00
main.py Initial commit: RTfMC bridge with dashboard, bot, and telemetry poller 2026-04-29 18:50:05 +00:00
README.en.md docs: add English README (README.en.md) 2026-04-29 19:00:01 +00:00
README.md Initial commit: RTfMC bridge with dashboard, bot, and telemetry poller 2026-04-29 18:50:05 +00:00
requirements.txt Initial commit: RTfMC bridge with dashboard, bot, and telemetry poller 2026-04-29 18:50:05 +00:00
ruff.toml chore: add CI/release workflows, docs, versioning 2026-04-29 18:57:47 +00:00
VERSION chore: add CI/release workflows, docs, versioning 2026-04-29 18:57:47 +00:00

meshcore-rtfmc-bridge

Integration bridge between Remote-Terminal-for-MeshCore (RTfMC) and a custom web dashboard + bot.

RTfMC handles the direct radio communication with the MeshCore device. This bridge consumes the RTfMC REST API and WebSocket stream to provide:

  • a web dashboard (aiohttp, port 8880) with live repeater telemetry, contact list and message stream
  • a bot handler that responds to !commands in DMs and channel messages
  • a telemetry poller that periodically fetches repeater status and optionally publishes it via MQTT

Architecture

MeshCore Radio (USB/TCP)
        │
        ▼
┌─────────────────────────────┐
│  Remote-Terminal-for-MeshCore│  port 8765
│  (RTfMC  external service) │
│                             │
│  REST API  /contacts        │
│            /messages        │
│            /channels        │
│            /repeaters       │
│            /statistics      │
│  WebSocket /ws              │
└──────────────┬──────────────┘
               │ HTTP + WS
               ▼
┌─────────────────────────────────────────────────────┐
│              meshcore-rtfmc-bridge                  │
│                                                     │
│  bridge/rtfmc_client.py   ← async REST + WS client │
│  bridge/state.py          ← shared in-memory state  │
│  bridge/telemetry_poller.py ← periodic poll         │
│                                                     │
│  bot/bot_handler.py       ← !command handler        │
│                                                     │
│  dashboard/dashboard.py   ← aiohttp web UI + API    │
│  dashboard/templates/     ← HTML frontend           │
└──────┬──────────────────────────────┬───────────────┘
       │ WS push                      │ HTTP REST
       ▼                              ▼
  Browser dashboard           bot responses
  (port 8880)                 (via RTfMC API)

Quickstart

cp config.example.yaml config.yaml
# edit config.yaml: set RTfMC URL, dashboard port, admin keys

python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
python main.py
# → http://localhost:8880

Docker / Portainer

cp config.example.yaml config.yaml
# edit config.yaml, then:
docker compose up -d

If RTfMC runs on the same host outside Docker, set the URL in config.yaml:

rtfmc:
  url: "http://host.docker.internal:8765"

host.docker.internal is mapped via extra_hosts in the Compose file.

Configuration

All settings live in config.yaml (copy from config.example.yaml):

rtfmc:
  url: "http://localhost:8765"   # RTfMC backend URL
  password: ""                    # leave empty if not set

telemetry:
  interval_seconds: 300           # how often to poll repeater status

dashboard:
  host: "0.0.0.0"
  port: 8880

bot:
  admin_keys:
    - "<your-64-char-public-key>" # hex string; grants access to privileged commands

Bot Commands

Send these as a DM or channel flood message to your own node:

Command Arguments Description
!help List available commands
!ping Responds with pong
!status Radio status and network summary
!nodes All known nodes (up to 20)
!repeater [name] Telemetry for a repeater; without argument: first repeater in state
!advert Trigger a manual advert (admin keys only)

Rate limit: 10 seconds per sender / channel.

Dashboard API

The bridge exposes its own REST API and WebSocket on port 8880:

Endpoint Description
GET /api/summary Network overview (contact counts, radio status)
GET /api/contacts?type=repeater Contact list, optional type filter
GET /api/messages?limit=50 In-memory message buffer
GET /api/telemetry Cached repeater telemetry
GET /api/statistics Packet statistics forwarded from RTfMC
POST /api/repeater/{key}/status Trigger immediate telemetry fetch
WS /ws Live events: contact, message, telemetry, health

Project Structure

meshcore-rtfmc-bridge/
├── main.py                      # entry point
├── config.example.yaml          # configuration template
├── requirements.txt             # aiohttp, pyyaml
├── VERSION                      # current version (SemVer)
├── CHANGELOG.md                 # per-version release notes
├── Dockerfile
├── docker-compose.yml
│
├── bridge/
│   ├── rtfmc_client.py          # async REST + WS client
│   ├── state.py                 # shared in-memory state singleton
│   └── telemetry_poller.py      # background repeater poll task
│
├── bot/
│   └── bot_handler.py           # !command parser and responder
│
├── dashboard/
│   ├── dashboard.py             # aiohttp routes, WS broadcast
│   └── templates/index.html     # dark-mode single-page dashboard
│
├── docs/
│   ├── architecture.md          # system design and data flow
│   ├── api-reference.md         # full REST, WS and Python API docs
│   ├── deployment.md            # local, Docker, Portainer, systemd, Caddy
│   └── versioning.md            # SemVer strategy and release workflow
│
└── .forgejo/workflows/
    ├── ci.yml                   # lint + syntax check on push / PR
    ├── bump-version.yml         # manual SemVer bump (ppfeiffer only)
    └── release.yml              # auto-release on version tags

Versioning

This project uses Semantic Versioning (MAJOR.MINOR.PATCH).

Level When
PATCH Bug fixes, no API changes
MINOR New features, backwards compatible
MAJOR Breaking changes

Releases are created exclusively by the repository owner via the bump-version Forgejo Actions workflow (Actions → bump-version → Run workflow). The workflow updates VERSION, appends a section to CHANGELOG.md, commits both, creates an annotated tag, and triggers the release workflow which publishes a Forgejo release with changelog notes and a source archive.

See docs/versioning.md for the full guide.

CI

Every push and pull request runs the CI workflow:

  • ruff check style and import linting
  • pyflakes import error detection
  • YAML validation of config.example.yaml
  • py_compile of all Python modules

Security Note

RTfMC should not be exposed to the public internet directly (the built-in bot code execution uses exec() and carries RCE risk). Place Caddy or another reverse proxy with authentication in front, or restrict RTfMC to loopback only.

Documentation

License

See repository for license details.