A high-precision, community-driven signal mapping suite for Meshcore radios. This project uses a Cloud Bridge architecture to manage data persistence and signal logic centrally.
- 2-Day Sticky Signal: If a grid square has recorded a successful node discovery within the last 48 hours, it will remain "Green." New "No Signal" reports will be ignored for that square until the 48-hour window expires.
- 10-Entry History: Each grid square stores exactly the last 10 signal reports, including SNR, RSSI, and the Observer ID.
- Precision GPS: Polls high-speed hardware GPS from the mobile device via Termux only during active discovery.
- GitHub: Upload the server.js, root package.json, and the client/ folder to a repository.
- New Service: On the Render Dashboard, create a Web Service and link your repository.
- Environment:
- Runtime: Node
- Build Command: npm install && cd client && npm install && npm run build
- Start Command: node server.js
- Variables: In the 'Environment' tab, add PORT with value 10000.
The bridge acts as the link between your Radio hardware and the Render Cloud.
Open Termux and run these two commands:
pkg update && pkg upgrade
pkg install nodejs termux-api
Install the hardware interface tool globally:
npm install -g meshcore-cli
Note: Ensure your phone has hotspot enabled and connect the Node to your hotspot.
Run these commands to set up the bridge folder and initialize the script:
mkdir mesh-bridge && cd mesh-bridge
npm install socket.io-client
nano bridge.js
Paste the JavaScript code below into the editor, then press CTRL+O, Enter, and CTRL+X to save:
import { spawn, exec } from 'child_process';
import { io } from 'socket.io-client';
import readline from 'readline';
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
console.log("\x1b[35m--- Meshcore Bridge Setup ---\x1b[0m");
rl.question('Node IP (default: 10.38.109.27): ', (ip) => {
rl.question('Node Port (default: 5000): ', (port) => {
rl.question('Station/Mapper Name: ', (name) => {
const config = {
ip: ip || '10.38.109.27',
port: port || '5000',
name: name || 'Surveyor_Alpha'
};
const socket = io("https://meshcore-coverage-map.onrender.com");
socket.on('connect', () => {
socket.emit('join-room', config.name);
console.log(`\n\x1b[32m[LIVE]\x1b[0m Connected to Render as: ${config.name}`);
});
socket.on('command', (cmd) => {
if (cmd.type === 'EXEC_DISCOVER') {
console.log("\x1b[33m[SCAN]\x1b[0m App triggered node_discover...");
const cli = spawn('meshcore-cli', ['-t', config.ip, '-p', config.port, 'nd']);
cli.stdout.on('data', (data) => {
const raw = data.toString();
if (raw.includes("RSSI:")) {
exec('termux-location -p gps -r once', (err, stdout) => {
const loc = err ? null : JSON.parse(stdout);
socket.emit('data-update', {
room: config.name,
preciseLoc: loc ? {lat: loc.latitude, lng: loc.longitude} : null,
nodes: [],
ts: Date.now(),
observer: config.name
});
console.log("\x1b[32m[SYNC]\x1b[0m Data pushed to cloud.");
});
}
});
}
});
});
});
});
node bridge.js
- Open the Render URL in your browser.
- Select "Install App" from your browser menu to save it as a PWA.
- Ensure your Termux Bridge is running and configured with your radio's IP.
- Tap SCAN AREA on the map to trigger a hardware discovery.