- Python 46.5%
- JavaScript 41.8%
- TypeScript 11.5%
The periodic health_update in main.py only sent score/tier/totals but no pillars dict. Dashboard setHealth() replaced the full REST response with this incomplete object, causing all pillar bars to drop to 0.0. Now sends the complete payload matching mesh_routes.py and ws.py (pillars, util_percent, flagged_nodes, battery_warnings, recommendations) and gates on composite > 0 + infra_total > 0 to skip partial state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| config | ||
| dashboard-frontend | ||
| docs | ||
| meshai | ||
| tests | ||
| .dockerignore | ||
| .gitattributes | ||
| .gitignore | ||
| config.example.yaml | ||
| docker-compose.yml | ||
| docker-entrypoint.sh | ||
| Dockerfile | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
MeshAI
LLM-powered mesh intelligence assistant for Meshtastic networks. MeshAI connects to your mesh as a physical node, monitors network health in real-time, and answers questions about your infrastructure over LoRa.
What It Does
MeshAI runs on your Meshtastic node and provides:
- Mesh Intelligence — 5-pillar health scoring, per-region breakdowns, infrastructure monitoring, coverage gap analysis, and environmental sensing
- Conversational Queries — ask "how's the mesh?" or "tell me about MHR" and get data-driven answers over LoRa
- Node Distance — GPS-based distance calculations between any two nodes on the mesh
- Multi-Source Awareness — aggregates data from multiple Meshview instances and MeshMonitor with staggered polling
- Feeder Gateway Tracking — identifies which physical MQTT gateways hear each node and signal quality
- Subscriptions — scheduled daily/weekly health reports and instant alerts delivered via DM
- LLM Chat — general conversation, knowledge base lookups, and weather queries
- Multi-Backend — supports Google Gemini, OpenAI, Anthropic Claude, and local LLMs via LiteLLM
Quick Start
# Clone
git clone https://github.com/zvx-echo6/meshai.git
cd meshai
# Install
pip install -e .
# Configure (interactive TUI)
meshai --config
# Run
meshai
Or with Docker:
mkdir -p meshai/data && cd meshai
curl -O https://raw.githubusercontent.com/zvx-echo6/meshai/main/docker-compose.yml
curl -o data/config.yaml https://raw.githubusercontent.com/zvx-echo6/meshai/main/config.example.yaml
# Edit data/config.yaml
docker compose up -d
Commands
| Command | Description |
|---|---|
!health |
Mesh health overview with colored status dots |
!region |
List all regions with health status |
!region [name] |
Detailed region breakdown |
!neighbors [node] |
Top infrastructure neighbors with signal quality |
!sub daily 6pm |
Subscribe to daily health reports |
!sub weekly 8am sun |
Subscribe to weekly digest |
!sub alerts |
Subscribe to instant alerts on issues |
!unsub [type] |
Remove a subscription |
!mysubs |
List your active subscriptions |
!clear |
Clear conversation history |
!help |
Show available commands |
!help [cmd] |
Detailed help for a command |
!quakes |
Recent earthquakes in monitored area |
!fires |
Active wildfires from NIFC |
!hotspots |
NASA FIRMS satellite fire detections |
!hotspots --new |
Only hotspots not matching known fires |
!traffic |
Traffic incidents from TomTom |
!space |
Space weather conditions (solar/geomagnetic) |
!water |
USGS stream gauge readings |
!air |
Air quality index |
Commands can be disabled in config if another service (like MeshMonitor) handles them.
Mesh Intelligence
MeshAI continuously polls mesh data sources and computes a 5-pillar health score:
| Pillar | Weight | What It Measures |
|---|---|---|
| Infrastructure | 30% | Router uptime — how many infra nodes are online |
| Utilization | 25% | Channel busyness — RF congestion across the mesh |
| Coverage | 20% | Gateway reach — how many monitoring sources see each node |
| Behavior | 15% | Traffic patterns — detecting noisy or misconfigured nodes |
| Power | 10% | Battery health — infrastructure nodes only |
Health Display
!health shows a compact overview with personality:
📡 Mesh 🟢 healthy
🏗️ 15/16 routers up
❌ Down: TVM Tablerock Relay
📶 152 full coverage, 94 on thin ice
🔥 Hayden Peak Router at 21% util
🔋 All infra powered ✅
🌡️ 29-34°C across 2 sensors
Treasure Valley 🟢 | Magic Valley 🟢
Status dots: 🔵 perfect (100) · 🟢 healthy (75+) · 🟠 warning (50+) · 🔴 critical (<50)
Monitoring Rules
Infrastructure nodes (routers, repeaters) are monitored individually with full detail — battery, offline alerts, coverage, neighbors, hardware. Client nodes dying is normal and not tracked. Channel utilization and environmental sensors are monitored for all nodes.
Conversational Queries
Ask questions naturally over LoRa:
- "how's the mesh?" → health overview with top issues
- "tell me about MHR" → full node detail with neighbors, coverage, feeders
- "where do we need more coverage?" → named gaps with specific nodes
- "how far is MHR from AIDA?" → GPS distance calculation
- "which nodes only reach one gateway?" → named nodes with their gateway
- "which gateway has the best signal?" → feeder comparison
Geographic Regions
Regions are configurable with local names, descriptions, aliases, and cities — all manageable through the TUI. No hardcoded geography in the code.
mesh_intelligence:
regions:
- name: "South Central ID"
local_name: "Magic Valley"
description: "Twin Falls area"
aliases: ["southern Idaho", "magic valley"]
cities: ["Twin Falls", "Burley", "Jerome"]
lat: 42.5
lon: -114.5
radius_km: 80
Environmental Feeds
MeshAI integrates real-time environmental data for situational awareness beyond mesh network health.
USGS Earthquake Monitoring
env:
usgs:
enabled: true
min_magnitude: 2.5
radius_km: 500
center_lat: 43.6150
center_lon: -116.2023
No API key required. Data from USGS Earthquake Hazards Program.
NWS Weather Alerts
env:
nws:
enabled: true
zone: IDZ025 # NWS zone ID
point: "43.6150,-116.2023"
No API key required. Find your zone at NWS Zone Lookup.
NOAA Space Weather
env:
noaa_space:
enabled: true
No API key required. Data from NOAA SWPC.
NIFC Wildfire Perimeters
env:
nifc:
enabled: true
radius_km: 200
center_lat: 43.6150
center_lon: -116.2023
No API key required. Data from NIFC Open Data.
NASA FIRMS Satellite Fire Detection
env:
firms:
enabled: true
map_key: "your-map-key" # Required
radius_km: 200
center_lat: 43.6150
center_lon: -116.2023
source: VIIRS_SNPP # VIIRS_SNPP, VIIRS_NOAA20, MODIS_NRT
day_range: 1 # 1, 2, or 10 days
API Key Required: Register at NASA FIRMS. Free MAP_KEY provides access to near real-time satellite fire detections. Hotspots are cross-referenced against NIFC perimeters to identify potential new ignitions.
TomTom Traffic
env:
tomtom:
enabled: true
api_key: "your-api-key" # Required
bbox: "-117.5,42.5,-115.0,44.5" # lon1,lat1,lon2,lat2
API Key Required: Register at TomTom Developer Portal. Free tier includes 2,500 requests/day.
511 Road Conditions
env:
fiveonone:
enabled: true
state: ID # State code
api_key: "your-api-key" # If required by state
bbox: [-117.5, 42.5, -115.0, 44.5]
API key requirements vary by state. Check your state's 511 developer portal.
USGS Water Services
env:
usgs_water:
enabled: true
sites: ["13206000", "13202000"] # USGS site numbers
No API key required. Find sites at USGS Water Services.
AirNow Air Quality
env:
airnow:
enabled: true
api_key: "your-api-key" # Required
zipcode: "83702"
API Key Required: Register at AirNow API.
Dashboard Configuration
dashboard:
enabled: true
host: 0.0.0.0
port: 8080
The web dashboard provides real-time visualization of mesh nodes, environmental conditions, and alerts with WebSocket push notifications.
Data Sources
MeshAI aggregates from multiple sources using staggered tick-based polling (one API call per 30-second tick):
Meshview
Unauthenticated REST API. Supports multiple instances.
| Endpoint | Interval | Data |
|---|---|---|
/api/packets |
30s | Near real-time packet feed |
/api/nodes |
2 min | Node list with metadata |
/api/stats |
3 min | Traffic statistics |
/api/edges |
3 min | Node-to-node connections |
/api/traceroutes |
5 min | Route data |
/api/packets_seen |
10 min | Per-gateway RSSI/SNR (sampled) |
MeshMonitor
Authenticated (Bearer token). Single instance.
| Endpoint | Interval | Data |
|---|---|---|
/api/v1/packets |
60s | Packet feed |
/api/v1/nodes |
2 min | Nodes with battery, utilization, hardware |
/api/v1/telemetry |
2 min | Environmental sensors, device metrics |
/api/v1/traceroutes |
5 min | Route data |
/api/v1/channels |
5 min | Channel configuration |
/api/v1/network |
5 min | Network statistics |
/api/v1/solar |
10 min | Solar estimates |
Rate Limiting
Built-in protection for all sources: HTTP 429 backoff with Retry-After, exponential backoff on consecutive errors, slow response warnings, and optional polite mode for shared instances.
Source Configuration
mesh_sources:
- name: "local-meshview"
type: meshview
url: "http://192.168.1.100:8080"
enabled: true
- name: "meshmonitor"
type: meshmonitor
url: "http://192.168.1.100:3333"
api_token: "your-bearer-token"
enabled: true
Knowledge Base (RAG)
MeshAI uses a hybrid knowledge retrieval system with two backends:
Primary: RECON Qdrant Backend
Queries RECON's knowledge extraction pipeline — 2.8M+ vectors covering survival skills, communications, medical, technical documentation, Meshtastic docs, and more. Uses the same embedding infrastructure as RECON:
- Dense embeddings: TEI service with BAAI/bge-m3 (1024-dim)
- Sparse embeddings: bge-m3-sparse with IDF modifier
- Search: Qdrant hybrid with Reciprocal Rank Fusion (dense + sparse)
No data is copied — MeshAI queries RECON's Qdrant and TEI services over the network.
knowledge:
enabled: true
backend: auto # "qdrant", "sqlite", or "auto" (try qdrant, fall back)
qdrant_host: "192.168.1.150"
qdrant_port: 6333
qdrant_collection: "recon_knowledge_hybrid"
tei_host: "192.168.1.150"
tei_port: 8090
sparse_host: "192.168.1.150"
sparse_port: 8091
use_sparse: true
top_k: 5
Fallback: Local SQLite
If the Qdrant backend is unreachable, MeshAI falls back to a local SQLite knowledge base using FTS5 keyword search and bge-small-en-v1.5 vector embeddings (384-dim).
# Build from Meshtastic ZIM file
python scripts/zim_to_knowledge.py meshtastic.zim --output knowledge.db
knowledge:
enabled: true
backend: sqlite
db_path: /data/meshai_knowledge.db
top_k: 5
Requires sqlite-vec and fastembed for the SQLite backend.
Architecture
┌──────────────────────────────────────────────────────────────────────┐
│ MeshAI │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ DATA SOURCES INTELLIGENCE DELIVERY │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ Meshview ×N │─────┐ │ Health Engine │────────▶│ Reporter │ │
│ │ (staggered) │ │ │ 5-pillar │ │ Tier 1/2 │ │
│ └─────────────┘ ▼ │ scoring │ └─────┬──────┘ │
│ ┌─────────────┐ ┌──────┴──┐ │ │ │
│ │ MeshMonitor │─▶│ Data │─┘ │ ┌─────▼──────┐ │
│ │ (staggered) │ │ Store │ │ │ Router │ │
│ └─────────────┘ │ SQLite │ │ │ scope/dist │ │
│ └─────────┘ │ └─────┬──────┘ │
│ │ │ │ │
│ ┌────▼────┐ ┌─────▼──────┐ ┌────▼────┐ │
│ │ Feeder │ │ LLM │ │ Chunker │ │
│ │ Sampling│ │ Backend │ │LoRa-fit │ │
│ └─────────┘ └────────────┘ └────┬────┘ │
│ │ │
│ KNOWLEDGE ALERTS DELIVERY │ │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ │ │
│ │ RECON/Qdrant│ │ Alert │ │ Subscription │ │ │
│ │ 2.8M vectors│ │ Engine │ │ Manager │ │ │
│ │ (network) │ │ 17 triggers │ │ daily/weekly │ │ │
│ ├─────────────┤ │ scaling │ │ alerts │ │ │
│ │ SQLite FTS5 │ │ cooldown │ └──────┬───────┘ │ │
│ │ (fallback) │ └──────┬──────┘ │ │ │
│ └─────────────┘ │ ┌─────▼────────┐ │ │
│ └─────────▶│ Responder │◀──┘ │
│ ┌─────────────┐ │ ACK-paced DM │ │
│ │ Conversation│ │ Channel alert│ │
│ │ History │ └──────────────┘ │
│ └─────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────┘
│ │
┌────▼────┐ ┌────▼────┐
│ TEI │ │ Qdrant │
│ bge-m3 │ │ hybrid │
│ cortex │ │ cortex │
└─────────┘ └─────────┘
Dashboard API Reference
The dashboard exposes a REST API (default port 8080):
Core Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/health |
GET | System health check |
/api/status |
GET | Full system status with health scores |
/api/nodes |
GET | Connected mesh nodes |
/api/messages |
GET | Recent mesh messages |
Environmental Data
| Endpoint | Method | Description |
|---|---|---|
/api/env/earthquakes |
GET | Recent earthquakes |
/api/env/weather |
GET | Weather conditions and alerts |
/api/env/fires |
GET | Active wildfires from NIFC |
/api/env/hotspots |
GET | NASA FIRMS satellite detections |
/api/env/traffic |
GET | Traffic incidents |
/api/env/water |
GET | Stream gauge readings |
/api/env/space |
GET | Space weather data |
/api/env/air |
GET | Air quality readings |
Alerts
| Endpoint | Method | Description |
|---|---|---|
/api/alerts/active |
GET | Currently active alerts |
/api/alerts/history |
GET | Historical alerts (?severity=, ?source=, ?limit=, ?offset=) |
/api/alerts/{id}/ack |
POST | Acknowledge an alert |
/api/subscriptions |
GET | Alert subscriptions |
WebSocket
Connect to /ws for real-time updates:
const ws = new WebSocket('ws://localhost:8080/ws');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
// data.type: 'message', 'alert', 'node_update', 'health_update'
};
Message Chunking
Long responses are split into mesh-friendly chunks with sentence-aware splitting, configurable limits, and continuation prompts. Command output (like !health) packs multiple lines into 2-3 messages using newlines within each message to minimize airtime usage.
response:
max_length: 200 # Max chars per message
max_messages: 3 # Messages before continuation prompt
Alerting
Real-time alerts when mesh conditions change, with scaling cooldowns to prevent spam.
Alert Conditions (17 total, each toggleable)
| Pillar | Condition | Default Threshold |
|---|---|---|
| Infrastructure | Router goes offline | — |
| Infrastructure | Router recovery | — |
| Infrastructure | New router appears | — |
| Power | Battery warning | <50% |
| Power | Battery critical | <25% |
| Power | Battery emergency | <10% |
| Power | 7-day declining trend | >10% drop with rate |
| Power | USB → battery (power outage) | — |
| Power | Solar not charging during day | — |
| Utilization | Sustained high utilization | >20% for 6h |
| Utilization | Packet flood | >500 pkts/24h |
| Coverage | Infra drops to single gateway | — |
| Coverage | Feeder gateway stops responding | — |
| Coverage | Region total blackout | All infra offline |
| Scores | Mesh health score drop | <70/100 |
| Scores | Region health score drop | <60/100 |
Scaling Cooldown
Alerts don't spam. When a condition triggers:
- Alert 1: fires immediately
- Alert 2: 12 hours later (if still in condition)
- Alert 3: 24 hours after that
- Alert 4: 48 hours after that
- Stops until condition resolves
When the condition clears, one recovery notification fires and the tracker resets.
Delivery
Alerts are delivered two ways:
- Channel broadcast: configurable channel index for mesh-wide visibility
- DM to subscribers: users who ran
!sub alertsreceive DMs matching their scope
Critical Nodes
Designate important infrastructure (e.g., MHR, HPR) as critical. When a critical node goes offline, alerts use priority formatting.
mesh_intelligence:
critical_nodes: ["MHR", "HPR"]
alert_channel: 0 # Channel for broadcast alerts (-1 = disabled)
All conditions and thresholds are configurable via the TUI under Mesh Intelligence → Alert Rules.
LLM Configuration
llm:
backend: "google" # openai, anthropic, google
api_key: "your-api-key"
model: "gemini-2.0-flash"
Local LLMs
MeshAI works with any OpenAI-compatible API:
- LiteLLM:
base_url: "http://localhost:4000/v1" - Open WebUI:
base_url: "http://localhost:3000/api" - Ollama:
base_url: "http://localhost:11434/v1"
Docker
TCP Connection (recommended)
connection:
type: "tcp"
tcp_host: "192.168.1.100"
tcp_port: 4403
Serial Connection
connection:
type: "serial"
serial_port: "/dev/ttyUSB0"
Edit docker-compose.serial.yml to match your device path.
Environment Variables
LLM_API_KEY=your-key-here docker compose up -d
Running Alongside Other Services
advBBS
MeshAI coexists with advBBS on the same node. BBS protocol messages (sync, RAP, mail notifications) are automatically filtered. No configuration needed.
bot:
filter_bbs_protocols: true
MeshMonitor
MeshAI integrates with MeshMonitor at two levels: it fetches MeshMonitor's auto-responder patterns to avoid duplicate responses, and it uses MeshMonitor's API as a data source for mesh intelligence (battery, telemetry, traceroutes, solar).
meshmonitor:
enabled: true
url: "http://192.168.1.100:8080"
inject_into_prompt: true
refresh_interval: 300
Running as a Service
# /etc/systemd/system/meshai.service
[Unit]
Description=MeshAI - Meshtastic Mesh Intelligence
After=network.target
[Service]
Type=simple
User=your-user
WorkingDirectory=/path/to/meshai
ExecStart=/usr/bin/python3 -m meshai
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable meshai
sudo systemctl start meshai
Acknowledgments
- Meshtastic — the mesh networking platform
- MeshMonitor by Yeraze — monitoring integration and data source
- advBBS — BBS coexistence design
- sqlite-vec by Alex Garcia — vector search in SQLite
- fastembed by Qdrant — fast local embeddings
License
MIT License
Author
K7ZVX - matt@echo6.co