No description
  • Python 46.6%
  • JavaScript 41.8%
  • TypeScript 11.4%
Find a file
Matt Johnson (via Claude) f69a05dd6d feat(v0.7-fire-tracker-4): fix LLM DM path + daily fire digest + ?status queries
Phase 4 of FIRMS+WFIGS fusion. Foundation: every direct LLM DM
mentioning a fire/weather/quake/avalanche/flood/etc. keyword was
failing silently in prod with UnboundLocalError because router.py
referenced scope_type before assigning it. With that path restored,
two new features land: a twice-daily fire-digest scheduled broadcast
(LLM-rendered) and a ?status <fire_name> on-demand mesh-DM intent.

BUG-FIX ROOT CAUSE (Job Zero):
  router.py:745 ("if should_inject_mesh and scope_type == 'env'") read
  `scope_type` -- a local variable bound only at line 761 inside an
  unrelated `if self.source_manager and self.mesh_reporter` block.
  Python's lexical scoping made scope_type a local of the whole
  generate_llm_response function, so reading it before the assignment
  raised UnboundLocalError on every env-keyword DM. The exception
  propagated to main.py's outer except, no response went out, bot
  appeared dead on fire/weather/quake/avalanche/flood queries.

  Evidence (synthetic in-process trace against the live container's
  config + GoogleBackend):
    "are there any fires near me?" -> UnboundLocalError (pre-fix)
                                  -> real LLM answer (post-fix)
                                     "Yes, there are a few active
                                      fires reported in the region.
                                      Salmon River: 4,200 acres, 78%
                                      contained. Cache Peak: 1,847
                                      acres, 23% contained. ..."
    "what's the weather?"          -> UnboundLocalError (pre-fix)
                                  -> "I do not have current weather
                                      information. I can tell you
                                      about active fires, stream gauge
                                      levels, space weather, or band
                                      conditions if you'd like." (post-fix)
    "hi there"                     -> normal LLM answer in both cases

  Fix: hoist `scope_type, scope_value = self._detect_mesh_scope(query)`
  to right after `should_inject_mesh` is computed; remove the
  now-duplicate detection inside the source_manager block.

  Secondary mitigation: tightened the "do not invent commands" prompt
  with an explicit "if no list appears above, you have NO commands"
  clause. The prior prompt told the LLM "answer based on the command
  list provided below" without always providing one, so the LLM
  hallucinated plausible-sounding !commands (the "use ! commands"
  canned-looking response Matt was seeing on non-env queries).

PHASE 4 FEATURES:

1. Fire-digest scheduler (meshai/notifications/scheduled/fire_digest.py).
   Modeled after BandConditionsScheduler. Runs in the pipeline's
   start_pipeline coroutine alongside band_conditions + reminders.
   On each slot (default 06:00 + 18:00 America/Boise):
     - Queries active fires (tombstoned_at IS NULL) + last 24h passes.
     - Builds a prompt asking for a single mesh-wire summary <= 200
       chars.
     - Calls the LLM (Google/Anthropic/OpenAI per config).
     - Falls back to a terse "Fires today (N): Cache Peak 1847 ac;
       Twin Peaks 320 ac; +N more" line when the LLM is unavailable.
     - Dispatches via dispatcher.dispatch_scheduled_broadcast (same
       path band_conditions uses).
   Idempotency: v16.sql adds fire_digest_broadcasts(slot_epoch PK,
   sent_at, summary, source). INSERT OR IGNORE pattern blocks the same
   slot firing twice (matters when container restarts mid-day).

2. ?status <fire_name> on-demand intent (router.py).
   Before falling through to the LLM, route() now checks for a leading
   "?status" / "status:" sigil or natural-language triggers like
   "how is X fire?". On match:
     - _lookup_fire_fuzzy walks fires by exact -> startswith ->
       contains -> word-overlap (skipping a trailing " fire" word so
       "cache peak fire" matches "Cache Peak"). Active fires rank
       above tombstoned ones.
     - _build_fire_status_context composes a small context block
       (name, acres, containment, county/state, last 3 passes with
       drift).
     - The query is REWRITTEN into an LLM prompt with that context
       inlined; the rest of the normal LLM path (chunking, history,
       summary persistence) runs unchanged.
   Live verification: "?status Cache Peak" -> "The Cache Peak fire is
   1,847 acres and 23% contained. It's located in Probe / ID.";
   "?status Salmon" -> word-overlap matches "Salmon River" ->
   "The Salmon River fire is 4,200 acres and 78% contained, located
   in Probe / ID."

