Scale default intervals based for *online* mesh size past 40 nodes (#4277)

* Add congestion scaling coefficient

* Added active mesh sized based interval scaling

* Moved back to bottom

* Format

* Add observers and use correct number of online nodes
This commit is contained in:
Ben Meadors 2024-07-13 05:59:19 -05:00 committed by GitHub
parent 0fa9974518
commit c5d747cd3e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 100 additions and 26 deletions

View File

@ -1,12 +1,5 @@
#include "Default.h" #include "Default.h"
uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval)
{
if (configuredInterval > 0)
return configuredInterval * 1000;
return default_broadcast_interval_secs * 1000;
}
uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval) uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval)
{ {
if (configuredInterval > 0) if (configuredInterval > 0)
@ -14,10 +7,37 @@ uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t
return defaultInterval * 1000; return defaultInterval * 1000;
} }
uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval)
{
if (configuredInterval > 0)
return configuredInterval * 1000;
return default_broadcast_interval_secs * 1000;
}
uint32_t Default::getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue) uint32_t Default::getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue)
{ {
if (configured > 0) if (configured > 0)
return configured; return configured;
return defaultValue; return defaultValue;
}
/**
* Calculates the scaled value of the configured or default value in ms based on the number of online nodes.
*
* For example a default of 30 minutes (1800 seconds * 1000) would yield:
* 45 nodes = 2475 * 1000
* 60 nodes = 4500 * 1000
* 75 nodes = 6525 * 1000
* 90 nodes = 8550 * 1000
* @param configured The configured value.
* @param defaultValue The default value.
* @param numOnlineNodes The number of online nodes.
* @return The scaled value of the configured or default value.
*/
uint32_t Default::getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes)
{
// If we are a router, we don't scale the value. It's already significantly higher.
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER)
return getConfiguredOrDefaultMs(configured, defaultValue);
return getConfiguredOrDefaultMs(configured, defaultValue) * congestionScalingCoefficient(numOnlineNodes);
} }

View File

@ -29,4 +29,17 @@ class Default
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval); static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval);
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval); static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval);
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue); static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
static uint32_t getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes);
private:
static float congestionScalingCoefficient(int numOnlineNodes)
{
if (numOnlineNodes <= 40) {
return 1.0; // No scaling for 40 or fewer nodes
} else {
// Sscaling based on number of nodes over 40
int nodesOverForty = (numOnlineNodes - 40);
return 1.0 + (nodesOverForty * 0.075); // Each number of online node scales by 0.075
}
}
}; };

View File

