From 05c3d309a620d9d24235e4158f4fb2612895cb3a Mon Sep 17 00:00:00 2001 From: cjkas Date: Sun, 11 Oct 2026 20:35:42 +0200 Subject: [PATCH] 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 --- src/ESPNetwork.cpp | 7 +++++-- src/ESPNetwork.h | 5 +++++ src/Utils.cpp | 5 +++++ src/Utils.h | 4 ++++ test/test_utils/test_utils.cpp | 25 +++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/ESPNetwork.cpp b/src/ESPNetwork.cpp index 98d2c5d..9a8cbd5 100644 --- a/src/ESPNetwork.cpp +++ b/src/ESPNetwork.cpp @@ -181,8 +181,9 @@ bool ESPNetwork::changeAP(const uint8_t *bssid, const int32_t channel) { } void ESPNetwork::emitSockets() { this->emitHeap(); - if(this->needsBroadcast || - (this->connType == conn_types_t::wifi && (abs(abs(WiFi.RSSI()) - abs(this->lastRSSI)) > 1 || WiFi.channel() != this->lastChannel))) { + if(this->needsBroadcast || + (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); sockEmit.loop(); this->needsBroadcast = false; @@ -212,6 +213,7 @@ void ESPNetwork::emitSockets(uint8_t num) { sockEmit.endEmit(num); this->lastRSSI = WiFi.RSSI(); this->lastChannel = WiFi.channel(); + this->lastRSSIEmit = millis(); } else { JsonSockEvent *json = sockEmit.beginEmit("wifiStrength"); @@ -231,6 +233,7 @@ void ESPNetwork::emitSockets(uint8_t num) { sockEmit.endEmit(num); this->lastRSSI = -100; this->lastChannel = -1; + this->lastRSSIEmit = millis(); } } this->emitHeap(num); diff --git a/src/ESPNetwork.h b/src/ESPNetwork.h index a77921c..f1594d0 100644 --- a/src/ESPNetwork.h +++ b/src/ESPNetwork.h @@ -8,10 +8,15 @@ #define CONNECT_TIMEOUT 20000 #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 { protected: unsigned long lastEmit = 0; unsigned long lastMDNS = 0; + unsigned long lastRSSIEmit = 0; int lastRSSI = 0; int lastChannel = 0; int linkSpeed = 0; diff --git a/src/Utils.cpp b/src/Utils.cpp index 74af2ea..68a9043 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -130,3 +130,8 @@ int Timestamp::tzOffset() { time(&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; +} diff --git a/src/Utils.h b/src/Utils.h index 51a29b2..5088bbc 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -56,6 +56,10 @@ struct rebootDelay_t { else if(str[0] == 'f' || str[0] == 'F' || str[0] == '0') return false; 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 { char _timeBuffer[128]; diff --git a/test/test_utils/test_utils.cpp b/test/test_utils/test_utils.cpp index 0a14039..ebde1d5 100644 --- a/test/test_utils/test_utils.cpp +++ b/test/test_utils/test_utils.cpp @@ -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")); } +/********************************************************************* + * 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) { (void)argc; (void)argv; @@ -193,5 +213,10 @@ int main(int argc, char **argv) { RUN_TEST(test_calcTZOffset_half_hour_west); RUN_TEST(test_parseUTCTime_in_utc); 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(); }