3. adapter_config rows (GUI-editable per CONFIG-vs-CODE rule):
     fires.digest_enabled         = true   (master toggle)
     fires.digest_schedule        = ["06:00", "18:00"]
     fires.digest_timezone        = "America/Boise"
     fires.digest_max_chars       = 200

Schema (v16.sql):
- fire_digest_broadcasts(slot_epoch INTEGER PK, sent_at, summary,
  source) with source in {'llm', 'fallback_terse', 'skipped_no_fires'}.
- Index on sent_at for ops queries.

Tests (tests/test_fire_tracker_phase4.py, 10 cases all green):
- Regression guard: scope_type appears as an assignment BEFORE the
  env_reporter check (prevents the UnboundLocalError from coming back).
- adapter_config seeds all 4 digest keys with expected defaults.
- render_digest returns ('', 'no_fires') when no active fires.
- render_digest falls back to terse line when LLM is None; wire fits cap.
- render_digest with a stub LLM returns ('<llm text>', 'llm').
- _lookup_fire_fuzzy: exact, "X fire" trim, word-overlap, no-match.
- _maybe_rewrite_status_query: builds context-bearing prompt; returns
  None on non-status queries.

Combined suite: 60 passed in 3.81s across phase1+phase2+phase3+phase4
+or-arch+include-roundtrip.

Live verification on CT108 after rebuild:
- v16 migration applied (schema_meta=16, no Traceback in 3 min).
- FireDigestScheduler started: enabled=True schedule=['06:00','18:00']
  tz=America/Boise.
- LLM DM probe (real Gemini) returns real answers on env queries
  (Bug A fixed end-to-end).
- ?status Cache Peak + ?status Salmon return fire-specific summaries.
- render_digest with real LLM returns source=llm + non-empty wire.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-06 07:13:17 +00:00
.github/workflows
config build: normalize all line endings to LF 2026-05-14 22:43:06 +00:00
dashboard-frontend feat(v0.6-tail-3): enforce OR-not-AND continuously -- close USGS direct-lookup leak + flag environmental config changes as restart-required 2026-06-06 03:51:10 +00:00
meshai feat(v0.7-fire-tracker-4): fix LLM DM path + daily fire digest + ?status queries 2026-06-06 07:13:17 +00:00
tests feat(v0.7-fire-tracker-4): fix LLM DM path + daily fire digest + ?status queries 2026-06-06 07:13:17 +00:00
.dockerignore
.gitattributes build: add .gitattributes to enforce LF line endings 2026-05-14 22:42:14 +00:00
.gitignore feat(v0.5.8b): persistence foundation + WFIGS handler + universal cold-start grace 2026-06-05 03:54:04 +00:00
config.example.yaml build: normalize all line endings to LF 2026-05-14 22:43:06 +00:00
docker-compose.yml fix(infra): point meshai container DNS at LXC working resolver 2026-05-27 17:15:29 +00:00
docker-entrypoint.sh feat: Hybrid RAG knowledge base, sentence-aware chunking, MeshMonitor HTTP sync 2026-05-04 07:44:12 +00:00
Dockerfile feat(dashboard): embedded FastAPI backend with REST API + WebSocket 2026-05-12 15:47:58 +00:00
LICENSE
pyproject.toml feat(central): v0.4 C.1 Central connector backend (no-op until adapter source flipped) 2026-05-28 02:28:19 +00:00
README.md docs: comprehensive README with full setup guide 2026-05-12 21:02:17 -06:00
requirements.txt feat(content): v0.5.8-state_511_atis -- central_normalizer with Photon nearest_town + composer bypass + SB->S route normalization 2026-06-04 21:38:40 +00:00

MeshAI

LLM-powered mesh intelligence assistant for Meshtastic networks. MeshAI connects to your mesh as a physical node, monitors network health in real-time, and answers questions about your infrastructure over LoRa.

What It Does

