Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 46 additions & 37 deletions Integrations/ESPHome/Core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -427,22 +427,24 @@ sensor:
id: sys_esp_temperature
filters:
- lambda: |-
static float last_reported_value = -6.0;
static float last_reported_value = NAN;
static uint32_t last_report_time = 0;
float current_value = x;

// Check if the reduce_db_reporting switch is on
// Reduce DB Reporting: report on a meaningful change, but at least hourly so the sensor never looks frozen
if (id(reduce_db_reporting).state) {
// Apply delta filter: only report if the value has changed by 5 or more
if (abs(current_value - last_reported_value) >= 5.0) {
last_reported_value = current_value; // Update the last reported value
uint32_t now = millis();
if (isnan(last_reported_value) ||
abs(current_value - last_reported_value) >= 5.0 ||
(now - last_report_time) >= 3600000UL) {
last_reported_value = current_value;
last_report_time = now;
return current_value;
} else {
// Return the last reported value without updating if change is less than 5
return {}; // Discard the update
}
return {}; // Within delta and under the hourly heartbeat -> discard
} else {
// If reduce_db_reporting is off, report the current value normally
last_reported_value = current_value;
last_report_time = millis();
return current_value;
}

Expand Down Expand Up @@ -645,45 +647,49 @@ sensor:
id: ltr390light
filters:
- lambda: |-
static float last_reported_value = -21.0;
static float last_reported_value = NAN;
static uint32_t last_report_time = 0;
float current_value = x;

// Check if the reduce_db_reporting switch is on
// Reduce DB Reporting: report on a meaningful change, but at least hourly so the sensor never looks frozen
if (id(reduce_db_reporting).state) {
// Apply delta filter: only report if the value has changed by 5 or more
if (abs(current_value - last_reported_value) >= 5.0) {
last_reported_value = current_value; // Update the last reported value
uint32_t now = millis();
if (isnan(last_reported_value) ||
abs(current_value - last_reported_value) >= 5.0 ||
(now - last_report_time) >= 3600000UL) {
last_reported_value = current_value;
last_report_time = now;
return current_value;
} else {
// Return the last reported value without updating if change is less than 20
return {}; // Discard the update
}
return {}; // Within delta and under the hourly heartbeat -> discard
} else {
// If reduce_db_reporting is off, report the current value normally
last_reported_value = current_value;
last_report_time = millis();
return current_value;
}
uv_index:
name: "LTR390 UV Index"
id: ltr390uvindex
filters:
- lambda: |-
static float last_reported_value = -21.0;
static float last_reported_value = NAN;
static uint32_t last_report_time = 0;
float current_value = x;

// Check if the reduce_db_reporting switch is on
// Reduce DB Reporting: report on a meaningful change, but at least hourly so the sensor never looks frozen
if (id(reduce_db_reporting).state) {
// Apply delta filter: only report if the value has changed by 1 or more
if (abs(current_value - last_reported_value) >= 1.0) {
last_reported_value = current_value; // Update the last reported value
uint32_t now = millis();
if (isnan(last_reported_value) ||
abs(current_value - last_reported_value) >= 1.0 ||
(now - last_report_time) >= 3600000UL) {
last_reported_value = current_value;
last_report_time = now;
return current_value;
} else {
// Return the last reported value without updating if change is less than 20
return {}; // Discard the update
}
return {}; // Within delta and under the hourly heartbeat -> discard
} else {
// If reduce_db_reporting is off, report the current value normally
last_reported_value = current_value;
last_report_time = millis();
return current_value;
}

Expand All @@ -694,34 +700,37 @@ sensor:
id: dps310pressure
filters:
- lambda: |-
static float last_reported_value = -6.0;
static float last_reported_value = NAN;
static uint32_t last_report_time = 0;
float current_value = x;
float offset = id(dps310_pressure_offset).state;
if (!isnan(offset)) {
current_value += offset;
}

// Check if the reduce_db_reporting switch is on
// Reduce DB Reporting: report on a meaningful change, but at least hourly so the sensor never looks frozen.
// Barometric pressure normally drifts only 1-3 hPa a day, so the old 5 hPa delta could freeze the reading for hours.
if (id(reduce_db_reporting).state) {
// Apply delta filter: only report if the value has changed by 5 or more
if (abs(current_value - last_reported_value) >= 5.0) {
last_reported_value = current_value; // Update the last reported value
uint32_t now = millis();
if (isnan(last_reported_value) ||
abs(current_value - last_reported_value) >= 0.5 ||
(now - last_report_time) >= 3600000UL) {
last_reported_value = current_value;
last_report_time = now;
return current_value;
} else {
// Return the last reported value without updating if change is less than 5
return {}; // Discard the update
}
return {}; // Within delta and under the hourly heartbeat -> discard
} else {
// If reduce_db_reporting is off, report the current value normally
last_reported_value = current_value;
last_report_time = millis();
return current_value;
}
Comment on lines +703 to 727

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Fix NAN handling to prevent database spam and delayed error reporting.

The new lambda logic mishandles NAN values (which ESPHome uses to indicate a failed sensor read) in two critical ways:

  1. Database Spam: Once last_reported_value becomes NAN, isnan(last_reported_value) will evaluate to true on every subsequent poll. This bypasses the filter entirely, spamming Home Assistant with NAN updates every 60 seconds and defeating the reduce_db_reporting toggle.
  2. Delayed Error Reporting: If the sensor fails and transitions from a valid reading to NAN, abs(NAN - last_reported_value) >= threshold evaluates to false. The error won't be sent to Home Assistant until the 1-hour heartbeat expires, leaving stale data in the UI.

To fix this, track the initial run explicitly with a boolean and handle NAN state transitions separately.

  • Integrations/ESPHome/Core.yaml#L702-L726: Update the DPS310 Pressure filter to use static bool first_run and explicitly check for NAN transitions.
  • Integrations/ESPHome/Core.yaml#L429-L446: Apply the same logic to the ESP Temperature filter (using its 5.0 delta).
  • Integrations/ESPHome/Core.yaml#L649-L668: Apply the same logic to the LTR390 Light filter (using its 5.0 delta).
  • Integrations/ESPHome/Core.yaml#L669-L691: Apply the same logic to the LTR390 UV Index filter (using its 1.0 delta).
🛠️ Proposed fix for the DPS310 Pressure filter (adapt for the other 3 sensors)
             static float last_reported_value = NAN;
             static uint32_t last_report_time = 0;
+            static bool first_run = true;
             float current_value = x;
             float offset = id(dps310_pressure_offset).state;
             if (!isnan(offset)) {
               current_value += offset;
             }
 
             // Reduce DB Reporting: report on a meaningful change, but at least hourly so the sensor never looks frozen.
             // Barometric pressure normally drifts only 1-3 hPa a day, so the old 5 hPa delta could freeze the reading for hours.
             if (id(reduce_db_reporting).state) {
               uint32_t now = millis();
-              if (isnan(last_reported_value) ||
-                  abs(current_value - last_reported_value) >= 0.5 ||
+              bool is_nan_transition = isnan(current_value) != isnan(last_reported_value);
+              
+              if (first_run ||
+                  is_nan_transition ||
+                  (!isnan(current_value) && abs(current_value - last_reported_value) >= 0.5) ||
                   (now - last_report_time) >= 3600000UL) {
                 last_reported_value = current_value;
                 last_report_time = now;
+                first_run = false;
                 return current_value;
               }
               return {};  // Within delta and under the hourly heartbeat -> discard
             } else {
               last_reported_value = current_value;
               last_report_time = millis();
+              first_run = false;
               return current_value;
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static float last_reported_value = NAN;
static uint32_t last_report_time = 0;
float current_value = x;
float offset = id(dps310_pressure_offset).state;
if (!isnan(offset)) {
current_value += offset;
}
// Check if the reduce_db_reporting switch is on
// Reduce DB Reporting: report on a meaningful change, but at least hourly so the sensor never looks frozen.
// Barometric pressure normally drifts only 1-3 hPa a day, so the old 5 hPa delta could freeze the reading for hours.
if (id(reduce_db_reporting).state) {
// Apply delta filter: only report if the value has changed by 5 or more
if (abs(current_value - last_reported_value) >= 5.0) {
last_reported_value = current_value; // Update the last reported value
uint32_t now = millis();
if (isnan(last_reported_value) ||
abs(current_value - last_reported_value) >= 0.5 ||
(now - last_report_time) >= 3600000UL) {
last_reported_value = current_value;
last_report_time = now;
return current_value;
} else {
// Return the last reported value without updating if change is less than 5
return {}; // Discard the update
}
return {}; // Within delta and under the hourly heartbeat -> discard
} else {
// If reduce_db_reporting is off, report the current value normally
last_reported_value = current_value;
last_report_time = millis();
return current_value;
}
static float last_reported_value = NAN;
static uint32_t last_report_time = 0;
static bool first_run = true;
float current_value = x;
float offset = id(dps310_pressure_offset).state;
if (!isnan(offset)) {
current_value += offset;
}
// Reduce DB Reporting: report on a meaningful change, but at least hourly so the sensor never looks frozen.
// Barometric pressure normally drifts only 1-3 hPa a day, so the old 5 hPa delta could freeze the reading for hours.
if (id(reduce_db_reporting).state) {
uint32_t now = millis();
bool is_nan_transition = isnan(current_value) != isnan(last_reported_value);
if (first_run ||
is_nan_transition ||
(!isnan(current_value) && abs(current_value - last_reported_value) >= 0.5) ||
(now - last_report_time) >= 3600000UL) {
last_reported_value = current_value;
last_report_time = now;
first_run = false;
return current_value;
}
return {}; // Within delta and under the hourly heartbeat -> discard
} else {
last_reported_value = current_value;
last_report_time = millis();
first_run = false;
return current_value;
}
📍 Affects 1 file
  • Integrations/ESPHome/Core.yaml#L702-L726 (this comment)
  • Integrations/ESPHome/Core.yaml#L429-L446
  • Integrations/ESPHome/Core.yaml#L649-L668
  • Integrations/ESPHome/Core.yaml#L669-L691
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Integrations/ESPHome/Core.yaml` around lines 702 - 726, The sensor reporting
filters mishandle NAN values, causing repeated invalid updates and delayed
failure reporting. In Integrations/ESPHome/Core.yaml at lines 702-726, 429-446,
649-668, and 669-691, update each filter to track initialization with a static
first_run boolean and explicitly detect NAN state transitions, reporting the
initial value and transitions between valid and NAN immediately while retaining
normal delta and hourly heartbeat behavior. Use deltas of 0.5 for DPS310
pressure, 5.0 for ESP temperature and LTR390 light, and 1.0 for LTR390 UV index.

temperature:
name: "DPS310 Temperature"
id: dps310temperature
filters:
- lambda: return x - id(dps310_temperature_offset).state;
update_interval: 30s
update_interval: 60s
i2c_id: bus_a


Expand Down
Loading