All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
power_consumptionandelectricity_costunder-counted on any installation polling slower than 10 s (down to about 1% of the real consumption at a 20 s interval). The energy integrator discarded every increment whose time since the previous poll exceeded a hard-coded2 × DEFAULT_SCAN_INTERVAL(10 s), while the coordinator polls at the configuredscan_interval, so at 20 s only the rare polls landing under 10 s apart were counted. The tolerance now derives from the configured interval (3 × scan_interval, never below 30 s: the gap between polls is the interval plus the Modbus read time, and slow gateways at the default 5 s were already losing a quarter to a third of their energy to the old guard), and a longer gap is clamped to that tolerance rather than dropped, so a gateway outage costs at most that much phantom energy instead of losing the increment that ends it.electrical_poweritself was correct throughout (#403).power_consumption,electricity_costand thethermal_energy_*totals no longer publish0.0for one poll after a Home Assistant restart or an integration reload. Their last recorded state was restored after the first poll had already publishedcoordinator.data, and nothing re-injected the restored value, so the first state seen by the entities was 0.0 before jumping back to the lifetime total on the next poll. Home Assistant statistics read that as a meter reset followed by new consumption and re-added the whole total to thesumstatistic at every restart. The counters are now restored before the first poll, as the refrigerant detector state already was (#432).
- A configured Power Sensor (
power_entity) is now read even when the compressor reports 0 A. The electrical-power computation was guarded bycompressor_current > 0, but the measured-power path does not use the current at all, so the external meter was simply ignored whenever the compressor current read zero: standby draw was never counted for anyone, and wherever the gateway itself reports a constant 0 A (an HC-A(16/64)MB serves no compressor current for a unit read at a secondary refrigerant cycle, even with the compressor running)electrical_power,power_consumptionandelectricity_costwere stuck at 0 forever, even with a dedicated meter correctly configured. TheP ≈ U × I × cosφestimate is unchanged. Note that DHW COP still cannot be computed on a Yutampo R32: it requires water inlet/outlet temperatures and flow, which that unit does not report (#403).
- Telemetry on installations with more than one Hitachi gateway: every config entry
shared a single
instance_hashderived from the Home Assistant instance, so the ingestion endpoint's rate limit (1 request per 60s per identity) rejected all but one flush per 5-minute cycle, permanently. Each entry now sends its owndevice_hash, derived from the gateway hardware identifier, so the rate limit, the R2 archive keys and the fleet dashboard address a heat-pump unit rather than a household. Two silent archive defects are fixed with it: installation payloads from different units no longer overwrite each other, and two entries flushing in the same second no longer collide on the same metrics object name. Failed sends now re-queue their buffered points instead of dropping them (bounded to 30 minutes and to 80 points per request, so a backlog drains over several cycles instead of growing into a request the endpoint refuses; a batch refused as too large is dropped rather than retried indefinitely), and every telemetry log line carries the config entry name, with rate-limit rejections raised from DEBUG to WARNING so the cause is visible. Legacy installations whose config entry never got a hardware identifier now include the unit id in their fallback identifier, so several units behind one HC-A(16/64)MB gateway no longer collapse into a single identity. Single-gateway installations are unaffected and their fleet history is continuous (#395). - Telemetry no longer loses points on installations polling faster than about 3.75 seconds. A flush carries at most 80 points, so a faster poll produced more per 5-minute cycle than one request could take and the buffer silently discarded the surplus forever. Collection is now thinned to one poll out of N so a cycle never outruns what a flush can send, and any point a full buffer still evicts is counted and logged instead of vanishing. The default 5-second interval, and anything slower, collects every poll exactly as before (#395).
- Telemetry no longer archives the same points twice after a lost response. When a send timed out on a batch the endpoint had in fact stored, the immediate retry hit the rate-limit window that very attempt had armed, and the points were re-queued and sent again on the next cycle. Such a rejection is now recognised for what it is and the batch is not re-queued (#395).
- Telemetry requests are now bounded in bytes rather than in points. A point carries one field per register plus the derived metrics, so its size depends on the heat-pump profile: 80 points measure about 90 KB on the narrowest profile but about 233 KB on the widest, against a 256 KB limit at the endpoint. A wide installation that had one failed send could therefore build a batch the endpoint refuses, losing those points. A batch is now filled up to a serialized budget, so a wide profile sends fewer points per request instead of an oversized body (#395).
- The telemetry buffer now holds the same 30 minutes at any poll cadence. Its size was a fixed number of points, which meant 30 minutes at the default 5-second poll but six hours at a 60-second one, while re-queued points were discarded after 30 minutes either way (#395).
- Buffered telemetry points are no longer lost when Home Assistant shuts down while
a send is in flight. The cancellation that shutdown raises does not derive from
Exception, so the points already taken out of the buffer were dropped instead of being put back for the final flush (#395). - Unloading or reloading the integration no longer waits on an unreachable telemetry endpoint. The final flush retried three times with backoff, holding up a Home Assistant shutdown for the better part of a minute for anonymous, best-effort data; it is now bounded to about one attempt (#395).
- A batch rejected as too large is now dropped even when the connection breaks before the error body can be read. The read failure was previously mistaken for a transient error, so the batch was re-queued and rejected again on every cycle (#395).
- Refrigerant charge detection (beta) is now opt-in and off by default. It lives in a new "Advanced features (beta)" panel (its first toggle) shown as the last step of setup and in the integration Options (the cog), and existing installations get a one-time onboarding notification ("Try refrigerant charge monitoring (beta)") whose fix flow enables it. The panel is only offered on profiles with the extended compressor sensors (never the Yutampo R32). The consent text strongly cautions that the feature is experimental, rests on very little validation data, and will only be considered stable after a full winter heating season: any alert is a hint to look closer, not a diagnosis (it can be a false positive), so do not call a technician or pay for a service on an alert alone, always double-check first. It also invites enabling anonymous telemetry so the detector's reliability can be validated across the fleet. The detector, its
Refrigerant Charge Statussensor, theReset Refrigerant Baselinebutton and the repair issue now run only when both the heat-pump profile exposes the extended compressor sensors and you have consented (#393). - Refrigerant charge alert: the repair issue is now fixable: confirming the circuit was serviced resets the detection baseline (same as the Reset Refrigerant Baseline button) (#384).
- Refrigerant charge detection (beta): the gas-line superheat plausibility bounds now live per heat-pump profile (
gas_superheat_plausible_range, all provisionally(-10, 80)K) instead of a fixed module cap. The previous40 Kcap came from a wrong reading of the physics (Tg, register 1206, is the THMg gas-pipe thermistor, soTg - Teis a condensing-side lift of about 40-60 K in heating, not a suction superheat) and it starved the detector on Yutaki S80 and Yutaki M, which risked staying inlearningor freezing a biased baseline. Detection is unchanged in principle (drifts are measured against a per-installation learned baseline). When a baseline is frozen outside its model's observed fleet band, a diagnostic warning is now logged (helps catch profile misdetection or a multi-unit HC-A(16/64)MB topology). Documentation now states clearly that this detection is in test (beta) and will likely remain so for at least 1 to 2 years while cross-season fleet data is collected. Upgrade note (action required): raising the plausibility cap changes which samples are collected, so baselines learned under the old cap (notably on S80 and M) are biased. After updating, press Reset Refrigerant Baseline (Primary Compressor device) to re-learn a clean reference. No stored-data migration is performed (#393).
- Refrigerant charge status: an alert frozen at end of heating season is now annotated as stale (new
last_valid_day/days_since_valid_datasensor attributes, dedicated issue text) instead of silently reporting months-old data (#384). - Refrigerant anomaly detection: hardened the persisted-state restore path. The detector state is now restored before the coordinator's first poll, so a Home Assistant restart no longer briefly flaps the
Refrigerant Charge Statussensor to a spuriouslearningstate: the persisted verdict (and its repair issue, when an alert is active) is re-established from the very first poll. A corrupt or malformed persisted snapshot no longer fails the integration setup: the payload is fully validated before any state is touched (restore is atomic), a warning is logged, and the detector restarts cleanly inlearningmode (#383). - Coordinator: a crash in a post-fetch stage (derived-metrics enrichment, refrigerant repair-issue update, telemetry collection or
system_configpersistence) was misreported as a gatewayconnection_errorrepair issue and marked every entity unavailable, even though the Modbus poll had returned complete valid register data. Such failures are now logged with a full stack trace as integration bugs and the raw register data is returned: register-backed entities keep updating and noconnection_errorissue is raised (derived sensors may readunknownfor the affected cycles). Real Modbus/communication failures keep the exact previous behavior:connection_errorissue,UpdateFailed, and gateway-not-ready backoff (#386). - Removing the integration's config entry now cleans up everything it persisted: the refrigerant detector's baseline file (
.storage/hitachi_yutaki_refrigerant_<entry_id>) and the per-entry repair issues (refrigerant charge alert, missing configuration, telemetry and energy-cost onboarding). Domain-wide issues (connection_error, gateway desync/initializing warnings) are also swept when the last entry is removed. Previously these were orphaned forever after deleting the entry (#385).
- Refrigerant-circuit anomaly detection (first iteration): a continuous, local early-warning for a slow refrigerant charge loss, built from the compressor signals the integration already reads. A new diagnostic sensor
Refrigerant Charge Status(learning/ok/watch/alert, on the Primary Compressor device) tracks the joint drift of suction superheat (Tg − Te) and the outdoor expansion-valve opening (EVO) against a per-installation baseline learned over ~2 weeks of heating; superheat (a regulated, season-robust quantity) is the primary signal andEVOis only compared at equivalent outdoor temperature to avoid weather-driven false alarms. A self-clearing repair issue is raised when the alert persists for several days, and aReset Refrigerant Baselinebutton re-learns the reference after a refrigerant top-up or expansion-valve service. The baseline persists across restarts. Advisory only — it complements and does not replace the mandatory F-Gas leak-tightness inspection. Available on all profiles with extended compressor sensors (every model except the Yutampo R32). See docs/reference/refrigerant-monitoring.md (#310).
- Docs: clarified that
electrical_powerandpower_consumptionare compressor-only estimates (P ≈ U × I × cosφ), not full-unit measurements. They exclude the electric backup/immersion heater, pumps, fan and standby loads, so they structurally under-report (notably on Yutampo/DHW-only setups); a configured Power Sensor takes priority and yields accurate readings. Fixed the misleading "Total electrical energy consumed by the unit" description indocs/reference/entities.mdand documented the scope indocs/reference/domain-services.md(#373).
- Config flow: a second unit on the same HC-A(16/64)MB gateway was wrongly rejected as "already configured" when it shared the same model as an existing unit. The hardware identifier read for the
unique_id(input registers 0-2) is gateway-wide, so every unit on one gateway produced the sameunique_id; two identical models therefore collided (two different models only avoided it by coincidence). Theunique_idis now suffixed with the per-unit H-LINK address (unit_id) on both the hardware-id and IP-fallback paths, so physically distinct units — even of the same model — no longer collide. Existing config entries keep their storedunique_idand are unaffected. Upgrade note: entries created before this version keep the old (unsuffixed)unique_id, so the duplicate guard will not recognise them if you re-add the same already-configured unit through the setup flow without removing the old entry first — remove the old entry first, or delete the resulting duplicate. New and re-created entries are fully deduplicated (#370). - HC-A(8/16/64)MB: read each unit's outdoor-unit registers (Primary Compressor discharge
Td, evaporatorTe, current, frequency and outdoor expansion valveEVO) from the correct refrigerant-cycle block. The outdoor block is keyed on the outdoor refrigerant cycle (30000 + Cycle × 100 + offset, datasheet PMML0351 rev.6 §5.2.3), but the map read it at a fixed base30000, so on a gateway hosting several independent systems every unit reported cycle-0's compressor data. The cycle is arbitrary and is not theunit_id(on the reporter's hardware units 0/1/2 map to cycles 0/5/7), so it is now detected from the gateway unit table (input register200 + unit_id × 4 + 1,0xFFmeaning "no unit"), persisted at config time underoutdoor_cycle, and used to address the outdoor block. Existing installations self-heal on the next setup: the cycle is detected from the gateway and stored automatically, with no need to re-add the unit. When the cycle cannot be read the map falls back to cycle 0, preserving the previous behaviour (#353).
- ATW-MBS-02 (Before Line-up 2016): ECO mode support. Unlike the 2016+ line-up where ECO is controlled per circuit, pre-2016 units expose a single global "Space mode" toggle (address 1027, read/write on the same address) and a single global ECO offset (STATUS 1090 / CONTROL 1030, range 1~10) shared by all circuits. They surface as a new ECO Mode switch and Eco Offset number on the Control Unit device, created only when the active register map defines these registers (#253).
- CI/tooling: raised
requires-pythonfrom>=3.13to>=3.13.2, which collapses a staleuv.lockresolution fork. Because>=3.13allowed 3.13.0/3.13.1, the resolver forked to an ancienthomeassistant 2024.1.5(which we never support -- our floor is 2025.1.0) that pinnedorjson==3.9.9; that sdist fails to build under recentuv, so any lockfile-regenerating dependency PR broke on the lint/test jobs. The lock is now single-version. - Yutampo R32: stop creating entities for hardware a DHW-only unit does not have. The ATW-MBS-02 gateway reports a constant
0(not a sentinel) for the space-heating water circuit (water_inlet/outlet/2/3/target_temp,water_flow,pump_speed, pump 1/2/3), the heating thermal meters (thermal_power_heating,thermal_energy_heating_daily/total) and the extended compressor sensors (gasTg/ liquidTitemperatures, indoor/outdoor expansion valve openings), so those readings could not be filtered by value and surfaced as permanentlyunavailable/0entities. These are now gated on two new profile capabilities —supports_water_circuitandsupports_extended_compressor_sensors— bothFalsefor the Yutampo R32 (confirmed against the anonymized telemetry fleet). The core compressor sensors (frequency, current, dischargeTd, evaporatorTe) and the DHW entities are unaffected (#365). - Compressor timing:
Compressor rest time(and run/cycle time) could report a negative value. When Recorder-replayed states (local wall-clock) interleaved with livedatetime.now()readings across a clock/DST shift, an off→on transition could compute a negative duration and average it in. Negative durations are now discarded while the state transition is still recorded (#365).
- Yutampo R32 upgrade note (release note action required): existing Yutampo installations already have the now-removed water-circuit and extended-compressor entities registered. Home Assistant does not delete them automatically, so after upgrading they linger in the entity registry as restored
unavailableentries. Affected users should delete them manually (Settings > Devices & Services > the entity > Delete) to clear dead references in dashboards, the Energy configuration and automations. New installations are unaffected (#365). - CI/tooling: Dependabot now ignores
zeroconf, a transitive dependency pinned exactly by Home Assistant (==0.148.0); bumping it independently forces the resolver to backtrack HA and can never merge. - Docs: refreshed the HC-A(8/16/64)MB datasheet to the official PMML0351 rev.6 (04/2026) and corrected the outdoor-unit register addressing in
docs/gateway/hc-a-mb.md. The outdoor block is keyed on the outdoor unit refrigerant cycle (30000 + (Cycle × 100) + offset), not the indoorModbus_Id— the previous5000 + (Modbus_Id × 200)formula was wrong (groundwork for #353).
- Logging: the gateway now logs an explicit recovery line (with the real not-ready duration) when its
system_statetransitions back from initializing/desynchronized to synchronized. Previously the recovery was silent in the Modbus layer, so the full outage window (and its true length) was not visible in the logs; only the "not ready" detection and the periodic "still not ready" reminders were. This makes it possible to measure the actual desync windows directly from Home Assistant's logs (#356).
- Telemetry backend:
backend/grafana/koppen-zones.geojson, a simplified Köppen-Geiger climate-zone polygon set (29 classes, polarEF/ETexcluded, keyed byCODE/name) for a climate-zone choropleth panel on the fleet-inventory Grafana dashboard. Active zones are painted with their canonical Köppen family colours (the install count shows in the tooltip and as a per-zone label); zones with no installs stay a neutral, theme-aware grey. Provenance and themapshaperregeneration command are documented in the dashboard design doc.
- COP: fix electrical power double-counting on S80 units when a whole-unit power meter (
power_entity) is configured. The derived-metrics calculator was called once per compressor and the results summed; with a power meter each call returns the total unit power, so the sum was ~2x the real consumption and COP was roughly halved. Electrical power is now computed with a single calculator call using the summed compressor current, which is correct for both the measured-power path (whole unit returned once) and the I×U estimate (U×(I1+I2) == U×I1 + U×I2) (#316). - COP: fix incorrect COP reconstruction on restart for installations using a whole-unit power meter. During Recorder rehydration every replayed point was stamped with a single live
power_entityreading captured at startup, instead of each point's own historical value. Rehydration now fetches the historicalpower_entity(andvoltage_entity) from the Recorder and reconstructs the electrical power per point at its own timestamp (falling back to the per-point I×U estimate when no power meter is configured), matching how historical water temperatures are already replayed (#316). - Setup: when the first refresh is tolerated through
gateway_not_ready(#303/#307), the gateway's livesystem_configis unavailable (register data is empty), so live capability flags all readFalse. Setup now keeps using the persistedsystem_config(#308) in that case instead of the empty live data. This fixes two regressions: (1) COP services seeded from the persisted capabilities are no longer destroyed by a spurious live-vs-persisted mismatch re-init, and (2) DHW, Pool and Circuit 1/2 devices are now registered from the persisted capabilities instead of silently disappearing until a later reload hits a successful poll. When the first refresh succeeds, live capabilities remain authoritative and behaviour is unchanged (#317). - ATW-MBS-02 (Before Line-up 2016): the "Room Thermostat available" flag is a single global register (address 1029), not a per-circuit control as on the 2016 line-up. The pre-2016 map previously defined
circuit2_thermostatat the same address 1029 ascircuit1_thermostat, so toggling circuit 2 silently rewrote the global flag (and shadowed circuit 1). The duplicatecircuit2_thermostatkey has been removed; the flag is now modelled once ascircuit1_thermostat(#318). - COP: the measurement-interval timer was advanced before sensor inputs were validated. A transient
Noneon water inlet/outlet temperature, water flow or compressor current advanced the timer then returned early, so the next complete poll arriving within the measurement interval was rejected by the interval gate. This dropped valid measurements and degraded COP accuracy/quality. The timer now advances only after a complete, valid measurement is attempted (#319). - Sensors that report a
0xFFFFsensor-error (e.g. outdoor, water inlet/target temperatures, water flow, compressor temperatures/pressures) now correctly become unavailable instead of retaining their last good value forever. Previously, a register that went to0xFFFFwith no configured fallback deserialized toNoneand was silently kept in the data cache; the entity kept reporting a frozen reading. A post-deserializationNone(after any fallback attempt) now clears the stored value, consistent with the existing sentinel-filtered handling (#320). - Climate: the HVAC action (heating/cooling indicator on the thermostat card) now resolves correctly when the unit operating mode is
auto. Previously the card showed "unknown" while the heat pump was actively running, because only explicitheat/coolmodes were mapped. The running direction is now derived from the STATUSoperation_stateregister (heat_thermo_on/cool_thermo_on);off/defrosting/idlebehaviour is unchanged (#321). - Switch entities: a failed Modbus write no longer leaves the UI showing the wrong state. The base switch now honours the boolean success flag returned by
set_fn: on failure it logs a warning and requests a refresh so the entity reverts to the real device state, instead of unconditionally applying an optimistic value. Toggling a switch before the first successful poll (coordinator.dataisNone) no longer raisesTypeError, since state is re-synced viaasync_request_refresh()rather than a subscript-assign intocoordinator.data(#322). - Options flow: allow clearing a previously-configured optional external sensor (voltage, power, energy, water inlet/outlet temperature, electricity price). Clearing a selector left the field omitted from the submitted input, and the schema's
default=re-applied the old value, so a configured sensor could never be unset. The sensors step now pre-fills viasuggested_valueand cleared optional sensor keys are reconciled out of the merged entry data (#323). - Telemetry backend (Cloudflare Worker): a transient R2 outage no longer consumes the per-instance rate-limit slot. The Worker now performs a read-only rate-limit check before archiving and only commits the 60s marker after a successful R2 write. Previously, the marker was set before archiving, so when R2 returned a 502 the client's retry within the next minute was rejected with 429, turning a recoverable outage into guaranteed telemetry loss for that
(instance_hash, type). Deploy withcd backend/worker && npx wrangler deploy(#324). - Reconfigure flow: the gateway variant selector now defaults to the variant already stored in the config entry when auto-detection fails, instead of resetting to no selection and forcing the user to re-pick it (#325).
- Options/reconfigure flow: fill missing translations in
translations/en.json,translations/fr.json,translations/nl.jsonandtranslations/ro.jsonso the connection step shows translated error messages and field labels (name,scan_interval) instead of raw keys likegateway_not_ready. Both ATW-MBS-02 and HC-A(16/64)MB connection steps now mirror the initial setup flow (#302). - Setup: tolerate a transient
gateway_not_ready(Modbus TCP up, H-LINK still initializing after a gateway power-cycle) during entry setup/reload. Previously a duplicateasync_config_entry_first_refresh()call re-raisedConfigEntryNotReadyand produced a "Setup failed, will retry" banner even though the gateway was simply in its H-LINK initialization window. Setup now completes; entities areunavailableuntil the next successful poll. Genuine connection failures (TCP unreachable, other Modbus errors) still raiseConfigEntryNotReadyso HA's standard retry mechanism applies (#303).
- Config flow: preserve user-typed values (host, port, slave, name, scan interval, gateway variant) when a provider step fails validation (
cannot_connect,gateway_not_ready,invalid_slave, ...). Applies to both initial setup and reconfigure/options flows, for ATW-MBS-02 and HC-A(16/64)MB providers. Previously, fields were reset to defaults on every retry (#304). - Persist the gateway
system_config(capability bitfield) in the config entry data on every successful refresh. At setup time, COP services for cooling, DHW and pool are now initialised from this persisted value before the first refresh, so they survive a reload that hitsgateway_not_readyduring the gateway's H-LINK init window. Existing installations get the value populated on their next successful poll; until then the previous (post-refresh) behaviour applies as a fallback (#308).
- Config flow: surface a clear
gateway_not_readyerror (with H-LINK troubleshooting hints) instead of crashing withTypeErrorwhen the gateway reports an unhealthysystem_state(initializing or desynchronized) during integration setup. Affects both ATW-MBS-02 and HC-A(16/64)MB providers. Regression introduced in 2.1.0-beta.2 (#260): the new short-circuit inread_valueswas not propagated to the config providers (#300, #301).
ReadResultenum andread_valuesnow document the contract explicitly: callers MUST check the return value before consumingread_value()output, sinceGATEWAY_NOT_READYshort-circuits before populating internal data.decode_configdefensively coerces a missing/Nonesystem_configto0instead of raising, so an upstream contract violation degrades to "no modules detected" rather than crashing.
- Telemetry backend: fleet-inventory dashboard. The Worker now mirrors each
installationpayload into Cloudflare Workers Analytics Engine (datasethitachi_installations), feeding a Grafana dashboard that shows active integration/HA versions, heat-pump profiles, gateway types, and configuration flags (cooling, DHW, pool, S80, circuits, power supply) plus per-installation drill-down by anonymous hash. R2 remains the single permanent archive. The integration re-sends the (anonymous) installation payload once per day so the dashboard's 90-day window reflects the active fleet.
- Telemetry backend: Cloudflare R2 is now the single source of truth. The Worker no longer dual-writes to TimescaleDB / TigerData; the
pgdriver,db.tsmodule, and Hyperdrive binding have been removed. R2 partitioning (metrics/year=YYYY/month=MM/day=DD/) is unchanged. Notebooks should consume the JSON archive directly via DuckDB + httpfs. - Dev tooling: bump
rufffrom 0.15.11 to 0.15.14 (#287, #294, #297)
- ATW-MBS-02: read R/W registers from STATUS addresses instead of CONTROL. The CONTROL range only reflects what was last commanded; STATUS reflects what the unit is actually using. This fixes silent divergences when the unit internally overrides a setpoint (anti-legionella cycle, OTC adjustment, central-control conflict). Affects both Line-up 2016 (29 keys) and Before Line-up 2016 (19 keys) maps. Writes still target CONTROL via the existing
write_addressmechanism, mirroring the HC-A(16/64)MB pattern. Likely root cause of the DHW reference temperature jumping reported in #293 (#295) - Telemetry backend: parallelize TigerData and R2 writes via
Promise.allSettledso that an R2 archive is performed even when the TigerData insert fails. Previously the R2 archive was only attempted after a successful database write, which meant payloads received during a TigerData outage were lost. The endpoint now returns202when at least one sink succeeds, and502 Bad Gatewayonly when both upstream sinks fail (#284)
This release adds support for pre-2016 ATW-MBS-02 gateways (Gen 1 Yutaki S/S Combi), an opt-in anonymous telemetry system to grow realistic test fixtures across all heat pump models, and an electricity cost estimation feature. Internally, derived metrics (COP, thermal/electrical power, compressor timing) are now centralized in a single adapter, fixing COP accuracy for S80 cascade installations.
- Support for Before Line-up 2016 ATW-MBS-02 gateway — Gen 1 Yutaki S and S Combi units with full read/write support (#248)
- Gateway variant system — config flow asks for hardware generation with auto-detection after connection
- Interactive model decoder tool to identify hardware generation (
docs/tools/model-decoder.html) - Scanner auto-detection and annotation for before-2016 units
- Model nomenclature reference documentation (
docs/reference/model-nomenclature.md) - Config entry migration v2.4 — adds
gateway_variantfield to existing entries - Anonymous telemetry system (Off / On) — helps build realistic test fixtures for all heat pump models (Discussion #200)
- Telemetry consent step in config flow (options) and repair flow for existing users
- Telemetry diagnostic sensor (
sensor.telemetry_status) with send tracking attributes - Backend: Cloudflare Worker (ingestion proxy), TigerData migrations, R2 cold archive
- DHW demand mode diagnostic sensor (standard/high demand) read from STATUS register — disabled by default (#255)
- Electricity cost estimation sensor — configure an electricity price entity to track cumulative energy costs (#273)
- Repair flow to onboard existing users to the electricity cost feature (#273)
electrical_powersensor (kW) derived from external power entity or Modbus register (#273)- Currency-aware descriptions in config/options/repair flows using
{currency}placeholder (#273)
- Refactor config flow to provider-based orchestrator — each gateway declares its own configuration steps via
GatewayConfigProviderprotocol, eliminating all gateway-specific conditionals fromconfig_flow.py - DerivedMetricsAdapter — COP, thermal power, electrical power, and compressor timing are now computed centrally in
adapters/derived_metrics.pybefore entities and telemetry consume the data. COP now uses the external power entity when configured. - Dict-based telemetry —
MetricPointdataclass (60+ fields) replaced with plain dicts. Adding a new data key to telemetry requires zero code changes. Client-side daily stats aggregation removed (server-side TimescaleDB continuous aggregate is the source of truth). - Entities COP, thermal, and timing simplified from complex subclasses (~590 lines) to simple
value_fnreaders power_consumptionsensor now reads fromDerivedMetricsAdapterlike all other derived sensors (#273)- Entity recategorization: sensors vs diagnostic (#273)
- Reorganize gateway tests to mirror source structure (
tests/api/modbus/) - Grafana dashboard queries migrated to JSONB with
time_bucketsampling for performance
- Cooling OTC compensation method showing "Unknown" and not settable on ATW-MBS-02 (#239)
- Entities depending on missing registers (eco mode, DHW boost/high demand) are now hidden automatically on gateways that lack them
- Gateway sync state sensor showing raw integer instead of translated string during initializing/desynchronized states (#254)
- Entities remaining "available" with stale data when gateway is stuck in initializing state (#254)
- Log spam reduced from ~685 identical warnings to periodic reminders every 5 minutes during extended gateway sync issues (#254)
- Adaptive polling backoff (5s → 10s → ... → 300s max) when gateway is not ready, reducing unnecessary Modbus traffic (#254)
- COP telemetry was wrong for S80 cascade (8.2 avg vs 1.32 in HA) — now uses same calculation path as HA entities
- Gateway sentinel filtering — Modbus sentinel values (-127, -67) for absent sensors are now filtered at the gateway layer instead of propagating to entities and telemetry (#272)
- Module gating — unconfigured modules (DHW, pool, circuit 2) no longer leak default register values into data and telemetry (#272)
- Remove hardcoded
-127checks from hydraulic entity conditions (#272) - Restore accumulated electricity cost on restart (#273)
MetricPoint,DailyStatsdataclasses and client-side aggregatorHitachiYutakiCOPSensor,HitachiYutakiThermalSensor,HitachiYutakiTimingSensorsubclassespower_consumptionsensorsourceattribute — energy source selection is now internal to the adapter (#273)
- Remove incorrect tenths conversion on pool target temperature (#233)
- Remove phantom secondary compressor pressure registers at non-existent addresses 1150/1151 (#225)
- Scan interval not editable in reconfiguration flow (options flow missing the field)
- Migrated runtime data storage from
hass.data[DOMAIN]toConfigEntry.runtime_data(modern HA pattern) - Restructured documentation: unified
docs/directory, all English, centralized architecture docs - Slimmed
CLAUDE.mdto rules and conventions only (details moved todocs/) - Slimmed
CONTRIBUTING.mdwith pointers todocs/development/
- Water Outlet 2 (Two2) and Water Outlet 3 (Two3) temperature sensors for systems with buffer tanks (#161)
- Local brand assets for HA 2026.3+ brand proxy API
- Base entity module (
entity.py) for common-modules quality standard - Documentation for
set_room_temperatureservice action - Quality scale tracking file (
quality_scale.yaml) for Bronze tier - Config flow test suite: 12 tests covering user, gateway_config, profile, power, validation, options flow
docs/architecture.md: unified architecture reference (merged 5 sources)docs/development/: getting started, adding entities, Modbus registers, profiles guidesdocs/reference/: entity patterns, domain services, quality scale references- GitHub issue templates (bug report, feature request) and PR template
- MIT LICENSE file
- CI: test against Python 3.13 and 3.14
documentation/directory (content migrated todocs/)- In-code READMEs (
domain/,adapters/,entities/) absorbed intodocs/ - Root
TODO-hc-a-mb-registers.md(content in gateway docs)
CONTRIBUTING.mdwith contributor workflow documentation
- Config flow: removed unused
dev_modeoption from advanced settings - Config flow: moved Modbus Device ID from advanced step to gateway configuration step
- Config flow: namespaced Modbus connection keys with
modbus_prefix (modbus_host,modbus_port,modbus_device_id) to prepare for future non-Modbus gateway support - Automatic config entry migration (v2.1 → v2.2) renames stored connection keys for existing installations
- Dev tooling: bump
rufffrom 0.13.3 to 0.15.2
- HC-A(16/64)MB outdoor compressor registers mapped to wrong address block (5000+offset instead of 30000+offset), causing discharge temp, evaporator temp, current, frequency, and EVO opening to show as unavailable (#96)
- DHW/pool COP calculation used circuit outlet register (1094) instead of HP-level outlet register (1201) — when the 3-way valve redirects to the tank, the circuit register becomes stale, causing zero thermal power and no COP during DHW runs (#205)
- Electrical power unit conversion now uses HA's
PowerConverterinstead of a naive> 50heuristic (#182) — a heat pump in standby consuming < 50 W was incorrectly interpreted as kW, causing wildly inaccurate COP values - Dutch (nl) translations updated
A major rewrite of the integration with hexagonal architecture, multi-gateway support, and significantly improved accuracy for thermal and COP calculations.
- Multi-gateway support: HC-A(16/64)MB alongside ATW-MBS-02
- Hexagonal architecture: pure domain layer, testable without Home Assistant
- Accurate thermal energy: separate heating/cooling tracking, defrost filtering
- Seamless migration: automatic entity migration from v1.9.x with preserved history
- HC-A(16/64)MB gateway support — New Modbus gateway type alongside ATW-MBS-02. Both HC-A16MB and HC-A64MB are protocol-identical (same registers, same features — only the capacity differs: 16 vs 64 indoor units). Introduces a register abstraction layer (
HitachiRegisterMapABC) enabling polymorphic gateway support with separate read/write address ranges, unit_id-based address computation, and gateway-specific deserialization - Outdoor unit registers for HC-A(16/64)MB gateway (#96) — Compressor frequency, current, discharge/liquid/gas/evaporator temperatures, and expansion valve openings now available on HC-A-MB gateways
- New heat pump profiles — YCC and Yutaki SC Lite profiles for models only available via HC-A(16/64)MB gateway
- External energy sensor (
energy_entity) — New optional configuration to replace the Modbus power consumption register with an external lifetime energy sensor (device_class=energy, kWh,TOTAL_INCREASING). Thepower_consumptionentity exposes asourceattribute for transparency set_room_temperatureservice — New entity platform service to write measured room temperature to the heat pump via climate entities, enabling automations when the Modbus thermostat is enabled- Operation state numeric attribute (#187) — Raw Modbus numeric value (0-11) exposed as a
codeattribute for simpler automation logic - Conditional circuit climate modes (#186) — Two-circuit setups expose only
off/heat_cool(power toggle); single-circuit retains fullheat/cool/auto/offcontrol - Complete hexagonal architecture — Domain layer with pure business logic (zero HA dependencies), adapters layer bridging domain with Home Assistant, 100% testable domain layer
- Domain-driven entity organization — Business domain structure (circuit, compressor, control_unit, dhw, gateway, hydraulic, performance, pool, power, thermal) with builder pattern for all entity types
- Robust Modbus connection recovery — Exponential backoff retry logic with automatic reconnection on network interruptions (#118)
- Enhanced heat pump profile system — Explicit hardware capabilities per model (
dhw_min_temp,dhw_max_temp,max_circuits,supports_cooling,max_water_outlet_temp,supports_high_temperature) - Smart profile auto-detection — Decentralized detection logic with improved Yutampo R32 and S Combi detection
- Recorder-based data rehydration — COP and compressor timing sensors automatically reconstruct history from HA Recorder on startup, eliminating data loss after restarts
- Separate thermal energy sensors for heating and cooling:
thermal_power_heating/thermal_power_cooling: Real-time power outputthermal_energy_heating_daily/thermal_energy_cooling_daily: Daily energy (resets at midnight)thermal_energy_heating_total/thermal_energy_cooling_total: Total cumulative energy
- Post-cycle thermal inertia tracking — Thermal energy from system inertia correctly counted after compressor stops
- Automatic entity migration — Seamless upgrade from v1.9.x to 2.0.0 with preserved entity history and IDs
- Functional repair flow — Dedicated
repairs.pyfor 1.9.x → 2.0.0 migration with automatic integration reload - Hardware-based unique_id (#162) — Config entries use gateway hardware identifier (Modbus Input Registers 0-2) instead of IP+slave, preventing duplicates and surviving DHCP changes
- Annotated Modbus register scanner — New
scripts/scan_gateway.pytool withmake scantarget for diagnosing register values across all gateway types, with human-readable annotations and scan reference documentation
- Minimum Home Assistant version raised to 2025.1.0 to align with
WaterHeaterEntityDescriptioncomponent signature - Minimum Python version raised to 3.13
- CI tests against min and latest HA versions via matrix (HA 2025.1.0 and latest)
- Complete platform refactoring to domain-driven architecture — all platform files act as pure orchestrators
- Entity organization moved from technical grouping to business domain grouping
- Modbus register organization by logical device for improved clarity
- Alarm sensor displays descriptions as state with numeric codes as attributes
- Storage strategy — COP and compressor data relies on HA Recorder instead of custom storage
- Thermal service split into modular package:
calculators.py,accumulator.py,service.py,constants.py - Thermal energy classification uses operation mode (#196) — DHW and pool cycles now force heating classification regardless of ΔT sign, preventing transient negative deltas from being incorrectly counted as cooling energy
- Sensor subclasses extracted into dedicated package —
entities/base/sensor.pysplit intoentities/base/sensor/package with specialized subclasses (COP, thermal, timing) for better maintainability - Register map factory extracted into
api/__init__.py, eliminating duplication ⚠️ BREAKING: Thermal energy calculation logic (#123):- Correctly separates heating (ΔT > 0) from cooling (ΔT < 0)
- Defrost cycles are now filtered (not counted as energy production)
- Post-cycle lock mechanism prevents counting noise after compressor stops
- Results in accurate COP calculations (previously inflated by defrost)
⚠️ Old thermal energy sensors (disabled by default, still available for backward compatibility):thermal_power→ usethermal_power_heatinginsteaddaily_thermal_energy→ usethermal_energy_heating_dailyinsteadtotal_thermal_energy→ usethermal_energy_heating_totalinstead- Migration required: Update your Energy Dashboard and automations to use the new sensors
- Legacy technical modules and monolithic entity files in favor of domain-specific builders
- Direct entity instantiation replaced with builder pattern
- Legacy services directory
- Redundant climate number entities (target_temp, current_temp) — now handled by climate entity
- Anti-legionella temperature range (#178) — DHW anti-legionella target temperature now uses profile-based min/max instead of hardcoded values, respecting each model's actual capabilities
- COP DHW identical to COP Heating (#191) — COP sensors now use
operation_stateto differentiate heating, DHW, cooling, and pool cycles - Anti-legionella binary sensor (#178) — Read from STATUS registers instead of CONTROL registers
- Cooling capability detection (#177) — Fixed system_config bitmask order regression from v1.9.x
- OTC cooling serialization for HC-A(16/64)MB — Correct mapping (Disabled=0, Points=1, Fix=2)
- Recorder database access warning — Use recorder executor for database operations
- Pressure sensor error handling —
0xFFFFsentinel check in both gateway register maps - Config flow translations — Added missing translations for gateway/profile selection (EN and FR)
- Profile detection robustness — Yutampo R32
detect()no longer returnsNonewhenhas_dhwis missing - Temperature deserialization — Properly differentiates between tenths and signed 16-bit values
- Sensor reading accuracy for secondary compressor current and pressure sensors
- Unit power switch "Unknown" state due to inconsistent condition checks
- COP measurement period — Fixed negative time span values
- Legacy entities — Automatic migration with preserved history
- Fixed aberrant COP (Coefficient of Performance) values by implementing comprehensive data validation and intelligent unit detection for power sensors
- Added robust validation for all input parameters: temperature ranges (-10°C to 80°C), water flow rates (0.1 to 10.0 m³/h), temperature differences (0.5 to 30 K), power ranges (0.1 to 50.0 kW thermal, 0.1 to 20.0 kW electrical), and final COP values (0.5 to 8.0)
- Implemented automatic power unit detection (W vs kW) using
unit_of_measurementattribute with intelligent fallback detection based on value ranges - Added validation for energy accumulation to prevent calculation errors in COP measurements
- Enhanced debug logging for unit detection, validation failures, and COP calculations
- Improved COP calculation accuracy by rejecting invalid data instead of producing incorrect values
- Enhanced support for external power and voltage sensors with automatic unit detection
- Updated power unit handling to seamlessly support both W and kW sensors
- Options flow: avoid providing
default=Noneto entity selectors to prevent the UI error "Entity None is neither a valid entity ID nor a valid UUID" when opening Options. (#109) - Options flow: stop storing the
config_entryon the options flow instance to comply with Home Assistant deprecation and silence the warning that will become an error in 2025.12. (#109) - CI: update GitHub Actions
actions/setup-pythonto v6 - Dev tooling: bump
ruffto 0.13.3
- Fixed pymodbus compatibility issue with Home Assistant 2025.9.0+ by implementing automatic version detection for the device/slave parameter. The integration now works with both pymodbus < 3.10.0 (using
slaveparameter) and pymodbus >= 3.10.0 (usingdevice_idparameter), ensuring compatibility across all Home Assistant versions. (#97)
- Improved error handling in the data update coordinator to consistently create a repair issue in Home Assistant for any Modbus or network communication error.
- Resolved an issue where a loss of IP connectivity to the Modbus gateway could cause the integration to crash or behave unexpectedly. The integration now correctly handles network errors (
OSError), ensuring that all entities becomeunavailableand properly recover once the connection is restored. (#76)
- New sensor to monitor the gateway's synchronization state (
Synchronized,Desynchronized,Initializing). - Pre-flight check during setup and updates to verify gateway synchronization status. This creates a persistent notification ("Repair") if the gateway is desynchronized, guiding the user to resolve the issue.
- Improved startup resilience. The integration now caches the heat pump's configuration during the first successful setup. This ensures that all devices and entities are registered during subsequent Home Assistant startups, even if the heat pump is temporarily offline.
- Resolved a critical issue where all integration entities would disappear if the heat pump was offline when Home Assistant started. Entities will now appear as
unavailableuntil the connection is restored.
- Corrected the HACS installation link in
README.mdto ensure it redirects correctly.
- Updated development dependencies, including
ruffto v0.12.0.
- New "Anti-legionella Cycle" button entity to manually start a high temperature anti-legionella treatment cycle.
- New binary sensor entity (
antilegionella_cycle) indicating if an anti-legionella cycle is currently running.
- Removed unused or redundant Domestic Hot Water (DHW) entities: DHW current temperature sensor, DHW target temperature number, DHW power switch, high demand switch, and periodic anti-legionella switch.
- Improved English and French translations for new entities and advanced configuration (water inlet/outlet temperature entities).
- The integration now allows configuration with central control modes Air (1), Water (2), or Total (3). Only Local (0) is forbidden.
- Error messages and documentation updated to reflect this change.
- The documentation now recommends using Air (1) mode for most installations.
- Support for Hitachi Yutampo R32 machines (requires 'Total' (3) mode).
- Bump ruff from 0.11.2 to 0.11.8 (#50)
- Updated development dependencies and minor fixes.
- Replaced standard DHW preset with heat pump mode
- Migrated from Pylint to Ruff for code linting
- Updated development dependencies (Ruff to 0.11.2, pre-commit to 4.2.0)
- Added ffmpeg dependency to development environment
- Implemented WaterHeaterEntity for Domestic Hot Water (DHW) control
- Better integration with Home Assistant UI for water heater controls
- Support for standard operation modes: off, standard, and high demand
- Fixed issue with multiple heat pumps not generating unique entity IDs
- Added config entry ID to all entity unique IDs to ensure uniqueness across multiple instances
- New thermal energy monitoring sensors:
- Real-time thermal power output (kW)
- Daily thermal energy production with midnight auto-reset (kWh)
- Total cumulative thermal energy production (kWh)
- Detailed monitoring attributes:
- Temperature differential and water flow tracking
- Average power calculation over measurement periods
- Precise measurement timing with compressor state tracking
- Full translations for all new features in French and English
- Optimized default sensor visibility based on configuration and relevance for standard users
- Compatibility with latest pymodbus API
- Improved logging for COP calculation and system state monitoring
- Updated pymodbus dependency to match Home Assistant's version
- Optimized COP calculation parameters for better accuracy
- Added quality indicators for COP measurements (no_data, insufficient_data, preliminary, optimal)
- Added translations for COP quality indicators in French and English
- Fixed sample size and interval for more accurate COP calculation
- Fixed COP calculation by applying water flow conversion (raw value was used instead of m³/h)
- Fixed COP calculation by removing incorrect water flow division
- Added more detailed debug logging for thermal power calculation
- Added runtime and rest time sensors for both compressors
- Added detailed logging for power calculations
- Added debug information for thermal power calculation
- Added comprehensive logging for COP measurements and accumulation
- Moved cycle time sensors to compressor devices for better organization
- Optimized COP calculation with more detailed debug information
- Simplified sensor code by moving value validation to conversion methods
- Fixed temperature conversion for special values (0xFFFF)
- Fixed water flow value scaling
- Fixed double conversion issue for temperature and pressure sensors
- Fixed connectivity sensor state calculation
- Added detailed logging for power calculations
- Added debug information for thermal power calculation
- Added comprehensive logging for COP measurements and accumulation
- Added external temperature entities configuration for more accurate COP calculations
- Added support for two COP calculation methods:
- Moving median over 10 measurements when using external temperature sensors
- Energy accumulation over 15 minutes when using internal sensors
- Modified configuration flow to include temperature entity selection
- Improved COP calculation accuracy with external temperature sensors
- Refactored sensor code to reduce complexity and improve maintainability
- Updated configuration documentation with new temperature entity options
- Added explanation of COP calculation methods in the documentation
- Added power meter entity configuration option for more accurate COP calculations
- Added support for external power meter in sensor calculations
- Modified configuration flow to include power meter entity selection
- Updated COP calculations to use power meter readings when available
- Enhanced power consumption accuracy with direct power meter readings
- Updated README with power meter configuration instructions
- Added power meter entity option in configuration documentation
- Added voltage entity configuration option for more accurate power calculations
- Introduced new configuration schemas for gateway, power supply and advanced settings
- Added support for custom voltage entity in sensor calculations
- Modified configuration flow to include voltage entity selection
- Updated power consumption calculations to use voltage entity when available
- Enhanced system configuration flexibility with new voltage setup options
- New COP (Coefficient of Performance) sensor with real-time calculation
- Power supply type configuration (single-phase/three-phase)
- Enhanced power calculations for S80 models with dual compressor support
- Improved power consumption calculations with smoothing algorithm
- Updated configuration options to include power supply type
- Enhanced accuracy of energy measurements
- Improved operation state sensor with more descriptive state values
- Downgraded pymodbus dependency to 3.6.9 to match Home Assistant's modbus integration
- New diagnostic sensor "Operation State" showing detailed heat pump operation mode
- New diagnostic sensor "Compressor Cycle Time" measuring average time between compressor starts
- Updated French and English translations for new sensors
- Removed unnecessary dependency to Home Assistant's modbus integration since we only use pymodbus library
- Changed temperature conversion to use integers instead of floats as documented by Hitachi
- Fixed Pylint warnings by implementing missing abstract methods in ClimateEntity
- Fixed unique_id generation in switch and number entities to prevent mismatched entities
- Fixed register key double prefixing issue in switch and number entities causing some controls to fail
- Removed climate entity for DHW control in favor of more appropriate water heater entity type
- Added new compressor diagnostic sensors:
- Gas Temperature (TG)
- Liquid Temperature (TI)
- Discharge Temperature (TD)
- Evaporator Temperature (TE)
- Indoor Expansion Valve Opening (EVI)
- Outdoor Expansion Valve Opening (EVO)
- Fixed alarm code descriptions not loading
- Added detailed error descriptions for all alarm codes
- Improved alarm code sensor to display both code and description
- Initial release of the Hitachi Yutaki integration
- Basic configuration flow with connection validation
- Multi-language support (English and French)
- Automatic model detection and feature discovery
- Support for Yutaki S, S Combi, S80, and M models
- Climate control features:
- Power control per circuit
- Operation mode selection (Heat/Cool/Auto)
- Target temperature adjustment
- Comfort/Eco presets
- Outdoor Temperature Compensation (OTC)
- DHW (Domestic Hot Water) control:
- Power control
- Target temperature adjustment
- Boost mode
- Anti-legionella function
- High demand mode
- Pool heating control (if configured)
- Monitoring features:
- Temperature sensors (outdoor, water inlet/outlet, circuits, DHW)
- Component status (compressors, pumps, heaters)
- Compressor frequencies and currents
- Power consumption
- Alarm codes
- Advanced configuration options:
- Circuit-specific settings
- Thermostat configuration
- OTC calculation methods
- ECO mode offsets
- Special features for S80 model:
- Secondary compressor monitoring
- R134a circuit sensors
- N/A (Initial release)
- N/A (Initial release)
- N/A (Initial release)
- N/A (Initial release)
- Validation of Modbus connection parameters
- Proper error handling for Modbus communication