MeshAI runs on your Meshtastic node and provides:

  • Mesh Intelligence — 5-pillar health scoring, per-region breakdowns, infrastructure monitoring, coverage gap analysis, and environmental sensing
  • Conversational Queries — ask "how's the mesh?" or "tell me about MHR" and get data-driven answers over LoRa
  • Node Distance — GPS-based distance calculations between any two nodes on the mesh
  • Multi-Source Awareness — aggregates data from multiple Meshview instances and MeshMonitor with staggered polling
  • Feeder Gateway Tracking — identifies which physical MQTT gateways hear each node and signal quality
  • Subscriptions — scheduled daily/weekly health reports and instant alerts delivered via DM
  • LLM Chat — general conversation, knowledge base lookups, and weather queries
  • Multi-Backend — supports Google Gemini, OpenAI, Anthropic Claude, and local LLMs via LiteLLM

Quick Start

# Clone
git clone https://github.com/zvx-echo6/meshai.git
cd meshai

# Install
pip install -e .

# Configure (interactive TUI)
meshai --config

# Run
meshai

Or with Docker:

mkdir -p meshai/data && cd meshai
curl -O https://raw.githubusercontent.com/zvx-echo6/meshai/main/docker-compose.yml
curl -o data/config.yaml https://raw.githubusercontent.com/zvx-echo6/meshai/main/config.example.yaml
# Edit data/config.yaml
docker compose up -d

Commands

Command Description
!health Mesh health overview with colored status dots
!region List all regions with health status
!region [name] Detailed region breakdown
!neighbors [node] Top infrastructure neighbors with signal quality
!sub daily 6pm Subscribe to daily health reports
!sub weekly 8am sun Subscribe to weekly digest
!sub alerts Subscribe to instant alerts on issues
!unsub [type] Remove a subscription
!mysubs List your active subscriptions
!clear Clear conversation history
!help Show available commands
!help [cmd] Detailed help for a command
!quakes Recent earthquakes in monitored area
!fires Active wildfires from NIFC
!hotspots NASA FIRMS satellite fire detections
!hotspots --new Only hotspots not matching known fires
!traffic Traffic incidents from TomTom
!space Space weather conditions (solar/geomagnetic)
!water USGS stream gauge readings
!air Air quality index

Commands can be disabled in config if another service (like MeshMonitor) handles them.

Mesh Intelligence

MeshAI continuously polls mesh data sources and computes a 5-pillar health score:

Pillar Weight What It Measures
Infrastructure 30% Router uptime — how many infra nodes are online
Utilization 25% Channel busyness — RF congestion across the mesh
Coverage 20% Gateway reach — how many monitoring sources see each node
Behavior 15% Traffic patterns — detecting noisy or misconfigured nodes
Power 10% Battery health — infrastructure nodes only

Health Display

!health shows a compact overview with personality:

📡 Mesh 🟢 healthy
🏗️ 15/16 routers up
❌ Down: TVM Tablerock Relay
📶 152 full coverage, 94 on thin ice
🔥 Hayden Peak Router at 21% util
🔋 All infra powered ✅
🌡️ 29-34°C across 2 sensors
Treasure Valley 🟢 | Magic Valley 🟢

Status dots: 🔵 perfect (100) · 🟢 healthy (75+) · 🟠 warning (50+) · 🔴 critical (<50)

Monitoring Rules

Infrastructure nodes (routers, repeaters) are monitored individually with full detail — battery, offline alerts, coverage, neighbors, hardware. Client nodes dying is normal and not tracked. Channel utilization and environmental sensors are monitored for all nodes.

Conversational Queries

Ask questions naturally over LoRa:

  • "how's the mesh?" → health overview with top issues
  • "tell me about MHR" → full node detail with neighbors, coverage, feeders
  • "where do we need more coverage?" → named gaps with specific nodes
  • "how far is MHR from AIDA?" → GPS distance calculation
  • "which nodes only reach one gateway?" → named nodes with their gateway
  • "which gateway has the best signal?" → feeder comparison

Geographic Regions

Regions are configurable with local names, descriptions, aliases, and cities — all manageable through the TUI. No hardcoded geography in the code.

mesh_intelligence:
  regions:
    - name: "South Central ID"
      local_name: "Magic Valley"
      description: "Twin Falls area"
      aliases: ["southern Idaho", "magic valley"]
      cities: ["Twin Falls", "Burley", "Jerome"]
      lat: 42.5
      lon: -114.5
      radius_km: 80

Environmental Feeds

MeshAI integrates real-time environmental data for situational awareness beyond mesh network health.

