mirror of
https://github.com/Cyclenerd/meshcore-bot.git
synced 2026-03-28 17:42:46 +01:00
telemetry removed to use less bandwidth
This commit is contained in:
29
README.md
29
README.md
@@ -5,9 +5,9 @@ This script is a command bot that connects to a [MeshCore](https://github.com/me
|
||||
> [!IMPORTANT]
|
||||
> 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 status and telemetry 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 bot is also able to fetch and log status data (uptime, TX air time, last SNR, noise floor...) from a repeater node.
|
||||
The status data is logged to a Comma-Separated Values (CSV) file.
|
||||
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.
|
||||
|
||||
| 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:
|
||||
|
||||
```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`.
|
||||
- `--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-interval` or `-i` (optional): The interval in minutes at which status and telemetry 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.
|
||||
- `--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 data is to be logged. If this file is specified, the data will be logged in this file.
|
||||
|
||||
### Examples
|
||||
|
||||
@@ -65,7 +65,7 @@ node meshcore-bot.js --port [SERIAL_PORT] --repeater-public-key-prefix [REPEATER
|
||||
node meshcore-bot.js --port "/dev/ttyUSB0"
|
||||
```
|
||||
|
||||
**With Repeater Status and Telemetry:**
|
||||
**With Repeater Status:**
|
||||
|
||||
```bash
|
||||
node meshcore-bot.js \
|
||||
@@ -74,7 +74,8 @@ node meshcore-bot.js \
|
||||
--repeater-password "your-password" \
|
||||
--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:**
|
||||
|
||||
@@ -84,17 +85,17 @@ node meshcore-bot.js \
|
||||
--repeater-public-key-prefix "935c6b694200644710a374c250c76f7aed9ec2ff3e60261447d4eda7c246ce5d" \
|
||||
--repeater-password "your-password" \
|
||||
--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:
|
||||
|
||||
```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
|
||||
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:08:32Z,3.96,3969,0,-110,-60,2033,1753,1401,700407,1676,77,1515,362,0,28,0,98
|
||||
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,3969,0,-111,-59,2029,1749,1399,700263,1672,77,1514,359,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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { Constants, NodeJSSerialConnection, CayenneLpp } from "@liamcottle/meshcore.js";
|
||||
import { Constants, NodeJSSerialConnection } from "@liamcottle/meshcore.js";
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import fs from 'fs';
|
||||
@@ -19,7 +19,7 @@ const argv = yargs(hideBin(process.argv))
|
||||
.option('repeaterPublicKeyPrefix', {
|
||||
alias: 'r',
|
||||
type: 'string',
|
||||
description: 'Public key of the repeater to fetch telemetry from'
|
||||
description: 'Public key of the repeater to fetch status from'
|
||||
})
|
||||
.option('repeaterInterval', {
|
||||
alias: 'i',
|
||||
@@ -36,7 +36,7 @@ const argv = yargs(hideBin(process.argv))
|
||||
.option('csv', {
|
||||
alias: 'c',
|
||||
type: 'string',
|
||||
description: 'CSV file to log telemetry to'
|
||||
description: 'CSV file to log status to'
|
||||
})
|
||||
.argv;
|
||||
|
||||
@@ -45,16 +45,16 @@ const argv = yargs(hideBin(process.argv))
|
||||
const port = argv.port;
|
||||
const repeaterPublicKeyPrefix = argv.repeaterPublicKeyPrefix;
|
||||
const repeaterPassword = argv.repeaterPassword;
|
||||
const telemetryIntervalMinutes = argv.repeaterInterval;
|
||||
const telemetryIntervalMs = telemetryIntervalMinutes * 60 * 1000;
|
||||
const statusIntervalMinutes = argv.repeaterInterval;
|
||||
const statusIntervalMs = statusIntervalMinutes * 60 * 1000;
|
||||
const csvFile = argv.csv;
|
||||
|
||||
console.log(`Connecting to ${port}`);
|
||||
if(repeaterPublicKeyPrefix){
|
||||
console.log(`Repeater public key prefix: ${repeaterPublicKeyPrefix}`);
|
||||
console.log(`Telemetry interval: ${telemetryIntervalMinutes} minutes`);
|
||||
console.log(`Status interval: ${statusIntervalMinutes} minutes`);
|
||||
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);
|
||||
|
||||
let reconnectInterval;
|
||||
let telemetryInterval;
|
||||
let statusInterval;
|
||||
|
||||
// wait until connected
|
||||
connection.on("connected", async () => {
|
||||
@@ -122,12 +122,12 @@ connection.on("connected", async () => {
|
||||
}
|
||||
|
||||
if(repeaterPublicKeyPrefix){
|
||||
// Start telemetry fetching interval
|
||||
if (telemetryInterval) {
|
||||
clearInterval(telemetryInterval);
|
||||
// Start fetching interval
|
||||
if (statusInterval) {
|
||||
clearInterval(statusInterval);
|
||||
}
|
||||
telemetryInterval = setInterval(() => getRepeaterTelemetry(repeaterPublicKeyPrefix, repeaterPassword), telemetryIntervalMs);
|
||||
getRepeaterTelemetry(repeaterPublicKeyPrefix, repeaterPassword); // Also fetch immediately on connect
|
||||
statusInterval = setInterval(() => getRepeater(repeaterPublicKeyPrefix, repeaterPassword), statusIntervalMs);
|
||||
getRepeater(repeaterPublicKeyPrefix, repeaterPassword); // Also fetch immediately on connect
|
||||
}
|
||||
});
|
||||
|
||||
@@ -141,9 +141,9 @@ connection.on("disconnected", () => {
|
||||
await connection.connect();
|
||||
}, 3000);
|
||||
|
||||
if (telemetryInterval) {
|
||||
clearInterval(telemetryInterval);
|
||||
telemetryInterval = null;
|
||||
if (statusInterval) {
|
||||
clearInterval(statusInterval);
|
||||
statusInterval = null;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -192,8 +192,8 @@ connection.on(Constants.PushCodes.Advert, async (advert) => {
|
||||
}
|
||||
});
|
||||
|
||||
async function getRepeaterTelemetry(publicKeyPrefix, repeaterPassword) {
|
||||
console.log("Fetching repeater status and telemetry...");
|
||||
async function getRepeater(publicKeyPrefix, repeaterPassword) {
|
||||
console.log("Fetching repeater status...");
|
||||
try {
|
||||
const contact = await connection.findContactByPublicKeyPrefix(Buffer.from(publicKeyPrefix, "hex"));
|
||||
if(!contact){
|
||||
@@ -201,35 +201,19 @@ async function getRepeaterTelemetry(publicKeyPrefix, repeaterPassword) {
|
||||
return;
|
||||
}
|
||||
|
||||
// login to repeater and get repeater status telemetry
|
||||
// login to repeater and get repeater status
|
||||
console.log("Logging in to repeater...");
|
||||
await connection.login(contact.publicKey, repeaterPassword);
|
||||
// get repeater status
|
||||
console.log("Fetching status...");
|
||||
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);
|
||||
// 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) {
|
||||
console.log("Write to CSV file...");
|
||||
const header = [
|
||||
'timestamp',
|
||||
'lpp_volts',
|
||||
'batt_milli_volts',
|
||||
'curr_tx_queue_len',
|
||||
'noise_floor',
|
||||
@@ -249,7 +233,6 @@ async function getRepeaterTelemetry(publicKeyPrefix, repeaterPassword) {
|
||||
].join(',') + '\n';
|
||||
const statusValues = [
|
||||
timestamp,
|
||||
lpp_volts,
|
||||
status.batt_milli_volts,
|
||||
status.curr_tx_queue_len,
|
||||
status.noise_floor,
|
||||
@@ -274,7 +257,7 @@ async function getRepeaterTelemetry(publicKeyPrefix, repeaterPassword) {
|
||||
}
|
||||
console.log("Done, waiting for the next interval.");
|
||||
} catch(e) {
|
||||
console.error("Error fetching repeater status or telemetry", e);
|
||||
console.error("Error fetching repeater status!", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user