diff --git a/README.md b/README.md index 336a15e..ee08d93 100644 --- a/README.md +++ b/README.md @@ -1,353 +1,358 @@ +
+ # 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. +**LLM-powered mesh intelligence and situational-awareness assistant for Meshtastic networks.** -## What It Does +MeshAI joins your mesh as a physical node, continuously scores network health, watches a stack of real-time environmental feeds (weather, wildfire, earthquakes, river gauges, space weather, road conditions, avalanche), and answers questions over LoRa — backed by a full web dashboard and a configurable alert pipeline. -MeshAI runs on your Meshtastic node and provides: +`Python 3.10+` · `FastAPI` · `React + Vite` · `Meshtastic` · `MIT License` · `v0.1.0` -- **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 — mesh health gauge, active alerts, node KPIs, mesh sources, and RF propagation](screenshots/dashboard.jpg) + +> A live MeshAI deployment: a 75/100 mesh-health score, 294 nodes online, 16/16 infrastructure routers up, and seven aggregated data sources across four configured regions. + +> [!IMPORTANT] +> **This is a vibe-coded project.** It was designed and built hands-on in close, iterative collaboration with AI coding tools — a real, deliberately-built solo project, not a team effort with formal QA behind it. That means it hasn't been independently security-audited, test coverage is uneven, and internal APIs can still change between commits. Read the source before you run it, don't deploy it anywhere sensitive, and use it at your own risk. Issues and PRs are welcome. + +## Table of Contents + +- [What MeshAI Does](#what-meshai-does) +- [The Dashboard](#the-dashboard) +- [Quick Start](#quick-start) +- [Mesh Commands](#mesh-commands) +- [Mesh Intelligence](#mesh-intelligence) +- [Environmental Feeds](#environmental-feeds) +- [Central Bus (Shared Feeds)](#central-bus-shared-feeds) +- [Notifications & Alerting](#notifications--alerting) +- [Knowledge Base (RAG)](#knowledge-base-rag) +- [Data Sources](#data-sources) +- [Dashboard API Reference](#dashboard-api-reference) +- [Configuration](#configuration) +- [LLM Backends](#llm-backends) +- [Deployment](#deployment) +- [Running Alongside Other Services](#running-alongside-other-services) +- [Architecture](#architecture) +- [Acknowledgments](#acknowledgments) + +--- + +## What MeshAI Does + +MeshAI runs as a single service attached to a Meshtastic node (TCP or serial) and combines four capabilities: + +**1. Mesh intelligence.** It polls one or more [Meshview](#meshview) and [MeshMonitor](#meshmonitor) instances on a staggered schedule, builds a unified picture of every node, and computes a five-pillar health score (infrastructure, utilization, coverage, behavior, power). Ask *"how's the mesh?"* over LoRa and get a data-driven answer. + +**2. Environmental awareness.** A stack of feed adapters pulls weather alerts, wildfire perimeters and satellite hotspots, earthquakes, river/stream gauges, space-weather and HF-propagation conditions, avalanche advisories, and road/work-zone closures — all geofenced to your mesh's footprint. + +**3. Alerting & notifications.** A notification pipeline turns mesh and environmental conditions into broadcasts and DMs, with cold-start suppression, per-category toggles, severity gating, scaling cooldowns to prevent spam, and scheduled digests. Delivery renderers cover mesh, email (SMTP), and webhooks. + +**4. Conversational LLM + knowledge.** General chat, plus optional retrieval-augmented answers from a vector knowledge base, with a self-contained local SQLite fallback. Backends: Google Gemini, OpenAI, Anthropic Claude, or any OpenAI-compatible local model. + +Everything is configurable from an interactive terminal configurator **or** the web dashboard — no hardcoded geography, thresholds, or message templates. + +--- + +## The Dashboard + +The bundled React dashboard (default `http://:8080/`) is the control center. Ten pages cover live monitoring and full configuration, with WebSocket push for live updates (health, alerts, environment). + +### Mesh topology & geography + +The **Mesh** page renders the whole network two ways. The topology view (ECharts) lays out every node by connectivity, sizes infrastructure nodes larger, and colors edges by link quality (SNR). A geographic view (Leaflet) places the same nodes and links on a real map. + +![Mesh topology graph — infrastructure and client nodes with SNR-colored links](screenshots/topology-chart.jpg) + +> The live mesh topology: large filled circles are infrastructure (routers/repeaters), small rings are clients, and edges are colored by signal quality from green (excellent) to red (poor). + +Click any node for a detail panel (role, battery, neighbors, coverage, feeder gateways, hardware). A searchable, filterable node table sits below the graph. + +### Deep configurability + +Beyond the basic **Config** page (bot, connection, response, history, memory, LLM, dashboard), the **Adapter Config** page exposes per-adapter tunables — thresholds, freshness windows, curation lists, and sentence templates — for every feed. Each adapter card has an *LLM context* toggle controlling whether its data is injected into the system prompt on DMs. + +![Adapter Config — 84 settings across 22 adapters, each with an LLM-context toggle](screenshots/adapter-config.jpg) + +### All ten pages + +| Page | Purpose | +|------|---------| +| **Dashboard** | Mesh health gauge, pillar scores, active alerts, node KPIs, source status | +| **Mesh** | Topology + geographic views, node table, per-node detail | +| **Environment** | Enable/configure every feed; switch feeds between `native` and `central` source | +| **Config** | Core settings: bot, connection, response, history, memory, context, LLM, dashboard | +| **Alerts** | Active alerts, filterable alert history, mesh subscriptions | +| **Notifications** | Notification rules, master toggles, scheduled digests, delivery (mesh/email/webhook) | +| **Reference** | In-app documentation (commands, broadcast types, fire tracker, CODE rule) | +| **Adapter Config** | Per-adapter thresholds, templates, and LLM-context gating | +| **Gauge Sites** | River/stream gauge editor with flood thresholds + USGS site lookup | +| **Town Anchors** | Named geographic anchors used to describe alert locations in plain language | + +--- ## Quick Start +### From source + ```bash -# Clone git clone https://github.com/zvx-echo6/meshai.git cd meshai -# Install pip install -e . -# Configure (interactive TUI) -meshai --config - -# Run -meshai +meshai --config # interactive terminal configurator +meshai # run ``` -Or with Docker: +### 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 +# edit data/config.yaml, then: docker compose up -d ``` -## Commands +> **Deploy note (Docker):** the Python source and dashboard bundle are baked into the image at build time — the repo is **not** bind-mounted. After any change (Python *or* frontend), rebuild: `docker compose build meshai && docker compose up -d`. A bare `restart` re-execs the old image. + +The only persistent volume is `meshai_data:/data` (SQLite databases + config). + +--- + +## Mesh Commands + +Send these on the mesh (default prefix `!`). Any command can be disabled in config if another service (e.g. MeshMonitor) already handles it. + +### Mesh intelligence + +| Command | Aliases | Description | +|---------|---------|-------------| +| `!health` | `!mesh`, `!status` | Compact mesh health overview with status dots | +| `!region` | — | List all regions with health status | +| `!region [name]` | — | Detailed breakdown for one region | +| `!neighbors [node]` | — | Top infrastructure neighbors with signal quality | + +### Subscriptions | 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 | +| `!sub daily 6pm` | Subscribe to a daily health report | +| `!sub weekly 8am sun` | Subscribe to a weekly digest | +| `!sub alerts` | Subscribe to instant alert DMs | | `!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. +### Environmental + +| Command | Aliases | Description | +|---------|---------|-------------| +| `!alerts` | `!wx-alerts` | Active NWS weather alerts for the mesh area | +| `!fire` | — | Active wildfires (NIFC) near the mesh | +| `!hotspots [--new]` | `!satellite`, `!ignitions` | NASA FIRMS satellite fire detections (`--new` = unmatched to known fires) | +| `!avy` | `!avalanche` | Avalanche advisories (off-season aware) | +| `!streams` | — | USGS river/stream gauge readings | +| `!roads` | — | Road conditions / closures (511) | +| `!solar` | `!hf` | Space weather + HF band conditions | + +### Utility + +| Command | Description | +|---------|-------------| +| `!weather` | Weather for the sender's location | +| `!ping` | Liveness check | +| `!status` | Bot/system status | +| `!clear` / `!reset` | Clear your conversation history | +| `!help` / `!help [cmd]` | List commands / detailed help | + +Custom static-response commands can be added in config. + +### Conversational queries + +You don't need commands — ask naturally over LoRa and the LLM answers from live mesh data: + +- *"how's the mesh?"* → health overview with the top issues +- *"tell me about North Router"* → full node detail with neighbors, coverage, feeders +- *"where do we need more coverage?"* → named gaps with specific nodes +- *"how far is North Router from Summit Router?"* → GPS distance calculation +- *"which nodes only reach one gateway?"* → named nodes with their gateway + +--- ## Mesh Intelligence -MeshAI continuously polls mesh data sources and computes a 5-pillar health score: +MeshAI computes a weighted five-pillar health score on every refresh: -| Pillar | Weight | What It Measures | -|--------|--------|------------------| -| Infrastructure | 30% | Router uptime — how many infra nodes are online | +| Pillar | Weight | Measures | +|--------|:-----:|----------| +| Infrastructure | 30% | Router/repeater 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 | +| Behavior | 15% | Traffic patterns — noisy or misconfigured nodes | +| Power | 10% | Battery health (infrastructure nodes only) | -### Health Display - -`!health` shows a compact overview with personality: +**Health display** — `!health` returns a compact, personality-driven summary: ``` 📡 Mesh 🟢 healthy 🏗️ 15/16 routers up -❌ Down: TVM Tablerock Relay +❌ Down: North Ridge Relay 📶 152 full coverage, 94 on thin ice -🔥 Hayden Peak Router at 21% util +🔥 Summit Router at 21% util 🔋 All infra powered ✅ 🌡️ 29-34°C across 2 sensors -Treasure Valley 🟢 | Magic Valley 🟢 +North Valley 🟢 | South Valley 🟢 ``` -Status dots: 🔵 perfect (100) · 🟢 healthy (75+) · 🟠 warning (50+) · 🔴 critical (<50) +Status dots: 🔵 perfect (100) · 🟢 healthy (75+) · 🟠 warning (50+) · 🔴 critical (<50). -### Monitoring Rules +**Monitoring rules.** Infrastructure nodes (routers, repeaters) are tracked individually with full detail — battery, offline alerts, coverage, neighbors, hardware. Client nodes going offline is normal and is not tracked. Channel utilization and environmental sensors are monitored for all nodes. -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. +**Geographic regions** are fully configurable — local names, descriptions, aliases, and cities, all editable from the configurator. No geography is hardcoded. ```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 + - name: "West Region" + local_name: "The Valley" + description: "Primary coverage area" + aliases: ["west region", "the valley"] + cities: ["Springfield", "Riverton", "Fairview"] + lat: 40.0 + lon: -111.0 radius_km: 80 + critical_nodes: ["ROUTER-A", "ROUTER-B"] # priority formatting when offline + alert_channel: 0 # broadcast channel (-1 = disabled) ``` -## 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. - --- -## Data Sources +## Environmental Feeds -MeshAI aggregates from multiple sources using staggered tick-based polling (one API call per 30-second tick): +Each feed is an independent adapter — enable only what you need. Most require no API key; the few that do are noted. Adapters geofence their data to your mesh footprint and feed both the `!commands`, the dashboard **Environment** page, and the alert pipeline. -### Meshview +| Feed | Source | API key | Provides | +|------|--------|:-------:|----------| +| **NWS weather alerts** | National Weather Service | — | Watches/warnings by zone, severity-filtered | +| **USGS earthquakes** | USGS FDSN | — | Quakes by magnitude floor + radius (regional/global) | +| **NIFC wildfires** | NIFC Open Data | — | Active fire perimeters, acreage, containment | +| **NASA FIRMS hotspots** | FIRMS (VIIRS/MODIS) | ✓ MAP_KEY | Satellite heat detections, cross-referenced to NIFC for new ignitions | +| **NOAA space weather** | NOAA SWPC | — | Solar/geomagnetic conditions, HF band ratings | +| **RF propagation (ducting)** | Computed | — | Tropospheric ducting from atmospheric refractivity gradient | +| **Avalanche** | Forecast centers | — | Danger-level advisories, season-aware | +| **USGS water / gauges** | USGS Water Services | — | River/stream stage + flood-threshold tracking | +| **Road conditions (511)** | State 511 / WZDx | varies | Closures, incidents, work zones | +| **Traffic** | TomTom | ✓ | Traffic incidents along configured corridors | -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 +Example geofenced configuration: ```yaml -mesh_sources: - - name: "local-meshview" - type: meshview - url: "http://192.168.1.100:8080" +environmental: + enabled: true + nws_zones: ["XXZ001", "XXZ002"] # your NWS public-forecast zone IDs + nws: enabled: true - - - name: "meshmonitor" - type: meshmonitor - url: "http://192.168.1.100:3333" - api_token: "your-bearer-token" + severity_min: "Severe" # Extreme | Severe | Moderate | Minor + usgs_quake: enabled: true + regional_mag_floor: 2.5 + regional_radius_mi: 300 + firms: + enabled: true + map_key: "your-map-key" # https://firms.modaps.eosdis.nasa.gov/api/area/ + source: "VIIRS_SNPP_NRT" # VIIRS_SNPP_NRT | VIIRS_NOAA20_NRT | MODIS_NRT + day_range: 1 + usgs: + enabled: true + sites: ["XXXXXXXX", "XXXXXXXX"] # USGS gauge site IDs ``` +--- + +## Central Bus (Shared Feeds) + +Every environmental adapter has a `feed_source` of either **`native`** (this node polls the upstream API itself) or **`central`** (it consumes already-normalized events from a shared **Central** bus over NATS JetStream). + +This lets a fleet of MeshAI nodes share one set of upstream pulls instead of each node hammering NWS/USGS/FIRMS independently. With every adapter defaulting to `native`, the Central consumer starts as a no-op (zero subscriptions, no NATS dependency at boot); flip individual adapters to `central` from the **Environment** page to opt in. + +```yaml +environmental: + central: + enabled: true + url: "nats://:4222" + durable: "meshai-central" + region: "" + nws: + feed_source: "central" # consume NWS from the bus instead of polling +``` + +--- + +## Notifications & Alerting + +Mesh and environmental conditions flow through an event pipeline (cold-start grace → grouping → inhibition → category/severity filtering → scheduling → rendering → dispatch). Configure it all on the **Notifications** page. + +### Alert conditions + +Each condition is individually toggleable, with thresholds set in config or Adapter Config: + +| Pillar | Condition | Default | +|--------|-----------|---------| +| Infrastructure | Router goes offline / recovers / new router appears | — | +| Infrastructure | Critical node offline (priority formatting) | per `critical_nodes` | +| Power | Battery warning / critical / emergency | <50% / <25% / <10% | +| Power | 7-day declining battery trend | >10% drop w/ rate | +| Power | USB→battery (power outage) | — | +| Power | Solar not charging during daylight | — | +| Utilization | Sustained high utilization | >20% for 6h | +| Utilization | Packet flood | >500 pkts/24h | +| Coverage | Infra drops to a 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 | +| Environmental | Weather, quake, fire, ducting and other feed triggers | per adapter | + +### Scaling cooldown + +Alerts don't spam. When a condition fires, follow-ups stretch out — immediately, then **+12h**, **+24h**, **+48h**, then stop until it resolves. When the condition clears, one recovery notification fires and the tracker resets. + +### Delivery + +- **Mesh broadcast** — configurable channel index for mesh-wide visibility. +- **DM to subscribers** — users who ran `!sub alerts`, scoped to their region. +- **Email (SMTP)** and **webhook** renderers for off-mesh delivery. + +### Scheduled broadcasts + +Beyond reactive alerts, MeshAI ships scheduled digests — e.g. a 3×/day HF band-conditions summary and a twice-daily wildfire digest (LLM-summarized active fires + recent growth), each with its own schedule and byte budget. Master toggles on the Notifications page enable/disable whole categories (Mesh Health, Weather, Fire, RF Propagation, …) per region and channel. + +--- + ## Knowledge Base (RAG) -MeshAI uses a hybrid knowledge retrieval system with two backends: +MeshAI answers technical questions from a hybrid retrieval system with two interchangeable 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. +**Optional — Qdrant hybrid.** If you run a Qdrant instance with a companion text-embeddings service, MeshAI can query it over the network for hybrid dense + sparse retrieval (Reciprocal Rank Fusion). Point it at your own hosts and collection — nothing is bundled or copied. ```yaml knowledge: enabled: true - backend: auto # "qdrant", "sqlite", or "auto" (try qdrant, fall back) - qdrant_host: "192.168.1.150" + backend: auto # qdrant | sqlite | auto (try qdrant, fall back) + qdrant_host: "" qdrant_port: 6333 - qdrant_collection: "recon_knowledge_hybrid" - tei_host: "192.168.1.150" + qdrant_collection: "" + tei_host: "" 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 -``` +**Fallback — local SQLite.** With no external services, MeshAI uses a self-contained on-device SQLite KB (FTS5 keyword search + `bge-small-en-v1.5` embeddings, 384-dim). Requires `sqlite-vec` and `fastembed`. Build it from a Meshtastic ZIM export or your own documents. ```yaml knowledge: @@ -357,234 +362,168 @@ knowledge: top_k: 5 ``` -Requires `sqlite-vec` and `fastembed` for the SQLite backend. +--- -## Architecture +## Data Sources +MeshAI aggregates mesh data from multiple sources using staggered, tick-based polling (one API call per 30-second tick) with built-in rate-limit protection: HTTP 429 backoff honoring `Retry-After`, exponential backoff on consecutive errors, slow-response warnings, and an optional polite mode for shared instances. + +### Meshview + +Unauthenticated REST. Multiple instances supported. + +| Endpoint | Interval | Data | +|----------|:--------:|------| +| `/api/packets` | 30s | Near real-time packet feed | +| `/api/nodes` | 2m | Node list + metadata | +| `/api/stats` | 3m | Traffic statistics | +| `/api/edges` | 3m | Node-to-node connections | +| `/api/traceroutes` | 5m | Route data | +| `/api/packets_seen` | 10m | Per-gateway RSSI/SNR (sampled) | + +### MeshMonitor + +Authenticated (Bearer token). Single instance. + +| Endpoint | Interval | Data | +|----------|:--------:|------| +| `/api/v1/packets` | 60s | Packet feed | +| `/api/v1/nodes` | 2m | Nodes w/ battery, utilization, hardware | +| `/api/v1/telemetry` | 2m | Environmental sensors, device metrics | +| `/api/v1/traceroutes` | 5m | Route data | +| `/api/v1/channels` | 5m | Channel configuration | +| `/api/v1/network` | 5m | Network statistics | +| `/api/v1/solar` | 10m | Solar estimates | + +```yaml +mesh_sources: + - name: "local-meshview" + type: meshview + url: "http://:8080" + enabled: true + - name: "meshmonitor" + type: meshmonitor + url: "http://:3333" + api_token: "your-bearer-token" + enabled: true ``` -┌──────────────────────────────────────────────────────────────────────┐ -│ 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 │ - └─────────┘ └─────────┘ -``` + +An MQTT source is also supported for direct packet ingestion. + +--- ## Dashboard API Reference -The dashboard exposes a REST API (default port 8080): +The dashboard serves a REST API under `/api` (default port `8080`). -### Core Endpoints +### Mesh & system | 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 | +|----------|:------:|-------------| +| `/api/health` | GET | Service health check | +| `/api/status` | GET | Full system status + health scores | +| `/api/sources` | GET | Mesh source status | +| `/api/nodes` · `/api/nodes/{n}` | GET | Node list / single node detail | +| `/api/edges` | GET | Node-to-node edges | +| `/api/regions` | GET | Configured regions + scores | +| `/api/restart` | POST | Restart the service | -### Environmental Data +### Environment | 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 | +|----------|:------:|-------------| +| `/api/env/status` | GET | Feed status summary | +| `/api/env/active` | GET | Active environmental events | +| `/api/env/swpc` · `/api/env/propagation` | GET | Space weather / HF propagation | +| `/api/env/ducting` | GET | Tropospheric ducting status | +| `/api/env/fires` · `/api/env/hotspots` | GET | Wildfires / FIRMS hotspots | +| `/api/env/avalanche` | GET | Avalanche advisories | +| `/api/env/streams` · `/api/env/usgs/lookup/{site_id}` | GET | Gauges / USGS site lookup | +| `/api/env/roads` · `/api/env/traffic` | GET | Road conditions / traffic | -### Alerts +### Alerts & config | 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/alerts/history` | GET | Alert history (`?severity=&source=&limit=&offset=`) | | `/api/subscriptions` | GET | Alert subscriptions | +| `/api/config` · `/api/config/{section}` | GET/PUT | Core configuration | +| `/api/adapter-config[/{adapter}[/{key}]]` | GET/PUT | Per-adapter settings (+ `/reset`) | +| `/api/gauge-sites` · `/api/town-anchors` | GET/POST/PUT/DELETE | Editors | +| `/api/rules` · `/api/categories` · `/api/channels` | GET/POST | Notification rules & helpers | ### WebSocket -Connect to `/ws` for real-time updates: +Connect to **`/ws/live`** for push 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' +const ws = new WebSocket('ws://:8080/ws/live'); +ws.onmessage = (e) => { + const msg = JSON.parse(e.data); + // msg.type: 'health_update' | 'alert_fired' | 'env_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. +## Configuration + +Three ways to configure, all backed by the same store: + +1. **Interactive configurator** — `meshai --config` launches a Rich-powered terminal UI covering every section. +2. **Web dashboard** — the **Config**, **Environment**, **Notifications**, and **Adapter Config** pages edit the same settings live. Most changes apply on the next handler tick; settings that need a restart surface a banner. +3. **YAML** — hand-edit `config.yaml` (see `config.example.yaml` for the fully documented template). + +Message chunking keeps responses LoRa-friendly: ```yaml response: - max_length: 200 # Max chars per message - max_messages: 3 # Messages before continuation prompt + max_length: 200 # max chars per message + max_messages: 3 # messages before a continuation prompt ``` -## Alerting +Long responses use sentence-aware splitting; command output packs multiple lines per message to minimize airtime. -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 +## LLM Backends ```yaml llm: - backend: "google" # openai, anthropic, google + backend: "google" # google | openai | anthropic api_key: "your-api-key" - model: "gemini-2.0-flash" + model: "gemini-2.5-flash" ``` -### Local LLMs +Any OpenAI-compatible endpoint works for local models — point `base_url` at it: -MeshAI works with any OpenAI-compatible API: +- **LiteLLM** — `http://localhost:4000/v1` +- **Ollama** — `http://localhost:11434/v1` +- **Open WebUI** — `http://localhost:3000/api` -- **LiteLLM**: `base_url: "http://localhost:4000/v1"` -- **Open WebUI**: `base_url: "http://localhost:3000/api"` -- **Ollama**: `base_url: "http://localhost:11434/v1"` +Optional conversation memory keeps a rolling window and auto-summarizes older turns. -## Docker +--- -### TCP Connection (recommended) +## Deployment + +### Connection ```yaml connection: - type: "tcp" - tcp_host: "192.168.1.100" + type: "tcp" # recommended + tcp_host: "" 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 +### systemd ```ini # /etc/systemd/system/meshai.service @@ -606,17 +545,84 @@ WantedBy=multi-user.target ```bash sudo systemctl daemon-reload -sudo systemctl enable meshai -sudo systemctl start meshai +sudo systemctl enable --now meshai ``` +### Docker 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 filtered automatically. + +```yaml +bot: + filter_bbs_protocols: true +``` + +**MeshMonitor.** MeshAI integrates with [MeshMonitor](https://github.com/Yeraze/meshmonitor) at two levels: it pulls MeshMonitor's auto-responder patterns to avoid duplicate replies, and uses its API as a data source (battery, telemetry, traceroutes, solar). + +```yaml +meshmonitor: + enabled: true + url: "http://:8080" + inject_into_prompt: true + refresh_interval: 300 +``` + +--- + +## Architecture + +``` +┌──────────────────────────────────────────────────────────────────────┐ +│ MeshAI │ +├──────────────────────────────────────────────────────────────────────┤ +│ DATA SOURCES INTELLIGENCE DELIVERY │ +│ ┌────────────┐ ┌──────────────┐ ┌────────────┐ │ +│ │ Meshview ×N│────┐ │ Health Engine│────────▶│ Reporter │ │ +│ │ MeshMonitor│ │ │ 5-pillar │ │ LoRa-fit │ │ +│ │ MQTT │ ▼ │ scoring │ └─────┬──────┘ │ +│ └────────────┘ ┌───────┴──┐ │ │ │ +│ │ Data │ │ ┌─────▼──────┐ │ +│ │ Store │ │ │ Router │ │ +│ │ (SQLite) │ │ │ scope/dist │ │ +│ └────┬─────┘ │ └─────┬──────┘ │ +│ │ ┌─────▼──────┐ │ │ +│ ENV FEEDS ┌────▼────┐ │ LLM │ ┌────▼────┐ │ +│ NWS/USGS/NIFC │ Feeder │ │ Backend │ │ Chunker │ │ +│ FIRMS/SWPC/... │ Sampling│ └────────────┘ └────┬────┘ │ +│ │ └─────────┘ │ │ +│ ▼ │ │ +│ ┌─────────────┐ ┌──────────────┐ ┌────────────┐ │ │ +│ │ Central bus │ │ Notification │ │ Alert │ │ │ +│ │ (NATS, opt) │ │ Pipeline │ │ Engine │ │ │ +│ └─────────────┘ └──────┬───────┘ └─────┬──────┘ │ │ +│ │ │ │ │ +│ KNOWLEDGE └────────┬────────┴──────────┘ │ +│ ┌─────────────┐ ┌────────▼─────────┐ ┌───────────────┐ │ +│ │ Qdrant (opt)│ │ Responder │ │ Dashboard │ │ +│ │ hybrid RAG │ │ ACK-paced DM + │ │ REST + /ws/live│ │ +│ │ SQLite (fb) │ │ channel broadcast│ │ React UI │ │ +│ └─────────────┘ └──────────────────┘ └───────────────┘ │ +└──────────────────────────────────────────────────────────────────────┘ +``` + +--- + ## Acknowledgments - [Meshtastic](https://meshtastic.org/) — the mesh networking platform -- [MeshMonitor](https://github.com/Yeraze/meshmonitor) by Yeraze — monitoring integration and data source +- [MeshMonitor](https://github.com/Yeraze/meshmonitor) by Yeraze — monitoring integration & 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 +- [ECharts](https://echarts.apache.org/), [Leaflet](https://leafletjs.com/), [Recharts](https://recharts.org/) — dashboard visualizations ## License @@ -624,4 +630,4 @@ MIT License ## Author -K7ZVX - matt@echo6.co +**K7ZVX** — matt@echo6.co diff --git a/config.example.yaml b/config.example.yaml index 92de160..4dd6fa0 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -1,8 +1,12 @@ # MeshAI Configuration # LLM-powered Meshtastic assistant # -# Copy this to config.yaml and customize as needed +# Copy this to config.yaml and customize as needed. # For Docker: mount as /data/config.yaml +# +# Placeholders in and empty strings ("") are meant to be +# filled in with your own values. Secrets are best supplied via environment +# variables (e.g. ${LLM_API_KEY}) rather than committed to this file. # === BOT IDENTITY === bot: @@ -15,7 +19,7 @@ bot: connection: type: tcp # serial | tcp serial_port: /dev/ttyUSB0 # For serial connection - tcp_host: localhost # For TCP connection (meshtasticd) + tcp_host: localhost # For TCP connection (meshtasticd / node IP) tcp_port: 4403 # === RESPONSE BEHAVIOR === @@ -52,15 +56,17 @@ context: llm: backend: openai # openai | anthropic | google api_key: "" # API key (or use LLM_API_KEY env var) - base_url: https://api.openai.com/v1 # API base URL - model: gpt-4o-mini # Model name + base_url: https://api.openai.com/v1 # API base URL (point at a local + # OpenAI-compatible server if desired) + model: gpt-4o-mini # Model name (e.g. gpt-4o-mini, + # claude-sonnet, gemini-2.5-flash) timeout: 30 # Request timeout (seconds) system_prompt: >- You are a helpful assistant on a Meshtastic mesh network. Keep responses very brief - 1-2 short sentences, under 300 characters. Only give longer answers if the user explicitly asks for detail or explanation. Be concise but friendly. No markdown formatting. - google_grounding: false # Enable Google Search grounding (Gemini only, $35/1k queries) + google_grounding: false # Enable Google Search grounding (Gemini only, billed per query) # === WEATHER === weather: @@ -71,11 +77,14 @@ weather: # === MESHMONITOR INTEGRATION === meshmonitor: enabled: false # Enable MeshMonitor trigger sync - url: "" # MeshMonitor web UI URL (e.g. http://192.168.1.100:3333) + url: "" # MeshMonitor web UI URL (e.g. http://:3333) inject_into_prompt: true # Include trigger list in LLM prompt refresh_interval: 300 # Seconds between trigger refreshes # === KNOWLEDGE BASE (RAG) === +# Optional. With no external services, MeshAI uses a self-contained +# on-device SQLite knowledge base. To use a network Qdrant hybrid backend +# instead, configure your own qdrant_host / tei_host (see README). knowledge: enabled: false # Enable knowledge base search db_path: "" # Path to knowledge SQLite database @@ -84,7 +93,7 @@ knowledge: # === MESH DATA SOURCES === # Connect to Meshview and/or MeshMonitor instances for live mesh # network analysis. Supports multiple sources. Configure via TUI -# with meshai --config (Mesh Sources menu). +# with `meshai --config` (Mesh Sources menu). # # mesh_sources: # - name: "my-meshview" @@ -95,17 +104,17 @@ knowledge: # # - name: "my-meshmonitor" # type: meshmonitor -# url: "http://192.168.1.100:3333" +# url: "http://:3333" # api_token: "${MM_API_TOKEN}" # refresh_interval: 300 # enabled: true # # - name: "mqtt-broker" # type: mqtt -# host: "mqtt.meshtastic.org" +# host: "" # port: 1883 -# username: "meshdev" -# password: "large4cats" +# username: "${MQTT_USER}" +# password: "${MQTT_PASSWORD}" # topic_root: "msh/US" # use_tls: false # enabled: true @@ -123,7 +132,7 @@ mesh_sources: [] # packet_threshold: 500 # Non-text packets per 24h to flag # battery_warning_percent: 30 # Battery level for warnings # infra_overrides: [] # Node IDs to exclude from infrastructure -# region_labels: {} # Override auto-names: {"Twin Falls": "Magic Valley"} +# region_labels: {} # Override auto-names: {"": ""} mesh_intelligence: enabled: false region_radius_miles: 40.0 @@ -135,22 +144,22 @@ mesh_intelligence: region_labels: {} # === ENVIRONMENTAL FEEDS === -# Live situational awareness from NWS, NOAA Space Weather, and Open-Meteo. +# Live situational awareness from NWS, NOAA Space Weather, Open-Meteo, and more. # Provides weather alerts, HF propagation assessment, and tropospheric ducting. +# All geographic values below are placeholders — set them for your own area. # environmental: enabled: false - nws_zones: - - "IDZ016" # Western Magic Valley - - "IDZ030" # Southern Twin Falls County + nws_zones: [] # Your NWS public-forecast zone IDs, e.g. ["XXZ001", "XXZ002"] + # Look yours up at https://www.weather.gov/pimar/PubZone # NWS Weather Alerts (api.weather.gov) nws: enabled: true tick_seconds: 60 - areas: ["ID"] + areas: [] # State/marine codes, e.g. ["ID"] severity_min: "moderate" - user_agent: "(meshai.example.com, ops@example.com)" # REQUIRED by NWS + user_agent: "(meshai.example.com, ops@example.com)" # REQUIRED by NWS — use your own contact # NOAA Space Weather (services.swpc.noaa.gov) swpc: @@ -160,20 +169,20 @@ environmental: ducting: enabled: true tick_seconds: 10800 # 3 hours - latitude: 42.56 # center of mesh coverage area - longitude: -114.47 + latitude: 0.0 # center of your mesh coverage area + longitude: 0.0 - # NIFC Fire Perimeters (Phase 2) + # NIFC Fire Perimeters fires: enabled: false tick_seconds: 600 - state: "US-ID" + state: "" # e.g. "US-ID" - # Avalanche Advisories (Phase 2) + # Avalanche Advisories avalanche: enabled: false tick_seconds: 1800 - center_ids: ["SNFAC"] + center_ids: [] # Your avalanche center ID(s), e.g. ["XXFAC"] season_months: [12, 1, 2, 3, 4] # USGS Stream Gauges (waterservices.usgs.gov) @@ -181,7 +190,7 @@ environmental: usgs: enabled: false tick_seconds: 900 # Min 15 min per USGS guidelines - sites: [] # e.g. ["13090500", "13088000"] + sites: [] # e.g. ["XXXXXXXX", "XXXXXXXX"] # TomTom Traffic Flow (api.tomtom.com, requires API key) traffic: @@ -189,22 +198,22 @@ environmental: tick_seconds: 300 api_key: "" # Get key at developer.tomtom.com corridors: [] - # Example corridors: - # - name: "I-84 Twin Falls" - # lat: 42.56 - # lon: -114.47 + # Example corridor: + # - name: "" + # lat: 0.0 + # lon: 0.0 # 511 Road Conditions (state-specific, configurable base URL) roads511: enabled: false tick_seconds: 300 api_key: "" - base_url: "" # e.g. "https://511.idaho.gov/api/v2" + base_url: "" # e.g. "https://511..gov/api/v2" endpoints: ["/get/event"] bbox: [] # [west, south, east, north] # NASA FIRMS Satellite Fire Detection - # Early warning via satellite hotspots, hours before official perimeters + # Early warning via satellite hotspots, hours before official perimeters. # Get MAP_KEY at: https://firms.modaps.eosdis.nasa.gov/api/area/ firms: enabled: false @@ -217,32 +226,26 @@ environmental: proximity_km: 10.0 # km to match known fire perimeters -# === NOTIFICATION DELIVERY (TRANSITIONAL) === -# NOTE: This notifications schema will be replaced in v0.3 by the 8-toggle model. -# These rule examples are transitional until Phase 1.2 lands. Do not extend. -# Severity levels: routine (informational), priority (needs attention), immediate (act now) -# +# === NOTIFICATION DELIVERY === # Route alerts to channels (mesh, email, webhook) based on rules. -# Categories match alert types from alert_engine.py. +# Categories match alert types from the alert engine. +# Severity levels: routine (informational), priority (needs attention), immediate (act now) notifications: enabled: false quiet_hours_enabled: true # Master toggle for quiet hours feature quiet_hours_start: "22:00" # Suppress non-emergency alerts during quiet hours quiet_hours_end: "06:00" - # Digest scheduler settings - # The digest collects priority/routine events and delivers a summary + # Digest scheduler: collects priority/routine events and delivers a summary # at the configured time to rules with trigger_type='schedule' and # schedule_match='digest'. digest: schedule: "07:00" # HH:MM local time to fire digest include: [] # Toggle names to include (empty = default set) # Default set: weather, fire, seismic, avalanche, roads, mesh_health, tracking, other - # Excludes rf_propagation by default - # Example: include: ["weather", "fire", "mesh_health"] - # Notification rules - each rule is self-contained with its own delivery config - # Default baseline rules are created on fresh install + # Notification rules - each rule is self-contained with its own delivery config. + # Default baseline rules are created on a fresh install. rules: # Emergency Broadcast - all emergencies go out immediately - name: "Emergency Broadcast" @@ -289,7 +292,6 @@ notifications: override_quiet: false # Example: Morning Digest -> mesh broadcast - # Delivers the accumulated digest at the configured schedule time # - name: "Morning Digest Mesh" # enabled: false # trigger_type: schedule @@ -303,38 +305,22 @@ notifications: # trigger_type: schedule # schedule_match: "digest" # delivery_type: email - # smtp_host: "smtp.gmail.com" + # smtp_host: "" # smtp_port: 587 - # smtp_user: "you@gmail.com" + # smtp_user: "" # smtp_password: "${SMTP_PASSWORD}" # smtp_tls: true - # from_address: "meshai@yourdomain.com" - # recipients: ["admin@yourdomain.com"] + # from_address: "meshai@example.com" + # recipients: ["admin@example.com"] - # Example: Fire alerts -> email - # - name: "Fire Alerts Email" - # enabled: true - # trigger_type: condition - # categories: ["wildfire_proximity", "new_ignition"] - # min_severity: "routine" - # delivery_type: email - # smtp_host: "smtp.gmail.com" - # smtp_port: 587 - # smtp_user: "you@gmail.com" - # smtp_password: "${SMTP_PASSWORD}" - # smtp_tls: true - # from_address: "meshai@yourdomain.com" - # recipients: ["admin@yourdomain.com"] - # cooldown_minutes: 30 - - # Example: All warnings -> Discord webhook - # - name: "Discord Alerts" + # Example: All warnings -> webhook (Discord/Slack/etc.) + # - name: "Webhook Alerts" # enabled: true # trigger_type: condition # categories: [] # min_severity: "priority" # delivery_type: webhook - # webhook_url: "https://discord.com/api/webhooks/..." + # webhook_url: "${ALERT_WEBHOOK_URL}" # cooldown_minutes: 10 # Example: Rule with no delivery (matches and logs, but doesn't send) diff --git a/screenshots/adapter-config.jpg b/screenshots/adapter-config.jpg new file mode 100644 index 0000000..8f89ad6 Binary files /dev/null and b/screenshots/adapter-config.jpg differ diff --git a/screenshots/dashboard.jpg b/screenshots/dashboard.jpg new file mode 100644 index 0000000..cf2e35a Binary files /dev/null and b/screenshots/dashboard.jpg differ diff --git a/screenshots/topology-chart.jpg b/screenshots/topology-chart.jpg new file mode 100644 index 0000000..eed2b6e Binary files /dev/null and b/screenshots/topology-chart.jpg differ