Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
346966b
Update sensor.py double entry error code 4
laurensdehoorne Jun 25, 2025
e5ac674
Update AlsavoPyCtrl.py
laurensdehoorne Jun 25, 2025
bcc4a24
Update climate.py
laurensdehoorne Jun 25, 2025
a376ec0
Update udpclient.py
laurensdehoorne Jun 25, 2025
23c9bf5
Update manifest.json
laurensdehoorne Jun 25, 2025
4642de0
1.0.1
laurensdehoorne Mar 23, 2026
ba12745
1.0.2
laurensdehoorne Mar 23, 2026
4727288
update readme
laurensdehoorne Mar 23, 2026
3f83808
alarm codes
laurensdehoorne Mar 23, 2026
070bfcb
1.0.4
laurensdehoorne Mar 23, 2026
4dcd40b
small update
laurensdehoorne Mar 23, 2026
85153b9
update readme
laurensdehoorne Mar 23, 2026
9040173
updates, code cleanup
laurensdehoorne May 13, 2026
2406db4
changelog
laurensdehoorne May 13, 2026
45567a3
fix auth failure and timeout
laurensdehoorne May 13, 2026
bd9e35f
Revert "fix auth failure and timeout"
laurensdehoorne May 13, 2026
d0dad8d
auth update
laurensdehoorne May 13, 2026
0c1c60d
revert changes
laurensdehoorne May 13, 2026
523c413
Fix typo in async_unload_entry function
laurensdehoorne May 16, 2026
bec36f2
Update __init__.py
laurensdehoorne May 16, 2026
334dd54
log errors
laurensdehoorne May 17, 2026
2baafda
Fix practical bugs in protocol handling, climate entity, and config flow
laurensdehoorne May 17, 2026
1b2231d
Merge pull request #1 from laurensdehoorne/fix/practical-bugs
laurensdehoorne May 17, 2026
908cfb4
Cleanup pass: remove dead code and fix target_temperature fallback
laurensdehoorne May 17, 2026
8842a65
Merge pull request #2 from laurensdehoorne/cleanup/dead-code
laurensdehoorne May 17, 2026
04882bc
docs: remove dead cloud-relay config and add cloud-retry troubleshooting
laurensdehoorne May 17, 2026
feea7c5
Merge pull request #3 from laurensdehoorne/docs/readme-cloud-cleanup
laurensdehoorne May 17, 2026
c02cbe4
Persist the auth session across calls
laurensdehoorne May 17, 2026
3ee5dd4
Merge pull request #4 from laurensdehoorne/refactor/persistent-session
laurensdehoorne May 17, 2026
569300a
Fix startup failure when pump is unreachable at HA boot
laurensdehoorne May 17, 2026
5713a51
Merge pull request #5 from laurensdehoorne/refactor/persistent-session
laurensdehoorne May 17, 2026
90eeb2e
Add 5-second follow-up refresh after each control command
laurensdehoorne May 17, 2026
f5a4c25
Merge pull request #6 from laurensdehoorne/refactor/persistent-session
laurensdehoorne May 17, 2026
c798e96
Fix follow-up refresh timer and silent zero-value responses
laurensdehoorne May 17, 2026
57c6cba
Re-auth on every call: pump session TTL < poll interval
laurensdehoorne May 17, 2026
cb73ee8
Revert "Re-auth on every call: pump session TTL < poll interval"
laurensdehoorne May 17, 2026
ed689c7
Merge pull request #7 from laurensdehoorne/refactor/persistent-session
laurensdehoorne May 17, 2026
1a926bc
Drain pump write-ACK in set_config to prevent query_all collision
laurensdehoorne May 17, 2026
b901ba9
Merge pull request #8 from laurensdehoorne/refactor/persistent-session
laurensdehoorne May 17, 2026
82a353b
Re-auth before every set_config; drop the immediate refresh
laurensdehoorne May 17, 2026
102aa1e
Merge pull request #9 from laurensdehoorne/refactor/persistent-session
laurensdehoorne May 17, 2026
aa9c497
Remove changelog from README
laurensdehoorne May 17, 2026
3298d66
Drop the session after each write to skip the post-write retry path
laurensdehoorne May 17, 2026
4063c9e
Merge pull request #10 from laurensdehoorne/refactor/persistent-session
laurensdehoorne May 17, 2026
a0fc3bd
Post-refactor cleanup: drop dead code, fix stale comments, cancel fol…
laurensdehoorne May 17, 2026
b6b3721
Merge pull request #11 from laurensdehoorne/cleanup/post-persistent-s…
laurensdehoorne May 17, 2026
8779dc6
Show Hot/Cold over as signed integers
laurensdehoorne May 17, 2026
2bd1388
Merge pull request #12 from laurensdehoorne/fix/cold-over-signed
laurensdehoorne May 17, 2026
0a5ed4c
Expose writeable settings from the official Android app
laurensdehoorne May 17, 2026
0e55163
Merge pull request #13 from laurensdehoorne/feature/writable-settings
laurensdehoorne May 17, 2026
60d1efb
docs: 1.1.0 changelog + README update for writeable settings
laurensdehoorne May 17, 2026
777e870
Merge pull request #14 from laurensdehoorne/docs/1.1.0
laurensdehoorne May 17, 2026
b8dfa71
Group entities into HA device-page categories
laurensdehoorne Jun 6, 2026
3530446
Merge pull request #15 from laurensdehoorne/feature/entity-categories
laurensdehoorne Jun 6, 2026
7d05e01
Add binary sensors + group all entities under one device
laurensdehoorne Jun 16, 2026
1581515
Merge pull request #16 from laurensdehoorne/feature/device-info-binar…
laurensdehoorne Jun 16, 2026
2e52ee1
docs: add fork comparison table to README
laurensdehoorne Jun 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Changelog

