11 · Changelog
Version history of the rbamp ESPHome external component. Dates in UTC.
Contents:
- v0.4.0 — 2026-05-28, protocol v1.2 parity
- v0.3 — 2026-05-28, 8-PR resilience audit
- v0.2 — 2026-05-24, SPEC §B.5 NACK discipline
- v0.1 — 2026-05-23, baseline import
- Forward compatibility with future firmware revisions
- Upgrade guide
- Deprecation policy
Deprecation policy
What the component promises not to break without warning, and what it may:
| Surface | Stability | What we promise |
|---|---|---|
YAML keys of the rbamp: block |
Stable | Removal or rename is possible only on a major bump (v1.0.0). Two minor releases before removal — a deprecation warning in the dump_config log. |
YAML keys of sensor.platform: rbamp (slots) |
Stable | Same rules. The names voltage/current/power/energy/frequency/power_factor are pinned as a contract with the HA Energy dashboard. |
Composition of HA entities and their device_class / state_class |
Stable | We will not change these without announcement; it affects entity_id in HA. |
Internal lambda-accessible methods RbAmpComponent::* |
Unstable | May change in minors. If you write lambda actions against internal APIs — pin the component version (refresh: <git-sha> in external_components:). |
| NVS-struct format | Versioned | Changes are accompanied by a bump of RBAMP_PREF_VERSION — old data is silently discarded, not corrupted. That means exactly one 5-minute energy-loss episode on upgrade, no more. |
Names and behavior of the i2c: block |
External | This is ESPHome core, not ours — follow upstream policy. |
| Wire-protocol surface (module registers) | Firmware SemVer | Smart-rules SPEC: minor adds registers; major may renumber. The component detects the firmware version and adapts behavior; see the compatibility table in README §Compatibility. |
What "deprecation warning" means: two minors before removal, the key starts logging a warning at boot. That's the signal to change the YAML before the next minor release. No silent breakage in stable surfaces — if something does break without warning, that's a bug, file an issue.
Pre-1.0 caveat: current 0.x releases are an alpha/beta series. We
strive to follow the policy above already, but we reserve a small amount
of room for critical breaking changes in minors before v1.0.0 — every
such change will be explicitly flagged in this changelog with a
[BREAKING] tag and migration instructions.
v0.4.0 — 2026-05-28, protocol v1.2 parity
The component reaches parity with firmware protocol v1.2 in step with sibling Arduino, ESP-IDF and Python v1.1.0 libraries.
New YAML keys (v0.4.0)
sensor_class:—SCT_013|WIRED_CT|BUILTIN_CT, defaultSCT_013. Pins the current sensor family on the module side. On firmware v1.2+ becomes a precondition for writing a CT-clamp model. On earlier firmware, accepted by the schema and applied automatically on upgrade.ct_models:— list of 1–3SCT_013_*enum values for UI2/UI3 with mixed clamp models on different channels (schema:cv.Length(min=1, max=3)). Mutually exclusive with globalct_model:.
Changed behavior
ct_model:now loads factory coefficients for the chosen model on firmware v1.2+ — writes both noise floor and gain automatically. On earlier firmware it works as in v0.3 (metadata-only).- Per-channel configuration for UI3 via
ct_models: [SCT_013_005, SCT_013_030, SCT_013_100]— the component sets its own model on each channel at boot. Total setup time for three channels is ~2–3 s (per-channel flash write).
Cross-platform parity
Full parity with Arduino + ESP-IDF + Python v1.1.0:
| Surface | Arduino | ESP-IDF | Python | ESPHome v0.4.0 |
|---|---|---|---|---|
Sensor class (sensor_class:) |
✓ | ✓ | ✓ | ✓ |
| Per-channel CT model | ✓ | ✓ | ✓ | ✓ |
| Class precondition for model write | ✓ | ✓ | ✓ | ✓ |
Breaking changes
None. All changes are additive — old YAML without the new keys continues to work as before.
Migration from v0.3
For typical deployments no action is required. For explicit v1.2 parity:
- Add
sensor_class: SCT_013to therbamp:block (optional — this is the default). - If on UI3 you have different clamps on different channels — replace
ct_model:withct_models: [...].
Example UI3 with mixed clamps:
rbamp:
id: home_meter
sensor_class: SCT_013 # default; can be omitted
ct_models: [SCT_013_005, SCT_013_030, SCT_013_100]More in Sensor Selection and Examples Example 2.
v0.3 — 2026-05-28, 8-PR resilience audit
Component resilience audit: cross-checked against 8 historical bug shapes in the ESPHome ecosystem (PRs / issues from esphome/esphome and emporia-vue-local/esphome). Result: 3 PASS, 3 N/A, 2 WOULD-BREAK (1 fixed, 1 hardened with a proactive guard).
New tests
tests/smoke.yaml— a compile-only smoke test for the YAML schema. ExercisesMULTI_CONFwith two instances, all single-sensor keys at once, phased keys on a separate instance, and all behavioral flags (ct_model,bidirectional,broadcast_latch,topology). Run:esphome compile smoke.yamlfrom thetests/directory. Protects against silent regressions of theesphome#7081class, where a refactor breaks the schema without being caught through a bench session.
Hardening
- Long flash-write windows (~700 ms per model write, ~300 ms post-reset) now feed the watchdog via
App.feed_wdt(). Protection against future ESPHome scheduler PRs that might shrink the default 15-secondsetup()budget. Added#include "esphome/core/application.h". - In the example YAMLs (
ui1,ui3,multi_module,address_change), inline comments were added about safe I²C pins on different ESP32 variants (classic / S2 / S3 / C3). The C++ itself is variant-agnostic; the risky point was YAML defaults targeting classic ESP32.
Audit verdicts
| Class | Verdict | Note |
|---|---|---|
| Multi-instance state desync (esphome#14152) | PASS | NVS slot key XORs the I²C address + a version constant |
| ADC saturation (esphome#2283) | N/A | Digitization is on the module side — no ESP32 ADC path |
| Multi-ADC contention (esphome#1915) | N/A | I²C bus mutex serializes between instances |
| IDF / Arduino SPI mode (esphome#14824) | N/A | I²C only; no framework-conditional code |
| Silent schema regression (esphome#7081) | WOULD-BREAK → fixed | Added tests/smoke.yaml |
| Per-channel cal cross-talk (esphome#12180) | PASS | Slot mapping verified |
| I²C pin defaults across ESP32 variants (emporia-vue#317) | WOULD-BREAK → hardened | YAML headers documented variant-safe pins |
| Boot crash + 0ms watchdog (emporia-vue#411 / #413) | PASS | + proactive App.feed_wdt() guard |
Breaking changes (v0.3)
None. All changes are additive (a new test file, new comments, defensive WDT feeds without behavioral influence in steady state).
Migration from v0.2 to v0.3
No action required. The App.feed_wdt() calls are invisible to users not triggering ct_model: or new_address: flows. Variant-pin comments are documentation only.
Credit
The pattern of multi-instance NVS-key derivation (XOR of I²C address + layout version) — the strongest line of defense against the esphome#14152 class (multi-instance cal-pref collision) — was already in the code before this audit. Credit to the component author: their pattern matched the one later adopted by the ATM90E32 fix in #14152 for the same reason (per-instance isolation + stale-data rejection on layout bump). The audit verified it — did not write it.
v0.2 — 2026-05-24, SPEC §B.5 NACK discipline
This release closes Phase 1 bench acceptance and brings the component in line with firmware v1.0 reality. Ready for production deployment for single-phase rbAmp.
New YAML keys (v0.2)
topology:—SINGLE|SPLIT_PHASE|THREE_PHASE, defaultSINGLE. Informational topology hint — the module on current firmware has no in-band channel-count register. Goes into adump_configline. Will become authoritative once the module starts publishing topology via its register. TheSINGLEdefault matches every current SKU — no action required for existing deployments.
New behavior
- NACK retry: each byte of a float32 register is retried up to 3 times with a 5 ms pause between attempts. Reduces the effective bad-read rate from ~20% (at 100 kHz due to NACK behavior in the master stack) to < 1%. See SPEC §B.5.
- Weak sanity filter: replaces the early per-register hard-bound switch. The new filter discards only non-finite floats and values with
|val| > 10000. No lower bound — brownout, mains drop-out (U → 0 V) and off-grid states pass through to HA unfiltered. - Warning on
broadcast_latch: trueat boot when the detected firmware version is< 0x02. Explains that v1 firmware silently drops writes to the broadcast address; the component falls back to a sequential latch for each module. The warning disappears automatically when firmware adds support.
Bug fixes
- ESPHome 2025.x API break —
get_object_id_hashremoved: previous NVS-key seed logic calledthis->get_object_id_hash(), a method removed fromPollingComponentin 2025.x. Replaced with a pattern that XORs the I²C address and a layout-version constant — gives per-instance isolation and stale-data rejection on layout bump. NVS data from pre-2025.x deployments is invalidated by this key change; Wh totals reset to 0 on the first boot after upgrade.
Doc updates
__init__.py— theCT_MODELSblock got a multi-line docstring explicitly stating thatct_model:on v1 firmware is only writing a model marker.README.md— sections on CT-model writing, broadcast LATCH limitations on v1, using the topology hint, and cross-references to SPEC §B.5 updated for v1 reality.- Example YAMLs —
i2c: frequency:changed from100kHzto50kHz. An inline comment in each file explains why. example/.gitignore— added/bench-*.yamlso that operator-local bench configs with WiFi credentials and OTA targets do not land in commits.
Bench acceptance (2026-05-24)
Five acceptance criteria verified on the operator's UI1 bench:
| # | Criterion | Result |
|---|---|---|
| 1 | esphome compile example/ui1.yaml clean |
PASS (58.71 s, 0 errors) |
| 2 | dump_config within 5 s of boot |
PASS (setup 67 ms; dump_config @ 121 ms) |
| 3 | Instantaneous entities within ±2% of baseline | PASS (U ≈ 228 V, I ≈ 0.9 A, P ≈ 117 W, PF ≈ 0.57, F = 50 Hz) |
| 4 | NVS energy rises monotonically, survives reboot | PASS (0.051 → 0.134 → 0.310 → ... → 4.069 Wh through several reboots) |
| 5 | Schema validation passes for all 4 example YAMLs | PASS |
Post-fix verification (6 cycles × 60 s, filter-relaxation run): U = 227–228 V, I = 0.81–0.83 A, P = 100–106 W, PF = 0.54–0.56, F = 50 Hz. Zero Failed to read or i2c.master: NACK in the log over a 6-minute capture.
Breaking changes (v0.2)
None in terms of YAML configuration. Existing rbamp: configurations without the new topology: key continue to work (default SINGLE). The broadcast_latch: warning is informational — no config changes required.
NVS key change: users upgrading from pre-2025.x ESPHome (where the old NVS path through get_object_id_hash was used) will see Wh totals reset to 0 on the first boot. This is a one-time event. HA long-term statistics energy history is preserved.
v0.1 — 2026-05-23, baseline import
Baseline import of an already-existing ESPHome component into the monorepo alongside the cross-platform family of client libraries. This commit pins the component as it existed before the Phase 1 bring-up session.
What was in the baseline
rbamp:YAML schema with keysid,address,update_interval,drdy_pin,ct_model,bidirectional,new_address,broadcast_latch. Thetopology:key was not yet present.- Sensor platform with a full set of single-phase and phased fields, the mutex validator, and the companion-field validator.
- C++ component layer with I²C read helpers, variant detection, NVS persistence, address change, CT-model write, latch pipeline, RT publish. Per-byte NACK retry was not yet present; the sanity filter was a simple
isfinitewithout a|val| < 10000cap. - Example YAMLs (
ui1.yaml,ui3.yaml,multi_module.yaml,address_change.yaml) withi2c: frequency: 100kHz. - README.md — configuration reference, migration guide, and known-limitations section.
- tests/README.md — checklist of Phase 1 milestone smoke tests.
State at v0.1
The component was functionally complete for single-phase deployments, but had three divergences from firmware v1.0 reality, fixed in v0.2:
- No warning on
broadcast_latch: true(v1 firmware silently drops general-call writes). - The
CT_MODELSdocstring did not state that v1ct_model:is metadata-only, does not calibrate NF / gain. - No
topology:key, no explicit topology-hint path.
Additionally, float reads had no retry — vulnerable to the ~20% NACK rate at 100 kHz.
Breaking changes v0.1 → v0.2
See the NVS key change note in the v0.2 entry above (one-time Wh totals reset).
Forward compatibility with future firmware revisions
The component is fully functional with current firmware. When the planned firmware improvements ship, three points in the component will get minor updates.
Point 1 — topology detection
Now: the component reads the topology: YAML key (default SINGLE) and uses it as the authoritative source for the number of phases.
After upgrade: the component will prefer the topology value published by the module via its register. If the module on old firmware returns 0 — the component falls back to the YAML hint. Cross-compatibility v1.0 / v1.2 + v1.x-with-topology-register / v1.x-with-topology-register is preserved.
Point 2 — broadcast LATCH
Now: with broadcast_latch: true and a detected firmware version < 0x02, the component logs a warning that broadcast writes are dropped by the module, and falls back to a sequential latch for each module.
After upgrade: no code changes required — the gate condition firmware_version_ < 0x02 already handles this. Once firmware lifts the version above 0x02, the warning stops printing and broadcast writes go through normally.
Verification: after flashing modules with the new version, no "general-call DISABLED" warning should appear in the boot log, and multiple modules should latch in a single bus transaction.
Point 3 — ct_model: metadata → coefficient auto-load
Now (v0.4.0 + firmware v1.2+): writing ct_model: automatically loads the noise floor and gain from the factory preset table on the module side. No calibration steps required.
On earlier firmware: writing ct_model: is only a model marker. The compatibility path is ensured via the sensor_class: precondition: a module on early firmware accepts the write (without auto-load), a module on v1.2+ provides auto-load automatically.
Non-blocking timeline
None of these changes is required in advance. The component is fully functional with current firmware through the YAML hint + warning + metadata-only paths. The points are small (< 10 LOC each) and can be closed in a single commit when new firmware becomes available for bench verification.
Upgrade guide
From v0.3 to v0.4.0
- Update the component sources:
git pull(if you cloned the monorepo) or rewrite thecomponents/rbamp/directory entirely. -
Optional — add new keys to the YAML for explicit v1.2 parity:
yaml rbamp: sensor_class: SCT_013 # default; can be omitted ct_model: SCT_013_030 # as before # or for UI3 with mixed clamps: # ct_models: [SCT_013_005, SCT_013_030, SCT_013_100] -
No breaking changes. Old YAMLs work without edits. The real difference shows up only when working with a module on firmware v1.2+ (coefficient auto-load).
From v0.1 to v0.2 (for historical reference)
- Update the component sources (git pull / rewrite the directory).
- Update the YAML:
i2c: frequency:from100kHzto50kHzin every config using rbamp. - No other YAML changes needed. The new
topology:key defaults toSINGLE, which matches every current SKU. - NVS Wh reset: the first boot after upgrading from pre-2025.x ESPHome + an older component version will show
No saved energy state — starting from 0 Wh. A one-time event due to the NVS-key change. HA long-term statistics history is preserved. - Remove
ct_model:from the YAML if you added it in a previous session and the flash write has already been applied. On v0.3- the key triggers a flash write again on every boot (on v0.4.0 + v1.2+ this is less of a problem, but it's still a ~700 ms blackout). On v0.4.0 idempotency is guaranteed: repeating the same model write does not produce a second flash write.
From pre-v0.1 (components copied before the monorepo import)
The pre-monorepo version of the component had no NACK retry, no energy NVS persistence, and no CT_MODELS enum. Walk through the v0.1 → v0.2 → v0.3 → v0.4.0 steps above sequentially; the NVS key will not collide (the key namespace is derived from the name, not from a per-installation string).
Source & issues: rb-amp/rbamp-esphome · this page in the repo: docs/11_changelog.md