Skip to content

Commit 794e664

Browse files
authored
Merge pull request #44 from 3dg1luk43/0.3.3
v0.4.0
2 parents 3912547 + 6319724 commit 794e664

104 files changed

Lines changed: 15507 additions & 4987 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agent/workflows/development.md

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
---
2+
description: HA WashData development workflow - project scope, architecture, and guardrails for all development sessions
3+
---
4+
5+
# HA WashData Development Guide
6+
7+
## Project Overview
8+
9+
**Purpose**: Home Assistant custom integration monitoring washing machines, dryers, dishwashers, and coffee machines via smart sockets (power readings). Uses NumPy-powered shape correlation matching to detect cycle programs and estimate completion times.
10+
11+
**Repository**: `/root/ha_washdata`
12+
**Version**: 0.4.0 (as of Feb 2026)
13+
**Status**: Available in HACS Default Repository, 1000+ installations, 500+ GitHub stars
14+
15+
---
16+
17+
## Non-Negotiable Constraints
18+
19+
// turbo-all
20+
21+
### 1. Dependency Policy
22+
- **ONLY NumPy allowed** - No SciPy, scikit-learn, or other ML libraries
23+
- Must be in `manifest.json` requirements field
24+
- No external API calls - 100% local
25+
- **Async I/O Mandatory**: All heavy matching (DTW, NumPy) MUST run in executor (`await hass.async_add_executor_job`). NEVER block the event loop.
26+
27+
### 2. dt-Aware Computations
28+
- All time/energy calculations MUST use timestamps (not sample counts)
29+
- Use `dt_util.now()` for timezone-aware datetimes
30+
- Energy integration: `Σ P * dt` with explicit gap handling
31+
32+
### 3. UI Text Handling
33+
- **NO inline strings in Python** - Use `strings.json` and `translations/en.json`
34+
- Config/Options flow labels must be translation keys
35+
36+
### 4. Options Flow Pattern
37+
- Advanced tuning in **OptionsFlowHandler** (not ConfigFlow only)
38+
- Store tunables in `entry.options`, identity in `entry.data`
39+
- Use `async_update_entry` for modifications
40+
41+
### 5. Migration Safety
42+
- Use config entry versioning (VERSION/MINOR_VERSION)
43+
- Implement `async_migrate_entry` in `__init__.py`
44+
- Migration must be **deterministic and idempotent**
45+
- Never drop user data during migration
46+
47+
### 6. Event Data Limits
48+
- Home Assistant limits event data to **32KB**
49+
- Exclude `power_data`, `debug_data`, `power_trace` from events
50+
51+
---
52+
53+
## Architecture Overview
54+
55+
```
56+
┌─────────────────────────────────────────────────────────────┐
57+
│ Home Assistant Integration │
58+
├─────────────────────────────────────────────────────────────┤
59+
│ ┌──────────────────────────────────────────────────────┐ │
60+
│ │ WashDataManager (manager.py ~110KB) │ │
61+
│ │ • Power sensor event handling │ │
62+
│ │ • Progress tracking & idle-based reset │ │
63+
│ │ • Feedback requests & notifications │ │
64+
│ │ • Watchdog timer for stuck cycles │ │
65+
│ │ • External end trigger support │ │
66+
│ └──────────────────────────────────────────────────────┘ │
67+
│ ↓ ↓ │
68+
│ ┌──────────────────┐ ┌──────────────────────────┐ │
69+
│ │ CycleDetector │ │ LearningManager │ │
70+
│ │ (cycle_detector) │ │ (learning.py) │ │
71+
│ │ │ │ │ │
72+
│ │ • State machine: │ │ • User feedback tracking │ │
73+
│ │ OFF→STARTING→ │ │ • Profile learning │ │
74+
│ │ RUNNING↔PAUSED │ │ • 80/20 weighting │ │
75+
│ │ →ENDING→OFF │ │ │ │
76+
│ └──────────────────┘ └──────────────────────────┘ │
77+
│ ↓ ↓ │
78+
│ ┌──────────────────────────────────────────────────────┐ │
79+
│ │ ProfileStore (profile_store.py ~108KB) │ │
80+
│ │ │ │
81+
│ │ • Multi-stage matching pipeline: │ │
82+
│ │ Stage 1: Fast Reject (duration/energy/signature) │ │
83+
│ │ Stage 2: Core Similarity (MAE+Correlation+Peak) │ │
84+
│ │ Stage 3: DTW-Lite tie-break (Sakoe-Chiba band) │ │
85+
│ │ • Cycle compression & storage (v2 schema) │ │
86+
│ │ • Profile CRUD operations │ │
87+
│ └──────────────────────────────────────────────────────┘ │
88+
└─────────────────────────────────────────────────────────────┘
89+
```
90+
91+
---
92+
93+
## Key Files Reference
94+
95+
| File | Purpose | Size |
96+
|------|---------|------|
97+
| `manager.py` | Main orchestrator, power event handling, progress tracking | ~110KB |
98+
| `profile_store.py` | Storage v2, compression, NumPy matching pipeline | ~108KB |
99+
| `config_flow.py` | Configuration wizard, options flow, all UI steps | ~105KB |
100+
| `cycle_detector.py` | State machine (OFF→STARTING→RUNNING↔PAUSED→ENDING→OFF) | ~36KB |
101+
| `learning.py` | User feedback processing, profile duration learning | ~23KB |
102+
| `__init__.py` | Entry point, setup, migration logic | ~25KB |
103+
| `sensor.py` | All sensor entity definitions | ~15KB |
104+
| `analysis.py` | Feature extraction and analysis utilities | ~15KB |
105+
| `const.py` | All constants, config keys, defaults | ~10KB |
106+
| `signal_processing.py` | dt-aware integration, resampling, smoothing | ~8KB |
107+
108+
---
109+
110+
## Cycle Detection Logic
111+
112+
### State Machine
113+
```
114+
OFF → STARTING → RUNNING ↔ PAUSED → ENDING → OFF
115+
```
116+
117+
### Key Thresholds (device-type aware)
118+
- `start_threshold_w` / `stop_threshold_w`: Hysteresis for clean transitions
119+
- `start_energy_threshold`: Wh required to confirm start (reject spikes)
120+
- `end_energy_threshold`: Max Wh during off_delay to confirm end
121+
- `off_delay`: Seconds below threshold before completing
122+
- `min_off_gap`: Minimum OFF time before new cycle can start
123+
- `running_dead_zone`: Ignore power dips in first N seconds after start
124+
- `end_repeat_count`: Consecutive low readings before ending
125+
126+
### Status Classification
127+
-`completed`: Natural finish after off_delay
128+
-`force_stopped`: Watchdog finalized while in low-power wait
129+
-`interrupted`: Abnormal early end (very short or abrupt drop)
130+
-`resumed`: Restored after HA restart
131+
132+
---
133+
134+
## Profile Matching Pipeline
135+
136+
### Stage 1: Fast Reject
137+
- Duration ratio filter (configurable min/max ratios)
138+
- Energy delta check (>50% = reject)
139+
- Signature mismatch (event density, time-to-first-high)
140+
141+
### Stage 2: Core Similarity
142+
- **MAE (40%)**: Mean absolute error, robust scaled
143+
- **Correlation (40%)**: NumPy corrcoef shape matching
144+
- **Peak Power (20%)**: Max power amplitude comparison
145+
- Confidence boost (+20%) if correlation > 0.85
146+
147+
### Stage 3: DTW-Lite (tie-breaker only)
148+
- Sakoe-Chiba band constraint (O(T*band) complexity)
149+
- Only runs when margin < ambiguity threshold
150+
- Normalized series (z-score) before comparison
151+
152+
### Key Matching Parameters
153+
- `profile_match_threshold`: Minimum score to accept match (default: 0.4)
154+
- `profile_unmatch_threshold`: Score below which to reject mid-cycle (default: 0.35)
155+
- `profile_duration_tolerance`: Duration band for matching (default: 0.25 = ±25%)
156+
- `profile_match_interval`: Seconds between match attempts (default: 300)
157+
158+
---
159+
160+
## Testing Workflow
161+
162+
### Run Tests
163+
```bash
164+
# All tests
165+
pytest tests/ -v
166+
167+
# Specific test files
168+
pytest tests/test_cycle_detector.py -v
169+
pytest tests/test_profile_store.py -v
170+
pytest tests/test_manager.py -v
171+
pytest tests/test_real_data.py -v
172+
173+
# Syntax check
174+
python3 -m py_compile custom_components/ha_washdata/*.py
175+
```
176+
177+
### Mock Socket Testing
178+
```bash
179+
cd /root/ha_washdata
180+
python3 devtools/mqtt_mock_socket.py --speedup 720 --default LONG --variability 0.15
181+
182+
# Fault injection
183+
mosquitto_pub -t homeassistant/mock_washer_power/cmd -m 'LONG_DROPOUT'
184+
mosquitto_pub -t homeassistant/mock_washer_power/cmd -m 'MEDIUM_GLITCH'
185+
```
186+
187+
---
188+
189+
## Development Checklist
190+
191+
Before any PR:
192+
1. [ ] `python3 -m py_compile custom_components/ha_washdata/*.py` passes
193+
2. [ ] `pytest tests/ -v` all green
194+
3. [ ] No SciPy or disallowed imports
195+
4. [ ] UI strings in `strings.json` / `translations/en.json`
196+
5. [ ] dt-aware calculations (timestamps, not sample counts)
197+
6. [ ] Event data < 32KB (exclude power_data from events)
198+
7. [ ] Migration is idempotent if schema changed
199+
8. [ ] Deprecated code removed (not kept alongside new)
200+
9. [ ] All removed settings also removed from localization files
201+
202+
---
203+
204+
## Removed/Deprecated Settings (Do Not Use)
205+
206+
These settings have been removed from the codebase and should NOT be re-added:
207+
- `auto_merge_gap_seconds` - Never used in actual logic
208+
- `auto_merge_lookback_hours` - Never used in actual logic
209+
- Legacy slider-based inputs (replaced with text boxes)
210+
- Sample-count based detection (replaced with dt-aware accumulators)
211+
212+
---
213+
214+
## Documentation References
215+
216+
- `README.md`: User guide, installation, basic usage, screenshots
217+
- `SETTINGS_VISUALIZED.md`: Visual explainers for all 20+ parameters
218+
- `IMPLEMENTATION.md`: Architecture, features, key classes
219+
- `TESTING.md`: Mock socket guide, test procedures, debugging
220+
- `CHANGELOG.md`: Release history (current: 0.4.0)

0 commit comments

Comments
 (0)