Skip to content

Commit 6efc3d7

Browse files
authored
Merge pull request #6 from MrAlders0n/copilot/add-meshmapper-api-post
Add automatic MeshMapper API posting on every ping
2 parents 15473f2 + 8c20911 commit 6efc3d7

6 files changed

Lines changed: 150 additions & 3 deletions

File tree

‎.github/workflows/deploy.yml‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
pages: write
12+
id-token: write
13+
14+
concurrency:
15+
group: "pages"
16+
cancel-in-progress: false
17+
18+
jobs:
19+
deploy:
20+
environment:
21+
name: github-pages
22+
url: ${{ steps.deployment.outputs.page_url }}
23+
runs-on: ubuntu-latest
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@v4
27+
28+
- name: Create config.js with API key from secrets
29+
env:
30+
API_KEY: ${{ secrets.MESHMAPPER_API_KEY }}
31+
run: |
32+
{
33+
echo "// MeshMapper API Configuration"
34+
echo "// This file is auto-generated during deployment from GitHub Secrets"
35+
node -e "console.log('window.MESHMAPPER_API_KEY = ' + JSON.stringify(process.env.API_KEY) + ';')"
36+
} > content/config.js
37+
38+
- name: Setup Pages
39+
uses: actions/configure-pages@v4
40+
41+
- name: Upload artifact
42+
uses: actions/upload-pages-artifact@v3
43+
with:
44+
path: '.'
45+
46+
- name: Deploy to GitHub Pages
47+
id: deployment
48+
uses: actions/deploy-pages@v4

‎.gitignore‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# MeshMapper API configuration (contains sensitive API key)
2+
content/config.js
3+
4+
# Node modules (if added in the future)
5+
node_modules/
6+
7+
# Build artifacts
8+
dist/
9+
build/
10+
11+
# Editor files
12+
.vscode/
13+
.idea/
14+
*.swp
15+
*.swo
16+
*~
17+
18+
# OS files
19+
.DS_Store
20+
Thumbs.db

‎README.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ Pings are sent to the wardriving MeshCore channel to build community coverage ma
101101
- **Screen Wake Lock API** - Power management
102102
- **Tailwind CSS** - Responsive UI design
103103
- **PWA Ready** - Progressive Web App manifest
104+
- **MeshMapper API Integration** - Automatic ping data posting for mesh network comparison
105+
106+
---
107+
108+
## 🔐 MeshMapper API Integration
109+
110+
This app automatically posts ping data to the YOW MeshMapper API to help compare if messages were received on the mesh. The API key is securely stored in GitHub Secrets.
104111

105112
---
106113

‎content/config.template.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// MeshMapper API Configuration
2+
// This file contains the API key for posting to MeshMapper API
3+
// Set MESHMAPPER_API_KEY to your actual API key
4+
window.MESHMAPPER_API_KEY = "YOUR_API_KEY_HERE";

‎content/wardrive.js‎

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ const WARDROVE_KEY = new Uint8Array([
1818
0xA9, 0x3F, 0x06, 0x60, 0x27, 0x32, 0x0F, 0xE5
1919
]);
2020

21+
// MeshMapper API Configuration
22+
const MESHMAPPER_API_URL = "https://yow.meshmapper.net/wardriving-api.php";
23+
// DO NOT EDIT: This placeholder is used to detect if the API key is configured
24+
const MESHMAPPER_API_KEY_PLACEHOLDER = "YOUR_API_KEY_HERE";
25+
// The API key is automatically injected from GitHub Secrets during deployment via config.js
26+
// You do NOT need to edit this file - just set MESHMAPPER_API_KEY in GitHub Secrets
27+
const MESHMAPPER_API_KEY = window.MESHMAPPER_API_KEY || MESHMAPPER_API_KEY_PLACEHOLDER;
28+
const MESHMAPPER_DEFAULT_WHO = "GOME-WarDriver"; // Default identifier
29+
2130
// ---- DOM refs (from index.html; unchanged except the two new selectors) ----
2231
const $ = (id) => document.getElementById(id);
2332
const statusEl = $("status");
@@ -333,14 +342,67 @@ function getGpsMaximumAge(minAge = 1000) {
333342
return Math.max(minAge, intervalMs - GPS_FRESHNESS_BUFFER_MS);
334343
}
335344

