Skip to content

[tfluna] Recover from transient runtime reconfiguration failures - #20992

Merged
J. Nick Koston (bdraco) merged 3 commits into
esphome:devfrom
fallenmi:codex/tfluna-currentbase-oct17
Oct 18, 2026
Merged

J. Nick Koston (bdraco) merged 3 commits into
esphome:devfrom
fallenmi:codex/tfluna-currentbase-oct17

Conversation

@fallenmi

@fallenmi Igor Stadnyk (fallenmi) commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

What does this implement/fix?

Keep TF-Luna usable after a transient I2C failure while reconfiguring after a factory reset. Runtime configuration failures now leave a warning and retry on the next update instead of permanently marking the component failed. Initial setup failures remain permanent.

Also check reset/restart writes before following them up, skip runtime writes on failed components, and clear the warning only after receiving a new measurement. The existing 100 ms factory-reset delay is retained. This does not guarantee persistence to flash after a failed save.

The shared Application lifecycle/test-harness changes were split into #21001 and merged separately, as requested. This PR now changes only the two TF-Luna production files and adds its 16 host tests. Existing maintainer merge history is preserved with a normal merge, without rebasing or force-pushing.

The three LOG_STR conversions overlap the existing cleanup in #20864; they are not claimed as a separate new fix.

Verification and limitations
  • The original regression A/B on base 1b4721d is retained: with the same test harness, reverting only the two TF-Luna production files changes 16/16 passing to 7/16; restoring the fix returns 16/16.
  • Independently renewed against dev c9ba6c3: TF-Luna 16/16 and combined TF-Luna/EmonTx/i2c 66/66 pass with ASAN/UBSAN.
  • Paired full host runs on that exact C9 base: pristine 2240/2261 pass; candidate 2256/2277 pass, including all 16 added tests. Both have the same 21 qualified failure names and 11 normalized UBSAN sites. This is NOT a fully green run. These are macOS runs in a network-denied sandbox.
  • Scoped native HOST clang-tidy 22.1.8, using the actual full-host compile database, passes for TF-Luna production/header and the test translation unit. In the separate no-sensor host configuration, three dead-store warnings also reproduce on the exact original C9 production/header; they are not reported as a passing no-sensor lint run. Checks and WarningsAsErrors remain unchanged; no new suppressions.
  • Official ci-custom passes on the three changed paths. Native ARM clang-format 13.0.1 dry-run passes on those same unchanged bytes. The normal unmodified pinned prek run has four passing hooks and six automatic no-matching-file skips; its bundled clang-format fails to execute on this ARM host (Bad CPU type). That normal run is not claimed fully green, and its hook binary/config was not replaced.
  • On this candidate, the normal component configuration driver passes for ESP32-IDF, ESP8266-Arduino and RP2040-Arduino. Normal C++ source generation also passes for each platform's generated test wrapper. No full firmware build or hardware testing.
  • Local runtime/lint results above cover C9, not every later dev commit. A clean native merge against dev 89afb11 was checked separately; the resulting diff is still exactly these three TF-Luna paths. Current CI for this updated head remains a separate check.

AI assistance: prepared and refined with Claude Code; independently reviewed, tested and integrated with Codex. No claim of manual hardware validation.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • New developer-facing feature (adds functionality for component developers; no end-user configuration change)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected) — policy
  • Developer breaking change (an API change that could break external components) — policy
  • Undocumented C++ API change (removal or change of undocumented public methods that lambda users may depend on) — policy
  • Code quality improvements to existing code or addition of tests
  • Other

Related issue or feature (if applicable):

  • No existing issue found in the scoped public searches. Related cleanup noted above is not the runtime recovery fix.

Pull request in esphome.io with documentation (if applicable):

  • Not applicable; no new configuration options.

Pull request in developers.esphome.io with developer documentation (if applicable):

  • Not applicable.

Test Environment

Native macOS host with ASAN/UBSAN; platform configuration/source-generation checks only. The hardware boxes below are intentionally unchecked.

  • ESP32
  • ESP32 IDF
  • ESP8266
  • RP2040/RP2350
  • BK72xx
  • RTL87xx
  • LN882x
  • nRF52840

Example entry for config.yaml:

Existing configuration is unchanged; the existing test fixture includes these controls:

tfluna:
  - i2c_id: i2c_bus

button:
  - platform: tfluna
    factory_reset:
      name: "factory reset"
    restart:
      name: "restart"

Checklist:

  • The code change is tested and works locally.
  • Tests have been added to verify that the new code works (under tests/ folder).

If user exposed functionality or configuration variables are added/changed:

Not applicable: no user-facing configuration changes.

Keep setup failures permanent, but retry runtime configuration after a transient I2C failure. Add regression coverage and use one shared Application lifetime in combined host tests.

