Skip to content

Commit e20bee5

Browse files
authored
Merge pull request #36 from 3dg1luk43/0.3.2
0.3.2
2 parents f88bd23 + 1ede9f8 commit e20bee5

19 files changed

Lines changed: 853 additions & 542 deletions

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ tests/__pycache__
1010
ha_washdata.code-workspace
1111
devtools/secrets.py
1212
.gitignore
13-
cycle_data
1413
custom_components/ha_washdata/test_data
15-
tests/repro/__pycache__
14+
tests/repro/__pycache__
15+
cycle_data

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ All notable changes to HA WashData will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.3.2] - 2026-01-02
9+
10+
### Added
11+
- **Manual Control**: "Force End Cycle" button to manually terminate stuck cycles (treats as "Completed" and saves data).
12+
- **Reliability**: "Cycle Resurrection" logic to restore active cycle state after Home Assistant restarts.
13+
- **Reliability**: "Smart Resume" estimation to provide progress updates during "detecting..." phase based on historical averages.
14+
- **Smart Cycle Extension**: New feature to prevent premature cycle termination during long low-power phases (e.g., dishwasher drying).
15+
- **Statistics**: Energy (kWh) estimates added to Profile Statistics table.
16+
- **UI**: Added legends to profile graphs and scaled them up by 50% for better readability.
17+
- **Config Flow**: Split "Manage Data" into "Manage Cycles" and "Manage Profiles" menus for better usability.
18+
- **Config Flow**: Added ability to manually edit profile "Average Duration" for tuning Smart Extension.
19+
20+
### Fixed
21+
- **Icons**: Fixed missing icon for "Cycle Program" select entity (now dynamically adapts to device type).
22+
- **Frontend**: Added missing "min" unit to "Time Remaining" display on card.
23+
- **Logic**: Improved filtering of "Ghost Cycles" (extremely short noise events).
24+
- **Bug**: Fixed JSON serialization error preventing status updates in some cases.
25+
- **Bug**: Ensure stats are immediately rebuilt after merging cycles.
26+
- **Translation Keys**: Corrected missing labels for "Smart Extension Threshold" and other advanced settings.
27+
828
## [0.3.1] - 2024-12-31
929

1030
### Added

README.md

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@
88

99
A Home Assistant custom component to monitor washing machines via smart sockets, learn power profiles, and estimate completion time using shape-correlation matching.
1010

11-
1211
> [!CAUTION]
13-
> **ELECTRICAL SAFETY WARNING**: Using smart plugs such as Shelly or Sonoff with high-amperage appliances (washing machines, dryers, dishwriters) carries significant risk.
12+
> **ELECTRICAL SAFETY WARNING**: Using smart plugs such as Shelly or Sonoff with high-amperage appliances (washing machines, dryers, dishwashers) carries significant risk.
1413
>
1514
> * **Fire Hazard**: Cheap or low-rated smart plugs may overheat, melt, or catch fire under sustained high loads (heating/drying phases).
1615
> * **Rating Check**: Ensure your smart plug is rated for the **maximum peak power** of your appliance (often >2500W). Standard 10A plugs may fail; 16A+ or hardwired modules are recommended.
@@ -21,7 +20,8 @@ A Home Assistant custom component to monitor washing machines via smart sockets,
2120
- **Multi-Device Support**: Track Washing Machines, Dryers, Dishwashers, or Coffee Machines with device-type tagging.
2221
- **Smart Cycle Detection**: Automatically detects starts/stops with **Predictive End** logic to finish faster when confidence is high.
2322
- **Power Spike Filtering**: Ignores brief boot spikes to prevent false starts.
24-
- **Shape-Correlation Matching**: Uses `numpy.corrcoef` with **Confidence Boosting** to distinguish similar cycles by their unique power curve signature.
23+
- **Shape-Correlation Matching**: Uses `numpy.corrcoef` with **Confidence Boosting** to distinguish similar cycles.
24+
- **Manual Training**: You define your profiles (e.g., "Cotton", "Quick") once; the system learns to recognize them thereafter. Integration **does not** auto-create profiles.
2525
- **Smart Time Estimation**: "Phase-aware" prediction detects variance (e.g., heating) and locks the countdown to prevent erratic jumps.
2626
- **Changeable Power Sensor**: Switch plugs without losing history.
2727
- **Minimal Status Card**: Optional custom Lovelace card.
@@ -36,49 +36,52 @@ A Home Assistant custom component to monitor washing machines via smart sockets,
3636
- **Auto-Maintenance**: Nightly cleanup - removes orphaned profiles, merges fragmented cycles.
3737
- **Export/Import**: Full configuration backup/restore with all settings and profiles via JSON.
3838

39-
## Installation (via HACS)
39+
---
40+
41+
## 📘 Basic User Guide
42+
43+
Designed for new users to get up and running quickly.
44+
45+
## 1. Installation (via HACS)
4046

4147
1. In Home Assistant, open **HACS → Settings → Custom repositories**.
4248
2. Add `https://github.com/3dg1luk43/ha_washdata` as a **Integration** repository.
4349
3. Back in HACS, search for **HA WashData**, install, and **Restart Home Assistant**.
4450

4551
Manual fallback (if not using HACS): copy `custom_components/ha_washdata` into your HA `custom_components` folder and restart.
4652

47-
## Configuration
53+
### 2. Initial Setup
4854