@ -13,6 +13,7 @@ template <class T> class ProtobufModule : protected SinglePortModule
const pb_msgdesc_t *fields; const pb_msgdesc_t *fields;
public: public:
uint8_t numOnlineNodes = 0;
/** Constructor /** Constructor
* name is for debugging output * name is for debugging output
*/ */
@ -61,6 +62,14 @@ template <class T> class ProtobufModule : protected SinglePortModule
return sender; return sender;
} }
int handleStatusUpdate(const meshtastic::Status *arg)
{
if (arg->getStatusType() == STATUS_TYPE_NODE) {
numOnlineNodes = nodeStatus->getNumOnline();
}
return 0;
}
private: private:
/** Called to handle a particular incoming message /** Called to handle a particular incoming message

View File

@ -58,8 +58,8 @@ int32_t DetectionSensorModule::runOnce()
// of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state // of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state
// change detections. // change detections.
else if (moduleConfig.detection_sensor.state_broadcast_secs > 0 && else if (moduleConfig.detection_sensor.state_broadcast_secs > 0 &&
(millis() - lastSentToMesh) >= (millis() - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs,
Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs)) { default_telemetry_broadcast_interval_secs)) {
sendCurrentStateMessage(); sendCurrentStateMessage();
return DELAYED_INTERVAL; return DELAYED_INTERVAL;
} }

View File

@ -39,11 +39,12 @@ NeighborInfoModule::NeighborInfoModule()
concurrency::OSThread("NeighborInfoModule") concurrency::OSThread("NeighborInfoModule")
{ {
ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP; ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP;
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
if (moduleConfig.neighbor_info.enabled) { if (moduleConfig.neighbor_info.enabled) {
isPromiscuous = true; // Update neighbors from all packets isPromiscuous = true; // Update neighbors from all packets
setIntervalFromNow( setIntervalFromNow(Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval,
Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs)); default_telemetry_broadcast_interval_secs));
} else { } else {
LOG_DEBUG("NeighborInfoModule is disabled\n"); LOG_DEBUG("NeighborInfoModule is disabled\n");
disable(); disable();
@ -119,7 +120,8 @@ int32_t NeighborInfoModule::runOnce()
if (airTime->isTxAllowedChannelUtil(true) && airTime->isTxAllowedAirUtil()) { if (airTime->isTxAllowedChannelUtil(true) && airTime->isTxAllowedAirUtil()) {
sendNeighborInfo(NODENUM_BROADCAST, false); sendNeighborInfo(NODENUM_BROADCAST, false);
} }
return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs); return Default::getConfiguredOrDefaultMsScaled(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs,
numOnlineNodes);
} }
/* /*

View File

@ -7,6 +7,9 @@
*/ */
class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, private concurrency::OSThread class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, private concurrency::OSThread
{ {
CallbackObserver<NeighborInfoModule, const meshtastic::Status *> nodeStatusObserver =
CallbackObserver<NeighborInfoModule, const meshtastic::Status *>(this, &NeighborInfoModule::handleStatusUpdate);
std::vector<meshtastic_Neighbor> neighbors; std::vector<meshtastic_Neighbor> neighbors;
public: public:

View File

@ -28,6 +28,8 @@ PositionModule::PositionModule()
{ {
precision = 0; // safe starting value precision = 0; // safe starting value
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
if (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER && if (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER &&
config.device.role != meshtastic_Config_DeviceConfig_Role_TAK_TRACKER) config.device.role != meshtastic_Config_DeviceConfig_Role_TAK_TRACKER)
setIntervalFromNow(60 * 1000); setIntervalFromNow(60 * 1000);
@ -333,8 +335,8 @@ int32_t PositionModule::runOnce()
// We limit our GPS broadcasts to a max rate // We limit our GPS broadcasts to a max rate
uint32_t now = millis(); uint32_t now = millis();
uint32_t intervalMs = uint32_t intervalMs = Default::getConfiguredOrDefaultMsScaled(config.position.position_broadcast_secs,
Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs); default_broadcast_interval_secs, numOnlineNodes);
uint32_t msSinceLastSend = now - lastGpsSend; uint32_t msSinceLastSend = now - lastGpsSend;
// Only send packets if the channel util. is less than 25% utilized or we're a tracker with less than 40% utilized. // Only send packets if the channel util. is less than 25% utilized or we're a tracker with less than 40% utilized.
if (!airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER && if (!airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER &&

View File

@ -8,6 +8,9 @@
*/ */
class PositionModule : public ProtobufModule<meshtastic_Position>, private concurrency::OSThread class PositionModule : public ProtobufModule<meshtastic_Position>, private concurrency::OSThread
{ {
CallbackObserver<PositionModule, const meshtastic::Status *> nodeStatusObserver =
CallbackObserver<PositionModule, const meshtastic::Status *>(this, &PositionModule::handleStatusUpdate);
/// The id of the last packet we sent, to allow us to cancel it if we make something fresher /// The id of the last packet we sent, to allow us to cancel it if we make something fresher
PacketId prevPacketId = 0; PacketId prevPacketId = 0;
@ -59,7 +62,7 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
void sendLostAndFoundText(); void sendLostAndFoundText();
const uint32_t minimumTimeThreshold = const uint32_t minimumTimeThreshold =
Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30); Default::getConfiguredOrDefaultMsScaled(config.position.broadcast_smart_minimum_interval_secs, 30, numOnlineNodes);
}; };
struct SmartPosition { struct SmartPosition {

View File

@ -47,8 +47,9 @@ int32_t AirQualityTelemetryModule::runOnce()
uint32_t now = millis(); uint32_t now = millis();
if (((lastSentToMesh == 0) || if (((lastSentToMesh == 0) ||
((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval, ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.air_quality_interval,
default_telemetry_broadcast_interval_secs))) && default_telemetry_broadcast_interval_secs,
numOnlineNodes))) &&
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
airTime->isTxAllowedAirUtil()) { airTime->isTxAllowedAirUtil()) {
sendTelemetry(); sendTelemetry();

View File

@ -10,6 +10,10 @@
class AirQualityTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry> class AirQualityTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry>
{ {
CallbackObserver<AirQualityTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
CallbackObserver<AirQualityTelemetryModule, const meshtastic::Status *>(this,
&AirQualityTelemetryModule::handleStatusUpdate);
public: public:
AirQualityTelemetryModule() AirQualityTelemetryModule()
: concurrency::OSThread("AirQualityTelemetryModule"), : concurrency::OSThread("AirQualityTelemetryModule"),
@ -18,6 +22,7 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf
lastMeasurementPacket = nullptr; lastMeasurementPacket = nullptr;
setIntervalFromNow(10 * 1000); setIntervalFromNow(10 * 1000);
aqi = Adafruit_PM25AQI(); aqi = Adafruit_PM25AQI();
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
} }
protected: protected:

View File

@ -17,8 +17,9 @@ int32_t DeviceTelemetryModule::runOnce()
{ {
refreshUptime(); refreshUptime();
if (((lastSentToMesh == 0) || if (((lastSentToMesh == 0) ||
((uptimeLastMs - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval, ((uptimeLastMs - lastSentToMesh) >=
default_telemetry_broadcast_interval_secs))) && Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval,
default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
airTime->isTxAllowedAirUtil() && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && airTime->isTxAllowedAirUtil() && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER &&
config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) { config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) {

View File

@ -7,6 +7,9 @@
class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry> class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry>
{ {
CallbackObserver<DeviceTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
CallbackObserver<DeviceTelemetryModule, const meshtastic::Status *>(this, &DeviceTelemetryModule::handleStatusUpdate);
public: public:
DeviceTelemetryModule() DeviceTelemetryModule()
: concurrency::OSThread("DeviceTelemetryModule"), : concurrency::OSThread("DeviceTelemetryModule"),
@ -14,6 +17,7 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu
{ {
uptimeWrapCount = 0; uptimeWrapCount = 0;
uptimeLastMs = millis(); uptimeLastMs = millis();
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
setIntervalFromNow(45 * 1000); // Wait until NodeInfo is sent setIntervalFromNow(45 * 1000); // Wait until NodeInfo is sent
} }
virtual bool wantUIFrame() { return false; } virtual bool wantUIFrame() { return false; }

View File

@ -145,8 +145,9 @@ int32_t EnvironmentTelemetryModule::runOnce()
uint32_t now = millis(); uint32_t now = millis();
if (((lastSentToMesh == 0) || if (((lastSentToMesh == 0) ||
((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval, ((now - lastSentToMesh) >=
default_telemetry_broadcast_interval_secs))) && Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.environment_update_interval,
default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
airTime->isTxAllowedAirUtil()) { airTime->isTxAllowedAirUtil()) {
sendTelemetry(); sendTelemetry();

View File

@ -11,12 +11,17 @@
class EnvironmentTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry> class EnvironmentTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry>
{ {
CallbackObserver<EnvironmentTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
CallbackObserver<EnvironmentTelemetryModule, const meshtastic::Status *>(this,
&EnvironmentTelemetryModule::handleStatusUpdate);
public: public:
EnvironmentTelemetryModule() EnvironmentTelemetryModule()
: concurrency::OSThread("EnvironmentTelemetryModule"), : concurrency::OSThread("EnvironmentTelemetryModule"),
ProtobufModule("EnvironmentTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg) ProtobufModule("EnvironmentTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg)
{ {
lastMeasurementPacket = nullptr; lastMeasurementPacket = nullptr;
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
setIntervalFromNow(10 * 1000); setIntervalFromNow(10 * 1000);
} }
virtual bool wantUIFrame() override; virtual bool wantUIFrame() override;

View File

@ -71,8 +71,9 @@ int32_t PowerTelemetryModule::runOnce()
uint32_t now = millis(); uint32_t now = millis();
if (((lastSentToMesh == 0) || if (((lastSentToMesh == 0) ||
((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval, ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.power_update_interval,
default_telemetry_broadcast_interval_secs))) && default_telemetry_broadcast_interval_secs,
numOnlineNodes))) &&
airTime->isTxAllowedAirUtil()) { airTime->isTxAllowedAirUtil()) {
sendTelemetry(); sendTelemetry();
lastSentToMesh = now; lastSentToMesh = now;

View File

@ -12,12 +12,16 @@
class PowerTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry> class PowerTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry>
{ {
CallbackObserver<PowerTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
CallbackObserver<PowerTelemetryModule, const meshtastic::Status *>(this, &PowerTelemetryModule::handleStatusUpdate);
public: public:
PowerTelemetryModule() PowerTelemetryModule()
: concurrency::OSThread("PowerTelemetryModule"), : concurrency::OSThread("PowerTelemetryModule"),
ProtobufModule("PowerTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg) ProtobufModule("PowerTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg)
{ {
lastMeasurementPacket = nullptr; lastMeasurementPacket = nullptr;
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
setIntervalFromNow(10 * 1000); setIntervalFromNow(10 * 1000);
} }
virtual bool wantUIFrame() override; virtual bool wantUIFrame() override;

View File

@ -100,8 +100,8 @@ int32_t PaxcounterModule::runOnce()
} else { } else {
sendInfo(NODENUM_BROADCAST); sendInfo(NODENUM_BROADCAST);
} }
return Default::getConfiguredOrDefaultMs(moduleConfig.paxcounter.paxcounter_update_interval, return Default::getConfiguredOrDefaultMsScaled(moduleConfig.paxcounter.paxcounter_update_interval,
default_telemetry_broadcast_interval_secs); default_telemetry_broadcast_interval_secs, numOnlineNodes);
} else { } else {
return disable(); return disable();
} }