Prepared with Claude Code; independently checked and integrated with Codex.
@esphome

esphome Bot commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

To use the changes from this PR as an external component, add the following to your ESPHome configuration YAML file:

external_components:
  - source: github://pr#20992
    components: [tfluna]
    refresh: 1h

(Added by the PR bot)

@esphome

esphome Bot commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

👋 Hi there! This PR modifies 2 file(s) with codeowners.

Craig Andrews (@candrews) - As codeowner(s) of the affected files, your review would be appreciated! 🙏

Note: Automatic review request may have failed, but you're still welcome to review.

@codecov

codecov Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.95%. Comparing base (c9ba6c3) to head (e3f93b5).
⚠️ Report is 9 commits behind head on dev.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##              dev   #20992   +/-   ##
=======================================
  Coverage   93.95%   93.95%           
=======================================
  Files          90       90           
  Lines       20465    20465           
  Branches     3176     3176           
=======================================
  Hits        19227    19227           
  Misses        947      947           
  Partials      291      291           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed

codspeed Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ 21 benchmarks spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

✅ 210 untouched benchmarks


Comparing fallenmi:codex/tfluna-currentbase-oct17 (60a41ad) with dev (635df9c)

Open in CodSpeed

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Memory Impact Analysis

Components: tfluna
Platform: esp8266-ard

Metric Target Branch This PR Change
RAM 29,400 bytes 29,292 bytes 📉 ✅ -108 bytes (-0.37%)
Flash 272,407 bytes 272,547 bytes 📈 🔸 +140 bytes (+0.05%)
📊 Component Memory Breakdown
Component Target Flash PR Flash Change
[esphome]tfluna 1,199 bytes 1,429 bytes 📈 🚨 +230 bytes (+19.18%)
app_framework 2,526 bytes 2,522 bytes 📉 -4 bytes (-0.16%)
🔍 Symbol-Level Changes (click to expand)

Changed Symbols