USGS Earthquake Monitoring

env:
  usgs:
    enabled: true
    min_magnitude: 2.5
    radius_km: 500
    center_lat: 43.6150
    center_lon: -116.2023

No API key required. Data from USGS Earthquake Hazards Program.

NWS Weather Alerts

env:
  nws:
    enabled: true
    zone: IDZ025         # NWS zone ID
    point: "43.6150,-116.2023"

No API key required. Find your zone at NWS Zone Lookup.

NOAA Space Weather

env:
  noaa_space:
    enabled: true

No API key required. Data from NOAA SWPC.

NIFC Wildfire Perimeters

env:
  nifc:
    enabled: true
    radius_km: 200
    center_lat: 43.6150
    center_lon: -116.2023

No API key required. Data from NIFC Open Data.

NASA FIRMS Satellite Fire Detection

env:
  firms:
    enabled: true
    map_key: "your-map-key"    # Required
    radius_km: 200
    center_lat: 43.6150
    center_lon: -116.2023
    source: VIIRS_SNPP         # VIIRS_SNPP, VIIRS_NOAA20, MODIS_NRT
    day_range: 1               # 1, 2, or 10 days

API Key Required: Register at NASA FIRMS. Free MAP_KEY provides access to near real-time satellite fire detections. Hotspots are cross-referenced against NIFC perimeters to identify potential new ignitions.

TomTom Traffic

env:
  tomtom:
    enabled: true
    api_key: "your-api-key"    # Required
    bbox: "-117.5,42.5,-115.0,44.5"  # lon1,lat1,lon2,lat2

API Key Required: Register at TomTom Developer Portal. Free tier includes 2,500 requests/day.

511 Road Conditions

env:
  fiveonone:
    enabled: true
    state: ID                  # State code
    api_key: "your-api-key"    # If required by state
    bbox: [-117.5, 42.5, -115.0, 44.5]

API key requirements vary by state. Check your state's 511 developer portal.

USGS Water Services

env:
  usgs_water:
    enabled: true
    sites: ["13206000", "13202000"]  # USGS site numbers

No API key required. Find sites at USGS Water Services.

AirNow Air Quality

env:
  airnow:
    enabled: true
    api_key: "your-api-key"    # Required
    zipcode: "83702"

API Key Required: Register at AirNow API.

Dashboard Configuration

dashboard:
  enabled: true
  host: 0.0.0.0
  port: 8080

The web dashboard provides real-time visualization of mesh nodes, environmental conditions, and alerts with WebSocket push notifications.


Data Sources

MeshAI aggregates from multiple sources using staggered tick-based polling (one API call per 30-second tick):

Meshview

Unauthenticated REST API. Supports multiple instances.

Endpoint Interval Data
/api/packets 30s Near real-time packet feed
/api/nodes 2 min Node list with metadata
/api/stats 3 min Traffic statistics
/api/edges 3 min Node-to-node connections
/api/traceroutes 5 min Route data
/api/packets_seen 10 min Per-gateway RSSI/SNR (sampled)

MeshMonitor

Authenticated (Bearer token). Single instance.

Endpoint Interval Data
/api/v1/packets 60s Packet feed
/api/v1/nodes 2 min Nodes with battery, utilization, hardware
/api/v1/telemetry 2 min Environmental sensors, device metrics
/api/v1/traceroutes 5 min Route data
/api/v1/channels 5 min Channel configuration
/api/v1/network 5 min Network statistics
/api/v1/solar 10 min Solar estimates

Rate Limiting

Built-in protection for all sources: HTTP 429 backoff with Retry-After, exponential backoff on consecutive errors, slow response warnings, and optional polite mode for shared instances.

Source Configuration

mesh_sources:
  - name: "local-meshview"
    type: meshview
    url: "http://192.168.1.100:8080"
    enabled: true

  - name: "meshmonitor"
    type: meshmonitor
    url: "http://192.168.1.100:3333"
    api_token: "your-bearer-token"
    enabled: true

Knowledge Base (RAG)

MeshAI uses a hybrid knowledge retrieval system with two backends:

Primary: RECON Qdrant Backend

