RF coverage tile server for Meshtastic networks
1.5K
C++ HTTP tile server that computes RF signal coverage for Meshtastic mesh network nodes using the NTIA ITM (Longley-Rice) propagation model and SRTM elevation data, then serves blended signal-strength tiles as 256x256 PNGs.

Requires: libcurl, zlib, a C++17 compiler.
mkdir build && cd build
cmake ..
make -j$(nproc)
CMake auto-downloads all third-party dependencies via FetchContent (NTIA ITM, cpp-httplib, nlohmann/json, lodepng).
./meshtile [options]
| Flag | Default | Description |
|---|---|---|
--host | 0.0.0.0 | Bind address |
--port | 8080 | Listen port |
--region | den | MeshMapper region prefix (see below) |
--nodes | meshmapper API | Override node source with a URL or local JSON file |
--noise-data | meshmapper API | Override noise floor data with a URL or local file |
--max-range | 30 | Max propagation range per node (km) |
Node and noise floor data are fetched from MeshMapper regional instances. Each instance uses a short prefix as its subdomain (e.g. den.meshmapper.net, oma.meshmapper.net). Use --region to select which instance to pull from:
./meshtile --region den # Denver (default)
./meshtile --region oma # Omaha
./meshtile --region pnw # Pacific Northwest
./meshtile --region yyc # Calgary
The full list of available regions is at meshmapper.net. The --nodes and --noise-data flags override the region-based URLs if you need a custom source.
| Flag | Default | Description |
|---|---|---|
--climate | 5 | ITM climate code (1=Equatorial, 2=Continental Subtropical, 3=Maritime Tropical, 4=Desert, 5=Continental Temperate, 6=Maritime Temperate Over Land, 7=Maritime Temperate Over Sea) |
--refractivity | 301.0 | Surface refractivity (N-units) |
--ground-dielectric | 15.0 | Ground dielectric constant |
--ground-conductivity | 0.005 | Ground conductivity (S/m) |
--clutter-height | 0.0 | Ground clutter height in meters (trees, buildings) |
--time-pct | 50.0 | ITM time variability (0-100%) |
--location-pct | 50.0 | ITM location variability (0-100%) |
--situation-pct | 50.0 | ITM situation variability (0-100%) |
| Flag | Default | Description |
|---|---|---|
--colormap | plasma | Tile colormap: plasma, red_yellow_green, viridis, turbo, inferno |
./meshtile --port 9090 --climate 6 --clutter-height 2 --colormap plasma
All effective parameters are logged at startup, whether set explicitly or left at defaults.
| Endpoint | Description |
|---|---|
GET /tiles/{z}/{x}/{y}.png | Signal coverage + node markers (256x256 RGBA PNG) |
GET /signal/{z}/{x}/{y}.png | Signal coverage only |
GET /nodes/{z}/{x}/{y}.png | Node markers only |
GET /overlay.kml | KML network link for Google Earth |
GET /health | Health check |
In Google Earth: hamburger menu > Map Style > Add Tile Overlay > http://host:port/tiles/{z}/{x}/{y}.png
~/.cache/meshtile/<region>/grids/~/.cache/meshtile/<region>/tiles/~/.cache/mesh3d/hgt/ (shared with mesh3d)docker build -t meshtile .
docker run -v meshtile-cache:/data/.cache -p 8080:8080 meshtile --region den
Or with Docker Compose:
services:
meshtile:
image: stevenlafl/meshtile
ports:
- "8080:8080"
volumes:
- meshtile-cache:/data/.cache
command: ["--region", "den"]
volumes:
meshtile-cache:
docker compose up
The cache volume persists signal grids and HGT elevation data across container restarts, avoiding expensive recomputation. Each region gets its own cache namespace within the volume.
max_range km| Library | Purpose |
|---|---|
| NTIA ITM | Longley-Rice propagation model |
| cpp-httplib | HTTP server |
| nlohmann/json | JSON parsing |
| lodepng | PNG encoding |
| libcurl | HTTP client |
| zlib | Gzip decompression |
MIT. See LICENSE for details.
Third-party dependency licenses are listed in THIRD_PARTY_LICENSES.
Content type
Image
Digest
sha256:ca506cba6…
Size
32.6 MB
Last updated
7 months ago
docker pull stevenlafl/meshtile