{"id":47597711,"url":"https://github.com/meshaddicts/meshinfo","last_synced_at":"2026-07-02T02:00:52.167Z","repository":{"id":241670095,"uuid":"807385363","full_name":"MeshAddicts/meshinfo","owner":"MeshAddicts","description":"Realtime web UI to run against a Meshtastic regional or private mesh network.","archived":false,"fork":false,"pushed_at":"2026-06-27T05:11:56.000Z","size":21971,"stargazers_count":141,"open_issues_count":13,"forks_count":17,"subscribers_count":1,"default_branch":"develop","last_synced_at":"2026-06-27T07:08:12.418Z","etag":null,"topics":["lora","m","mesh","mesh-networks","meshtastic","meshtastic-python","webapp"],"latest_commit_sha":null,"homepage":"https://meshinfo.cvme.sh","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MeshAddicts.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["kevinelliott","SimmerV","daviesgeek"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"custom":null}},"created_at":"2024-05-29T02:15:44.000Z","updated_at":"2026-06-27T05:11:05.000Z","dependencies_parsed_at":"2024-05-29T15:57:32.048Z","dependency_job_id":"82bd5bdb-123d-4672-b89c-15948b39549c","html_url":"https://github.com/MeshAddicts/meshinfo","commit_stats":null,"previous_names":["kevinelliott/meshinfo"],"tags_count":233,"template":false,"template_full_name":null,"purl":"pkg:github/MeshAddicts/meshinfo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MeshAddicts%2Fmeshinfo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MeshAddicts%2Fmeshinfo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MeshAddicts%2Fmeshinfo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MeshAddicts%2Fmeshinfo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MeshAddicts","download_url":"https://codeload.github.com/MeshAddicts/meshinfo/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MeshAddicts%2Fmeshinfo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35029796,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-02T02:00:06.368Z","response_time":173,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lora","m","mesh","mesh-networks","meshtastic","meshtastic-python","webapp"],"created_at":"2026-04-01T18:27:40.517Z","updated_at":"2026-07-02T02:00:52.162Z","avatar_url":"https://github.com/MeshAddicts.png","language":"TypeScript","funding_links":["https://github.com/sponsors/kevinelliott","https://github.com/sponsors/SimmerV","https://github.com/sponsors/daviesgeek"],"categories":[],"sub_categories":[],"readme":"# MeshInfo\n\nA real-time web application for visualizing and monitoring Meshtastic mesh networks.\n\n[![Docker Image](https://github.com/MeshAddicts/meshinfo/actions/workflows/docker.yml/badge.svg)](https://github.com/MeshAddicts/meshinfo/actions/workflows/docker.yml) ![GitHub Release](https://img.shields.io/github/v/release/meshaddicts/meshinfo) ![GitHub commit activity](https://img.shields.io/github/commit-activity/t/meshaddicts/meshinfo) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n\n## Overview\n\nMeshInfo connects to one or more MQTT brokers receiving Meshtastic traffic and provides a modern web UI for exploring your mesh. It decodes protobuf and JSON messages in real time, stores everything in PostgreSQL, and serves it through a FastAPI backend and React frontend.\n\nSee a live instance at [Central Valley Mesh](https://meshinfo.cvme.sh).\n\n## Features\n\n- **Interactive Map** -- Node positions on OpenStreetMap or Mapbox with hardware icons\n- **RF Coverage / Best Neighbors** -- Per-pixel RF coverage prediction using ITM (Longley-Rice) over real terrain plus per-pixel ITU-R clutter loss from USGS land cover. See [RF-MODEL.md](RF-MODEL.md).\n- **Chat** -- View and search mesh text messages across channels, with CSV/JSON export\n- **Node Explorer** -- Browse all nodes with filtering by status, hardware, role, and more\n- **Network Graph** -- Visualize mesh topology with adjacency heatmaps and arc diagrams\n- **Neighbor View** -- Inspect neighbor relationships and signal quality (SNR)\n- **Telemetry** -- Device metrics, environment sensors, and power data per node\n- **Traceroutes** -- Hop-by-hop path visualization between nodes\n- **MQTT Log** -- Live stream of raw mesh traffic for debugging\n- **Discord Integration** -- Bridge mesh messages and position updates to Discord channels\n- **Node Enrichment** -- Augment node data from the MeshInfo network discovery service\n- **Reverse Geocoding** -- Resolve node coordinates to human-readable locations\n- **Multi-topic MQTT** -- Subscribe to multiple MQTT topics with tag-based filtering in the UI\n- **Channel-aware Chat** -- Firmware 2.5+ channel hash support with configurable channel views\n\n## Architecture\n\n```\nMQTT Broker(s)  --\u003e  MeshInfo Backend (Python / FastAPI / uvicorn)\n                          |\n                     PostgreSQL 18\n                          |\n                     MeshInfo Frontend (React 19 / TypeScript / Vite)\n                          |\n                     Caddy (reverse proxy, automatic HTTPS)\n```\n\nAll components run as Docker containers orchestrated by Docker Compose.\n\n## Supported Message Types\n\n- `neighborinfo` -- neighbor lists and SNR data\n- `nodeinfo` -- hardware, firmware, and role information\n- `position` -- GPS coordinates and altitude\n- `telemetry` -- device, environment, and power metrics\n- `text` -- chat messages\n- `traceroute` -- hop-by-hop route data\n\n## Quick Start\n\n### Prerequisites\n\n- [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/)\n- An MQTT broker receiving Meshtastic traffic (or use a public one like `mqtt.meshtastic.org`)\n\n### 1. Clone and configure\n\n```sh\ngit clone https://github.com/MeshAddicts/meshinfo.git\ncd meshinfo\n\n# Backend config\ncp config.toml.sample config.toml\n# Edit config.toml -- set your MQTT broker, topics, mesh name, and node ID\n\n# Frontend config\ncp frontend/.env.sample frontend/.env\n# Edit frontend/.env if you want to use Mapbox instead of OpenStreetMap\n\n# MQTT broker config\ncp mosquitto/config/mosquitto.conf.sample mosquitto/config/mosquitto.conf\n# Edit mosquitto.conf -- add bridge connections to MQTT brokers for your region\n\n# Reverse proxy\ncp Caddyfile.sample Caddyfile\n# Edit Caddyfile -- set your domain (FQDN) and email for automatic TLS\n```\n\n### 2. Start\n\n```sh\ndocker compose up -d\n```\n\nMeshInfo will be available at `https://your-domain` (or `http://localhost` if using a local setup).\n\n### 3. Update\n\n```sh\ngit pull \u0026\u0026 docker compose pull \u0026\u0026 docker compose down \u0026\u0026 docker compose up -d\n```\n\n\u003e **PostgreSQL major version bumps:** if a release changes the `postgres` image\n\u003e to a new major version (e.g. 16 → 18), run the one-time migration **before**\n\u003e the final `up -d` — `docker compose pull` then `bash scripts/migrate-postgres.sh`.\n\u003e See [POSTGRES.md](POSTGRES.md#upgrading-postgresql-major-versions).\n\n### Configuration\n\nThe main configuration file is `config.toml`. Key sections:\n\n| Section | Purpose |\n|---------|---------|\n| `[broker]` | MQTT connection, topics, channel hashes, decoders |\n| `[server]` | Node ID, base URL, timezone, enrichment, graph settings |\n| `[storage.postgres]` | PostgreSQL connection and pool settings |\n| `[mesh]` | Network name, region, coordinates, external tool links |\n| `[integrations.*]` | Discord bridge, reverse geocoding |\n\nSee [config.toml.sample](config.toml.sample) for all options with inline documentation.\n\nFor PostgreSQL-specific details, see [POSTGRES.md](POSTGRES.md).\n\nFor the Coverage and Scan tools' propagation model (ITM + ITU-R clutter), see [RF-MODEL.md](RF-MODEL.md). To enable per-pixel land-cover-aware predictions, run the one-shot tile bake:\n\n```sh\ndocker compose --profile bake run --rm landcover-bake\n```\n\nThe bake auto-downloads NLCD from MRLC, extracts, and writes tiles to `output/landcover/`. ~15–90 min one-time, no manual download. See [scripts/README-landcover.md](scripts/README-landcover.md) for sub-region or offline options.\n\n### Caddy / Reverse Proxy\n\nThe included `Caddyfile.sample` routes `/api/*` and `/v1/*` to the backend and everything else to the frontend. Caddy automatically provisions Let's Encrypt certificates when you use a public FQDN on ports 80/443.\n\nIf you use a different reverse proxy, point `/api/*` and `/v1/*` at the backend container (port 9000) and `/` at the frontend container (port 80).\n\n### Maintenance Mode\n\nWhen you need to take the stack down — for example to upgrade PostgreSQL — Caddy can serve a branded maintenance page instead of a broken site. Caddy and the page itself stay up the whole time, so visitors get a clean \"we'll be back shortly\" landing page rather than a connection error.\n\n```sh\nscripts/maintenance.sh on       # show the maintenance page\n# ... perform the upgrade ...\nscripts/maintenance.sh off      # back to normal\nscripts/maintenance.sh status   # check current state\n```\n\nOn Windows, use the PowerShell port instead — `scripts\\maintenance.ps1 on|off|status`.\n\nThe toggle creates/removes the flag file `public/maintenance/ON`. Caddy checks for it on every request, so it takes effect immediately — no reload or restart. While enabled, every path (including `/api/*`) returns the page with HTTP `503` and a `Retry-After` header. The page auto-refreshes every 60 seconds, so visitors land on the live site automatically once you turn it off.\n\nA typical database upgrade then looks like:\n\n```sh\nscripts/maintenance.sh on\ndocker compose stop meshinfo postgres\n# ... upgrade / migrate ...\ndocker compose up -d meshinfo postgres\nscripts/maintenance.sh off\n```\n\nCustomize the look by editing [public/maintenance/index.html](public/maintenance/index.html) — it is a single self-contained file.\n\n### Map Providers\n\nMeshInfo supports two map providers, configured in `frontend/.env`:\n\n- **OpenStreetMap** (default) -- no account needed\n- **Mapbox** -- requires a [Mapbox access token](https://account.mapbox.com/)\n\n## Running Without Docker\n\n### Backend\n\nRequires Python 3.14+ and a running PostgreSQL 18 instance.\n\n```sh\npip install -r requirements.txt\n# Edit config.toml with storage.postgres.host = \"localhost\"\npython main.py\n```\n\n### Frontend\n\nRequires Node.js 22+ and Yarn 4 (managed via Corepack — no manual install needed).\n\n```sh\ncd frontend\ncp .env.sample .env\nyarn install\nyarn dev\n```\n\n## Development\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, project structure, and contribution guidelines.\n\n### Building Local Docker Images\n\n```sh\n# Build everything with docker-compose in dev mode\ndocker compose -f docker-compose-dev.yml up --build --force-recreate\n\n# Or build images individually\nscripts/docker-build.sh 0.0.1-dev\n```\n\n### Releasing\n\nTag the release and push. GitHub Actions builds and publishes images to `ghcr.io/meshaddicts/meshinfo` and `ghcr.io/meshaddicts/meshinfo-spa` for both amd64 and arm64.\n\n```sh\ngit tag v0.0.0 \u0026\u0026 git push \u0026\u0026 git push --tags\n```\n\n## API\n\nMeshInfo exposes a REST API used by the frontend. See [API.md](API.md) for endpoint documentation.\n\n## Community\n\nQuestions, feedback, or want to contribute? Join us on the [Central Valley Mesh Discord](https://discord.gg/2P63uauAws).\n\nIf you run a public MeshInfo instance, we'd love to hear about it -- drop a note in Discord.\n\n## Related Projects\n\n- [Airframes](https://airframes.io) / [GitHub](https://github.com/airframesio) -- ADS-B, ACARS, VDL, HFDL, SATCOM, and AIS tracking\n\n## License\n\n[GNU General Public License v3.0](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeshaddicts%2Fmeshinfo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeshaddicts%2Fmeshinfo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeshaddicts%2Fmeshinfo/lists"}