Queries RECON's knowledge extraction pipeline — 2.8M+ vectors covering survival skills, communications, medical, technical documentation, Meshtastic docs, and more. Uses the same embedding infrastructure as RECON:

  • Dense embeddings: TEI service with BAAI/bge-m3 (1024-dim)
  • Sparse embeddings: bge-m3-sparse with IDF modifier
  • Search: Qdrant hybrid with Reciprocal Rank Fusion (dense + sparse)

No data is copied — MeshAI queries RECON's Qdrant and TEI services over the network.

knowledge:
  enabled: true
  backend: auto            # "qdrant", "sqlite", or "auto" (try qdrant, fall back)
  qdrant_host: "192.168.1.150"
  qdrant_port: 6333
  qdrant_collection: "recon_knowledge_hybrid"
  tei_host: "192.168.1.150"
  tei_port: 8090
  sparse_host: "192.168.1.150"
  sparse_port: 8091
  use_sparse: true
  top_k: 5

Fallback: Local SQLite

If the Qdrant backend is unreachable, MeshAI falls back to a local SQLite knowledge base using FTS5 keyword search and bge-small-en-v1.5 vector embeddings (384-dim).

# Build from Meshtastic ZIM file
python scripts/zim_to_knowledge.py meshtastic.zim --output knowledge.db
knowledge:
  enabled: true
  backend: sqlite
  db_path: /data/meshai_knowledge.db
  top_k: 5

Requires sqlite-vec and fastembed for the SQLite backend.

Architecture

┌──────────────────────────────────────────────────────────────────────┐
│                              MeshAI                                  │
├──────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  DATA SOURCES              INTELLIGENCE              DELIVERY        │
│  ┌─────────────┐          ┌──────────────┐         ┌────────────┐   │
│  │ Meshview ×N  │─────┐   │ Health Engine │────────▶│  Reporter  │   │
│  │ (staggered)  │     │   │ 5-pillar     │         │ Tier 1/2   │   │
│  └─────────────┘     ▼   │ scoring      │         └─────┬──────┘   │
│  ┌─────────────┐  ┌──────┴──┐            │               │          │
│  │ MeshMonitor │─▶│  Data   │─┘          │         ┌─────▼──────┐   │
│  │ (staggered) │  │  Store  │            │         │   Router   │   │
│  └─────────────┘  │ SQLite  │            │         │ scope/dist │   │
│                   └─────────┘            │         └─────┬──────┘   │
│                        │                 │               │          │
│                   ┌────▼────┐      ┌─────▼──────┐  ┌────▼────┐    │
│                   │ Feeder  │      │    LLM     │  │ Chunker │    │
│                   │ Sampling│      │  Backend   │  │LoRa-fit │    │
│                   └─────────┘      └────────────┘  └────┬────┘    │
│                                                         │         │
│  KNOWLEDGE             ALERTS             DELIVERY      │         │
│  ┌─────────────┐  ┌─────────────┐  ┌──────────────┐    │         │
│  │ RECON/Qdrant│  │   Alert     │  │ Subscription │    │         │
│  │ 2.8M vectors│  │   Engine    │  │   Manager    │    │         │
│  │ (network)   │  │ 17 triggers │  │ daily/weekly │    │         │
│  ├─────────────┤  │  scaling    │  │   alerts     │    │         │
│  │ SQLite FTS5 │  │  cooldown   │  └──────┬───────┘    │         │
│  │ (fallback)  │  └──────┬──────┘         │            │         │
│  └─────────────┘         │          ┌─────▼────────┐   │         │
│                          └─────────▶│  Responder   │◀──┘         │
│  ┌─────────────┐                    │ ACK-paced DM │             │
│  │ Conversation│                    │ Channel alert│             │
│  │   History   │                    └──────────────┘             │
│  └─────────────┘                                                 │
│                                                                   │
└───────────────────────────────────────────────────────────────────┘
         │                    │
    ┌────▼────┐          ┌────▼────┐
    │  TEI    │          │ Qdrant  │
    │ bge-m3  │          │ hybrid  │
    │ cortex  │          │ cortex  │
    └─────────┘          └─────────┘

Dashboard API Reference

The dashboard exposes a REST API (default port 8080):

Core Endpoints

Endpoint Method Description
/api/health GET System health check
/api/status GET Full system status with health scores
/api/nodes GET Connected mesh nodes
/api/messages GET Recent mesh messages

Environmental Data