345+
function getCurrentPowerSetting() {
346+
const checkedPower = document.querySelector('input[name="power"]:checked');
347+
return checkedPower ? checkedPower.value : "";
348+
}
349+
336350
function buildPayload(lat, lon) {
337351
const coordsStr = `${lat.toFixed(5)}, ${lon.toFixed(5)}`;
338-
const checkedPower = document.querySelector('input[name="power"]:checked');
339-
const power = checkedPower ? checkedPower.value : "";
340-
const suffix = power ? ` [${power}]` : "";
352+
const power = getCurrentPowerSetting();
353+
const suffix = power ? ` [${power}]` : "";
341354
return `${PING_PREFIX} ${coordsStr} ${suffix}`;
342355
}
343356

357+
// ---- MeshMapper API ----
358+
async function postToMeshMapperAPI(lat, lon) {
359+
try {
360+
// Skip if API key is placeholder (not configured)
361+
if (!MESHMAPPER_API_KEY || MESHMAPPER_API_KEY === MESHMAPPER_API_KEY_PLACEHOLDER) {
362+
console.log("MeshMapper API key not configured, skipping API post");
363+
return;
364+
}
365+
366+
// Get current power setting
367+
const power = getCurrentPowerSetting();
368+
const powerValue = power || "N/A";
369+
370+
// Use device name if available, otherwise use default
371+
const deviceText = deviceInfoEl?.textContent;
372+
const whoIdentifier = (deviceText && deviceText !== "—") ? deviceText : MESHMAPPER_DEFAULT_WHO;
373+
374+
// Build API payload
375+
const payload = {
376+
key: MESHMAPPER_API_KEY,
377+
lat: lat,
378+
lon: lon,
379+
who: whoIdentifier,
380+
power: powerValue,
381+
test: 1
382+
};
383+
384+
console.log("Posting to MeshMapper API:", { lat, lon, who: whoIdentifier, power: powerValue });
385+
386+
// POST to MeshMapper API
387+
const response = await fetch(MESHMAPPER_API_URL, {
388+
method: "POST",
389+
headers: {
390+
"Content-Type": "application/json"
391+
},
392+
body: JSON.stringify(payload)
393+
});
394+
395+
if (!response.ok) {
396+
console.warn(`MeshMapper API returned status ${response.status}`);
397+
} else {
398+
console.log("Successfully posted to MeshMapper API");
399+
}
400+
} catch (error) {
401+
// Log error but don't fail the ping
402+
console.error("Failed to post to MeshMapper API:", error);
403+
}
404+
}
405+
344406
// ---- Ping ----
345407
async function sendPing(manual = false) {
346408
try {
@@ -374,6 +436,10 @@ async function sendPing(manual = false) {
374436
const ch = await ensureChannel();
375437
await state.connection.sendChannelTextMessage(ch.channelIdx, payload);
376438

439+
// Post to MeshMapper API (fire-and-forget pattern: non-blocking, errors are logged inside the function)
440+
// Not awaited intentionally to avoid delaying the ping flow
441+
postToMeshMapperAPI(lat, lon);
442+
377443
// Only refresh coverage iframe if GPS accuracy is good
378444
if (accuracy && accuracy < GPS_ACCURACY_THRESHOLD_M) {
379445
scheduleCoverageRefresh(lat, lon);

‎index.html‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ <h2 id="sessionPingsHeading" class="text-sm font-medium">Session Pings</h2>
196196
</div>
197197
</main>
198198

199+
<!-- Load config before main script -->
200+
<script src="content/config.js"></script>
199201
<script type="module" src="content/wardrive.js"></script>
200202
<script type="module">
201203
import { onLoad } from '/content/wardrive.js';

0 commit comments

Comments
 (0)