fix: send wifiStrength only for real signal changes

At -70 dBm the RSSI moves a dBm or two constantly, so the >1 dBm check
every 1.5s sent wifiStrength to every client about 270 times an hour.
That is extra traffic on an already lossy link and a state write in
Home Assistant for each one.

Broadcast on a channel change, or for a change of at least 3 dBm no
more than every 10s. A newly connected client still gets the current
value straight away.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-11 20:35:42 +02:00
parent 1d1f685fce
commit 05c3d309a6
5 changed files with 44 additions and 2 deletions

View file

@ -182,7 +182,8 @@ bool ESPNetwork::changeAP(const uint8_t *bssid, const int32_t channel) {
void ESPNetwork::emitSockets() { void ESPNetwork::emitSockets() {
this->emitHeap(); this->emitHeap();
if(this->needsBroadcast || if(this->needsBroadcast ||
(this->connType == conn_types_t::wifi && (abs(abs(WiFi.RSSI()) - abs(this->lastRSSI)) > 1 || WiFi.channel() != this->lastChannel))) { (this->connType == conn_types_t::wifi && rssiNeedsEmit(WiFi.RSSI(), this->lastRSSI, WiFi.channel(), this->lastChannel,
millis() - this->lastRSSIEmit, RSSI_EMIT_MIN_DBM, RSSI_EMIT_MIN_MS))) {
this->emitSockets(255); this->emitSockets(255);
sockEmit.loop(); sockEmit.loop();
this->needsBroadcast = false; this->needsBroadcast = false;
@ -212,6 +213,7 @@ void ESPNetwork::emitSockets(uint8_t num) {
sockEmit.endEmit(num); sockEmit.endEmit(num);
this->lastRSSI = WiFi.RSSI(); this->lastRSSI = WiFi.RSSI();
this->lastChannel = WiFi.channel(); this->lastChannel = WiFi.channel();
this->lastRSSIEmit = millis();
} }
else { else {
JsonSockEvent *json = sockEmit.beginEmit("wifiStrength"); JsonSockEvent *json = sockEmit.beginEmit("wifiStrength");
@ -231,6 +233,7 @@ void ESPNetwork::emitSockets(uint8_t num) {
sockEmit.endEmit(num); sockEmit.endEmit(num);
this->lastRSSI = -100; this->lastRSSI = -100;
this->lastChannel = -1; this->lastChannel = -1;
this->lastRSSIEmit = millis();
} }
} }
this->emitHeap(num); this->emitHeap(num);

View file

@ -8,10 +8,15 @@
#define CONNECT_TIMEOUT 20000 #define CONNECT_TIMEOUT 20000
#define SSID_SCAN_INTERVAL 600000 #define SSID_SCAN_INTERVAL 600000
// A weak signal moves a dBm or two all the time, so only broadcast real
// changes and not more often than this.
#define RSSI_EMIT_MIN_DBM 3
#define RSSI_EMIT_MIN_MS 10000
class ESPNetwork { class ESPNetwork {
protected: protected:
unsigned long lastEmit = 0; unsigned long lastEmit = 0;
unsigned long lastMDNS = 0; unsigned long lastMDNS = 0;
unsigned long lastRSSIEmit = 0;
int lastRSSI = 0; int lastRSSI = 0;
int lastChannel = 0; int lastChannel = 0;
int linkSpeed = 0; int linkSpeed = 0;

View file

@ -130,3 +130,8 @@ int Timestamp::tzOffset() {
time(&now); time(&now);
return Timestamp::calcTZOffset(&now); return Timestamp::calcTZOffset(&now);
} }
bool rssiNeedsEmit(int rssi, int lastRssi, int channel, int lastChannel, uint32_t sinceLastMs, int minDelta, uint32_t minMs) {
if(channel != lastChannel) return true;
int delta = rssi > lastRssi ? rssi - lastRssi : lastRssi - rssi;
return delta >= minDelta && sinceLastMs >= minMs;
}

View file

@ -56,6 +56,10 @@ struct rebootDelay_t {
else if(str[0] == 'f' || str[0] == 'F' || str[0] == '0') return false; else if(str[0] == 'f' || str[0] == 'F' || str[0] == '0') return false;
return def; return def;
} }
// Whether a wifiStrength broadcast is worth sending: always on a channel change,
// otherwise only for an RSSI change of at least minDelta dBm and not more often
// than every minMs.
bool rssiNeedsEmit(int rssi, int lastRssi, int channel, int lastChannel, uint32_t sinceLastMs, int minDelta, uint32_t minMs);
class Timestamp { class Timestamp {
char _timeBuffer[128]; char _timeBuffer[128];

View file

@ -168,6 +168,26 @@ static void test_parseUTCTime_ignores_local_zone() {
TEST_ASSERT_EQUAL_INT64((int64_t)SAMPLE_UTC, (int64_t)Timestamp::parseUTCTime("2024-03-05T07:08:09Z")); TEST_ASSERT_EQUAL_INT64((int64_t)SAMPLE_UTC, (int64_t)Timestamp::parseUTCTime("2024-03-05T07:08:09Z"));
} }
/*********************************************************************
* rssiNeedsEmit
********************************************************************/
static void test_rssiNeedsEmit_channel_change_always_emits() {
TEST_ASSERT_TRUE(rssiNeedsEmit(-70, -70, 6, 11, 0, 3, 10000));
}
static void test_rssiNeedsEmit_small_change_is_ignored() {
TEST_ASSERT_FALSE(rssiNeedsEmit(-72, -70, 6, 6, 60000, 3, 10000));
}
static void test_rssiNeedsEmit_real_change_after_interval_emits() {
TEST_ASSERT_TRUE(rssiNeedsEmit(-73, -70, 6, 6, 10000, 3, 10000));
}
static void test_rssiNeedsEmit_real_change_too_soon_waits() {
TEST_ASSERT_FALSE(rssiNeedsEmit(-73, -70, 6, 6, 5000, 3, 10000));
}
static void test_rssiNeedsEmit_either_direction() {
TEST_ASSERT_TRUE(rssiNeedsEmit(-67, -70, 6, 6, 10000, 3, 10000));
TEST_ASSERT_TRUE(rssiNeedsEmit(-73, -70, 6, 6, 10000, 3, 10000));
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
(void)argc; (void)argc;
(void)argv; (void)argv;
@ -193,5 +213,10 @@ int main(int argc, char **argv) {
RUN_TEST(test_calcTZOffset_half_hour_west); RUN_TEST(test_calcTZOffset_half_hour_west);
RUN_TEST(test_parseUTCTime_in_utc); RUN_TEST(test_parseUTCTime_in_utc);
RUN_TEST(test_parseUTCTime_ignores_local_zone); RUN_TEST(test_parseUTCTime_ignores_local_zone);
RUN_TEST(test_rssiNeedsEmit_channel_change_always_emits);
RUN_TEST(test_rssiNeedsEmit_small_change_is_ignored);
RUN_TEST(test_rssiNeedsEmit_real_change_after_interval_emits);
RUN_TEST(test_rssiNeedsEmit_real_change_too_soon_waits);
RUN_TEST(test_rssiNeedsEmit_either_direction);
return UNITY_END(); return UNITY_END();
} }