meshai/README.md

442 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
```bash
# 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:
```bash
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 |
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.
```yaml
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
```
## 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
```yaml
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](https://forge.echo6.co/matt/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.
```yaml
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).
```bash
# Build from Meshtastic ZIM file
python scripts/zim_to_knowledge.py meshtastic.zim --output knowledge.db
```
```yaml
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 │
└─────────┘ └─────────┘
```
## 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.
```yaml
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:
1. **Alert 1**: fires immediately
2. **Alert 2**: 12 hours later (if still in condition)
3. **Alert 3**: 24 hours after that
4. **Alert 4**: 48 hours after that
5. **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 alerts` receive 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.
```yaml
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
```yaml
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)
```yaml
connection:
type: "tcp"
tcp_host: "192.168.1.100"
tcp_port: 4403
```
### Serial Connection
```yaml
connection:
type: "serial"
serial_port: "/dev/ttyUSB0"
```
Edit `docker-compose.serial.yml` to match your device path.
### Environment Variables
```bash
LLM_API_KEY=your-key-here docker compose up -d
```
## Running Alongside Other Services
### advBBS
MeshAI coexists with [advBBS](https://github.com/zvx-echo6/advbbs) on the same node. BBS protocol messages (sync, RAP, mail notifications) are automatically filtered. No configuration needed.
```yaml
bot:
filter_bbs_protocols: true
```
### MeshMonitor
MeshAI integrates with [MeshMonitor](https://github.com/Yeraze/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).
```yaml
meshmonitor:
enabled: true
url: "http://192.168.1.100:8080"
inject_into_prompt: true
refresh_interval: 300
```
## Running as a Service
```ini
# /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
```
```bash
sudo systemctl daemon-reload
sudo systemctl enable meshai
sudo systemctl start meshai
```
## Acknowledgments
- [Meshtastic](https://meshtastic.org/) — the mesh networking platform
- [MeshMonitor](https://github.com/Yeraze/meshmonitor) by Yeraze — monitoring integration and data source
- [advBBS](https://github.com/zvx-echo6/advbbs) — BBS coexistence design
- [sqlite-vec](https://github.com/asg017/sqlite-vec) by Alex Garcia — vector search in SQLite
- [fastembed](https://github.com/qdrant/fastembed) by Qdrant — fast local embeddings
## License
MIT License
## Author
K7ZVX - matt@echo6.co