Symbol Target Size PR Size Change
esphome::tfluna::TFLuna::setup() 180 bytes 49 bytes 📉 -131 bytes (-72.78%)
esphome::tfluna::TFLuna::update() 65 bytes 113 bytes 📈 +48 bytes (+73.85%)
esphome::tfluna::TFLuna::restart() 48 bytes 59 bytes 📈 +11 bytes (+22.92%)
esphome::tfluna::TFLuna::factory_reset() 97 bytes 105 bytes 📈 +8 bytes (+8.25%)
esphome::tfluna::TFLuna::read_data_timeout_() 104 bytes 100 bytes 📉 -4 bytes (-3.85%)
setup 735 bytes 731 bytes 📉 -4 bytes (-0.54%)
esphome::tfluna::TFLuna::read_data_() 224 bytes 220 bytes 📉 -4 bytes (-1.79%)
std::_Function_handler<void (), esphome::tfluna::TFLuna::factory_reset()::{lambda()#1}>::_M_manag...std::_Function_handler<void (), esphome::tfluna::TFLuna::factory_reset()::{lambda()#1}>::_M_manager(std::_Any_data&, std::_Function_handler<void (), esphome::tfluna::TFLuna::factory_reset()::{lambda()#1}> const&, std::_Manager_operation)
17 bytes 20 bytes 📈 +3 bytes (+17.65%)
std::_Function_handler<void (), esphome::tfluna::TFLuna::factory_reset()::{lambda()#1}>::_M_invok...std::_Function_handler<void (), esphome::tfluna::TFLuna::factory_reset()::{lambda()#1}>::_M_invoke(std::_Any_data const&)
9 bytes 8 bytes 📉 -1 bytes (-11.11%)

New Symbols (top 15)

Symbol Size
esphome::tfluna::TFLuna::configure_() 163 bytes
esphome::tfluna::TFLuna::factory_reset()::__pstr__ 57 bytes
esphome::tfluna::TFLuna::reconfigure_() 53 bytes
esphome::tfluna::TFLuna::read_data_timeout_()::__pstr__ 27 bytes
esphome::tfluna::TFLuna::configure_()::__pstr__ 21 bytes

Removed Symbols (top 15)

Symbol Size
esphome::tfluna::TFLuna::setup()::__pstr__ 21 bytes

Note: This analysis measures static RAM and Flash usage only (compile-time allocation).
Dynamic memory (heap) cannot be measured automatically.
⚠️ You must test this PR on a real device to measure free heap and ensure no runtime memory issues.

This analysis runs automatically when components change. Memory usage is measured from a representative test configuration.

@esphbot

ESPHome Bot (esphbot) commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Previous review — superseded by a newer review below.

@esphbot ESPHome Bot (esphbot) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Tip

No blocking issues found — ready to merge.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Shared Application lifetime changes affect all host suites, and reported suite failures lack a clean matching-base comparison.

No open issues 🎉

What changed in this PR

Improves TF-Luna recovery from transient runtime reconfiguration failures while preserving permanent setup failures.

Changes:

  • Retries runtime configuration and retains warnings until a new measurement arrives.
  • Adds 16 host tests covering recovery and failure handling.
  • Centralizes shared Application construction and updates affected test fixtures.
File Description
tests/​components/​xiaomi_body_scale/​common.h Removes fixture-local Application construction.
tests/​components/​tmp102/​test_tmp102.cpp Pairs Application destruction and reconstruction.
tests/​components/​tfluna/​test_tfluna.cpp Adds runtime recovery regression tests.
tests/​components/​snapshot/​snapshot_test.cpp Uses centrally constructed Application.
tests/​components/​pd_pioneer_ir/​pd_pioneer_ir_tests.cpp Removes duplicate Application construction.
tests/​components/​mistral_ir/​mistral_ir_tests.cpp Removes duplicate Application construction.
tests/​components/​main.cpp Constructs Application before tests run.
tests/​components/​i2c/​test_i2c_chip_id.cpp Destroys Application before replacing it.
tests/​components/​haier_water_heater/​water_heater/​test_hon_controller.cpp Removes local construction and unused include.
tests/​components/​filter_lifetime/​test_filter_lifetime.cpp Preserves Application lifetime between tests.
tests/​components/​emontx/​common.h Makes the legacy construction helper a no-op.
tests/​components/​display/​test_test_card.cpp Removes redundant fixture setup.
tests/​components/​daikin/​daikin_tests.cpp Removes local construction and unused include.
tests/​components/​daikin/​daikin_regression_tests.cpp Removes local construction and unused include.
esphome/​components/​tfluna/​tfluna.h Declares reconfiguration helpers and retry state.
esphome/​components/​tfluna/​tfluna.cpp Separates setup failures from recoverable runtime failures.

Review effort: Balanced

@bdraco

Copy link
Copy Markdown
Member
  1. The shared test-harness change belongs in its own PR
    tests/components/main.cpp:35-38

Please split this PR

@esphome

esphome Bot commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts. Please merge the latest dev branch into your branch to resolve them.

@esphbot

Copy link
Copy Markdown
Contributor

J. Nick Koston (@bdraco): > 2. The shared test-harness change belongs in its own PR

Split done. Harness landed in #21001. Diff now three TF-Luna paths. construct_app() no-op removed.

@esphbot

Copy link
Copy Markdown
Contributor

PR Review — [tfluna] Recover from transient runtime reconfiguration failures

Mergeable. Two non-blocking suggestions remain.

The PR is now split as J. Nick Koston (@bdraco) asked: the shared App harness work landed in #21001, so this diff is just the two TF-Luna production files plus their tests. The no-op construct_app() from the previous review is gone too. The fix itself is sound:

  • configure_() is shared by two paths. A boot failure is permanent (mark_failed). A runtime failure leaves a warning and sets reconfigure_pending_, and the next update() retries.
  • factory_reset() clears the pending flag only after the reset write succeeds.
  • The is_failed() guards keep the buttons and update() off the bus once the component is dead.
  • The RegisterBus fake injects one NACK at each configuration step. Tests cover a double press, a reset while a reconfigure is pending, and a reset NACK while one is pending.

Suggestions:

  • A retry after a SAVE NACK sees trigger mode already set and skips the save. A later Restart or hung-device reboot then loses trigger mode, and the SAVE test does not check save_writes.
  • StagedForeignTimeoutBlocksOwnership tests fixture plumbing, not TF-Luna.

✅ Resolved since last review (1)

Previously-flagged issues verified fixed
  • tests/components/emontx/common.h:47 Remove the no-op construct_app() instead of keeping it


Checklist

  • No hardcoded secrets
  • Error paths handled (I2C NACKs at boot vs runtime)
  • New branches covered by tests
  • Test isolation / shared state
  • Scope matches PR description
  • Tests target component behaviour
  • Repo C++ conventions (LOG_STR, this->, constexpr ids)
ℹ️ Triage summary

2 pre-existing finding(s) on unchanged code suppressed (freeze).


Automated review by Kōan (Claude) HEAD=e3f93b5 36s

@esphbot ESPHome Bot (esphbot) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Tip

No blocking issues found — ready to merge.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The focused recovery changes have regression coverage and no unresolved blocking findings; firmware and hardware validation remain unverified.

No open issues 🎉

Review effort: Balanced

@bdraco J. Nick Koston (bdraco) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@bdraco
J. Nick Koston (bdraco) merged commit bb9067a into esphome:dev Oct 18, 2026
49 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants