Add physics-based predicted room temperature & humidity#102
Conversation
Adds two template sensors that estimate true room temperature and humidity, correcting for the Air-1 enclosure's self-heating: - Predicted Room Temperature: weighted blend of SEN55/DPS310/SCD40 temperatures with a thermal-gradient correction (Physics Multiplier P, Baseline Offset). - Predicted Room Humidity: re-references each sensor's RH to the predicted room temperature via the Magnus formula, then blends by manufacturing tolerance. Supporting additions, all additive (stock sensors and their defaults are unchanged): - New CONFIG numbers: Physics Multiplier P, Baseline Offset, SCD40 Temperature Offset, SCD40 Humidity Offset (all default to a neutral value). - Expose SCD40 Temperature/Humidity and name the DPS310 Temperature sensor so the prediction lambdas can read them. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
These are advanced, opt-in sensors. Mark the two Predicted Room sensors, their CONFIG tuning numbers, and the newly-exposed SCD40/DPS310 inputs as disabled_by_default so the stock device page stays clean. The prediction lambdas still read the on-device state regardless of HA enablement, so functionality is unaffected when the entities are hidden. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add attribution to Ellude (Apollo Discord), who did the research and coefficient fitting. Note that the Physics Multiplier P default (0.5357) is provisional pending a better fitted value. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughCore ESPHome config adds new tuning numbers, derives predicted room temperature and humidity from sensor data, exposes corrected SCD40 outputs, and disables the DPS310 temperature sensor by default. ChangesESPHome predicted-room sensing
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with 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.
Inline comments:
In `@Integrations/ESPHome/Core.yaml`:
- Around line 410-415: Clamp the SCD40 humidity correction before publishing so
the lambda under humidity does not emit values outside 0-100% RH. Update the
filter in the SCD40 humidity sensor block to apply the offset in the existing
lambda and bound the result to the valid range, using the scd40_humidity and
scd40_humidity_offset identifiers to locate the change.
- Line 316: The warm-up gate in the prediction lambdas currently compares
id(sys_uptime).state directly, which can pass too early when the value is still
NaN before the first publish. Update both lambda guards that use sys_uptime to
first check std::isnan(uptime) and only allow prediction once uptime is valid
and at least 180.0, using the existing lambda logic around id(sys_uptime) so
both paths behave consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 57e0793d-adb9-4d2c-b85e-f51d15820182
📒 Files selected for processing (1)
Integrations/ESPHome/Core.yaml
Code Review: Add physics-based predicted room temperature & humidity🔴 Critical—
|
- Guard the warm-up gate against a NaN sys_uptime. sys_uptime is NaN until its first publish (~60s) and NaN < 180.0 is false, so the gate could let both prediction lambdas run before warm-up. Check isnan() first. - Extend the temperature lambda's NaN check to the coefficient/baseline values so a bad restore can't slip a NaN through the arithmetic. - Add isnan offset guards to the SCD40 temperature/humidity filters, matching the existing DPS310 pressure-offset pattern. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
Thanks for the review. Applied in 225ebdb:
Skipped a few on purpose:
|
secondof9
left a comment
There was a problem hiding this comment.
📋 Review Summary
Review Status: 🟢 APPROVED (minor warnings only, no blockers)
Change Type: ✨ New Feature
Review Effort: 🟡 Medium
Core Impact: Adds opt-in, physics-based predicted room temperature and humidity sensors to the Air-1 ESPHome config, with configurable correction coefficients.
🔍 Architectural Walkthrough
🛠️ ESPHome Configuration — Core.yaml
Integrations/ESPHome/Core.yaml- 4 new CONFIG template numbers — Physics Multiplier P, Baseline Offset, SCD40 Temperature Offset, SCD40 Humidity Offset. All
disabled_by_default,restore_value: true,entity_category: "CONFIG". Correct additive-only pattern. - Predicted Room Temperature — Weighted blend of SEN55, DPS310, SCD40 temps with thermal-gradient correction. Includes 3-minute uptime guard and full NaN propagation. Coefficients sum to ~1.0 (0.4703 + 0.3809 + 0.1488 = 1.0000).
- Predicted Room Humidity — Re-references RH via Magnus formula, blends by sensor tolerance (64% SEN55, 36% SCD40). Clamped to [0, 100].
- SCD40 Temperature & Humidity sensors — Now exposed (previously internal) with configurable offset filters.
disabled_by_default: true. - DPS310 Temperature sensor — Now exposed with name and
disabled_by_default: true(was previously unnamed/internal).
- 4 new CONFIG template numbers — Physics Multiplier P, Baseline Offset, SCD40 Temperature Offset, SCD40 Humidity Offset. All
🛠️ Critical Review & Line Suggestions
⚠️ Warning: Magnus formula denominator can hit zero (NaN propagation)
File: Integrations/ESPHome/Core.yaml
Line: Predicted Room Humidity lambda, mag_room / mag_sen / mag_scd division
The saturation vapor pressure calculation expf((17.62 * t_room) / (243.12 + t_room)) is safe for reasonable t_room values. However, 243.12 + t_room hits zero at t_room = -243.12°C — which is essentially physically impossible, but the denominator could theoretically be zero or negative if sensor data is corrupted. Division by zero yields INF, and INF / INF yields NaN. More critically, mag_room could underflow to zero (very cold room), causing division-by-zero in true_rh_sen = rh_sen * (mag_sen / mag_room).
If the predicted room temperature is extremely low, mag_room underflows to zero, and dividing mag_sen / mag_room produces INF, making true_rh_sen and true_rh_scd both INF. The final clamping at 100% masks this, but INF is a silent data integrity issue.
Suggestion:
// Calculate Saturation Vapor Pressures (Magnus Formula)
float mag_room = expf((17.62 * t_room) / (243.12 + t_room));
float mag_sen = expf((17.62 * t_sen) / (243.12 + t_sen));
float mag_scd = expf((17.62 * t_scd) / (243.12 + t_scd));
// Guard against division by zero if mag_room underflows
if (mag_room <= 0.0f) {
return NAN;
}
// Calculate Actual Room RH for each sensor
float true_rh_sen = rh_sen * (mag_sen / mag_room);
float true_rh_scd = rh_scd * (mag_scd / mag_room);
⚠️ Warning: Sensor state staleness — humidity prediction updates every 10s but depends on SEN55 at 60s
File: Integrations/ESPHome/Core.yaml
Line: Predicted Room Humidity update_interval: 10s
The humidity prediction runs every 10 seconds, but the SEN55 sensor updates every 60 seconds. This means 5 out of 6 prediction cycles recompute with stale data, wasting ESPHome lambda evaluation cycles. The temperature prediction has the same issue. Consider aligning update_interval to 60s, or at least document this staleness trade-off.
Suggestion:
update_interval: 60s # Align with SEN55 update cycle; prediction won't improve more often⚠️ Warning: SCD40 Temperature Offset cancels itself out of the temperature prediction formula
File: Integrations/ESPHome/Core.yaml
Line: SCD40 Temperature filter + Predicted Room Temperature lambda
The SCD40 Temperature sensor applies x - offset, and the temperature prediction uses t_offset = p_val * (t_scd - t_sen). Since t_scd is the offset-corrected SCD40 reading, the offset cancels out:
t_offset = p_val * ((raw_scd - offset) - t_sen) = p_val * (raw_scd - t_sen) - p_val * offset
The offset term p_val * offset is not zero — it actually does shift the prediction. This is arguably correct behavior (letting the user fine-tune), but it's a subtle coupling that's easy to misread. A brief comment explaining the interaction would prevent future confusion.
💡 Suggestion: Expose dps310temperature under consistent naming convention
File: Integrations/ESPHome/Core.yaml
New sensors follow camelCase or title_case naming (e.g., scd40_temperature), but dps310temperature is left camelCase without underscore. Consider renaming to dps310_temperature for consistency — though this is a cosmetic nit since the ID is internal-only.
💡 Suggestion: Document the coefficient source in a code comment
File: Integrations/ESPHome/Core.yaml
The weights 0.4703, 0.3809, 0.1488 and the 0.5357 multiplier are empirical. Since the PR body credits Ellude, adding a brief comment with the derivation or a link to the Discord thread would make future coefficient updates auditable.
✅ Looks Good
- NaN guard chain is thorough — Both prediction lambdas check
isnanon every dependency before computing. Theisnan(offset) ? x : x ± offsetpattern in the SCD40 filter correctly falls back to raw data when the offset entity isn't yet initialized. - Additive-only design — All new entities are
disabled_by_default, so existing Air-1 users are unaffected. The stock SEN55/SCD40/DPS310 sensors remain unchanged. - Uptime guard — The 3-minute boot delay is well-justified and properly implemented with NaN-safe comparison.
- Humidity clamping — Final RH is properly clamped to [0, 100] range.
restore_value: trueon CONFIG entities — Correct; user tuning survives device reboots.- Offset filter direction —
x - offsetmeans a positive offset reduces the sensor reading, which is correct for a sensor that runs warm (subtracting the warm bias).
Version: deferred — no bump for now (this can sit in beta a while; set the
date-based YY.M.D.N at merge time)
What does this implement/fix?
Credit to Ellude (Apollo Discord) — they did the research and coefficient
fitting that make this work.
Adds two opt-in template sensors that estimate true room temperature and
humidity, correcting for the Air-1 enclosure's self-heating:
SCD40 temperatures with a thermal-gradient correction.
room temperature (Magnus formula), then blends by manufacturing tolerance.
Supporting CONFIG numbers for per-unit tuning:
Physics Multiplier P,Baseline Offset,SCD40 Temperature Offset,SCD40 Humidity Offset. TheSCD40 temperature/humidity and DPS310 temperature are exposed so the prediction
lambdas can read them.
Physics Multiplier Pdefaults to 0.5357, which isprovisional pending a better fitted value from Ellude.
Everything added here is additive and
disabled_by_default— the stockSEN55/SCD40/DPS310 sensors and their defaults are unchanged, and the new
entities stay hidden until a user enables them. The lambdas read on-device
state regardless of HA enablement, so disabling the entities doesn't affect the
calculation.
A wiki article covering how to enable and tune these (against a reference
thermometer) is in progress and will be linked here.
Types of changes
Checklist / Checklijst:
If user-visible functionality or configuration variables are added/modified:
🤖 Generated with Claude Code
Summary by CodeRabbit