mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
* repeater and room server: new CLI command: "set advert.interval {mins}"
This commit is contained in:
parent
5395214ef2
commit
5fb83c9bf7
2 changed files with 126 additions and 24 deletions
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
/* ------------------------------ Config -------------------------------- */
|
||||
|
||||
#define FIRMWARE_VER_TEXT "v3 (build: 4 Feb 2025)"
|
||||
#define FIRMWARE_VER_TEXT "v3 (build: 8 Feb 2025)"
|
||||
|
||||
#ifndef LORA_FREQ
|
||||
#define LORA_FREQ 915.0
|
||||
|
|
@ -51,6 +51,8 @@
|
|||
#define ADMIN_PASSWORD "password"
|
||||
#endif
|
||||
|
||||
#define MIN_LOCAL_ADVERT_INTERVAL 8
|
||||
|
||||
#if defined(HELTEC_LORA_V3)
|
||||
#include <helpers/HeltecV3Board.h>
|
||||
#include <helpers/CustomSX1262Wrapper.h>
|
||||
|
|
@ -121,13 +123,15 @@ struct NodePrefs { // persisted to file
|
|||
float freq;
|
||||
uint8_t tx_power_dbm;
|
||||
uint8_t disable_fwd;
|
||||
uint8_t unused[2];
|
||||
uint8_t advert_interval; // minutes
|
||||
uint8_t unused;
|
||||
};
|
||||
|
||||
class MyMesh : public mesh::Mesh {
|
||||
RadioLibWrapper* my_radio;
|
||||
FILESYSTEM* _fs;
|
||||
mesh::MainBoard* _board;
|
||||
unsigned long next_local_advert;
|
||||
NodePrefs _prefs;
|
||||
uint8_t reply_data[MAX_PACKET_PAYLOAD];
|
||||
int num_clients;
|
||||
|
|
@ -185,6 +189,31 @@ class MyMesh : public mesh::Mesh {
|
|||
return 0; // reply_len
|
||||
}
|
||||
|
||||
void checkAdvertInterval() {
|
||||
if (_prefs.advert_interval < MIN_LOCAL_ADVERT_INTERVAL) {
|
||||
_prefs.advert_interval = 0; // turn it off, now that device has been manually configured
|
||||
}
|
||||
}
|
||||
|
||||
void updateAdvertTimer() {
|
||||
if (_prefs.advert_interval > 0) { // schedule local advert timer
|
||||
next_local_advert = futureMillis(_prefs.advert_interval * 60 * 1000);
|
||||
} else {
|
||||
next_local_advert = 0; // stop the timer
|
||||
}
|
||||
}
|
||||
|
||||
mesh::Packet* createSelfAdvert() {
|
||||
uint8_t app_data[MAX_ADVERT_DATA_SIZE];
|
||||
uint8_t app_data_len;
|
||||
{
|
||||
AdvertDataBuilder builder(ADV_TYPE_REPEATER, _prefs.node_name, _prefs.node_lat, _prefs.node_lon);
|
||||
app_data_len = builder.encodeTo(app_data);
|
||||
}
|
||||
|
||||
return createAdvert(self_id, app_data, app_data_len);
|
||||
}
|
||||
|
||||
protected:
|
||||
float getAirtimeBudgetFactor() const override {
|
||||
return _prefs.airtime_factor;
|
||||
|
|
@ -369,6 +398,7 @@ public:
|
|||
{
|
||||
my_radio = &radio;
|
||||
num_clients = 0;
|
||||
next_local_advert = 0;
|
||||
|
||||
// defaults
|
||||
memset(&_prefs, 0, sizeof(_prefs));
|
||||
|
|
@ -381,6 +411,7 @@ public:
|
|||
_prefs.password[sizeof(_prefs.password)-1] = 0; // truncate if necessary
|
||||
_prefs.freq = LORA_FREQ;
|
||||
_prefs.tx_power_dbm = LORA_TX_POWER;
|
||||
_prefs.advert_interval = 2; // default to 2 minutes for NEW installs
|
||||
}
|
||||
|
||||
float getFreqPref() const { return _prefs.freq; }
|
||||
|
|
@ -397,6 +428,8 @@ public:
|
|||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
updateAdvertTimer();
|
||||
}
|
||||
|
||||
void savePrefs() {
|
||||
|
|
@ -413,14 +446,7 @@ public:
|
|||
}
|
||||
|
||||
void sendSelfAdvertisement(int delay_millis) {
|
||||
uint8_t app_data[MAX_ADVERT_DATA_SIZE];
|
||||
uint8_t app_data_len;
|
||||
{
|
||||
AdvertDataBuilder builder(ADV_TYPE_REPEATER, _prefs.node_name, _prefs.node_lat, _prefs.node_lon);
|
||||
app_data_len = builder.encodeTo(app_data);
|
||||
}
|
||||
|
||||
mesh::Packet* pkt = createAdvert(self_id, app_data, app_data_len);
|
||||
mesh::Packet* pkt = createSelfAdvert();
|
||||
if (pkt) {
|
||||
sendFlood(pkt, delay_millis);
|
||||
} else {
|
||||
|
|
@ -428,6 +454,19 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
mesh::Mesh::loop();
|
||||
|
||||
if (next_local_advert && millisHasNowPassed(next_local_advert)) {
|
||||
mesh::Packet* pkt = createSelfAdvert();
|
||||
if (pkt) {
|
||||
sendZeroHop(pkt);
|
||||
}
|
||||
|
||||
updateAdvertTimer(); // schedule next local advert
|
||||
}
|
||||
}
|
||||
|
||||
void handleCommand(uint32_t sender_timestamp, const char* command, char reply[]) {
|
||||
while (*command == ' ') command++; // skip leading spaces
|
||||
|
||||
|
|
@ -467,6 +506,7 @@ public:
|
|||
// change admin password
|
||||
strncpy(_prefs.password, &command[9], sizeof(_prefs.password)-1);
|
||||
_prefs.password[sizeof(_prefs.password)-1] = 0; // truncate if necesary
|
||||
checkAdvertInterval();
|
||||
savePrefs();
|
||||
sprintf(reply, "password now: %s", _prefs.password); // echo back just to let admin know for sure!!
|
||||
} else if (memcmp(command, "set ", 4) == 0) {
|
||||
|
|
@ -475,9 +515,22 @@ public:
|
|||
_prefs.airtime_factor = atof(&config[3]);
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else if (memcmp(config, "advert.interval ", 16) == 0) {
|
||||
int mins = _atoi(&config[16]);
|
||||
if (mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) {
|
||||
sprintf(reply, "Error: min is %d mins", MIN_LOCAL_ADVERT_INTERVAL);
|
||||
} else if (mins > 120) {
|
||||
strcpy(reply, "Error: max is 120 mins");
|
||||
} else {
|
||||
_prefs.advert_interval = (uint8_t)mins;
|
||||
updateAdvertTimer();
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
}
|
||||
} else if (memcmp(config, "name ", 5) == 0) {
|
||||
strncpy(_prefs.node_name, &config[5], sizeof(_prefs.node_name)-1);
|
||||
_prefs.node_name[sizeof(_prefs.node_name)-1] = 0; // truncate if nec
|
||||
checkAdvertInterval();
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else if (memcmp(config, "repeat ", 7) == 0) {
|
||||
|
|
@ -486,10 +539,12 @@ public:
|
|||
strcpy(reply, _prefs.disable_fwd ? "OK - repeat is now OFF" : "OK - repeat is now ON");
|
||||
} else if (memcmp(config, "lat ", 4) == 0) {
|
||||
_prefs.node_lat = atof(&config[4]);
|
||||
checkAdvertInterval();
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else if (memcmp(config, "lon ", 4) == 0) {
|
||||
_prefs.node_lon = atof(&config[4]);
|
||||
checkAdvertInterval();
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else if (memcmp(config, "tx ", 3) == 0) {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
/* ------------------------------ Config -------------------------------- */
|
||||
|
||||
#define FIRMWARE_VER_TEXT "v4 (build: 4 Feb 2025)"
|
||||
#define FIRMWARE_VER_TEXT "v4 (build: 8 Feb 2025)"
|
||||
|
||||
#ifndef LORA_FREQ
|
||||
#define LORA_FREQ 915.0
|
||||
|
|
@ -59,6 +59,8 @@
|
|||
#define MAX_UNSYNCED_POSTS 16
|
||||
#endif
|
||||
|
||||
#define MIN_LOCAL_ADVERT_INTERVAL 8
|
||||
|
||||
|
||||
#if defined(HELTEC_LORA_V3)
|
||||
#include <helpers/HeltecV3Board.h>
|
||||
|
|
@ -138,12 +140,14 @@ struct NodePrefs { // persisted to file
|
|||
float freq;
|
||||
uint8_t tx_power_dbm;
|
||||
uint8_t disable_fwd;
|
||||
uint8_t unused[2];
|
||||
uint8_t advert_interval; // minutes
|
||||
uint8_t unused;
|
||||
};
|
||||
|
||||
class MyMesh : public mesh::Mesh {
|
||||
RadioLibWrapper* my_radio;
|
||||
FILESYSTEM* _fs;
|
||||
unsigned long next_local_advert;
|
||||
NodePrefs _prefs;
|
||||
uint8_t reply_data[MAX_PACKET_PAYLOAD];
|
||||
int num_clients;
|
||||
|
|
@ -242,6 +246,31 @@ class MyMesh : public mesh::Mesh {
|
|||
return false;
|
||||
}
|
||||
|
||||
void checkAdvertInterval() {
|
||||
if (_prefs.advert_interval < MIN_LOCAL_ADVERT_INTERVAL) {
|
||||
_prefs.advert_interval = 0; // turn it off, now that device has been manually configured
|
||||
}
|
||||
}
|
||||
|
||||
void updateAdvertTimer() {
|
||||
if (_prefs.advert_interval > 0) { // schedule local advert timer
|
||||
next_local_advert = futureMillis(_prefs.advert_interval * 60 * 1000);
|
||||
} else {
|
||||
next_local_advert = 0; // stop the timer
|
||||
}
|
||||
}
|
||||
|
||||
mesh::Packet* createSelfAdvert() {
|
||||
uint8_t app_data[MAX_ADVERT_DATA_SIZE];
|
||||
uint8_t app_data_len;
|
||||
{
|
||||
AdvertDataBuilder builder(ADV_TYPE_ROOM, _prefs.node_name, _prefs.node_lat, _prefs.node_lon);
|
||||
app_data_len = builder.encodeTo(app_data);
|
||||
}
|
||||
|
||||
return createAdvert(self_id, app_data, app_data_len);
|
||||
}
|
||||
|
||||
protected:
|
||||
float getAirtimeBudgetFactor() const override {
|
||||
return _prefs.airtime_factor;
|
||||
|
|
@ -480,6 +509,7 @@ public:
|
|||
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables)
|
||||
{
|
||||
my_radio = &radio;
|
||||
next_local_advert = 0;
|
||||
|
||||
// defaults
|
||||
memset(&_prefs, 0, sizeof(_prefs));
|
||||
|
|
@ -493,6 +523,7 @@ public:
|
|||
_prefs.freq = LORA_FREQ;
|
||||
_prefs.tx_power_dbm = LORA_TX_POWER;
|
||||
_prefs.disable_fwd = 1;
|
||||
_prefs.advert_interval = 2; // default to 2 minutes for NEW installs
|
||||
|
||||
num_clients = 0;
|
||||
next_post_idx = 0;
|
||||
|
|
@ -515,6 +546,8 @@ public:
|
|||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
updateAdvertTimer();
|
||||
}
|
||||
|
||||
void savePrefs() {
|
||||
|
|
@ -530,17 +563,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void sendSelfAdvertisement() {
|
||||
uint8_t app_data[MAX_ADVERT_DATA_SIZE];
|
||||
uint8_t app_data_len;
|
||||
{
|
||||
AdvertDataBuilder builder(ADV_TYPE_ROOM, _prefs.node_name, _prefs.node_lat, _prefs.node_lon);
|
||||
app_data_len = builder.encodeTo(app_data);
|
||||
}
|
||||
|
||||
mesh::Packet* pkt = createAdvert(self_id, app_data, app_data_len);
|
||||
void sendSelfAdvertisement(int delay_millis) {
|
||||
mesh::Packet* pkt = createSelfAdvert();
|
||||
if (pkt) {
|
||||
sendFlood(pkt, 1200); // add slight delay
|
||||
sendFlood(pkt, delay_millis);
|
||||
} else {
|
||||
MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!");
|
||||
}
|
||||
|
|
@ -552,7 +578,7 @@ public:
|
|||
if (memcmp(command, "reboot", 6) == 0) {
|
||||
board.reboot(); // doesn't return
|
||||
} else if (memcmp(command, "advert", 6) == 0) {
|
||||
sendSelfAdvertisement();
|
||||
sendSelfAdvertisement(400);
|
||||
strcpy(reply, "OK - Advert sent");
|
||||
} else if (memcmp(command, "clock sync", 10) == 0) {
|
||||
uint32_t curr = getRTCClock()->getCurrentTime();
|
||||
|
|
@ -587,6 +613,18 @@ public:
|
|||
_prefs.airtime_factor = atof(&config[3]);
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else if (memcmp(config, "advert.interval ", 16) == 0) {
|
||||
int mins = _atoi(&config[16]);
|
||||
if (mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) {
|
||||
sprintf(reply, "Error: min is %d mins", MIN_LOCAL_ADVERT_INTERVAL);
|
||||
} else if (mins > 120) {
|
||||
strcpy(reply, "Error: max is 120 mins");
|
||||
} else {
|
||||
_prefs.advert_interval = (uint8_t)mins;
|
||||
updateAdvertTimer();
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
}
|
||||
} else if (memcmp(config, "name ", 5) == 0) {
|
||||
strncpy(_prefs.node_name, &config[5], sizeof(_prefs.node_name)-1);
|
||||
_prefs.node_name[sizeof(_prefs.node_name)-1] = 0; // truncate if nec
|
||||
|
|
@ -657,6 +695,15 @@ public:
|
|||
next_push = futureMillis(SYNC_PUSH_INTERVAL);
|
||||
}
|
||||
|
||||
if (next_local_advert && millisHasNowPassed(next_local_advert)) {
|
||||
mesh::Packet* pkt = createSelfAdvert();
|
||||
if (pkt) {
|
||||
sendZeroHop(pkt);
|
||||
}
|
||||
|
||||
updateAdvertTimer(); // schedule next local advert
|
||||
}
|
||||
|
||||
// TODO: periodically check for OLD/inactive entries in known_clients[], and evict
|
||||
}
|
||||
};
|
||||
|
|
@ -760,7 +807,7 @@ void setup() {
|
|||
}
|
||||
|
||||
// send out initial Advertisement to the mesh
|
||||
the_mesh.sendSelfAdvertisement();
|
||||
the_mesh.sendSelfAdvertisement(2000);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue