telemetry removed to use less bandwidth

This commit is contained in:
Nils
2025-09-13 15:22:32 +02:00
parent 2922c313a3
commit f69020ddfc
2 changed files with 37 additions and 53 deletions

View File

@@ -5,9 +5,9 @@ This script is a command bot that connects to a [MeshCore](https://github.com/me
> [!IMPORTANT] > [!IMPORTANT]
> To prevent spam in public channels, this bot only responds in private channels! > To prevent spam in public channels, this bot only responds in private channels!
The bot is also able to fetch and log status (uptime, TX air time, last SNR, noise floor...) and telemetry sensor data (currently only voltage) from a repeater node. The bot is also able to fetch and log status data (uptime, TX air time, last SNR, noise floor...) from a repeater node.
The status and telemetry data is logged to a Comma-Separated Values (CSV) file. The status data is logged to a Comma-Separated Values (CSV) file.
The interval at which the status and telemetry data is fetched can be configured. The interval at which the status data is fetched can be configured.
This bot is ideal for testing MeshCore setup with repeater and distance of communication. This bot is ideal for testing MeshCore setup with repeater and distance of communication.
| Client | Bot | | Client | Bot |
@@ -48,14 +48,14 @@ This bot is ideal for testing MeshCore setup with repeater and distance of commu
To run the bot use the following command: To run the bot use the following command:
```bash ```bash
node meshcore-bot.js --port [SERIAL_PORT] --repeater-public-key-prefix [REPEATER_PUBLIC_KEY_PREFIX] --repeater-password [REPEATER_PASSWORD] --repeater-interval [TELEMETRY_INTERVAL_MINUTES] --csv [CSV_FILE] node meshcore-bot.js --port [SERIAL_PORT] --repeater-public-key-prefix [REPEATER_PUBLIC_KEY_PREFIX] --repeater-password [REPEATER_PASSWORD] --repeater-interval [STATUS_INTERVAL_MINUTES] --csv [CSV_FILE]
``` ```
- `--port` or `-s` (optional): The serial port of the MeshCore device. Defaults to `/dev/cu.usbmodem1101`. - `--port` or `-s` (optional): The serial port of the MeshCore device. Defaults to `/dev/cu.usbmodem1101`.
- `--repeater-public-key-prefix` or `-r` (optional): The public key prefix of a repeater node to fetch status and telemetry from. If provided, this feature is enabled. - `--repeater-public-key-prefix` or `-r` (optional): The public key prefix of a repeater node to fetch status from. If provided, this feature is enabled.
- `--repeater-password` or `-p` (optional): The password for the repeater. By default, this is an empty string. - `--repeater-password` or `-p` (optional): The password for the repeater. By default, this is an empty string.
- `--repeater-interval` or `-i` (optional): The interval in minutes at which status and telemetry data is retrieved from the repeater. The default value is `15`. - `--repeater-interval` or `-i` (optional): The interval in minutes at which status data is retrieved from the repeater. The default value is `15`.
- `--csv` or `-c` (optional): The CSV file in which the repeater's status and telemetry data is to be logged. If this file is specified, the data will be logged in this file. - `--csv` or `-c` (optional): The CSV file in which the repeater's status data is to be logged. If this file is specified, the data will be logged in this file.
### Examples ### Examples
@@ -65,7 +65,7 @@ node meshcore-bot.js --port [SERIAL_PORT] --repeater-public-key-prefix [REPEATER
node meshcore-bot.js --port "/dev/ttyUSB0" node meshcore-bot.js --port "/dev/ttyUSB0"
``` ```
**With Repeater Status and Telemetry:** **With Repeater Status:**
```bash ```bash
node meshcore-bot.js \ node meshcore-bot.js \
@@ -74,7 +74,8 @@ node meshcore-bot.js \
--repeater-password "your-password" \ --repeater-password "your-password" \
--repeater-interval 30 --repeater-interval 30
``` ```
This will connect to the device on `/dev/ttyUSB0` and fetch telemetry from the specified repeater every 30 minutes.
This will connect to the device on `/dev/ttyUSB0` and fetch status data from the specified repeater every 30 minutes.
**With Repeater and CSV Logging:** **With Repeater and CSV Logging:**
@@ -84,17 +85,17 @@ node meshcore-bot.js \
--repeater-public-key-prefix "935c6b694200644710a374c250c76f7aed9ec2ff3e60261447d4eda7c246ce5d" \ --repeater-public-key-prefix "935c6b694200644710a374c250c76f7aed9ec2ff3e60261447d4eda7c246ce5d" \
--repeater-password "your-password" \ --repeater-password "your-password" \
--repeater-interval 30 \ --repeater-interval 30 \
--csv "telemetry.csv" --csv "status.csv"
``` ```
This will do the same as the previous example, but it will also log the telemetry data to `telemetry.csv`. This will do the same as the previous example, but it will also log the status data to `status.csv`.
Example CSV: Example CSV:
```csv ```csv
timestamp,lpp_volts,batt_milli_volts,curr_tx_queue_len,noise_floor,last_rssi,n_packets_recv,n_packets_sent,total_air_time_secs,total_up_time_secs,n_sent_flood,n_sent_direct,n_recv_flood,n_recv_direct,err_events,last_snr,n_direct_dups,n_flood_dups timestamp,batt_milli_volts,curr_tx_queue_len,noise_floor,last_rssi,n_packets_recv,n_packets_sent,total_air_time_secs,total_up_time_secs,n_sent_flood,n_sent_direct,n_recv_flood,n_recv_direct,err_events,last_snr,n_direct_dups,n_flood_dups
2025-09-12T19:06:07Z,3.97,3969,0,-111,-59,2029,1749,1399,700263,1672,77,1514,359,0,28,0,98 2025-09-12T19:06:07Z,3969,0,-111,-59,2029,1749,1399,700263,1672,77,1514,359,0,28,0,98
2025-09-12T19:08:32Z,3.96,3969,0,-110,-60,2033,1753,1401,700407,1676,77,1515,362,0,28,0,98 2025-09-12T19:08:32Z,3969,0,-110,-60,2033,1753,1401,700407,1676,77,1515,362,0,28,0,98
``` ```
### Commands ### Commands

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
import { Constants, NodeJSSerialConnection, CayenneLpp } from "@liamcottle/meshcore.js"; import { Constants, NodeJSSerialConnection } from "@liamcottle/meshcore.js";
import yargs from 'yargs'; import yargs from 'yargs';
import { hideBin } from 'yargs/helpers'; import { hideBin } from 'yargs/helpers';
import fs from 'fs'; import fs from 'fs';
@@ -19,7 +19,7 @@ const argv = yargs(hideBin(process.argv))
.option('repeaterPublicKeyPrefix', { .option('repeaterPublicKeyPrefix', {
alias: 'r', alias: 'r',
type: 'string', type: 'string',
description: 'Public key of the repeater to fetch telemetry from' description: 'Public key of the repeater to fetch status from'
}) })
.option('repeaterInterval', { .option('repeaterInterval', {
alias: 'i', alias: 'i',
@@ -36,7 +36,7 @@ const argv = yargs(hideBin(process.argv))
.option('csv', { .option('csv', {
alias: 'c', alias: 'c',
type: 'string', type: 'string',
description: 'CSV file to log telemetry to' description: 'CSV file to log status to'
}) })
.argv; .argv;
@@ -45,16 +45,16 @@ const argv = yargs(hideBin(process.argv))
const port = argv.port; const port = argv.port;
const repeaterPublicKeyPrefix = argv.repeaterPublicKeyPrefix; const repeaterPublicKeyPrefix = argv.repeaterPublicKeyPrefix;
const repeaterPassword = argv.repeaterPassword; const repeaterPassword = argv.repeaterPassword;
const telemetryIntervalMinutes = argv.repeaterInterval; const statusIntervalMinutes = argv.repeaterInterval;
const telemetryIntervalMs = telemetryIntervalMinutes * 60 * 1000; const statusIntervalMs = statusIntervalMinutes * 60 * 1000;
const csvFile = argv.csv; const csvFile = argv.csv;
console.log(`Connecting to ${port}`); console.log(`Connecting to ${port}`);
if(repeaterPublicKeyPrefix){ if(repeaterPublicKeyPrefix){
console.log(`Repeater public key prefix: ${repeaterPublicKeyPrefix}`); console.log(`Repeater public key prefix: ${repeaterPublicKeyPrefix}`);
console.log(`Telemetry interval: ${telemetryIntervalMinutes} minutes`); console.log(`Status interval: ${statusIntervalMinutes} minutes`);
if (csvFile) { if (csvFile) {
console.log(`Logging telemetry to: ${csvFile}`); console.log(`Logging status to: ${csvFile}`);
} }
} }
@@ -62,7 +62,7 @@ if(repeaterPublicKeyPrefix){
const connection = new NodeJSSerialConnection(port); const connection = new NodeJSSerialConnection(port);
let reconnectInterval; let reconnectInterval;
let telemetryInterval; let statusInterval;
// wait until connected // wait until connected
connection.on("connected", async () => { connection.on("connected", async () => {
@@ -122,12 +122,12 @@ connection.on("connected", async () => {
} }
if(repeaterPublicKeyPrefix){ if(repeaterPublicKeyPrefix){
// Start telemetry fetching interval // Start fetching interval
if (telemetryInterval) { if (statusInterval) {
clearInterval(telemetryInterval); clearInterval(statusInterval);
} }
telemetryInterval = setInterval(() => getRepeaterTelemetry(repeaterPublicKeyPrefix, repeaterPassword), telemetryIntervalMs); statusInterval = setInterval(() => getRepeater(repeaterPublicKeyPrefix, repeaterPassword), statusIntervalMs);
getRepeaterTelemetry(repeaterPublicKeyPrefix, repeaterPassword); // Also fetch immediately on connect getRepeater(repeaterPublicKeyPrefix, repeaterPassword); // Also fetch immediately on connect
} }
}); });
@@ -141,9 +141,9 @@ connection.on("disconnected", () => {
await connection.connect(); await connection.connect();
}, 3000); }, 3000);
if (telemetryInterval) { if (statusInterval) {
clearInterval(telemetryInterval); clearInterval(statusInterval);
telemetryInterval = null; statusInterval = null;
} }
}); });
@@ -192,8 +192,8 @@ connection.on(Constants.PushCodes.Advert, async (advert) => {
} }
}); });
async function getRepeaterTelemetry(publicKeyPrefix, repeaterPassword) { async function getRepeater(publicKeyPrefix, repeaterPassword) {
console.log("Fetching repeater status and telemetry..."); console.log("Fetching repeater status...");
try { try {
const contact = await connection.findContactByPublicKeyPrefix(Buffer.from(publicKeyPrefix, "hex")); const contact = await connection.findContactByPublicKeyPrefix(Buffer.from(publicKeyPrefix, "hex"));
if(!contact){ if(!contact){
@@ -201,35 +201,19 @@ async function getRepeaterTelemetry(publicKeyPrefix, repeaterPassword) {
return; return;
} }
// login to repeater and get repeater status telemetry // login to repeater and get repeater status
console.log("Logging in to repeater..."); console.log("Logging in to repeater...");
await connection.login(contact.publicKey, repeaterPassword); await connection.login(contact.publicKey, repeaterPassword);
// get repeater status // get repeater status
console.log("Fetching status..."); console.log("Fetching status...");
const timestamp = getTimestamp(); // Store timestamp of first fetch for CSV const timestamp = getTimestamp(); // Store timestamp of first fetch for CSV
const status = await connection.getStatus(contact.publicKey); const status = await connection.getStatus(contact.publicKey, 5000);
console.log(`[${timestamp}] Repeater status`, status); console.log(`[${timestamp}] Repeater status`, status);
// get repeater telemetry
console.log("Fetching telemetry...");
const telemetry = await connection.getTelemetry(contact.publicKey);
console.log(`[${getTimestamp()}] Repeater telemetry`, telemetry);
// parse telemetry
const parsedTelemetry = CayenneLpp.parse(telemetry.lppSensorData);
console.log(`[${getTimestamp()}] Decoded repeater telemetry`, parsedTelemetry);
// find battery voltage telemetry on channel 1
const lpp_volts = parsedTelemetry.find((item) => item.channel === 1 && item.type === CayenneLpp.LPP_VOLTAGE)?.value;
if(lpp_volts !== undefined) {
console.log(`LPP Voltage: ${lpp_volts} V`);
} else {
console.log("LPP Voltage not found in telemetry");
}
if (csvFile) { if (csvFile) {
console.log("Write to CSV file..."); console.log("Write to CSV file...");
const header = [ const header = [
'timestamp', 'timestamp',
'lpp_volts',
'batt_milli_volts', 'batt_milli_volts',
'curr_tx_queue_len', 'curr_tx_queue_len',
'noise_floor', 'noise_floor',
@@ -249,7 +233,6 @@ async function getRepeaterTelemetry(publicKeyPrefix, repeaterPassword) {
].join(',') + '\n'; ].join(',') + '\n';
const statusValues = [ const statusValues = [
timestamp, timestamp,
lpp_volts,
status.batt_milli_volts, status.batt_milli_volts,
status.curr_tx_queue_len, status.curr_tx_queue_len,
status.noise_floor, status.noise_floor,
@@ -274,7 +257,7 @@ async function getRepeaterTelemetry(publicKeyPrefix, repeaterPassword) {
} }
console.log("Done, waiting for the next interval."); console.log("Done, waiting for the next interval.");
} catch(e) { } catch(e) {
console.error("Error fetching repeater status or telemetry", e); console.error("Error fetching repeater status!", e);
} }
} }