feat: parameterize community info (#55)

* feat: parameterize community info

* chore: restore test data and document env defaults

* also make default channel configurable
This commit is contained in:
l5y
2025-09-15 12:15:51 +02:00
committed by GitHub
parent 003db7c36a
commit da2e5fbde1
4 changed files with 45 additions and 15 deletions

View File

@@ -1,10 +1,10 @@
# potato-mesh
a simple meshtastic node dashboard for your local community. here: berlin mediumfast.
a simple meshtastic node dashboard for your local community.
demo: [potatomesh.net](https://potatomesh.net)
demo for berlin mediumfast: [potatomesh.net](https://potatomesh.net)
![screenshot of the first version](./scrot-0.1.png)
![screenshot of the first version](./scrot-0.1.png)
## status
@@ -24,7 +24,6 @@ what works:
what does not work _(yet):_
* posting nodes and messages to the api endpoints _(wip)_
* white-label for your community (need to updated some berlin-specific hardcoded stuff)
## requirements
@@ -81,6 +80,20 @@ Puma starting in single mode...
set `API_TOKEN` required for authorizations on the api post-endpoints (wip).
the web app can be configured with environment variables (defaults shown):
* `SITE_NAME` - title and header shown in the ui (default: "Meshtastic Berlin")
* `DEFAULT_CHANNEL` - default channel shown in the ui (default: "#MediumFast")
* `MAP_CENTER_LAT` / `MAP_CENTER_LON` - default map center coordinates (default: `52.502889` / `13.404194`)
* `MAX_NODE_DISTANCE_KM` - hide nodes farther than this distance from the center (default: `137`)
* `MATRIX_ROOM` - matrix room id for a footer link (default: `#meshtastic-berlin:matrix.org`)
example:
```bash
SITE_NAME="Meshtastic Berlin" MAP_CENTER_LAT=52.502889 MAP_CENTER_LON=13.404194 MAX_NODE_DISTANCE_KM=137 MATRIX_ROOM="#meshtastic-berlin:matrix.org" ./app.sh
```
## api
the web app contains an api:

View File

@@ -8,6 +8,14 @@ DB_PATH = ENV.fetch("MESH_DB", File.join(__dir__, "../data/mesh.db"))
WEEK_SECONDS = 7 * 24 * 60 * 60
set :public_folder, File.join(__dir__, "public")
set :views, File.join(__dir__, "views")
SITE_NAME = ENV.fetch("SITE_NAME", "Meshtastic Berlin")
DEFAULT_CHANNEL = ENV.fetch("DEFAULT_CHANNEL", "#MediumFast")
MAP_CENTER_LAT = ENV.fetch("MAP_CENTER_LAT", "52.502889").to_f
MAP_CENTER_LON = ENV.fetch("MAP_CENTER_LON", "13.404194").to_f
MAX_NODE_DISTANCE_KM = ENV.fetch("MAX_NODE_DISTANCE_KM", "137").to_f
MATRIX_ROOM = ENV.fetch("MATRIX_ROOM", "#meshtastic-berlin:matrix.org")
def query_nodes(limit)
db = SQLite3::Database.new(DB_PATH, readonly: true, results_as_hash: true)
@@ -155,5 +163,12 @@ ensure
end
get "/" do
send_file File.join(settings.public_folder, "index.html")
erb :index, locals: {
site_name: SITE_NAME,
default_channel: DEFAULT_CHANNEL,
map_center_lat: MAP_CENTER_LAT,
map_center_lon: MAP_CENTER_LON,
max_node_distance_km: MAX_NODE_DISTANCE_KM,
matrix_room: MATRIX_ROOM
}
end

0
web/public/.keep Normal file
View File

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Meshtastic Berlin</title>
<title><%= site_name %></title>
<!-- Leaflet CSS/JS (CDN) -->
<link
@@ -73,7 +73,7 @@
</style>
</head>
<body>
<h1>Meshtastic Berlin</h1>
<h1><%= site_name %></h1>
<div class="row meta">
<div>
<span id="refreshInfo"></span>
@@ -116,9 +116,11 @@
</table>
<footer>
PotatoMesh GitHub: <a href="https://github.com/l5yth/potato-mesh" target="_blank">l5yth/potato-mesh</a>
Meshtastic Berlin Matrix:
<a href="https://matrix.to/#/#meshtastic-berlin:matrix.org" target="_blank">#meshtastic-berlin:matrix.org</a>
PotatoMesh GitHub: <a href="https://github.com/l5yth/potato-mesh" target="_blank">l5yth/potato-mesh</a>
<% if matrix_room && !matrix_room.empty? %>
— <%= site_name %> Matrix:
<a href="https://matrix.to/#/<%= matrix_room %>" target="_blank"><%= matrix_room %></a>
<% end %>
</footer>
<script>
@@ -139,10 +141,10 @@
const NODE_LIMIT = 1000;
const CHAT_LIMIT = 1000;
const REFRESH_MS = 60000;
refreshInfo.textContent = `#MediumFast — auto-refresh every ${REFRESH_MS / 1000} seconds.`;
refreshInfo.textContent = `<%= default_channel %> — auto-refresh every ${REFRESH_MS / 1000} seconds.`;
const MAP_CENTER = L.latLng(52.502889, 13.404194);
const MAX_NODE_DISTANCE_KM = 137;
const MAP_CENTER = L.latLng(<%= map_center_lat %>, <%= map_center_lon %>);
const MAX_NODE_DISTANCE_KM = <%= max_node_distance_km %>;
const roleColors = Object.freeze({
CLIENT: '#A8D5BA',
@@ -167,7 +169,7 @@
attribution: '&copy; OpenStreetMap contributors &amp; Stadia Maps'
});
let tiles = lightTiles.addTo(map);
// Default view (Berlin center) until first data arrives
// Default view until first data arrives
map.setView(MAP_CENTER, 10);
const markersLayer = L.layerGroup().addTo(map);
@@ -483,7 +485,7 @@
const c = nodes.filter(n => n.last_heard && nowSec - Number(n.last_heard) <= w.secs).length;
return `${c}/${w.label}`;
}).join(', ');
refreshInfo.textContent = `#MediumFast — active nodes: ${counts} — auto-refresh every ${REFRESH_MS / 1000} seconds.`;
refreshInfo.textContent = `<%= default_channel %> — active nodes: ${counts} — auto-refresh every ${REFRESH_MS / 1000} seconds.`;
}
</script>
</body>