## [1.2.0] - 2026-06-16

### Added
- **`binary_sensor` platform** — three new binary sensors:
- **Frost protection** (`device_class: cold`) — on when the pump's anti-freeze protection (PP07) is active. Reads alarm register 50 bit `0x40`, matching this firmware's register layout.
- **Connectivity** (`device_class: connectivity`) — stays available to report `off` when the pump goes offline.
- **Alarm** (`device_class: problem`) — on when any alarm is active, with the decoded message in the `error_message` attribute.
- **Device registry grouping** — all entities (sensors, climate, numbers, switches, times, binary sensors) now attach to a single Alsavo Pro *device* via a shared `AlsavoProEntity` mixin, with manufacturer/model/serial and live HW/SW versions. Entity IDs and names are unchanged — entities just group under one device card.

## [1.1.0] - 2026-05-17

### Added
- **`number` platform** — five writeable installer settings, with min/max taken directly from the official Android app:
- Defrost in temperature (-30 … 0 °C)
- Defrost out temperature (2 … 30 °C)
- Defrost in time (30 … 90 min)
- Defrost out time (1 … 12 min)
- Water temperature compensation (-9.0 … 9.0 °C, step 0.1)
- **`switch` platform** — three boolean flags on config register 4:
- Timer on enabled
- Timer off enabled
- Pump continuous run (water circulation mode)
- **`time` platform** — daily timer schedule:
- Timer on time (HH:MM)
- Timer off time (HH:MM)
- HVAC modes are now device-type-aware: each Alsavo device type (FreqAll, Single, FixCh, FreqCh, FixAll) only exposes the modes its hardware supports
- 5-second follow-up refresh after every control command — UI reflects the settled pump state without waiting for the next 60 s poll

### Fixed
- **Set-target/mode/preset writes no longer silently dropped.** The pump only commits config writes on a freshly authenticated session; the persistent-session refactor briefly broke this by reusing a CSID/DSID across writes. Writes now always re-handshake; reads keep reusing the session.
- **`Cold over` sensor showed `65516` instead of `-20`.** The register is a signed 16-bit hysteresis offset but was being read as unsigned. Both `Hot over` and `Cold over` now use the signed interpretation.
- **First query after a write no longer wastes 2 s on a stale-packet retry.** The pump invalidates the session right after a config write; the integration now disconnects proactively so the follow-up read does a fast handshake instead of going through the bad-response → sleep → re-auth path.
- **Startup no longer fails permanently if the pump is briefly unreachable.** Up to 5 consecutive polling failures are tolerated before entities go unavailable.
- **Empty/truncated response packets no longer return zeros silently** — `query_all` now validates the response carries both a status and config section and raises `ConnectionError` otherwise.
- Pre-existing `_followup_cancel` `TypeError` on the second consecutive command (the handle was being called instead of `.cancel()`-ed).
- Follow-up refresh timer is now properly cancelled on config-entry unload, so reloading the integration mid-window no longer leaves a dangling timer firing against a torn-down coordinator.

