Web Viewer
A browser-based dashboard for monitoring and managing your MeshCore bot. The viewer shares the bot’s SQLite database by default and provides real-time streams, contact management, mesh graph visualization, radio control, and in-browser configuration.
Features
- Contacts — Live contact list with signal, path, and location; star contacts; purge inactive contacts; export CSV/JSON
- Mesh graph — Interactive node graph at
/mesh - Radio — Channel management, reboot, connect/disconnect radio
- Feeds — RSS/API feed subscriptions per channel
- Packets — Raw packet monitor
- Live activity — Real-time packet/command/message feed at
/realtime(pause and clear) - Logs — Real-time log viewer at
/logswith level filtering - Config — SMTP, log rotation, backups, maintenance status at
/config - Admin config — Read-only effective config with secrets redacted at
/admin/config - API Explorer — Interactive API documentation at
/api-explorer - Operational banners — Initializing, zombie-radio, and radio-offline alerts when applicable
- Version footer — Displays resolved bot version
For SMTP and nightly maintenance email details, see the README Web Viewer section.
Quick start
Integrated with the bot (recommended)
- Edit
config.ini:
[Web_Viewer]
enabled = true
auto_start = true
host = 127.0.0.1
port = 8080
web_viewer_password = yourpassword
-
Start the bot. The viewer starts automatically when
auto_start = true. -
Open
http://localhost:8080(orhttp://<bot-ip>:8080ifhost = 0.0.0.0).
Standalone mode
Use standalone mode only for debugging or when the bot is not running:
pip install flask flask-socketio
python3 -m modules.web_viewer.app --config config.ini --host 127.0.0.1 --port 8080
The viewer reads [Web_Viewer] from the config file. Override host/port on the command line if needed.
Configuration
All options are in the [Web_Viewer] section of config.ini:
[Web_Viewer]
enabled = false
# web_viewer_password = changeme
host = 127.0.0.1
port = 8080
debug = false
auto_start = false
decode_hashtag_channels =
# db_path = meshcore_bot.db
| Option | Description |
|---|---|
enabled |
Enable the web viewer |
web_viewer_password |
If set, login is required for all routes and Socket.IO. If empty, auth is disabled (not recommended when host = 0.0.0.0) |
host |
127.0.0.1 (localhost only) or 0.0.0.0 (all interfaces) |
port |
HTTP port (default 8080, range 1024–65535) |
debug |
Flask debug mode (development only) |
auto_start |
Start viewer when the bot starts |
decode_hashtag_channels |
Comma-separated hashtag channels to decrypt in the packet stream without adding them to the radio |
db_path |
Optional separate DB path; if unset, uses [Bot] db_path (recommended) |
Security: Using host = 0.0.0.0 without web_viewer_password logs an error at startup. Always set a password when exposing the viewer on a LAN or the internet.
Authentication and security
When web_viewer_password is set:
- A login page protects all HTML routes and Socket.IO connections.
- CSRF protection applies to mutating HTTP POST requests.
- Security headers are set on responses.
When the password is empty, the UI is reachable without login. Use host = 127.0.0.1 for localhost-only access, or set a password before binding to 0.0.0.0.
For production deployments on untrusted networks, also use a reverse proxy with TLS and restrict access by firewall.
Pages overview
| Path | Purpose |
|---|---|
/ |
Dashboard — database stats, quick navigation |
/contacts |
Repeater contacts and contact tracking |
/mesh |
Interactive mesh network graph |
/radio |
Radio settings and control |
/feeds |
Feed manager subscriptions |
/realtime |
Live packet, command, and message activity |
/logs |
Real-time bot log stream |
/config |
Notifications, log rotation, backups, maintenance |
/admin/config |
Effective config (secrets redacted) |
/api-explorer |
API documentation and try-it UI |
/stats |
Message/command/path statistics |
/greeter |
Greeter configuration |
/cache |
Cache inspection |
Legacy routes such as /cache remain for compatibility; primary navigation is from the dashboard navbar.
Real-time streams
The viewer uses Socket.IO for live data. After connecting, the client emits subscription events; the navbar indicator reflects connection state (subscriptions are silent—no per-subscribe toast).
| Client event | Data |
|---|---|
subscribe_packets |
Raw packet stream |
subscribe_commands |
Command invocations |
subscribe_messages |
Channel messages |
subscribe_logs |
Log lines |
subscribe_mesh |
Mesh graph updates |
Use Live activity (/realtime) for a combined color-coded feed, or subscribe from custom clients via the same events.
API endpoints
JSON APIs are available for automation (authentication required when web_viewer_password is set). Examples:
curl http://localhost:8080/api/stats
curl http://localhost:8080/api/contacts
curl http://localhost:8080/api/mesh/nodes
See API Explorer (/api-explorer) for the full list of routes and request formats.
Database
The viewer uses the same database as the bot by default ([Bot] db_path, typically meshcore_bot.db). That file holds repeater contacts, mesh graph, packet stream, and related tables.
Dashboard stats (message/command/path counts) come from message_stats, command_stats, and path_stats. To populate these when the stats chat command is disabled, set under [Stats_Command]:
Packet stream retention is controlled by [Data_Retention] packet_stream_retention_days. See Data retention.
Migrating from a separate web viewer database
If you previously used a separate viewer database (e.g. [Web_Viewer] db_path = bot_data.db):
-
Stop the bot and viewer so neither has the databases open.
-
Optionally migrate packet stream history:
Adjust paths as needed. The script copiespacket_streamrows and skips duplicates. -
Remove or comment out
[Web_Viewer] db_pathso the viewer uses[Bot] db_path. -
Start the bot and verify the viewer shows contacts and mesh data.
Troubleshooting
Web viewer not accessible (e.g. Orange Pi / SBC)
- Confirm config under
[Web_Viewer]: enabled = trueauto_start = true(if starting with the bot)host = 0.0.0.0for access from other devicesport = 8080(or another port 1024–65535)web_viewer_passwordset when using0.0.0.0- Check the port is listening:
ss -tlnp | grep 8080 - Inspect logs:
logs/web_viewer_stdout.log,logs/web_viewer_stderr.log - Bot integration: Look for
Web viewer integration initializedorWeb viewer integration failedin bot logs. - Firewall: Allow TCP on your viewer port (
ufw allow 8080/tcpor equivalent). - Test locally:
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/ - Standalone debug:
Flask not found
Database not found
- Run the bot at least once to create the database.
- Check file permissions on the DB path.
Port already in use
- Change
portinconfig.inior stop the conflicting service. ss -tlnp | grep 8080orlsof -i :8080to find the process.
Login required but password forgotten
- Set a new
web_viewer_passwordinconfig.iniand restart the bot (or viewer process).