Files
Remote-Terminal-for-MeshCore/README.md
2026-02-04 14:46:41 -08:00

7.3 KiB

RemoteTerm for MeshCore

Backend server + browser interface for MeshCore mesh radio networks. Connect your radio over Serial, TCP, or BLE, and then you can:

  • Send and receive DMs and GroupTexts
  • Cache all received packets, decrypting as you gain keys
  • Monitor unlimited contacts and channels (radio limits don't apply -- packets are decrypted server-side)
  • Access your radio remotely over your network or VPN
  • Brute force hashtag room names for GroupTexts you don't have keys for yet

Warning: This app has no authentication. Run it on a private network only -- do not expose to the internet unless you want strangers sending traffic as you.

Screenshot of the application's web interface

Disclaimer

This is entirely vibecoded slop -- no warranty of fitness for any purpose. It's been lovingly guided by an engineer with a passion for clean code and good tests, but it's still mostly LLM output, so you may find some bugs.

If extending, have your LLM read the three AGENTS.md files: ./AGENTS.md, ./frontend/AGENTS.md, and ./app/AGENTS.md.

Requirements

  • Python 3.10+
  • Node.js 18+ (for frontend development only)
  • UV package manager: curl -LsSf https://astral.sh/uv/install.sh | sh
  • MeshCore radio connected via USB serial, TCP, or BLE
Finding your serial port
#######
# Linux
#######
ls /dev/ttyUSB* /dev/ttyACM*

#######
# macOS
#######
ls /dev/cu.usbserial-* /dev/cu.usbmodem*

######
# WSL2
######
# Run this in an elevated PowerShell (not WSL) window
winget install usbipd

# restart console

# find device ID (e.g. 3-8)
usbipd list

# attach device to WSL
usbipd bind --busid 3-8

Quick Start

This approach is recommended over Docker due to intermittent serial communications issues I've seen on *nix systems.

The frontend is pre-built -- just run the backend:

git clone https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
cd Remote-Terminal-for-MeshCore

uv sync
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000

The server auto-detects the serial port. To specify a transport manually:

# Serial (explicit port)
MESHCORE_SERIAL_PORT=/dev/ttyUSB0 uv run uvicorn app.main:app --host 0.0.0.0 --port 8000

# TCP (e.g. via wifi-enabled firmware)
MESHCORE_TCP_HOST=192.168.1.100 MESHCORE_TCP_PORT=4000 uv run uvicorn app.main:app --host 0.0.0.0 --port 8000

# BLE (address and PIN both required)
MESHCORE_BLE_ADDRESS=AA:BB:CC:DD:EE:FF MESHCORE_BLE_PIN=123456 uv run uvicorn app.main:app --host 0.0.0.0 --port 8000

Access at http://localhost:8000

Note: WebGPU cracking requires HTTPS when not on localhost. See the HTTPS section under Additional Setup.

Docker

Warning: Docker has intermittent issues with serial event subscriptions. The native method above is more reliable.

Note: BLE-in-docker is outside the scope of this README, but the env vars should all still work.

# Serial
docker run -d \
  --device=/dev/ttyUSB0 \
  -v remoteterm-data:/app/data \
  -p 8000:8000 \
  jkingsman/remote-terminal-for-meshcore:latest

# TCP
docker run -d \
  -e MESHCORE_TCP_HOST=192.168.1.100 \
  -e MESHCORE_TCP_PORT=4000 \
  -v remoteterm-data:/app/data \
  -p 8000:8000 \
  jkingsman/remote-terminal-for-meshcore:latest

Development

Backend

uv sync
uv run uvicorn app.main:app --reload

# Or with explicit serial port
MESHCORE_SERIAL_PORT=/dev/ttyUSB0 uv run uvicorn app.main:app --reload

Frontend

cd frontend
npm install
npm run dev      # Dev server at http://localhost:5173 (proxies API to :8000)
npm run build    # Production build to dist/

Run both the backend and npm run dev for hot-reloading frontend development.

Code Quality & Tests

Please test, lint, format, and quality check your code before PRing or committing. At the least, run a lint + autoformat + pyright check on the bakend, and a lint + autoformat on the frontend.

But how?
# python
uv run ruff check app/ tests/ --fix  # lint + auto-fix
uv run ruff format app/ tests/       # format (always writes)
uv run pyright app/                  # type checking
PYTHONPATH=. uv run pytest tests/ -v # backend tests

# frontend
cd frontend
npm run lint:fix                     # esLint + auto-fix
npm run test:run                     # run tests
npm run format                       # prettier (always writes)
npm run build                        # build the frontend

Configuration

Variable Default Description
MESHCORE_SERIAL_PORT (auto-detect) Serial port path
MESHCORE_SERIAL_BAUDRATE 115200 Serial baud rate
MESHCORE_TCP_HOST TCP host (mutually exclusive with serial/BLE)
MESHCORE_TCP_PORT 4000 TCP port
MESHCORE_BLE_ADDRESS BLE device address (mutually exclusive with serial/TCP)
MESHCORE_BLE_PIN BLE PIN (required when BLE address is set)
MESHCORE_LOG_LEVEL INFO DEBUG, INFO, WARNING, ERROR
MESHCORE_DATABASE_PATH data/meshcore.db SQLite database path
MESHCORE_MAX_RADIO_CONTACTS 200 Max recent contacts to keep on radio for DM ACKs

Only one transport may be active at a time. If multiple are set, the server will refuse to start.

Additional Setup

HTTPS (Required for WebGPU Cracking outside localhost)

WebGPU requires a secure context. When not on localhost, serve over HTTPS:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/CN=localhost'
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --ssl-keyfile=key.pem --ssl-certfile=cert.pem

For Docker:

# generate TLS cert
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/CN=localhost'

# run with cert
docker run -d \
  --device=/dev/ttyUSB0 \
  -v remoteterm-data:/app/data \
  -v $(pwd)/cert.pem:/app/cert.pem:ro \
  -v $(pwd)/key.pem:/app/key.pem:ro \
  -p 8000:8000 \
  jkingsman/remote-terminal-for-meshcore:latest \
  uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --ssl-keyfile=/app/key.pem --ssl-certfile=/app/cert.pem

Accept the browser warning, or use mkcert for locally-trusted certs.

Systemd Service (Linux)
# Create service user
sudo useradd -r -m -s /bin/false remoteterm

# Install to /opt/remoteterm
sudo mkdir -p /opt/remoteterm
sudo cp -r . /opt/remoteterm/
sudo chown -R remoteterm:remoteterm /opt/remoteterm

# Install dependencies
cd /opt/remoteterm
sudo -u remoteterm uv venv
sudo -u remoteterm uv sync

# Build frontend (optional -- already built in repo and served by backend)
cd /opt/remoteterm/frontend
sudo -u remoteterm npm install
sudo -u remoteterm npm run build

# Install and start service
sudo cp /opt/remoteterm/remoteterm.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now remoteterm

# Check status
sudo systemctl status remoteterm
sudo journalctl -u remoteterm -f

Edit /etc/systemd/system/remoteterm.service to set MESHCORE_SERIAL_PORT if needed.

Testing

Backend:

PYTHONPATH=. uv run pytest tests/ -v

Frontend:

cd frontend
npm run test:run

API Documentation

With the backend running: http://localhost:8000/docs