### Changed
- Persistent UDP session across the 60 s poll interval (reads); fresh handshake per write. Reduces protocol overhead from ~56 ms per call to ~10 ms per call for reads.
- Dropped dead code: `AlsavoSocketCom.send_packet`, `AlsavoSocketCom.send`, `UDPClient.send`, `UDPClient.SimpleClientProtocol` — only the request/response path is used now.

## [1.0.5] - 2026-05-13

### Fixed
- Replaced deprecated `async_timeout` package with stdlib `asyncio.timeout` (HA 2024.x compatibility)
- Replaced deprecated `async_forward_entry_unload` (called twice) with `async_forward_entry_unloads` accepting a list
- Removed deprecated `CONNECTION_CLASS` from `ConfigFlow`
- Fixed `OptionsFlowHandler` constructor — HA no longer passes `config_entry`; moved `async_get_options_flow` as a `@staticmethod` inside `ConfigFlow`
- Fixed `MissingPasswordValue` exception being raised but never caught in `async_step_user`
- Replaced `asyncio.get_event_loop()` (deprecated in Python 3.10+) with `asyncio.get_running_loop()` in `UDPClient`
- Fixed absolute import `from custom_components.alsavopro.const import ...` to relative `from .const import ...`
- Renamed `async_add_devices` to `async_add_entities` in sensor setup
- Replaced bare `"°C"` strings with `UnitOfTemperature.CELSIUS` constant in sensor definitions
- Fixed log strings with double closing parentheses in `AlsavoPyCtrl`
- Removed unused imports (`CONF_PASSWORD`, `CONF_IP_ADDRESS`, `CONF_PORT`, `CONF_NAME`) from `climate.py`
- Fixed `manifest.json` version to match released version

## [1.0.4] - 2024

### Added
- Additional sensor entities (EEV opening, compressor speed, device status, min/max temperatures, manual settings)

## [1.0.3] - 2024

### Added
- Alarm code registers 48, 49, 50 with full error descriptions
- Error messages sensor aggregating all active alarm codes

## [1.0.2] - 2024

### Added
- Initial HACS release
- Climate entity with heat, cool, auto, and off modes
- Preset modes: Silent, Smart, Powerful
- Temperature sensors: water in, water out, ambient, cold pipe, heating pipe, IPM module, exhaust
- Config sensors: heating/cooling/auto target temperatures, power mode
- Compressor current, frequency, and fan speed sensors
238 changes: 231 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,252 @@

Custom component for controlling pool heatpumps that uses the Alsavo Pro app in Home Assistant.

**Warning:** This is made by someone with no previous knowledge of Python and no knowledge of Home Assistant framework. And one could argue that both is still the case. Use this at your own risk, and please take backups!
## Why this fork