Endpoint Method Description
/api/env/earthquakes GET Recent earthquakes
/api/env/weather GET Weather conditions and alerts
/api/env/fires GET Active wildfires from NIFC
/api/env/hotspots GET NASA FIRMS satellite detections
/api/env/traffic GET Traffic incidents
/api/env/water GET Stream gauge readings
/api/env/space GET Space weather data
/api/env/air GET Air quality readings

Alerts

Endpoint Method Description
/api/alerts/active GET Currently active alerts
/api/alerts/history GET Historical alerts (?severity=, ?source=, ?limit=, ?offset=)
/api/alerts/{id}/ack POST Acknowledge an alert
/api/subscriptions GET Alert subscriptions

WebSocket

Connect to /ws for real-time updates:

const ws = new WebSocket('ws://localhost:8080/ws');
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  // data.type: 'message', 'alert', 'node_update', 'health_update'
};

Message Chunking

Long responses are split into mesh-friendly chunks with sentence-aware splitting, configurable limits, and continuation prompts. Command output (like !health) packs multiple lines into 2-3 messages using newlines within each message to minimize airtime usage.

response:
  max_length: 200       # Max chars per message
  max_messages: 3       # Messages before continuation prompt

Alerting

Real-time alerts when mesh conditions change, with scaling cooldowns to prevent spam.

Alert Conditions (17 total, each toggleable)

Pillar Condition Default Threshold
Infrastructure Router goes offline
Infrastructure Router recovery
Infrastructure New router appears
Power Battery warning <50%
Power Battery critical <25%
Power Battery emergency <10%
Power 7-day declining trend >10% drop with rate
Power USB → battery (power outage)
Power Solar not charging during day
Utilization Sustained high utilization >20% for 6h
Utilization Packet flood >500 pkts/24h
Coverage Infra drops to single gateway
Coverage Feeder gateway stops responding
Coverage Region total blackout All infra offline
Scores Mesh health score drop <70/100
Scores Region health score drop <60/100

Scaling Cooldown

Alerts don't spam. When a condition triggers:

  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.

mesh_intelligence:
  critical_nodes: ["MHR", "HPR"]
  alert_channel: 0        # Channel for broadcast alerts (-1 = disabled)

All conditions and thresholds are configurable via the TUI under Mesh Intelligence → Alert Rules.

LLM Configuration

llm:
  backend: "google"            # openai, anthropic, google
  api_key: "your-api-key"
  model: "gemini-2.0-flash"

Local LLMs

MeshAI works with any OpenAI-compatible API:

  • LiteLLM: base_url: "http://localhost:4000/v1"
  • Open WebUI: base_url: "http://localhost:3000/api"
  • Ollama: base_url: "http://localhost:11434/v1"

Docker

connection:
  type: "tcp"
  tcp_host: "192.168.1.100"
  tcp_port: 4403

Serial Connection

connection:
  type: "serial"
  serial_port: "/dev/ttyUSB0"

Edit docker-compose.serial.yml to match your device path.

Environment Variables

LLM_API_KEY=your-key-here docker compose up -d

Running Alongside Other Services

advBBS

MeshAI coexists with advBBS on the same node. BBS protocol messages (sync, RAP, mail notifications) are automatically filtered. No configuration needed.

bot:
  filter_bbs_protocols: true

MeshMonitor

MeshAI integrates with MeshMonitor at two levels: it fetches MeshMonitor's auto-responder patterns to avoid duplicate responses, and it uses MeshMonitor's API as a data source for mesh intelligence (battery, telemetry, traceroutes, solar).

meshmonitor:
  enabled: true
  url: "http://192.168.1.100:8080"
  inject_into_prompt: true
  refresh_interval: 300

Running as a Service

# /etc/systemd/system/meshai.service
[Unit]
Description=MeshAI - Meshtastic Mesh Intelligence
After=network.target

[Service]
Type=simple
User=your-user
WorkingDirectory=/path/to/meshai
ExecStart=/usr/bin/python3 -m meshai
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable meshai
sudo systemctl start meshai

Acknowledgments

  • Meshtastic — the mesh networking platform
  • MeshMonitor by Yeraze — monitoring integration and data source
  • advBBS — BBS coexistence design
  • sqlite-vec by Alex Garcia — vector search in SQLite
  • fastembed by Qdrant — fast local embeddings

License

MIT License

Author

K7ZVX - matt@echo6.co