Skip to content

Releases: 3dg1luk43/ha_washdata

v0.4.4.1

05 May 13:34
f8ae167

Choose a tag to compare

0.4.4.1 - 2026-04-29

✨ Features

  • New Device Type: Oven (#137): Added support for electric ovens with defaults tuned for the heating profile of a thermostat-regulated cavity (4-hour active timeout to cover slow roasts and pyrolytic self-clean, 10-minute off-delay and 15-minute min-off-gap to bridge thermostat-driven silences without splitting one bake into multiple cycles, 0.5 Wh start-energy gate to filter incidental fan/light draws, 5.0 % progress-smoothing tolerance for the bistable on/off swings during temperature regulation, 10-minute completion threshold). Includes five built-in phases: Pre-Heat, Heating, Maintaining Temp, Cool Down, and Pyrolytic Clean. Selectable in the device-type dropdown with a mdi:stove icon. Issue and feature-request templates updated to list the new option.

🐛 Bug Fixes

  • Issue Automation: Comment Responses No Longer Trigger Auto-Close: The issue-automation pipeline closed reports as "no response in 5 days" even when the reporter had answered. The validator only re-checked on issue-body edits, so reporters who replied via a comment (often with a debug log attached) went undetected; the daily auto-closer then closed the issue purely on the age of the bot's first flag. The validator now also fires on comments from the issue reporter and swaps the more info required label for awaiting maintainer review, surfacing the response to the maintainer immediately. The auto-closer additionally checks for reporter comments since the bot flag as a backstop, so a stale flag never trumps an actual reply.
  • Dishwasher Pump-Out Registers as a Ghost Cycle (#43): On dishwashers with passive drying and an end-of-cycle drain pump, the integration was closing the cycle ~12 minutes before the real pump-out and then registering the pump-out itself as a brand-new "starting → running → ending" sequence visible in the UI. Root cause: a brief mid-cycle drain wind-down at ~50% of the expected duration set _end_spike_seen=True, which pre-armed Smart Termination so it fired at 99% of expected duration before the real pump-out arrived. After Smart Termination closed the cycle, the pump-out (a 16–20 W spike for ~1 min) was then 12 min outside the 600 s suspicious-window for ghost suppression on devices whose previous cycle had finished slightly earlier (e.g. a longer-trained profile), so it slipped through unsuppressed and started a fresh detection. Fix: the end-spike marker is now only armed when the spike occurs at ≥ 85% of the expected duration (mid-cycle drain spikes are ignored for end-spike tracking but still keep the cycle in ENDING via the existing long_ending_tail path). Additionally, between 85% expected and the smart-termination wait window (expected + 300 s), the dishwasher passive drying protection now defers the cycle finish whenever no end spike has been seen yet — so the pump-out gets folded into the original cycle instead of being treated as a new cycle. Verified against a real diag-export power trace from issue #43: pre-fix → 1 cycle (233 min) + 1 ghost cycle; post-fix → 1 cycle (234.3 min) + 0 ghost cycles. No behavioural change for non-dishwasher devices, for unmatched cycles (no profile), or for dishwashers whose end spike fires within the last 15% of expected duration.
  • Translation Placeholder Mismatch in notify_finish_message (#219): Home Assistant logged a startup validation error for all non-English locales because en.json described the finish notification format with only three placeholders ({device}, {duration}, {program}), while the German, Czech, and Italian translations already listed all five ({energy_kwh} and {cost} were added in v0.4.4 but the English source string was only partially updated). HA validates every localization against the English reference, so any language whose description matched the updated set was flagged as inconsistent. The English source string is now corrected to include all five placeholders, and the description in all 57 remaining language files has been updated accordingly so placeholder sets are consistent across all locales.

v0.4.4

27 Apr 15:04
bdb3bec

Choose a tag to compare

0.4.4 - 2026-04-27

✨ Features

  • Delayed Start Detection (#193): When enabled under Advanced Settings, WashData now detects machines programmed with a delayed start. A brief low-power drain spike (e.g. the initial drain-check a washing machine performs before sleeping) followed by sustained standby power is recognised as the machine waiting to begin its cycle. The state sensor transitions to "Waiting to Start" (delay_wait) during the delay period — no program time, progress, or ETA is tracked until the real cycle begins. Configurable thresholds: Drain Spike Min/Max Power (defaults 10 W / 80 W), Max Drain Spike Duration (60 s), and a Max Wait Time safety timeout (8 h, after which the state resets to Off). The feature is disabled by default and requires start_threshold_w to be set above the drain spike power level to function correctly.
  • Wall-Clock Time in Trim Cycle Editor (#212): The Trim Cycle graph now shows real wall-clock times (HH:MM) on the x-axis as the primary label, with the relative offset (+N min) shown below each tick as a secondary reference. The S and E trim-point markers display the exact wall-clock time (HH:MM:SS) instead of a relative offset. The Set Trim Start and Set Trim End forms have been redesigned: both now show the full cycle window (start → end), the current trim position in wall-clock time and minutes, and a single clock-picker field pre-populated with the current position — making it straightforward to set a trim point by entering a known time from another source (e.g. HA history graphs or a smart plug log) without having to calculate offsets manually.
  • Energy & Cost Placeholders in Finish Notifications (#196): The finish message template now supports two new placeholders: {energy_kwh} (energy consumed during the cycle, formatted to 3 decimal places) and {cost} (energy cost, formatted to 2 decimal places). To enable {cost}, configure an electricity price under Notifications → Energy Price - either a static value (e.g. 0.22) or a Home Assistant entity that holds the current tariff (any sensor.*, input_number.*, or number.* with a numeric state). The entity takes precedence if both are set; {cost} resolves to an empty string when no price is configured. Currency is not included - add it directly in your template (e.g. {cost} €). Example: {device} finished. Duration: {duration}m | Energy: {energy_kwh} kWh | Cost: {cost} €. Energy per cycle is now also stored in the cycle history record (energy_wh) computed from the stored power trace at save time, covering all storage paths including the manual recorder.
  • Multi-Target Notifications (#203): The notification system now supports multiple recipients per event type. The single Notification Service dropdown and Events to Notify checkbox have been replaced with three independent multi-select fields - Cycle Start, Cycle Finish, and Live Progress - each accepting any number of notify.* services. A family member who only needs to know when laundry is done can be added to Cycle Finish only, while another person who also wants live progress can be added to all three. Existing configurations are migrated automatically: the previous single service is mapped into each list that matches the previously selected events, so no manual reconfiguration is required after upgrade. Notification actions and presence gating continue to work across all targets.
  • New Device Type: Bread Maker (#190): Added full support for bread makers with optimised defaults (2-hour no-update timeout for long proving periods, 5-minute off-delay for keep-warm, 30-minute completion threshold) and five built-in phases: Kneading, Resting, Proving, Baking, and Keep Warm.
  • New Device Type: Pump / Sump Pump (#195): Added a dedicated pump device type (mdi:water-pump) with defaults tuned for short, high-frequency cycles: 10 s sampling interval (captures sub-30 s runs that the 30 s default misses), 20 s off-delay (pumps stop sharply with no warm-down), 5 s minimum cycle threshold (valid with 1–2 readings), 60 s minimum off-gap (handles pumps cycling every few minutes), and a 0.003 Wh start-energy gate. Includes a Pump Stuck Alert - a configurable threshold (pump_stuck_duration, default 30 min) that fires a single ha_washdata_pump_stuck HA event if a pump cycle runs longer than expected, enabling automations to alert on a jammed motor or continuous-run fault.
  • Pump Runs (Last 24 h) Sensor (#195): When using the Pump device type, a new pump_runs_today sensor (mdi:counter) counts completed pump cycles in a rolling 24-hour window - useful for monitoring sump pump activity during heavy rain or drought periods.
  • Cycle Counter Sensor (#210): A new cycle_count sensor (mdi:counter, unit: cycles, state class: total_increasing) tracks the total number of completed cycles stored for the device. Use this in automations to schedule maintenance tasks - such as cleaning filters, refilling consumables, or checking bearing wear - based on a fixed cycle interval rather than a calendar schedule.
  • Chronometer Countdown Notifications (#194): Added an optional Chronometer Countdown Timer toggle to the Notifications settings. When enabled, each live progress notification push includes chronometer, when, and countdown fields pointing to the estimated cycle finish time. The Android companion app renders a live countdown timer on the notification that ticks down automatically between pushes - eliminating the "frozen at X minutes" problem without requiring more frequent server-side sends. Disabled by default; Android companion app only.
  • Live Diagnostics in HA Diagnostics Export: async_get_config_entry_diagnostics now includes a live_diagnostics snapshot from a new in-memory DiagBuffer - a rolling 24-hour ring buffer capturing every raw power reading, every detector state transition, and the last 5000 log lines. Zero disk I/O; vanishes on HA restart.
  • User-Triggered Pause (#146): Cycles can now be paused and resumed explicitly via a Pause Cycle button entity, a Resume Cycle button entity, or the new ha_washdata.pause_cycle / ha_washdata.resume_cycle HA services (both accept device_id). While paused, the cycle is protected from watchdog termination (verified_pause = True) - the appliance can sit at zero or low power indefinitely without WashData closing the session. All time metrics (elapsed time, time remaining, total duration, and progress %) exclude the time spent paused, so a cycle paused for 30 minutes does not inflate the estimated total. The primary use case is energy price management: trigger a pause when tariff is high, resume when it drops (e.g. with Cheapest Energy Hours). An optional Cut Power When Pausing toggle (pause_cuts_power, off by default) instructs WashData to also call switch.turn_off / switch.turn_on on the configured switch entity when pause or resume is triggered - useful for appliances that remember their position after a power cut. The Pause button is only available while a cycle is Running or Starting; the Resume button is only available while the cycle is user-paused.
  • Door Sensor & Clean State (#153): An optional Door Sensor field (any binary_sensor, on = open) can now be configured under Advanced Settings. When set, WashData uses door state in two ways. During an active cycle, opening the door automatically sets verified_pause = True - the same protection used by user-triggered pauses - confirming the interruption is intentional and guarding the cycle against watchdog termination (useful for add-clothes machines such as Samsung AddWash). Closing the door does not auto-resume the cycle - this is intentional and is stated explicitly in the field description; the user must press Resume or call the service. After a cycle ends, if the door is still closed the device enters a new Clean state (STATE_CLEAN) indicating laundry is waiting to be unloaded. The state clears as soon as the door is opened. A configurable Laundry Waiting Notification Delay (notify_unload_delay_minutes, default 60 min, set to 0 to disable) fires a single reminder via the existing finish notification channel once the door has remained closed for that many minutes after cycle end - the "your wash has been sitting there for an hour" nag. The reminder message is fully customizable via a Laundry Waiting Message template (notify_unload_message); the default reads "{device} finished {duration}m ago - laundry is still inside." and supports {device} and {duration} placeholders.

🛠️ Improvements

  • delay_wait State Now Has a Human-Readable Label: The delay_wait state was missing from the sensor state translation map in strings.json, causing the UI to display the raw key. It now renders as "Delay Start".
  • Bug Report Template: Pump Label Aligned: The device type dropdown in bug_report.yml now reads "Pump / Sump Pump", matching the feature_request.yml template.
  • Issue Template: Outdated Version Check: The automated issue validator now fetches the latest stable and pre-release versions from the GitHub Releases API and flags any bug report submitted against an older version. The reporter is asked to confirm the bug still exists on the latest release before the issue is investigated. The version field description now links directly to the Releases page.
  • Issue Template: Device Type Sync: Added Bread Maker and Pump / Sump Pump to the Feature Request template's device type dropdown — these device types were supported since v0.4.4 but were missing from that template.
  • Issue Automation: Auto-Assign: All newly opened and reopened issues are now automatically assigned to the maintainer, so every report lands in the triage queue without a manual step.
  • **Issue Automation: Auto-Close Incomplete Reports...
Read more

v0.4.4-alpha

20 Apr 20:35

Choose a tag to compare

v0.4.4-alpha Pre-release
Pre-release

0.4.4 - 2026-04-14

✨ Features

  • Energy & Cost Placeholders in Finish Notifications (#196): The finish message template now supports two new placeholders: {energy_kwh} (energy consumed during the cycle, formatted to 3 decimal places) and {cost} (energy cost, formatted to 2 decimal places). To enable {cost}, configure an electricity price under Notifications → Energy Price - either a static value (e.g. 0.22) or a Home Assistant entity that holds the current tariff (any sensor.*, input_number.*, or number.* with a numeric state). The entity takes precedence if both are set; {cost} resolves to an empty string when no price is configured. Currency is not included - add it directly in your template (e.g. {cost} €). Example: {device} finished. Duration: {duration}m | Energy: {energy_kwh} kWh | Cost: {cost} €. Energy per cycle is now also stored in the cycle history record (energy_wh) computed from the stored power trace at save time, covering all storage paths including the manual recorder.
  • Multi-Target Notifications (#203): The notification system now supports multiple recipients per event type. The single Notification Service dropdown and Events to Notify checkbox have been replaced with three independent multi-select fields - Cycle Start, Cycle Finish, and Live Progress - each accepting any number of notify.* services. A family member who only needs to know when laundry is done can be added to Cycle Finish only, while another person who also wants live progress can be added to all three. Existing configurations are migrated automatically: the previous single service is mapped into each list that matches the previously selected events, so no manual reconfiguration is required after upgrade. Notification actions and presence gating continue to work across all targets.
  • New Device Type: Bread Maker (#190): Added full support for bread makers with optimised defaults (2-hour no-update timeout for long proving periods, 5-minute off-delay for keep-warm, 30-minute completion threshold) and five built-in phases: Kneading, Resting, Proving, Baking, and Keep Warm.
  • New Device Type: Pump / Sump Pump (#195): Added a dedicated pump device type (mdi:water-pump) with defaults tuned for short, high-frequency cycles: 10 s sampling interval (captures sub-30 s runs that the 30 s default misses), 20 s off-delay (pumps stop sharply with no warm-down), 5 s minimum cycle threshold (valid with 1–2 readings), 60 s minimum off-gap (handles pumps cycling every few minutes), and a 0.003 Wh start-energy gate. Includes a Pump Stuck Alert - a configurable threshold (pump_stuck_duration, default 30 min) that fires a single ha_washdata_pump_stuck HA event if a pump cycle runs longer than expected, enabling automations to alert on a jammed motor or continuous-run fault.
  • Pump Runs (Last 24 h) Sensor (#195): When using the Pump device type, a new pump_runs_today sensor (mdi:counter) counts completed pump cycles in a rolling 24-hour window - useful for monitoring sump pump activity during heavy rain or drought periods.
  • Cycle Counter Sensor (#210): A new cycle_count sensor (mdi:counter, unit: cycles, state class: total_increasing) tracks the total number of completed cycles stored for the device. Use this in automations to schedule maintenance tasks - such as cleaning filters, refilling consumables, or checking bearing wear - based on a fixed cycle interval rather than a calendar schedule.
  • Chronometer Countdown Notifications (#194): Added an optional Chronometer Countdown Timer toggle to the Notifications settings. When enabled, each live progress notification push includes chronometer, when, and countdown fields pointing to the estimated cycle finish time. The Android companion app renders a live countdown timer on the notification that ticks down automatically between pushes - eliminating the "frozen at X minutes" problem without requiring more frequent server-side sends. Disabled by default; Android companion app only.
  • Live Diagnostics in HA Diagnostics Export: async_get_config_entry_diagnostics now includes a live_diagnostics snapshot from a new in-memory DiagBuffer - a rolling 24-hour ring buffer capturing every raw power reading, every detector state transition, and the last 5000 log lines. Zero disk I/O; vanishes on HA restart.
  • User-Triggered Pause (#146): Cycles can now be paused and resumed explicitly via a Pause Cycle button entity, a Resume Cycle button entity, or the new ha_washdata.pause_cycle / ha_washdata.resume_cycle HA services (both accept device_id). While paused, the cycle is protected from watchdog termination (verified_pause = True) - the appliance can sit at zero or low power indefinitely without WashData closing the session. All time metrics (elapsed time, time remaining, total duration, and progress %) exclude the time spent paused, so a cycle paused for 30 minutes does not inflate the estimated total. The primary use case is energy price management: trigger a pause when tariff is high, resume when it drops (e.g. with Cheapest Energy Hours). An optional Cut Power When Pausing toggle (pause_cuts_power, off by default) instructs WashData to also call switch.turn_off / switch.turn_on on the configured switch entity when pause or resume is triggered - useful for appliances that remember their position after a power cut. The Pause button is only available while a cycle is Running or Starting; the Resume button is only available while the cycle is user-paused.
  • Door Sensor & Clean State (#153): An optional Door Sensor field (any binary_sensor, on = open) can now be configured under Advanced Settings. When set, WashData uses door state in two ways. During an active cycle, opening the door automatically sets verified_pause = True - the same protection used by user-triggered pauses - confirming the interruption is intentional and guarding the cycle against watchdog termination (useful for add-clothes machines such as Samsung AddWash). Closing the door does not auto-resume the cycle - this is intentional and is stated explicitly in the field description; the user must press Resume or call the service. After a cycle ends, if the door is still closed the device enters a new Clean state (STATE_CLEAN) indicating laundry is waiting to be unloaded. The state clears as soon as the door is opened. A configurable Laundry Waiting Notification Delay (notify_unload_delay_minutes, default 60 min, set to 0 to disable) fires a single reminder via the existing finish notification channel once the door has remained closed for that many minutes after cycle end - the "your wash has been sitting there for an hour" nag. The reminder message is fully customizable via a Laundry Waiting Message template (notify_unload_message); the default reads "{device} finished {duration}m ago - laundry is still inside." and supports {device} and {duration} placeholders.

🛠️ Improvements

  • Import Accepts HA Diagnostic Export Format: The import feature (Configure → Diagnostic Settings → Import) now accepts three JSON formats without any manual preprocessing: (1) the regular WashData export; (2) the raw diagnostics dict produced by WashData (with store_export at the top level, e.g. copy-pasted from a log or API response); and (3) the full HA diagnostics download file (the .json file downloaded via Settings → Devices & Services → (device) → Download Diagnostics), which wraps our data in a home_assistant / data envelope. When importing from a diagnostic source, any fields replaced by the redactor (**REDACTED**) are silently stripped, so sensitive fields such as power_sensor and notify_service are never overwritten with the placeholder string.
  • Offline Diagnostic Analyser (devtools/analyze_diag.py): New developer tool that processes any WashData diagnostics export and prints a side-by-side table of current vs. suggested settings with a per-parameter rationale. Covers power thresholds, energy gates, timing/operational parameters, and matching tolerances - all derived from the device's own recorded cycle data without requiring a running Home Assistant instance. Surfaces suggestions already computed by live HA operation for cross-checking, and includes a cycle-history summary per programme (average duration, standard deviation, variance). Run python3 devtools/analyze_diag.py <export.json> from the repo root with the venv activated; see devtools/README.md for full usage.
  • Batch Multi-Cycle Simulation (suggestion engine): The suggestion engine now derives power thresholds, dead-zone, and end-energy gate from the aggregate of all labeled cycles (run_batch_simulation) rather than only the most recent one. The 5th-percentile minimum-active-power across cycles is used for the stop threshold (more robust against outlier cycles), and the 75th-percentile of early-dip timestamps is used for the running dead zone. A new process_cycle_end hook re-runs the batch every 5 newly labeled cycles so suggestions improve progressively as more data accumulates.
  • Min-Off-Gap Suggestion: The suggestion engine now derives a min_off_gap recommendation from observed inter-cycle gaps. The p05 gap × 0.8 is used as the proposed value, floored by the device-type default, so the suggestion is always conservative enough to avoid splitting real cycles.
  • DataLoader New Export Format Support (benchmark tooling): tests/benchmarks/parameter_optimizer.DataLoader now handles both the new data → store_export → data → past_cycles export path and the legacy data → store_data → past_cycles path, so all user-contributed diagnostic exports in cycle_data/ are usable by the benchmark suite.
  • Dishwasher Post-Cycle Ghost Suppression (#43): The ghost suppressor now uses a 10-minute suspicious window f...
Read more

v0.4.3.1

17 Mar 10:28
7e00459

Choose a tag to compare

0.4.3.1 - 2026-03-16

✨ Features

  • Trim Cycle Service: Added a new trim_cycle HA service call that trims a cycle's stored power trace to a user-specified [trim_start_s, trim_end_s] window. Offsets are renormalized to start at zero, and all cycle metadata — start_time, end_time, duration, signature, sampling_interval — is recomputed and persisted atomically. Useful for removing noisy preamble or lingering standby readings from a recorded cycle.
  • Trim Cycle UI: Added a "Trim Cycle Data" action under Manage Cycles in the options flow. The UI presents an SVG preview of the full power curve with the kept region highlighted, and separate steps for setting the trim start and end points in whole minutes. Changes can be previewed, reset, and applied without leaving the interface.

🛠️ Improvements

  • Power Data Preserved for Pending Feedback: Cycles that have an open feedback request are now exempted from the periodic power-data strip pass in ProfileStore. Previously, the background cleanup could remove the stored power trace before the user had reviewed the feedback dialog, causing the SVG comparison chart to show no data. Pending cycles are identified by their presence in pending_feedback and are skipped unconditionally until feedback is resolved.
  • Streamlined Power Data Decompression: Replaced a duplicate inline decompression loop in ProfileStore with a call to the shared decompress_power_data() utility. The utility correctly handles both the legacy ISO-timestamp format and the newer relative-offset format, removing a subtle inconsistency where the old inline code only handled one variant.
  • Translation Overhaul: Comprehensively reviewed and rewrote all 60 non-English translation files. Machine-translated strings that were semantically incorrect, awkward, or technically wrong have been replaced with idiomatic translations. Common fixes applied across languages include: missing {suggestions_count} placeholders in settings descriptions; translated JSON parameter key names in apply_suggestions (keys must stay in English); translated MDI icon names; nonsensical state labels (e.g. "jogging" for "running", "country" for "device state", "fire/combustion" for notification trigger); and leftover untranslated English strings. sr-Latn.json was fully rewritten from scratch — the previous file contained Serbian Cyrillic script instead of Latin script.
  • Full Diagnostics Export: The HA diagnostics download now returns the complete store export — all profiles (including power samples), all past cycles, envelopes, feedback history, auto-adjustments, suggestions, custom phases, and full entry_data/entry_options config. Previously it returned only counts and a single-cycle summary, making it nearly useless for debugging. Personally identifiable fields (power_sensor, notify_service, notify_people, name, unique_id, etc.) are still redacted.
  • Unix Timestamp Format Recognition: detect_power_data_format now identifies absolute Unix epoch timestamps (> 1e8) as the unix_timestamp variant rather than silently discarding them. migrate_power_data_to_offsets accepts this format and converts epoch-based traces to relative offsets by subtracting the cycle start time, so imported or externally generated power traces are handled correctly without data loss.
  • Translated Service Errors: Service validation errors in trim_cycle (device not found, integration not loaded, cycle missing, invalid trim range, empty trim window) now raise ServiceValidationError with translation_domain and translation_key instead of plain ValueError strings, giving users localized error messages in automations and the developer tools panel.
  • SVG Safety and Robustness: HTML special characters in SVG titles and no-data labels are now escaped, preventing rendering artefacts when cycle names contain &, <, or >. The "no power data" placeholder in merge-preview and trim-preview SVGs is now a configurable parameter rather than a hardcoded English string, enabling full localization.
  • Per-Device Logging Extended: DeviceLoggerAdapter coverage extended to ProfileStore and CycleRecorder. All log messages from these components now carry the device name prefix, consistent with the rest of the engine.
  • Removed Stub UI Option: Removed the "Label Multiple Cycles" entry from the Manage Cycles menu. The option was listed in the UI but had no backing implementation, leading to a silent no-op when selected.

🐛 Bug Fixes

  • Trim Offsets: Negative Input Clamping: handle_trim_cycle in __init__.py now clamps both trim_start_s and trim_end_s to max(0.0, ...) before the range-validity check. Previously a negative input bypassed the trim_invalid_range guard and was forwarded to the store unchanged.

  • Envelope Persistence After Startup Repair: async_load now calls await self.async_save() a second time after async_rebuild_all_envelopes() completes. Previously, rebuilt envelopes were applied to self._data in memory but never written to durable storage; a subsequent restart would redo the repair and lose any downstream use of the rebuilt data.

  • start_time String Validation in add_cycle: String start_time values are now validated with dt_util.parse_datetime() (falling back to a float conversion attempt) before being stored as canonical ISO timestamps. Previously any non-empty string passed through unconditionally, so a malformed or placeholder value could reach power_data_to_offsets and corrupt the stored offset array.

  • Test Alignment with _clean in test_trailing_zero_impact: duration_before and the n_trailing == len(…) - len(trimmed) assertion now operate on _clean(pd) rather than the raw pd list. Malformed rows filtered by _clean inside _trim_trailing / _trailing_zero_count caused length mismatches and potential index errors when real-world cycle files contained non-numeric entries.

  • lt.json Smart-Quote Corruption: The Lithuanian translation file had its trim_cycle services block committed with Unicode curly quotes (" / ") used as JSON structural delimiters instead of ASCII ". This produced an Invalid JSON error at startup. The block was rewritten with correct ASCII quoting while preserving the Lithuanian „…" content quotes inside string values.

  • Profile Statistics Graph Flat Line: Fixed a bug where newly detected cycles showed a flat line at zero and 0.00 kWh in the Profile Statistics graph. The cycle storage routine (_add_cycle_data) incorrectly treated already-converted offset values ([seconds, power]) as unix timestamps, subtracting the cycle start unix timestamp from them a second time. This produced large negative offsets (≈ −1.7 billion seconds) that caused np.interp in the envelope builder to extrapolate to the boundary power value (typically ~0 W) across the entire time grid, rendering a flat zero curve regardless of actual power draw.

  • Automatic Recovery of Corrupted Cycles: On startup, the integration now automatically detects and repairs any cycles stored with the corrupted negative offsets (first offset < −10⁸ s is physically impossible for an appliance cycle). The original offsets are recovered by adding the cycle's start_time unix timestamp back. Affected cycles are repaired in-place and saved transparently — no manual action required.

v0.4.3

16 Mar 15:49
7152e05

Choose a tag to compare

0.4.3 - 2026-03-16

✨ Features

  • New Device Types: Added full support for Air Fryer (#133) and Heat Pump (#134), with optimized defaults and custom icons (mdi:pot-steam, mdi:heat-pump).
  • Anti-Wrinkle Mode: Added a dedicated anti-wrinkle state for dryers and washer-dryer combos, including state transitions and shielding (#68).
  • Card Customization: Added new dashboard card settings including specialized toggles for Spinning Icon, Show State, Show Program, and Show Details.
  • Automated Translation Sync: Enhanced translate.py to automatically update the frontend card's TRANSLATIONS object from language files, providing out-of-the-box localization for all 27+ supported languages.
  • Inverted External Trigger: Added a new setting to invert the logic of the external cycle end trigger. Users can now choose to complete a cycle when an external binary sensor turns OFF instead of ON.
  • Randomized Cache Buster: The dashboard card now uses a timestamp-based cache buster that refreshes every time the integration is loaded, ensuring immediate updates without browser cache clearance.
  • Action-Based Notifications: Added notification actions with priority dispatch and fallback routing (actions → notify service → persistent notification).
  • Presence-Gated Notifications: Optional home/away gating to defer notifications until a tracked person is home.
  • Live Progress Mobile Notifications: Added in-place companion-app live updates (cycle_live) with per-cycle throttling, overrun protection caps, mobile-only payload routing, and automatic clear on cycle completion.
  • Feedback Review Power Visualization: Added an inline SVG chart in "Review Learned Feedbacks" that overlays the current cycle trace with learned profile data for faster manual verification.
  • Multi-Profile Comparison Graph: Feedback review now renders all candidate profiles in a single combined chart, highlighting the detected profile and showing the actual cycle trace for direct visual comparison.
  • Top Match Candidates Summary: Added ranked candidate details (confidence, MAE, correlation, duration ratio) to feedback review to improve correction decisions.

🛠️ Improvements

  • Per-Device Log Context: All log messages emitted by the core engine (WashDataManager, ProfileStore, CycleDetector, LearningManager, CycleRecorder) now include the device name as a [Device Name] prefix. When running two or more devices simultaneously, every log line is immediately attributable to its source without cross-referencing entry IDs.
  • UI Menu Clarity: All SelectSelector dropdowns in the configuration flow now use SelectOptionDict with explicit human-readable labels (e.g. "Split a Cycle (Find gaps)", "Export All Data", "Confirm - Correct Detection"). Previously, raw internal values such as "split" or "auto_label_cycles" were displayed directly in the UI.
  • Translation Cleanup: Removed stale action option keys from strings.json and en.json that were no longer backed by selectors in the config flow (assign_mode, export/import mode, cycle history editor actions, and several management menu entries). Reduces translator noise and prevents spurious untranslated keys in other languages.
  • Phase Catalog Translations: Extended manage_phase_catalog action labels and descriptions to Swedish, Tamil, Telugu, and Simplified Chinese.
  • Unified Time Handling: Refactored the core engine to use a single canonical offset-based time format for storage. Includes automatic migration of legacy data to prevent corruption and fixes "offset-naive/offset-aware" comparison bugs (#144).
  • Profile Rename Cascade: Renaming a profile now automatically updates all historically recorded cycles and pending feedback requests, maintaining end-to-end data integrity (#154).
  • Detection Persistence: Implemented temporal persistence for profile matching. Start notifications now only fire after a match remains stable over several intervals, drastically reducing false or jittery alerts.
  • Enhanced Feedback Resolution: Overhauled the feedback resolution flow with new "Delete" and "Ignore" actions, giving users more granular control over learned cycles.
  • Sub-State Extraction: The dashboard card now intelligently extracts and displays the specific phase from the state (e.g., showing "Rinsing" instead of "Running (Rinsing)") for a cleaner UI experience.
  • History Timeline Restoration: Restored categorical history diagrams for State and Program sensors by implementing the enum device class (#157).
  • Localized Menus: Updated configuration flow to use SelectSelector, enabling natively localized menu options across all supported languages.
  • Notification Event Toggle: Added notify_fire_events option to control emission of cycle start/end events.
  • Migration Normalization: Added migration helper defaults for new notification options to ensure deterministic upgrades.
  • Notification Options UX: Moved notification settings to a dedicated "Notifications" options step and removed duplicate live-enable controls, using event selection as the single source of truth.
  • Live Progress Match-Aware Flow: Live notifications now send a one-time "no profile matched yet" message before detection converges, then switch to periodic progress updates only after a profile duration is available.
  • Ultra-Long Cycle Support: Significantly improved handling for modern high-efficiency dishwashers with cycles exceeding 230 minutes.
    • Increased DEFAULT_MAX_DEFERRAL_SECONDS to 4 hours to prevent long silent Eco drying phases from being cut off.
    • Extended dishwasher-specific NO_UPDATE_ACTIVE_TIMEOUT to 4 hours.
    • Increased the default dishwasher MIN_OFF_GAP to 1 hour to prevent fragmentation when no profile is matched.
  • Robust Zombie Killer: Refined the "Zombie Killer" hard-limit to be more lenient, now triggering at 300% of expected duration (previously 200%) and requiring at least 4 hours of runtime. This prevents premature termination of long-running appliances while still protecting against runaway ghost cycles.
  • Device-Aware Suggestions: The SuggestionEngine is now aware of the configured device type and uses device-specific safety floors for off_delay recommendations, preventing it from suggesting dangerously short timeouts for dishwashers.
  • Translation Tool Docs: Added documentation for the Home Assistant integration translation helper script.
  • Learning Pipeline Context Propagation: Propagated runtime match ranking through manager/learning flow so feedback requests retain candidate context.
  • Feedback Chart Readability: Increased chart and legend typography and spacing to improve readability on Home Assistant dialogs.
  • Phase Assignment Visualization: Replaced ASCII timeline with interactive SVG power curve chart showing average cycle profile, colored phase spans, and gating line boundaries for better profile phase visualization.
  • Phase Catalog Management: Implemented full create/edit/delete capabilities for custom phases in the phase catalog, allowing users to build device-specific phase vocabularies. Default phases can also be edited, with overrides automatically stored in the custom phases list.
  • Device-Type Phase Filtering: Phase options in the profile assignment flow are now automatically filtered by the currently selected device type, ensuring only relevant phases appear in dropdowns.
  • Cross-Device Catalog View: "Manage Phase Catalog" now displays and groups phases for all supported device types in one place, instead of only the current integration device type.
  • Phase Action Wording Cleanup: Updated phase management action labels to clearer wording ("Create New Phase", "Edit Phase", "Delete Phase").
  • Current Phase Sensor Exposure: Added a standard device sensor for current phase (sensor.<device>_current_phase) so active phase is visible in normal entity views without enabling diagnostics.
  • Phase-Only Offset Input: Simplified phase assignment to use offset-based time entry (minutes from cycle start) instead of timestamp selection, reducing complexity and user error.
  • Suggested Settings Discoverability: Improved the Suggested Settings UX with sensor-first guidance, a one-time "suggestions ready" notification when recommendations become available, and an explicit review step before suggested values are staged in Advanced Settings.
  • Phase Unique ID Management: Built-in and custom phases are now assigned stable unique IDs. Phase catalog operations (edit, delete) resolve by ID rather than by name, eliminating ambiguity when similarly-named phases exist across different scopes. Includes improved error handling for rename/delete conflicts.
  • Duration Consistency Metric: Profile sensor attributes now expose a consistency_min field (standard deviation of recorded cycle durations, in minutes), allowing users to diagnose variability in learned profiles directly from the entity state.
  • Signal Processing Edge-Case Guards: Added guards against non-positive step and gap values in the resampling pipeline, preventing division-by-zero and NaN propagation in high-noise or sparse-sensor environments.
  • Cycle Detector Numeric Guards: update_match now validates confidence and expected-duration values with math.isfinite(), falling back to 0.0 with a debug log entry instead of propagating NaN or infinity into downstream sensors.
  • Suggestion Engine Resilience: Added TypeError/ValueError guards when parsing profile data in the SuggestionEngine, preventing crashes when stored profile fields contain unexpected types.
  • Card Registration Resilience: Dashboard card asset registration now catches all setup exceptions and logs a warning, allowing the rest of the integration to load normally; setup will retry on the next Home Assi...
Read more

v0.4.3-pre-release

11 Mar 19:31

Choose a tag to compare

v0.4.3-pre-release Pre-release
Pre-release

[0.4.3-PRE-RELEASE] - 2026-03-10

✨ Features

  • New Device Types: Added full support for Air Fryer (#133) and Heat Pump (#134), with optimized defaults and custom icons (mdi:pot-steam, mdi:heat-pump).
  • Anti-Wrinkle Mode: Added a dedicated anti-wrinkle state for dryers and washer-dryer combos, including state transitions and shielding (#68).
  • Slovak Localization: Full support for Slovak language in the integration, diagnostics, and frontend card (#156).
  • Traditional Chinese Localization: Added full Traditional Chinese (zh-Hant) translations for all configuration and options menus.
  • Card Customization: Added new dashboard card settings including specialized toggles for Spinning Icon, Show State, Show Program, and Show Details.
  • Automated Translation Sync: Enhanced translate.py to automatically update the frontend card's TRANSLATIONS object from language files, providing out-of-the-box localization for all 27+ supported languages.
  • Inverted External Trigger: Added a new setting to invert the logic of the external cycle end trigger. Users can now choose to complete a cycle when an external binary sensor turns OFF instead of ON.
  • Randomized Cache Buster: The dashboard card now uses a timestamp-based cache buster that refreshes every time the integration is loaded, ensuring immediate updates without browser cache clearance.
  • Action-Based Notifications: Added notification actions with priority dispatch and fallback routing (actions → notify service → persistent notification).
  • Presence-Gated Notifications: Optional home/away gating to defer notifications until a tracked person is home.
  • Live Progress Mobile Notifications: Added in-place companion-app live updates (cycle_live) with per-cycle throttling, overrun protection caps, mobile-only payload routing, and automatic clear on cycle completion.
  • Feedback Review Power Visualization: Added an inline SVG chart in "Review Learned Feedbacks" that overlays the current cycle trace with learned profile data for faster manual verification.
  • Multi-Profile Comparison Graph: Feedback review now renders all candidate profiles in a single combined chart, highlighting the detected profile and showing the actual cycle trace for direct visual comparison.
  • Top Match Candidates Summary: Added ranked candidate details (confidence, MAE, correlation, duration ratio) to feedback review to improve correction decisions.

🛠️ Improvements

  • UI Menu Clarity: All SelectSelector dropdowns in the configuration flow now use SelectOptionDict with explicit human-readable labels (e.g. "Split a Cycle (Find gaps)", "Export All Data", "Confirm - Correct Detection"). Previously, raw internal values such as "split" or "auto_label_cycles" were displayed directly in the UI.
  • Translation Cleanup: Removed stale action option keys from strings.json and en.json that were no longer backed by selectors in the config flow (assign_mode, export/import mode, cycle history editor actions, and several management menu entries). Reduces translator noise and prevents spurious untranslated keys in other languages.
  • Phase Catalog Translations: Extended manage_phase_catalog action labels and descriptions to Swedish, Tamil, Telugu, and Simplified Chinese.
  • Unified Time Handling: Refactored the core engine to use a single canonical offset-based time format for storage. Includes automatic migration of legacy data to prevent corruption and fixes "offset-naive/offset-aware" comparison bugs (#144).
  • Profile Rename Cascade: Renaming a profile now automatically updates all historically recorded cycles and pending feedback requests, maintaining end-to-end data integrity (#154).
  • Detection Persistence: Implemented temporal persistence for profile matching. Start notifications now only fire after a match remains stable over several intervals, drastically reducing false or jittery alerts.
  • Enhanced Feedback Resolution: Overhauled the feedback resolution flow with new "Delete" and "Ignore" actions, giving users more granular control over learned cycles.
  • Sub-State Extraction: The dashboard card now intelligently extracts and displays the specific phase from the state (e.g., showing "Rinsing" instead of "Running (Rinsing)") for a cleaner UI experience.
  • History Timeline Restoration: Restored categorical history diagrams for State and Program sensors by implementing the enum device class (#157).
  • Localized Menus: Updated configuration flow to use SelectSelector, enabling natively localized menu options across all supported languages.
  • Notification Event Toggle: Added notify_fire_events option to control emission of cycle start/end events.
  • Migration Normalization: Added migration helper defaults for new notification options to ensure deterministic upgrades.
  • Notification Options UX: Moved notification settings to a dedicated "Notifications" options step and removed duplicate live-enable controls, using event selection as the single source of truth.
  • Live Progress Match-Aware Flow: Live notifications now send a one-time "no profile matched yet" message before detection converges, then switch to periodic progress updates only after a profile duration is available.
  • Ultra-Long Cycle Support: Significantly improved handling for modern high-efficiency dishwashers with cycles exceeding 230 minutes.
    • Increased DEFAULT_MAX_DEFERRAL_SECONDS to 4 hours to prevent long silent Eco drying phases from being cut off.
    • Extended dishwasher-specific NO_UPDATE_ACTIVE_TIMEOUT to 4 hours.
    • Increased the default dishwasher MIN_OFF_GAP to 1 hour to prevent fragmentation when no profile is matched.
  • Robust Zombie Killer: Refined the "Zombie Killer" hard-limit to be more lenient, now triggering at 300% of expected duration (previously 200%) and requiring at least 4 hours of runtime. This prevents premature termination of long-running appliances while still protecting against runaway ghost cycles.
  • Device-Aware Suggestions: The SuggestionEngine is now aware of the configured device type and uses device-specific safety floors for off_delay recommendations, preventing it from suggesting dangerously short timeouts for dishwashers.
  • Translation Tool Docs: Added documentation for the Home Assistant integration translation helper script.
  • Learning Pipeline Context Propagation: Propagated runtime match ranking through manager/learning flow so feedback requests retain candidate context.
  • Feedback Chart Readability: Increased chart and legend typography and spacing to improve readability on Home Assistant dialogs.
  • Phase Assignment Visualization: Replaced ASCII timeline with interactive SVG power curve chart showing average cycle profile, colored phase spans, and gating line boundaries for better profile phase visualization.
  • Phase Catalog Management: Implemented full create/edit/delete capabilities for custom phases in the phase catalog, allowing users to build device-specific phase vocabularies. Default phases can also be edited, with overrides automatically stored in the custom phases list.
  • Device-Type Phase Filtering: Phase options in the profile assignment flow are now automatically filtered by the currently selected device type, ensuring only relevant phases appear in dropdowns.
  • Cross-Device Catalog View: "Manage Phase Catalog" now displays and groups phases for all supported device types in one place, instead of only the current integration device type.
  • Phase Action Wording Cleanup: Updated phase management action labels to clearer wording ("Create New Phase", "Edit Phase", "Delete Phase").
  • Current Phase Sensor Exposure: Added a standard device sensor for current phase (sensor.<device>_current_phase) so active phase is visible in normal entity views without enabling diagnostics.
  • Phase-Only Offset Input: Simplified phase assignment to use offset-based time entry (minutes from cycle start) instead of timestamp selection, reducing complexity and user error.

🐛 Bug Fixes

  • Manual Recording Revert (#151): Fixed an issue where manual recordings could unexpectedly revert configuration changes.
  • Data Import Fix (#152): Resolved a bug that prevented successful data imports into the profile store.
  • Profile Store Reliability (#155): Fixed synchronization issues when updating profile statuses and statistics.
  • Translation Consistency: Synchronized en.json with strings.json to ensure a canonical source of truth for translations.
  • Energy Threshold Defaults: Fixed a bug where start_energy_threshold and end_energy_threshold were incorrectly defaulting to 0.0W in the detector configuration, which could lead to premature cycle ends in noisy environments. They now correctly respect device-specific constant defaults.
  • Config Reload Consistency: Added missing energy threshold updates to the configuration reload logic, ensuring settings take effect immediately when changed in the UI.
  • Config Flow Null Option Guard: Fixed a crash in the options flow where a SelectSelector entry with a None value would cause a KeyError during form processing. Such entries are now silently skipped.
  • Profile Stats After Deletion: Fixed async_rebuild_envelope incorrectly computing min_duration and max_duration from the outlier-filtered duration set. min/max now reflect the true observed range of all cycles; only avg_duration uses the IQR-filtered set for robustness. This means deleting an outlier cycle now correctly recalculates the profile's duration range.
  • Feedback Translation Placeholder Mismatch: Fixed options-flow description placeholders ({comparison_data}) to prevent missing-value translation errors during feedback review.
  • Feedback SVG Legend Clipping: Fixed a viewBox heig...
Read more

v0.4.2.1

13 Feb 14:45

Choose a tag to compare

[0.4.2.1] - 2026-02-13

🐛 Fixed

  • Manual Recording Trimming: Fixed a bug where manual recordings (e.g., Dishwashers in Eco mode) were internally shortened by incorrectly snapping the cycle duration to the last recorded power reading, losing trailing silence like drying phases.
  • Profile Statistics Accuracy: Corrected profile duration calculations to use the authoritative cycle duration instead of data-offset bounds. This fixes incorrect remaining-time predictions and profile "shrinkage" over time.
  • Aggressive Tail Trimming: Modified recorder suggestions to be less aggressive. Suggested tail trims are now 0.0 for silence periods under 10 minutes, protecting legitimate silent phases in appliances.
  • Data Optimization Logic: Fixed maintenance logic that was incorrectly snapping durations to the last power reading during start-time shift corrections.
  • Envelope Reconstruction: Updated the statistical engine to correctly respect explicit cycle durations even when power sensor updates are sparse or missing at the end of a run.

v0.4.2

11 Feb 21:27
40857aa

Choose a tag to compare

[0.4.2] - 2026-02-11

✨ Features

  • Advanced Parameter Auto-Suggestion:
    • New SuggestionEngine that analyzes your appliance's actual power traces to recommend optimal settings.
    • Automatically suggests values for start_threshold_w, off_delay, watchdog_interval, and more based on observed behavior.
    • Periodic background optimization to keep settings tuned as your appliance ages or use patterns change.
  • Electric Vehicle (EV) Support:
    • Added new "Electric Vehicle" device type with optimized defaults.
    • New icons and phase heuristics ("Charging", "Maintenance").
  • Divergence Detection:
    • Improved matching logic to detect when a cycle starts diverging from its matched profile.
    • Automatically reverts to "Detecting..." if confidence drops significantly below the cycle's peak (default 40% drop).
  • Card Animation:
    • Added native spinning animation to the dashboard card icon when the appliance is running.
  • Configurable Stability Thresholds:
    • Added DEFAULT_MATCH_REVERT_RATIO and DEFAULT_DEFER_FINISH_CONFIDENCE to const.py for easier fine-tuning.
  • Profile-Aware Watchdog:
    • The watchdog now uses "look-ahead" logic from the matched profile to prevent premature cycle termination during long legitimate pauses (e.g., dishwasher drying).
    • Automatically extends silence timeouts if the cycle is within its expected profile duration.
  • Zombie Protection:
    • Implemented a hard "Zombie Killer" limit that force-ends cycles exceeding 200% of their expected profile duration (min 2 hours).
  • Stuck Power Prevention:
    • Automatically resets the power sensor to 0W when a cycle is forced to end by the watchdog or manual stop, fixing issues where the entity remained at a high value.
  • Zero-Latency Low-Power Processing:
    • Power updates below min_power now bypass all debouncing, smoothing, and sampling interval filters, ensuring immediate cycle-end detection.
  • Program Detection Stability:
    • Implemented temporal persistence for profile matching: requires 3 consecutive consistent matches before switching from "detecting..." to a profile, or before unmatching a profile.
    • Added a minimum confidence gap for mid-cycle profile switching to prevent "flapping" between similar programs.
  • Total Duration Sensor:
    • New total_duration sensor providing the predicted total cycle time (Elapsed + Remaining).
    • Designed specifically to support full progress bars in timer-bar-card.
    • Dynamically updates as estimates are refined.
      -Languages
    • Added many new languages

🛠️ Improvements

  • Manual Recording Robustness:
    • Increased gap threshold to 6 hours to support very long Eco cycles with multi-hour silent phases.
    • Unified automatic trimming threshold to 1.0W across the integration.
  • Clean Card UI:
    • Removed redundant "off" label from completion details when the appliance is inactive.
  • Zigbee2MQTT Guidance:
    • Added optimized configuration tips for Z2M smart plug users in README.

🐛 Bug Fixes

  • Profile Alignment Error (#112):
    • Fixed a critical TypeError: 'float' object is not subscriptable in the profile matching pipeline.
  • Terminal State Persistence:
    • Fixed a bug where finished and interrupted states were not resetting to off after the intended 30-minute timeout.
  • Profile Shrinking:
    • Fixed an issue where maintenance tasks would aggressively trim trailing silence from completed cycles, causing profiles to shorten over time.
  • Termination Hangs:
    • Restricted "Deferred Finish" logic to require high confidence (> 0.55) or a verified pause, preventing cycles from hanging on mismatched long profiles.
  • Long Drying Phase Support:
    • Fixed an issue where dishwashers with multi-hour silent drying phases were being split into multiple cycles by the watchdog.
    • Recognizes "Verified Pause" from profile envelope to extend silence timeouts.
  • Test Stability:
    • Resolved several TypeError issues in the test suite and improved mocking reliability for sensors and configs.

v0.4.1

03 Feb 15:59
02ae96f

Choose a tag to compare

[0.4.1] - 2026-02-03

✨ Features

  • Persistent Terminal States:
    • Implemented proper finished, interrupted, and force_stopped states that persist for 30 minutes after cycle completion.
    • Improves visibility of cycle outcomes in the UI (users can now see "Finished" instead of just "Off").
    • Auto-resets to off after 30 minutes, or immediately if a new cycle starts.
  • Coffee Machine Defaults: Added dedicated defaults for coffee machines (faster sampling, shorter timeouts) to improve detection out-of-the-box.
  • French Translation: Added full French localization (thanks to @MaximeNagel).

🛠️ Improvements

  • Profile Sorting: Improved sorting for profile lists (natural sort), ensuring correct numeric order (e.g. 1, 2, 10 instead of 1, 10, 2).
  • Refactored Device Defaults: Consolidated and cleaned up device-specific default settings logic.
  • Test Suite: Enhanced test coverage for cycle state transitions and manager notifications.

🐛 Bug Fixes

  • Stuck Power Value: Fixed issue where the power entity would get stuck at the last non-zero value after a cycle ended.
  • Timezone Display: Fixed issue where timestamps in specific UI menus were shown in GMT instead of local time.
  • Advanced Settings Error: Fixed a crash that prevented advanced settings from being saved in the configuration flow.
  • State Logic: Fixed assertions and logic validation for terminal states.
  • Notification Tests: Fixed test environment formatting for notification services.

What's Changed

New Contributors

Full Changelog: v0.4.0...0.4.1

v0.4.0

01 Feb 13:39
794e664

Choose a tag to compare

[0.4.0] - 2026-01-12

Major Architectural Rewrite ("vNext")

This release marks a complete re-engineering of the HA WashData core, transitioning from simple heuristics to a rigorous signal processing pipeline and robust state machine. While the version number is minor, this is effectively a new engine under the hood.

🎉 Milestones Reached!

  • HA WashData is now available in the HACS Default Repository!
  • Passed 1,000 active installations across the community.
  • Reached 500+ stars on GitHub.

Thank you to everyone who has been patient during development and to all contributors who provided invaluable feedback, bug reports, and feature suggestions. This release wouldn't be possible without you!

Important

Fresh Start Recommended

This release includes significant changes to how cycles are detected and profiles are matched. The new engine depends on clean, accurate data to work properly.

If you're unsure whether your previously recorded cycles were captured correctly (e.g., cycles that ended prematurely, incorrectly merged fragments, or noisy data from before tuning your thresholds), we recommend:

  1. Delete your existing cycle history via Configure → Manage Cycles → Delete All
  2. Use the new "Record Cycle" feature to capture fresh, clean training data for each program you use

This ensures the best possible matching accuracy with the new architecture.

Core Architecture: Signal Processing & State Machine

  • New Signal Processing Engine (signal_processing.py):

    • Dt-Aware Integration: Replaced simple averaging with trapezoidal Riemann sum integration (integrate_wh) that respects variable sampling intervals.
    • Robust Smoothing: Implemented robust_smooth, a hybrid algorithm combining a Median Filter (spike rejection) with a Time-Aware Exponential Moving Average (EMA) for clean trend detection.
    • Adaptive Resampling: New primitives (resample_adaptive, resample_uniform) handle irregular sensor updates and enforce strict gap handling (no interpolation across large gaps).
    • Idle Baseline Learning: Automatically learns the device's "true zero" using Median Absolute Deviation (MAD), removing the need for manual calibration.
  • Finite State Machine (FSM):

    • Replaced binary ON/OFF logic with a formal FSM: OFFSTARTINGRUNNINGPAUSEDENDINGOFF.
    • Dt-Aware Gating: Start/End detection now uses accumulated time/energy gates (e.g., "energy since idle > X Wh") rather than sample counts, making it immune to sensor update frequency.
    • Smart Pausing: Distinguishes between "End of Cycle" and "Mid-Cycle Pause" using dynamic thresholds derived from the sensor's sampling cadence (_p95_dt).

Storage v2 & Migration

  • Profile Store v2 (profile_store.py):
    • New Schema: Introduced a versioned storage schema (v2) optimized for performance.
    • Trace Compression: Historical power traces are now compressed using relative time deltas, significantly reducing disk usage.
    • Robust Migration: Included a designated WashDataStore engine that automatically upgrades v1 data to v2 without data loss, preserving user labels and corrections.

✨ functionality & Features

  • Configurable Sampling Interval: New "Sampling Interval" setting allows users to throttle high-frequency sensors (e.g., 1s updates) to reduce CPU load.
  • Precision Configuration: Configuration flow now uses Text Box inputs for all numeric thresholds, offering precise control over parameters like start_energy_threshold (Wh) and drop_ratio.
  • Smart Resume: "Resurrection" logic restores the exact cycle state (including sub-state) after a Home Assistant restart.
  • Auto-Labeling: Increased default confidence threshold to 0.75 (from 0.70) to leverage the improved accuracy of the new engine.
  • Diagnostic Sensors: Added dynamic diagnostic sensors for each profile (e.g., sensor.washdata_..._profile_cotton_count) showing the total cycle count properly.
  • Statistics: Added "Total Energy" column to the Profile Statistics table, showing the cumulative energy consumed for each profile.
  • Low-Rate Polling Support: Optimized default settings for devices with 30-60s update intervals (e.g., Shelly Cloud, Tuya), including a 30s watchdog and 180s off-delay.
  • User Experience: moved "Review Learned Feedbacks" to the main menu (bottom) for easier access, and removed confusing options.

🛠️ Technical Improvements

  • Logging: Added more granular termination_reason logging (e.g., smart, timeout, force_stopped) to cycle_detector and profile_store.
  • Timezone Robustness: Complete refactor to use timezone-aware datetimes (dt_util.now()) exclusively, permanently fixing "offset-naive/offset-aware" comparison errors.
  • Strict Typing: Codebase now strictly adheres to type hinting, with extensive use of TypeAlias and dataclass for internal structures.
  • Performance: Optimized last_match_details sensor attribute to exclude large raw data arrays, preventing Home Assistant state update bloat.
  • Serialization: Fixed MatchResult JSON serialization issues that were blocking sensor updates.

🐛 Bug Fixes

  • Premature Termination & Dishwasher Logic: Major robustness improvements for dishwashers.
    • Implemented "Verified Pause" logic to prevent early termination during long drying phases.
    • Added "End Spike Wait Period": Dishwashers now wait up to 5 extra minutes after expected duration to capture final pump-out spikes.
    • Increased Smart Termination duration ratio to 0.99 (from 96%) to ensure strictly conservative termination for dishwashers.
  • Ghost Cycles: Enhanced filtering and elimination of false detection.
    • Persistent Suppression: The "Suspicious Window" (20 min) now persists across restarts (restoring last_cycle_end), preventing end-spikes from triggering ghosts after reboots.
    • Tail Preservation: Disabled "zero trimming" for confirmed completed cycles, preventing the "profile shrinking" feedback loop where tails were lost.
    • Implemented completion_min_seconds logic to ignore brief spikes.
  • Start/End Flutter: Start debounce and End repeat counts are now configurable and backed by robust accumulators, eliminating false starts/ends.
  • Cycle Detector: Adjusted duration validation logic to strict 90%-125% window for completion.
  • Translations: Fixed "intl string context variable not provided" errors in logs by properly passing placeholders to translation engine.
  • Debug Sensors: Fixed "Top Candidates" sensor showing "None" due to missing data propagation.
  • Code Quality: Addressed various linting issues (indentation, whitespace, unused arguments).
  • Crash Fixes: Resolved UnboundLocalError and specific edge-case crashes in profile_store.py during migration.
  • Critical Fix (Runtime Matching): Fixed an issue where runtime profile matching was blocking the event loop and skipping DTW; now uses the full async pipeline.
  • Legacy Data Repair: Added automatic reconstruction of missing time_grid in old profile envelopes to prevent errors.
  • Validation: Fixed missing dtw_bandwidth key in strings.json causing config flow validation errors.
  • Maintenance Safety: Fixed aggressive cleanup logic that was deleting empty/new profiles (pending training); these are now safely preserved.
  • Test Suite: Fixed verification tests for Smart Termination and Profile Store matching.

📚 Documentation

  • Visual Settings Guide: Expanded SETTINGS_VISUALIZED.md with comprehensive documentation for 20+ parameters, organized into logical sections (Signal Conditioning, Detection, Matching, Integrity, Interruption, Learning, Notifications).
  • Complete Parameter Coverage: All advanced settings now documented with explanations, including sampling_interval, watchdog_interval, profile_match_threshold, duration_tolerance, learning_confidence, auto_label_confidence, and abrupt_drop_ratio.

🧹 Cleanup & Removals

  • Removed auto_merge_gap_seconds: This setting was never used in the actual merge logic; removed from code, config flow, and translations.
  • Removed auto_merge_lookback_hours: Similar unused legacy setting removed from codebase and UI.
  • Fixed Unused Imports: Cleaned up unused DEFAULT_PROFILE_MATCH_MAX_DURATION_RATIO and duplicate import warnings.
  • Fixed F-String Warning: Removed empty f-string in config_flow post-process step.

⚠️ Deprecations

  • Legacy Logic: Removed "consecutive samples" based detection in favor of time-aware accumulators.
  • Sliders: Removed slider inputs in config flow in favor of precise text inputs.