diff --git a/README.md b/README.md index 336a15e..00595ba 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,62 @@ # 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. +**An LLM-powered assistant for LoRa mesh networks β€” on Meshtastic *and* MeshCore, at the same time.** -## What It Does +MeshAI connects to your mesh, watches network health and the world around it in real time, answers questions over the air, and broadcasts the alerts that matter β€” weather, wildfire, road, seismic, RF, and mesh-health β€” with a full web dashboard to drive it all. -MeshAI runs on your Meshtastic node and provides: +> ### πŸ€– Built with AI ("vibecoded") +> In the interest of transparency: **MeshAI was vibecoded** β€” designed, built, debugged, and documented in close collaboration with LLM coding assistants. The architecture, most of the implementation, and this README were produced that way. It's a real, running project on a live mesh, but expect the pragmatic style, opinionated shortcuts, and occasional rough edges that come with the territory. Issues and PRs are welcome. -- **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 +![MeshAI dashboard](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/dashboard.png) -## Quick Start +--- + +## Highlights + +- **Dual-transport** β€” runs on **Meshtastic** and **MeshCore** simultaneously. Each mesh is first-class: independent connection, routing, and behavior, one shared brain. +- **Conversational bot** β€” DM it "how's the mesh?" or ask about weather, fires, roads, or a specific node, and get a data-driven answer over LoRa. The reply goes back on whichever mesh you asked from. +- **Per-mesh awareness** β€” it watches chat on each mesh separately (rolling short-term memory), so "what's happening on the mesh?" answers about *your* mesh. Private DMs stay private; curated knowledge stays separate. +- **Broadcast intelligence** β€” weather alerts, wildfire updates, road/traffic, seismic, RF/band conditions, and mesh-health notifications, formatted to fit LoRa and routed per-mesh, per-family. +- **Mesh health** β€” a 5-pillar health score with per-region breakdowns, infrastructure monitoring, coverage-gap analysis, and battery/solar tracking (Meshtastic). +- **Web dashboard** β€” a clean React UI to configure every transport, route every message type, watch a live activity feed, browse contacts, and tune the bot β€” no config-file spelunking required. +- **Knowledge base (RAG)** β€” optional hybrid retrieval over a large curated vector store for survival/comms/technical Q&A. +- **Multi-backend LLM** β€” Google Gemini, OpenAI, Anthropic, or any OpenAI-compatible local model (Ollama, LiteLLM, etc.). + +--- + +## The dashboard + +Everything is driven from the web UI, organized into **General**, **Meshtastic**, and **MeshCore** sections β€” each mesh mirrors the other so there's nothing to relearn when you add the second transport. + +**Live activity log** β€” every broadcast, on both meshes, with per-mesh badges and Sent/Skip status: + +![Activity Log](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/activity.png) + +**Per-family routing** β€” decide exactly where each message type goes: broadcast vs. DM, which channel, which recipients β€” independently for each mesh: + +![Routing](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/mt-routing.png) + +**MeshCore contacts & companion** β€” the live roster from your MeshCore companion node, with names, types, last-heard, position, and optional telemetry polling: + +![MeshCore Contacts](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/mc-contacts.png) + +**Data feeds** β€” turn environmental sources on/off and tune thresholds in one place: + +![Data Feeds](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/datafeeds.png) + +**Nodes & health** β€” per-node infrastructure detail: battery, utilization, coverage, neighbors, hardware: + +![Nodes & Health](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/nodes.png) + +--- + +## 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 --config # interactive setup TUI meshai ``` @@ -38,272 +66,89 @@ 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 +# edit data/config.yaml, then: 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. - -```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 -``` - -## Environmental Feeds - -MeshAI integrates real-time environmental data for situational awareness beyond mesh network health. - -### USGS Earthquake Monitoring - -```yaml -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](https://earthquake.usgs.gov/fdsnws/event/1/). - -### NWS Weather Alerts - -```yaml -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](https://alerts.weather.gov/). - -### NOAA Space Weather - -```yaml -env: - noaa_space: - enabled: true -``` - -No API key required. Data from [NOAA SWPC](https://services.swpc.noaa.gov/). - -### NIFC Wildfire Perimeters - -```yaml -env: - nifc: - enabled: true - radius_km: 200 - center_lat: 43.6150 - center_lon: -116.2023 -``` - -No API key required. Data from [NIFC Open Data](https://data-nifc.opendata.arcgis.com/). - -### NASA FIRMS Satellite Fire Detection - -```yaml -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](https://firms.modaps.eosdis.nasa.gov/api/area/). 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 - -```yaml -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](https://developer.tomtom.com/). Free tier includes 2,500 requests/day. - -### 511 Road Conditions - -```yaml -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 - -```yaml -env: - usgs_water: - enabled: true - sites: ["13206000", "13202000"] # USGS site numbers -``` - -No API key required. Find sites at [USGS Water Services](https://waterservices.usgs.gov/). - -### AirNow Air Quality - -```yaml -env: - airnow: - enabled: true - api_key: "your-api-key" # Required - zipcode: "83702" -``` - -**API Key Required**: Register at [AirNow API](https://docs.airnowapi.org/). - -### Dashboard Configuration - -```yaml -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. +The dashboard comes up on `http://localhost:8080`. --- -## Data Sources +## Transports -MeshAI aggregates from multiple sources using staggered tick-based polling (one API call per 30-second tick): +MeshAI speaks two mesh protocols. **Meshtastic is always the base transport.** **MeshCore turns on automatically the moment you set a MeshCore host** β€” there's no separate on/off toggle to forget. -### Meshview +### Meshtastic -Unauthenticated REST API. Supports multiple instances. +Connect over TCP (recommended) or serial: -| 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) | +```yaml +connection: + type: "tcp" # or "serial" + tcp_host: "192.168.1.100" + tcp_port: 4403 + # serial_port: "/dev/ttyUSB0" +``` -### MeshMonitor +### MeshCore -Authenticated (Bearer token). Single instance. +MeshAI attaches to a MeshCore **companion** (the pyMC / MeshCore companion frame server) over TCP and acts as a node on the MeshCore mesh: -| 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 | +```yaml +connection: + meshcore_host: "192.168.1.253" # blank = MeshCore off + meshcore_port: 5050 +``` -### Rate Limiting +Once connected, MeshCore gets its own **Connection**, **Routing**, **Scheduled Broadcasts**, **Contacts & Companion**, and **Danger Zones** pages in the dashboard β€” the same capabilities as Meshtastic, using MeshCore's own idioms (channels by name, contacts by pubkey). Messages are sized to fit whichever mesh they go out on. -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 +## The conversational bot + +DM MeshAI on either mesh and it answers with the LLM, using live mesh data, environmental feeds, and (optionally) a knowledge base. A few things it's careful about: + +- **Answers on the mesh you asked from.** A MeshCore DM gets a MeshCore reply; a Meshtastic DM gets a Meshtastic reply. Each mesh's "answer DMs" switch is independent. +- **Per-mesh chat memory.** It keeps a short rolling window of recent channel chatter *per mesh* (configurable retention, default 14 days) so "what's happening on the mesh?" reflects the mesh you're on. Ask about the other mesh by name to cross over. +- **Three separate lanes.** Shared channel context, your private DM history, and the curated knowledge base never bleed into each other. +- **LoRa-fit replies.** Responses are chunked to a per-mesh character budget with sentence-aware splitting and continuation prompts. + +### Commands + +Alongside natural-language questions, a set of `!` commands are available (all toggleable, so they can defer to another service like MeshMonitor): + +| Category | Commands | +|----------|----------| +| Mesh | `!health` Β· `!mesh` Β· `!status` Β· `!region [name]` Β· `!neighbors [node]` | +| Weather / RF | `!wx-alerts` Β· `!solar` Β· `!hf` Β· `!satpass` | +| Fire | `!fire` Β· `!hotspots` Β· `!ignitions` | +| Hazards | `!avalanche` Β· `!roads` / `!traffic` Β· `!rivers` / `!gauges` | +| Utility | `!help` Β· `!clear` | + +--- + +## Mesh intelligence (Meshtastic) + +MeshAI continuously aggregates mesh data and computes a **5-pillar health score**: + +| Pillar | Weight | Measures | +|--------|--------|----------| +| Infrastructure | 30% | Router/repeater uptime | +| Utilization | 25% | Channel busyness / RF congestion | +| Coverage | 20% | How many monitoring sources see each node | +| Behavior | 15% | Traffic patterns (noisy/misconfigured nodes) | +| Power | 10% | Battery health of infrastructure nodes | + +Infrastructure nodes are tracked individually (battery, offline alerts, coverage, neighbors, hardware); client nodes coming and going is normal and ignored. Regions are fully configurable β€” local names, aliases, cities, and radius β€” with no hardcoded geography. + +Data comes from one or more **Meshview** instances and a **MeshMonitor** instance, polled on a staggered schedule with built-in rate-limiting: ```yaml mesh_sources: - - name: "local-meshview" + - name: "meshview" type: meshview url: "http://192.168.1.100:8080" enabled: true - - name: "meshmonitor" type: meshmonitor url: "http://192.168.1.100:3333" @@ -311,285 +156,91 @@ mesh_sources: enabled: true ``` -## Knowledge Base (RAG) +--- -MeshAI uses a hybrid knowledge retrieval system with two backends: +## Environmental & hazard feeds -### Primary: RECON Qdrant Backend +MeshAI pulls real-time situational data and turns it into LoRa broadcasts and query answers. Sources include **NWS weather alerts**, **NIFC wildfire perimeters**, **NASA FIRMS satellite fire detections**, **USGS earthquakes**, **USGS stream gauges**, **road/traffic (511 / TomTom)**, **NOAA space weather**, and **avalanche/RF-propagation** feeds. -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: +Everything is switched on/off and tuned from the dashboard's **Data Feeds** page β€” enable a source, set thresholds and geography, and route its output per-mesh on the **Routing** page. Broadcast wording is tightened to fit a single LoRa packet without dropping the important details (e.g. affected towns on a weather alert). -- **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 base (RAG) + +Optional hybrid retrieval for survival, comms, medical, and technical Q&A. + +- **Primary** β€” queries a **Qdrant** hybrid store (dense `bge-m3` + sparse, Reciprocal Rank Fusion) over a large curated vector set, via a networked TEI embedding service. Nothing is copied locally. +- **Fallback** β€” a local **SQLite** knowledge base (FTS5 keyword + `bge-small-en-v1.5` vectors) if the vector service is unreachable. ```yaml knowledge: enabled: true - backend: auto # "qdrant", "sqlite", or "auto" (try qdrant, fall back) + backend: auto # qdrant | sqlite | auto 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 +The curated channel chatter your bot observes is used only as short-term *context* β€” it is never written into the knowledge base. -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 -``` +## LLM configuration ```yaml -knowledge: - enabled: true - backend: sqlite - db_path: /data/meshai_knowledge.db - top_k: 5 +llm: + backend: "google" # google | openai | anthropic + api_key: "your-api-key" + model: "gemini-2.5-flash" ``` -Requires `sqlite-vec` and `fastembed` for the SQLite backend. +Any OpenAI-compatible endpoint works for local models β€” point `base_url` at Ollama (`http://localhost:11434/v1`), LiteLLM (`http://localhost:4000/v1`), or Open WebUI. + +--- ## 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 β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + Meshtastic ────────▢│ │◀──────── MeshCore + (TCP / serial) β”‚ CompositeTransport β”‚ (companion / pyMC TCP) + β”‚ per-mesh routing + sizing β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β–Ό β–Ό β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Router β”‚ β”‚ Notification β”‚ β”‚ Mesh Data β”‚ + β”‚ LLM / cmd β”‚ β”‚ Pipeline β”‚ β”‚ Store + β”‚ + β”‚ DM gating β”‚ β”‚ weather Β· fire β”‚ β”‚ Health β”‚ + β”‚ per-mesh β”‚ β”‚ road Β· seismic β”‚ β”‚ Engine β”‚ + β”‚ context β”‚ β”‚ RF Β· mesh-healthβ”‚ β”‚ 5-pillar β”‚ + β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ β”‚ + β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ + β”‚ LLM β”‚ β”‚ Knowledge β”‚ β”‚ β”‚ Env / Central β”‚β—€β”€β”€β”€β”€β”€β”˜ + β”‚ backend β”‚ β”‚ Qdrant/FTS5 β”‚ β”‚ β”‚ feed adapters β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–Ό β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Responderβ”‚ ACK-paced, LoRa-fit, + β”‚ + Chunkerβ”‚ routed per mesh + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + Web Dashboard (React) ── configure everything ``` -## 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: - -```javascript -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. - -```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 +## Running as a service ```ini # /etc/systemd/system/meshai.service [Unit] -Description=MeshAI - Meshtastic Mesh Intelligence +Description=MeshAI After=network.target [Service] @@ -606,22 +257,34 @@ WantedBy=multi-user.target ```bash sudo systemctl daemon-reload -sudo systemctl enable meshai -sudo systemctl start meshai +sudo systemctl enable --now meshai ``` +Every deployment is designed to survive a reboot; the dashboard's connection settings drive both transports. + +--- + +## Playing nice with other services + +- **advBBS** β€” MeshAI coexists on the same Meshtastic node; BBS protocol traffic (sync, RAP, mail) is auto-filtered (`bot.filter_bbs_protocols: true`). +- **MeshMonitor** β€” MeshAI reads MeshMonitor's auto-responder patterns to avoid duplicate replies, and uses its API as a mesh-intelligence data source. +- **MeshCore companion** β€” MeshAI attaches as its own companion identity so it can share the radio without evicting other companion clients. + +--- + ## 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 +- [Meshtastic](https://meshtastic.org/) β€” the mesh platform it started on +- [MeshCore](https://meshcore.io/) & [pyMC](https://github.com/rightup/pyMC_core) β€” the second transport +- [MeshMonitor](https://github.com/Yeraze/meshmonitor) by Yeraze β€” monitoring integration & data source +- [advBBS](https://github.com/zvx-echo6/advbbs) β€” coexistence design +- [Qdrant](https://github.com/qdrant/qdrant) Β· [sqlite-vec](https://github.com/asg017/sqlite-vec) Β· [fastembed](https://github.com/qdrant/fastembed) β€” retrieval stack +- The LLM coding assistants that vibecoded most of this ## License -MIT License +MIT ## Author -K7ZVX - matt@echo6.co +K7ZVX β€” matt@echo6.co diff --git a/docs/images/activity.png b/docs/images/activity.png new file mode 100644 index 0000000..3b6bdfa Binary files /dev/null and b/docs/images/activity.png differ diff --git a/docs/images/dashboard.png b/docs/images/dashboard.png new file mode 100644 index 0000000..4e32878 Binary files /dev/null and b/docs/images/dashboard.png differ diff --git a/docs/images/datafeeds.png b/docs/images/datafeeds.png new file mode 100644 index 0000000..d2412a0 Binary files /dev/null and b/docs/images/datafeeds.png differ diff --git a/docs/images/mc-contacts.png b/docs/images/mc-contacts.png new file mode 100644 index 0000000..69a545c Binary files /dev/null and b/docs/images/mc-contacts.png differ diff --git a/docs/images/mt-routing.png b/docs/images/mt-routing.png new file mode 100644 index 0000000..a756e01 Binary files /dev/null and b/docs/images/mt-routing.png differ diff --git a/docs/images/nodes.png b/docs/images/nodes.png new file mode 100644 index 0000000..eff4ee1 Binary files /dev/null and b/docs/images/nodes.png differ diff --git a/work/README.md b/work/README.md index 336a15e..00595ba 100644 --- a/work/README.md +++ b/work/README.md @@ -1,34 +1,62 @@ # 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. +**An LLM-powered assistant for LoRa mesh networks β€” on Meshtastic *and* MeshCore, at the same time.** -## What It Does +MeshAI connects to your mesh, watches network health and the world around it in real time, answers questions over the air, and broadcasts the alerts that matter β€” weather, wildfire, road, seismic, RF, and mesh-health β€” with a full web dashboard to drive it all. -MeshAI runs on your Meshtastic node and provides: +> ### πŸ€– Built with AI ("vibecoded") +> In the interest of transparency: **MeshAI was vibecoded** β€” designed, built, debugged, and documented in close collaboration with LLM coding assistants. The architecture, most of the implementation, and this README were produced that way. It's a real, running project on a live mesh, but expect the pragmatic style, opinionated shortcuts, and occasional rough edges that come with the territory. Issues and PRs are welcome. -- **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 +![MeshAI dashboard](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/dashboard.png) -## Quick Start +--- + +## Highlights + +- **Dual-transport** β€” runs on **Meshtastic** and **MeshCore** simultaneously. Each mesh is first-class: independent connection, routing, and behavior, one shared brain. +- **Conversational bot** β€” DM it "how's the mesh?" or ask about weather, fires, roads, or a specific node, and get a data-driven answer over LoRa. The reply goes back on whichever mesh you asked from. +- **Per-mesh awareness** β€” it watches chat on each mesh separately (rolling short-term memory), so "what's happening on the mesh?" answers about *your* mesh. Private DMs stay private; curated knowledge stays separate. +- **Broadcast intelligence** β€” weather alerts, wildfire updates, road/traffic, seismic, RF/band conditions, and mesh-health notifications, formatted to fit LoRa and routed per-mesh, per-family. +- **Mesh health** β€” a 5-pillar health score with per-region breakdowns, infrastructure monitoring, coverage-gap analysis, and battery/solar tracking (Meshtastic). +- **Web dashboard** β€” a clean React UI to configure every transport, route every message type, watch a live activity feed, browse contacts, and tune the bot β€” no config-file spelunking required. +- **Knowledge base (RAG)** β€” optional hybrid retrieval over a large curated vector store for survival/comms/technical Q&A. +- **Multi-backend LLM** β€” Google Gemini, OpenAI, Anthropic, or any OpenAI-compatible local model (Ollama, LiteLLM, etc.). + +--- + +## The dashboard + +Everything is driven from the web UI, organized into **General**, **Meshtastic**, and **MeshCore** sections β€” each mesh mirrors the other so there's nothing to relearn when you add the second transport. + +**Live activity log** β€” every broadcast, on both meshes, with per-mesh badges and Sent/Skip status: + +![Activity Log](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/activity.png) + +**Per-family routing** β€” decide exactly where each message type goes: broadcast vs. DM, which channel, which recipients β€” independently for each mesh: + +![Routing](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/mt-routing.png) + +**MeshCore contacts & companion** β€” the live roster from your MeshCore companion node, with names, types, last-heard, position, and optional telemetry polling: + +![MeshCore Contacts](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/mc-contacts.png) + +**Data feeds** β€” turn environmental sources on/off and tune thresholds in one place: + +![Data Feeds](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/datafeeds.png) + +**Nodes & health** β€” per-node infrastructure detail: battery, utilization, coverage, neighbors, hardware: + +![Nodes & Health](https://raw.githubusercontent.com/zvx-echo6/meshai/main/docs/images/nodes.png) + +--- + +## 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 --config # interactive setup TUI meshai ``` @@ -38,272 +66,89 @@ 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 +# edit data/config.yaml, then: 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. - -```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 -``` - -## Environmental Feeds - -MeshAI integrates real-time environmental data for situational awareness beyond mesh network health. - -### USGS Earthquake Monitoring - -```yaml -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](https://earthquake.usgs.gov/fdsnws/event/1/). - -### NWS Weather Alerts - -```yaml -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](https://alerts.weather.gov/). - -### NOAA Space Weather - -```yaml -env: - noaa_space: - enabled: true -``` - -No API key required. Data from [NOAA SWPC](https://services.swpc.noaa.gov/). - -### NIFC Wildfire Perimeters - -```yaml -env: - nifc: - enabled: true - radius_km: 200 - center_lat: 43.6150 - center_lon: -116.2023 -``` - -No API key required. Data from [NIFC Open Data](https://data-nifc.opendata.arcgis.com/). - -### NASA FIRMS Satellite Fire Detection - -```yaml -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](https://firms.modaps.eosdis.nasa.gov/api/area/). 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 - -```yaml -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](https://developer.tomtom.com/). Free tier includes 2,500 requests/day. - -### 511 Road Conditions - -```yaml -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 - -```yaml -env: - usgs_water: - enabled: true - sites: ["13206000", "13202000"] # USGS site numbers -``` - -No API key required. Find sites at [USGS Water Services](https://waterservices.usgs.gov/). - -### AirNow Air Quality - -```yaml -env: - airnow: - enabled: true - api_key: "your-api-key" # Required - zipcode: "83702" -``` - -**API Key Required**: Register at [AirNow API](https://docs.airnowapi.org/). - -### Dashboard Configuration - -```yaml -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. +The dashboard comes up on `http://localhost:8080`. --- -## Data Sources +## Transports -MeshAI aggregates from multiple sources using staggered tick-based polling (one API call per 30-second tick): +MeshAI speaks two mesh protocols. **Meshtastic is always the base transport.** **MeshCore turns on automatically the moment you set a MeshCore host** β€” there's no separate on/off toggle to forget. -### Meshview +### Meshtastic -Unauthenticated REST API. Supports multiple instances. +Connect over TCP (recommended) or serial: -| 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) | +```yaml +connection: + type: "tcp" # or "serial" + tcp_host: "192.168.1.100" + tcp_port: 4403 + # serial_port: "/dev/ttyUSB0" +``` -### MeshMonitor +### MeshCore -Authenticated (Bearer token). Single instance. +MeshAI attaches to a MeshCore **companion** (the pyMC / MeshCore companion frame server) over TCP and acts as a node on the MeshCore mesh: -| 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 | +```yaml +connection: + meshcore_host: "192.168.1.253" # blank = MeshCore off + meshcore_port: 5050 +``` -### Rate Limiting +Once connected, MeshCore gets its own **Connection**, **Routing**, **Scheduled Broadcasts**, **Contacts & Companion**, and **Danger Zones** pages in the dashboard β€” the same capabilities as Meshtastic, using MeshCore's own idioms (channels by name, contacts by pubkey). Messages are sized to fit whichever mesh they go out on. -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 +## The conversational bot + +DM MeshAI on either mesh and it answers with the LLM, using live mesh data, environmental feeds, and (optionally) a knowledge base. A few things it's careful about: + +- **Answers on the mesh you asked from.** A MeshCore DM gets a MeshCore reply; a Meshtastic DM gets a Meshtastic reply. Each mesh's "answer DMs" switch is independent. +- **Per-mesh chat memory.** It keeps a short rolling window of recent channel chatter *per mesh* (configurable retention, default 14 days) so "what's happening on the mesh?" reflects the mesh you're on. Ask about the other mesh by name to cross over. +- **Three separate lanes.** Shared channel context, your private DM history, and the curated knowledge base never bleed into each other. +- **LoRa-fit replies.** Responses are chunked to a per-mesh character budget with sentence-aware splitting and continuation prompts. + +### Commands + +Alongside natural-language questions, a set of `!` commands are available (all toggleable, so they can defer to another service like MeshMonitor): + +| Category | Commands | +|----------|----------| +| Mesh | `!health` Β· `!mesh` Β· `!status` Β· `!region [name]` Β· `!neighbors [node]` | +| Weather / RF | `!wx-alerts` Β· `!solar` Β· `!hf` Β· `!satpass` | +| Fire | `!fire` Β· `!hotspots` Β· `!ignitions` | +| Hazards | `!avalanche` Β· `!roads` / `!traffic` Β· `!rivers` / `!gauges` | +| Utility | `!help` Β· `!clear` | + +--- + +## Mesh intelligence (Meshtastic) + +MeshAI continuously aggregates mesh data and computes a **5-pillar health score**: + +| Pillar | Weight | Measures | +|--------|--------|----------| +| Infrastructure | 30% | Router/repeater uptime | +| Utilization | 25% | Channel busyness / RF congestion | +| Coverage | 20% | How many monitoring sources see each node | +| Behavior | 15% | Traffic patterns (noisy/misconfigured nodes) | +| Power | 10% | Battery health of infrastructure nodes | + +Infrastructure nodes are tracked individually (battery, offline alerts, coverage, neighbors, hardware); client nodes coming and going is normal and ignored. Regions are fully configurable β€” local names, aliases, cities, and radius β€” with no hardcoded geography. + +Data comes from one or more **Meshview** instances and a **MeshMonitor** instance, polled on a staggered schedule with built-in rate-limiting: ```yaml mesh_sources: - - name: "local-meshview" + - name: "meshview" type: meshview url: "http://192.168.1.100:8080" enabled: true - - name: "meshmonitor" type: meshmonitor url: "http://192.168.1.100:3333" @@ -311,285 +156,91 @@ mesh_sources: enabled: true ``` -## Knowledge Base (RAG) +--- -MeshAI uses a hybrid knowledge retrieval system with two backends: +## Environmental & hazard feeds -### Primary: RECON Qdrant Backend +MeshAI pulls real-time situational data and turns it into LoRa broadcasts and query answers. Sources include **NWS weather alerts**, **NIFC wildfire perimeters**, **NASA FIRMS satellite fire detections**, **USGS earthquakes**, **USGS stream gauges**, **road/traffic (511 / TomTom)**, **NOAA space weather**, and **avalanche/RF-propagation** feeds. -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: +Everything is switched on/off and tuned from the dashboard's **Data Feeds** page β€” enable a source, set thresholds and geography, and route its output per-mesh on the **Routing** page. Broadcast wording is tightened to fit a single LoRa packet without dropping the important details (e.g. affected towns on a weather alert). -- **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 base (RAG) + +Optional hybrid retrieval for survival, comms, medical, and technical Q&A. + +- **Primary** β€” queries a **Qdrant** hybrid store (dense `bge-m3` + sparse, Reciprocal Rank Fusion) over a large curated vector set, via a networked TEI embedding service. Nothing is copied locally. +- **Fallback** β€” a local **SQLite** knowledge base (FTS5 keyword + `bge-small-en-v1.5` vectors) if the vector service is unreachable. ```yaml knowledge: enabled: true - backend: auto # "qdrant", "sqlite", or "auto" (try qdrant, fall back) + backend: auto # qdrant | sqlite | auto 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 +The curated channel chatter your bot observes is used only as short-term *context* β€” it is never written into the knowledge base. -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 -``` +## LLM configuration ```yaml -knowledge: - enabled: true - backend: sqlite - db_path: /data/meshai_knowledge.db - top_k: 5 +llm: + backend: "google" # google | openai | anthropic + api_key: "your-api-key" + model: "gemini-2.5-flash" ``` -Requires `sqlite-vec` and `fastembed` for the SQLite backend. +Any OpenAI-compatible endpoint works for local models β€” point `base_url` at Ollama (`http://localhost:11434/v1`), LiteLLM (`http://localhost:4000/v1`), or Open WebUI. + +--- ## 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 β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + Meshtastic ────────▢│ │◀──────── MeshCore + (TCP / serial) β”‚ CompositeTransport β”‚ (companion / pyMC TCP) + β”‚ per-mesh routing + sizing β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β–Ό β–Ό β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Router β”‚ β”‚ Notification β”‚ β”‚ Mesh Data β”‚ + β”‚ LLM / cmd β”‚ β”‚ Pipeline β”‚ β”‚ Store + β”‚ + β”‚ DM gating β”‚ β”‚ weather Β· fire β”‚ β”‚ Health β”‚ + β”‚ per-mesh β”‚ β”‚ road Β· seismic β”‚ β”‚ Engine β”‚ + β”‚ context β”‚ β”‚ RF Β· mesh-healthβ”‚ β”‚ 5-pillar β”‚ + β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ β”‚ + β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ + β”‚ LLM β”‚ β”‚ Knowledge β”‚ β”‚ β”‚ Env / Central β”‚β—€β”€β”€β”€β”€β”€β”˜ + β”‚ backend β”‚ β”‚ Qdrant/FTS5 β”‚ β”‚ β”‚ feed adapters β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–Ό β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Responderβ”‚ ACK-paced, LoRa-fit, + β”‚ + Chunkerβ”‚ routed per mesh + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + Web Dashboard (React) ── configure everything ``` -## 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: - -```javascript -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. - -```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 +## Running as a service ```ini # /etc/systemd/system/meshai.service [Unit] -Description=MeshAI - Meshtastic Mesh Intelligence +Description=MeshAI After=network.target [Service] @@ -606,22 +257,34 @@ WantedBy=multi-user.target ```bash sudo systemctl daemon-reload -sudo systemctl enable meshai -sudo systemctl start meshai +sudo systemctl enable --now meshai ``` +Every deployment is designed to survive a reboot; the dashboard's connection settings drive both transports. + +--- + +## Playing nice with other services + +- **advBBS** β€” MeshAI coexists on the same Meshtastic node; BBS protocol traffic (sync, RAP, mail) is auto-filtered (`bot.filter_bbs_protocols: true`). +- **MeshMonitor** β€” MeshAI reads MeshMonitor's auto-responder patterns to avoid duplicate replies, and uses its API as a mesh-intelligence data source. +- **MeshCore companion** β€” MeshAI attaches as its own companion identity so it can share the radio without evicting other companion clients. + +--- + ## 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 +- [Meshtastic](https://meshtastic.org/) β€” the mesh platform it started on +- [MeshCore](https://meshcore.io/) & [pyMC](https://github.com/rightup/pyMC_core) β€” the second transport +- [MeshMonitor](https://github.com/Yeraze/meshmonitor) by Yeraze β€” monitoring integration & data source +- [advBBS](https://github.com/zvx-echo6/advbbs) β€” coexistence design +- [Qdrant](https://github.com/qdrant/qdrant) Β· [sqlite-vec](https://github.com/asg017/sqlite-vec) Β· [fastembed](https://github.com/qdrant/fastembed) β€” retrieval stack +- The LLM coding assistants that vibecoded most of this ## License -MIT License +MIT ## Author -K7ZVX - matt@echo6.co +K7ZVX β€” matt@echo6.co