4955
1. Go to **Settings > Devices & Services**.
5056
2. Click **Add Integration** and search for **HA WashData**.
51-
3. Follow the configuration flow:
52-
- Give your appliance a **Name**.
53-
- Select the **Device Type** (Washing Machine, Dryer, Dishwasher, or Coffee Machine).
54-
- Select the **Power Sensor** entity from your smart plug.
57+
3. Follow the wizard:
58+
- **Name**: Name your appliance (e.g., "Washing Machine").
59+
- **Device Type**: Select the type (Washer, Dryer, etc.) - this sets optimal defaults.
60+
- **Power Sensor**: Choose the smart plug entity monitoring the power (Watts).
5561
- Set the **Minimum Power** threshold (default 2W).
56-
- **Step 2 (Optional)**: You will be asked if you want to create your **First Profile** immediately (e.g., "Cotton"). This helps the system provide time estimates right away.
57-
- *Note: Device Type automatically sets optimal defaults (e.g., 60s completion threshold for Coffee Machines).*
62+
- **Step 2 (Optional)**: You will be asked if you want to create your **First Profile** immediately (e.g., "Cotton").
63+
- *Tip*: If you create this profile, you can **manually select it** via the card controls while a cycle is running. This forces the system to use that profile's duration for accurate **time remaining** and **progress %** estimates immediately, even before the system learns to recognize it automatically.
5864

59-
### Lovelace Status Card
65+
### 3. Add the Status Card
6066

67+
To see the beautiful status card on your dashboard:
68+
1. Edit your Dashboard (Top right menu -> **Edit Dashboard**).
69+
2. Add Card
70+
3. Search for **WashData Tile Card** (or just "Wash") and select it.
71+
4. The visual editor will appear. Select entities for your target device.
72+
5. Click **Save**.
6173

62-
After installation, you can add a minimal status card to your dashboard:
74+
### 4. Teach the Integration (Crucial Step!)
6375

64-
1. Edit your dashboard → Add Card → Manual.
65-
2. Enter:
66-
```yaml
67-
type: custom:ha-washdata-card
68-
entity: sensor.washing_machine
69-
title: "My Washer"
70-
```
71-
3. The card shows: Status icon, running state, current program, progress bar, and time remaining.
76+
**Important**: The integration **does not** automatically create profiles. You must teach it! It will not detect your programs "magically" until you define them.
7277

73-
*The card is served from `/ha_washdata/ha-washdata-card.js`. If it doesn't appear, clear your browser cache or restart HA.*
78+
1. **Run a Cycle**: Use your appliance as normal. The integration will record it as an "Unknown" cycle and show "detecting...".
79+
2. **Create a Profile**: After the cycle finishes, go to **Manage Data & Profiles**.
80+
3. **Label the Cycle**: Select the recent cycle, click **Create Profile** (e.g., name it "Cotton 60"), and save.
7481

75-
### UI & Parameter Tuning
82+
**Now** the integration knows what "Cotton 60" looks like. The next time you run this program, it will be detected automatically and you will get accurate time estimates. Repeat this for each of your common programs.
7683

77-
1. After adding the integration, click **Configure** on the integration entry.
78-
2. **Settings**: Centralized page for all tunables (Min Power, Off Delay, Smoothing, etc.). Use **numerical text boxes** for precise control.
79-
3. **💡 Apply Suggestions**: Check this box at the top of Settings to refresh the form with recommended values from your machine's history; review then submit to save.
80-
4. **Progress Estimation**: Remaining time is anchored to the matched profile’s average duration; progress is derived from `elapsed / (elapsed + remaining)` to avoid jumpy percentages.
81-
5. **Manage Data & Profiles**: Access tools to rename profiles, label past cycles, or auto-label historical data.
84+
---
8285

8386
## How it Works
8487

@@ -217,3 +220,4 @@ Access via **Configure → Settings**:
217220
## License
218221

219222
Non-commercial use only. See LICENSE file.
223+

custom_components/ha_washdata/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171

7272
_LOGGER = logging.getLogger(__name__)
7373

74-
PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.BINARY_SENSOR, Platform.SELECT]
74+
PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.BINARY_SENSOR, Platform.SELECT, Platform.BUTTON]
7575

7676

7777
def _require_str(value: Any, name: str) -> str:
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"""Button platform for HA WashData."""
2+
from __future__ import annotations
3+
4+
import logging
5+
from homeassistant.components.button import ButtonEntity
6+
from homeassistant.config_entries import ConfigEntry
7+
from homeassistant.core import HomeAssistant
8+
from homeassistant.helpers.entity_platform import AddEntitiesCallback
9+
10+
from .const import DOMAIN
11+
from .manager import WashDataManager
12+
13+
_LOGGER = logging.getLogger(__name__)
14+
15+
async def async_setup_entry(
16+
hass: HomeAssistant,
17+
entry: ConfigEntry,
18+
async_add_entities: AddEntitiesCallback,
19+
) -> None:
20+
"""Set up the WashData button."""
21+
manager: WashDataManager = hass.data[DOMAIN][entry.entry_id]
22+
23+
async_add_entities([WashDataTerminateButton(manager, entry)])
24+
25+
class WashDataTerminateButton(ButtonEntity):
26+
"""Button to force terminate the current cycle."""
27+
28+
_attr_has_entity_name = True
29+
_attr_name = "Force End Cycle"
30+
_attr_icon = "mdi:stop-circle-outline"
31+
32+
def __init__(self, manager: WashDataManager, entry: ConfigEntry) -> None:
33+
"""Initialize the button."""
34+
self._manager = manager
35+
self._entry = entry
36+
self._attr_unique_id = f"{entry.entry_id}_force_end"
37+
self._attr_device_info = {
38+
"identifiers": {(DOMAIN, entry.entry_id)},
39+
"name": entry.title,
40+
"manufacturer": "HA WashData",
41+
}
42+
43+
async def async_press(self) -> None:
44+
"""Handle the button press."""
45+
await self._manager.async_terminate_cycle()

0 commit comments

Comments
 (0)