If some adult with the proper knowledge could improve this, and maybe make it installable with HACS, please feel free to do so!
This fork builds on the original integration with substantially more control coverage and protocol robustness. Comparison against the upstream [`goev`](https://github.com/goev/AlsavoProHomeAssistantIntegration) fork:

| Capability | This fork | upstream `goev` |
|---|---|---|
| Writable settings | **10 entities** — heat/cool/auto target, defrost in/out temp + time, water compensation, pump-run mode, timer on/off times + enables | 2 — target temp, water calibration |
| `switch` platform | ✅ timer enables, pump continuous-run | ❌ |
| `time` platform | ✅ daily on/off schedule (HH:MM) | ❌ |
| UDP session | **Persistent across the 60 s poll** (~10 ms/read), fresh handshake per write | Full re-auth on every single call (~56 ms each) |
| Control reliability | Writes confirmed against a freshly-authenticated session; 5 s follow-up refresh reads the settled state | — |
| Device-type awareness | **HVAC modes filtered per device type** (Single/FixCh/FreqCh/FixAll/FreqAll) | Fixed mode list |
| `Cold over` reading | **Signed** (correctly shows negative offsets) | Unsigned (shows e.g. 65516 for −20) |
| Frost-protection sensor | Reads PP07 from alarm register 50 (this firmware's layout) | Reads register 49 |
| Robustness | Silent-zero/empty-packet detection, 5-failure offline tolerance, follow-up-timer cleanup on unload | — |
| Config flow | LAN-only (dead cloud-relay option removed) | Still offers the retired cloud endpoint |
| Settings tuning source | All ranges/encodings cross-checked against the official Android APK | — |

Both forks group entities under a single device (registry `DeviceInfo`) and split them into Sensors / Configuration / Diagnostic categories.

> Tradeoff for transparency: upstream uses Home Assistant's newer `has_entity_name` naming, while this fork keeps the original `alsavopro_<device>_<sensor>` entity-ID scheme to avoid renaming existing entities and breaking dashboards/automations on upgrade.

## Install
#### Manually
In Home Assistant, create a folder under *custom_components* named *AlsavoPro* and copy all the content of this project to that folder.
Restart Home Assistant and go to *Devices and Services* and press *+Add integration*.
Search for *AlsavoPro* and add it.
#### HACS Custom Repository
In HACS, add a custom repository and use https://github.com/goev/AlsavoProHomeAssistantIntegration
In HACS, add a custom repository and use https://github.com/laurensdehoorne/AlsavoProHomeAssistantIntegration
Download from HACS.
Restart Home Assistant and go to *Devices and Services* and press *+Add integration*.
Search for *AlsavoPro* and add it.

## Configuration
You must now choose a name for the device. The serial number for the heat pump can be found in the Alsavo Pro app by logging in to the heat pump and pressing the Alsavo Pro-logo in the upper right corner.
You must choose a name for the device. The serial number for the heat pump can be found in the Alsavo Pro app by logging in to the heat pump and pressing the Alsavo Pro-logo in the upper right corner.
Password is the same as the one you logged into the Alsavo Pro app with.

Ip-address and port can be one of two:
- If you want to use the cloud, set IP-address to 47.254.157.150 and port to 51192.
- If you want to bypass the cloud, enter the heat pumps ip-address and use port 1194.
For IP-address, enter the heat pump's local IP address on your network, and use port `1194`. The integration talks directly to the pump over UDP — no cloud connection is involved.

> **Note:** Earlier versions of this README documented a cloud-relay option using a public IP (`47.254.157.150:51192`). That cloud endpoint is no longer reachable (the GalaxyWind / Alsavo regional cloud servers appear to be retired for some regions), and the integration has always worked fine against the pump's LAN IP. The cloud option is no longer recommended or supported.

## Parameter setting
To access Alsavo Pro heat pump parameters, click "Parameter" in the app and enter password 0757. Key settings include water pump operating modes (P03), input calibration, temperature units, and system diagnostics. These settings allow control over water pump behavior (constant/compressor-dependent) and troubleshooting.

## Troubleshooting

### "Offline" in the app but works in HA
The official Alsavo Pro app routes everything through the GalaxyWind cloud (`*.ice.galaxywind.com`). This integration uses direct UDP on your LAN and doesn't need the cloud, so "offline in app, online in HA" is normal — and means local control is healthy.

### Intermittent HA timeouts or slow updates
If the pump can't reach its cloud server, its WiFi module enters a retry loop that can starve local UDP responses. The European/Australian/Brazilian dispatcher (`47.88.188.100`) currently doesn't respond, and that same IP is hardcoded as a fallback inside the pump firmware — so even DNS-blocking the hostname isn't enough on its own.

If you see slow or intermittent local responses, add a firewall rule on the IoT network that **REJECTs** (not drops) outbound traffic from the pump to:

- `47.88.188.100` (hardcoded EU/AU/BR fallback)
- `*.ice.galaxywind.com` if your firewall supports DNS-based rules

Use REJECT, not DROP — REJECT replies with "unreachable" immediately so the pump gives up fast, while DROP makes it hang on slow timeouts (same problem you're trying to solve). After applying the rule, power-cycle the pump so it discards its current retry state.

## Alarm codes

The integration exposes four alarm code sensors (`alarm_code_1` through `alarm_code_4`) that reflect the raw values of the pump's status registers. The `errors` attribute decodes all active alarms into human-readable messages.

### EE codes (Electrical/Component) — registers 48 & 49

| Code | Malfunction |
|------|-------------|
| EE01 | High pressure failure |
| EE02 | Low pressure failure |
| EE03 | Water flow failure |
| EE04 | Water temperature overheating protection (heating mode) |
| EE05 | Exhaust temperature too high |
| EE06 | Controller malfunction or communication failure |
| EE07 | Compressor current protection |
| EE08 | Communication failure (controller ↔ PCB) |
| EE09 | Communication failure (PCB ↔ driver board) |
| EE10 | VDC voltage too high protection |
| EE11 | IPM module protection |
| EE12 | VDC voltage too low protection |
| EE13 | Input current too strong protection |
| EE14 | IPM module thermal circuit abnormal |
| EE15 | IPM module temperature too high protection |
| EE16 | PFC module protection |
| EE17 | DC fan failure |
| EE18 | PFC module thermal circuit abnormal |
| EE19 | PFC module high temperature protection |
| EE20 | Input power failure |
| EE21 | Software control failure |
| EE22 | Current detection circuit failure |
| EE23 | Compressor start failure |
| EE24 | Ambient temperature sensor failure (driving board) |
| EE25 | Compressor phase failure |
| EE26 | 4-way valve reversal failure |
| EE27 | EEPROM data reading failure |
| EE28 | Inter-chip communication failure (main control board) |

### PP codes (Protection/Sensor) — register 50

| Code | Malfunction |
|------|-------------|
| PP01 | Inlet water temperature sensor failure |
| PP02 | Outlet water temperature sensor failure |
| PP03 | Heating coil pipe sensor failure |
| PP04 | Gas return sensor failure |
| PP05 | Ambient temperature sensor failure |
| PP06 | Exhaust temperature sensor failure |
| PP07 | Anti-freezing protection (winter) |
| PP08 | Low ambient temperature protection |
| PP10 | Coil pipe temperature too high protection (cooling mode) |
| PP11 | Water temperature (T2) too low protection (cooling mode) |

## Climate

The integration exposes a climate entity with the following HVAC modes:

| Mode | Description |
|------|-------------|
| Heat | Heating mode |
| Cool | Cooling mode |
| Auto | Automatic mode (heat or cool as needed) |
| Off | Power off |

The set of available modes is filtered per device type — single-mode units only show Heat, FixCh/FreqCh units show Heat + Cool, FreqAll/FixAll show all three plus Auto.

Preset modes control fan/compressor power: **Silent**, **Smart**, **Powerful**. Preset selection is only exposed for variable-frequency devices.

## Controls (writeable settings)

Beyond the climate entity, the integration also exposes installer-level settings that the official Android app lets you tune. After a setting is changed, the pump's new state is reflected in HA after ~5 seconds.

### Numbers

| Entity | Register | Range | Step |
|---|---|---|---|
| Defrost in temperature | 9 | -30 … 0 °C | 1 |
| Defrost out temperature | 10 | 2 … 30 °C | 1 |
| Defrost in time | 12 | 30 … 90 min | 1 |
| Defrost out time | 13 | 1 … 12 min | 1 |
| Water temperature compensation | 11 | -9.0 … 9.0 °C | 0.1 |

### Switches

| Entity | Register | Notes |
|---|---|---|
| Timer on enabled | config_sys1 bit 2 | Enables the scheduled daily power-on at *Timer on time* |
| Timer off enabled | config_sys1 bit 7 | Enables the scheduled daily power-off at *Timer off time* |
| Pump continuous run | config_sys1 bit 3 | Water circulation pump runs continuously (vs. cycling with the compressor) |

### Times

| Entity | Register | Encoding |
|---|---|---|
| Timer on time | 33 | HH:MM picker (stored as `hour << 8 \| minute`) |
| Timer off time | 34 | same |

### Tuning for winter operation

If you keep the heat pump running through winter, the factory defrost defaults often aren't aggressive enough — ice can build up faster than the cycle clears it. Reasonable starting points for Northwest-European climate (-5 … +5 °C ambient):

| Setting | Default | Winter |
|---|---|---|
| Defrost in temp | -7 °C | **-5 °C** (trigger sooner) |
| Defrost in time | 40 min | **30 min** (react faster) |
| Defrost out temp | 20 °C | **13 °C** (don't overheat the coil) |
| Defrost out time | 12 min | **8 min** |
| Pump continuous run | off | **on** (water keeps circulating through the heat exchanger between cycles) |

Below ~-7 °C ambient the air-source COP collapses; no defrost setting can compensate, and the practical answer is to winterize the pool and drain the heat exchanger.

## Sensors

### Temperature sensors

| Sensor | Description |
|--------|-------------|
| Water In | Inlet water temperature |
| Water Out | Outlet water temperature |
| Ambient | Ambient air temperature |
| Cold pipe | Cold pipe temperature |
| Heating pipe | Heating pipe temperature |
| IPM module | IPM module temperature |
| Exhaust temperature | Exhaust temperature |
| Compressor input temperature | Compressor input temperature |
| Heating max temperature | Maximum allowed heating setpoint |
| Cooling min temperature | Minimum allowed cooling setpoint |
| Defrost in temperature | Temperature threshold to start defrost |
| Defrost out temperature | Heating pipe temperature to end defrost |
| Water temperature calibration | Offset applied to all temperature readings |
| Heating mode target | Heating setpoint |
| Cooling mode target | Cooling setpoint |
| Auto mode target | Auto mode setpoint |

### Operational sensors

| Sensor | Description |
|--------|-------------|
| Fan speed | Fan speed in RPM |
| Compressor | Compressor current (A) |
| Compressor running frequency | Compressor frequency (Hz) |
| Compressor speed setting | 0=off, 1=P1 40Hz … 5=P5 82Hz |
| EEV opening | Electronic exhaust valve opening (0–450) |
| Frequency limit code | Active frequency limit code |
| System status code | System status code |
| System running code | 3=heating, 2=defrost |
| Device status code | Device status code |

### Config/diagnostic sensors

| Sensor | Description |
|--------|-------------|
| Power mode | 0=Silent, 1=Smart, 2=Powerful |
| Manual frequency setting | Manual compressor frequency (debug mode) |
| Manual EEV setting | Manual EEV setting (debug mode) |
| Manual fan speed setting | Manual fan speed (debug mode) |
| Defrost in time | Minimum time between defrost cycles (minutes) |
| Defrost out time | Maximum defrost duration (minutes) |
| Hot over | High-temperature hysteresis offset (signed) |
| Cold over | Low-temperature hysteresis offset (signed, can be negative) |
| Current time | Device clock (hi byte=hours, lo byte=minutes) |
| Timer on time | Scheduled power-on time |
| Timer off time | Scheduled power-off time |
| Device type | Device type code |
| Main board HW revision | Hardware revision |
| Main board SW revision | Software revision |
| Manual HW code | Manual hardware code |
| Manual SW code | Manual software code |

### Alarm sensors

| Sensor | Description |
|--------|-------------|
| Alarm code 1–4 | Raw alarm register values (registers 48–51) |
| Error messages | Decoded human-readable alarm messages |

## Binary sensors

| Sensor | Device class | Description |
|--------|--------------|-------------|
| Frost protection | cold | On when the pump's anti-freeze protection (PP07, register 50 bit `0x40`) is active. Useful as an automation trigger in winter. |
| Connectivity | connectivity | On while the pump answers on the LAN; reports off when it goes offline (stays available so you can alert on it). |
| Alarm | problem | On when any alarm is active; the decoded text is in the `error_message` attribute. |

## Device grouping

All entities are attached to a single **Alsavo Pro** device in the registry, so they appear together under one device card (Settings → Devices & Services → *device*), split into Sensors / Configuration / Diagnostic sections. The device exposes the pump's manufacturer, model, serial number, and live hardware/software revisions.


## AlsavoCtrl
This code is very much based on AlsavoCtrl: https://github.com/strandborg/AlsavoCtrl
Loading