From c8d1e968d753dee352afad12ac7e335815fee668 Mon Sep 17 00:00:00 2001 From: Constantin Pascal Date: Mon, 9 Feb 2026 11:17:37 +0200 Subject: [PATCH] more automation included --- excess_pv_boiler/CLAUDE.md | 195 +++++++ excess_pv_boiler/README.md | 258 +++++++++ excess_pv_boiler/use_excess_pv_in_boiler.yaml | 520 ++++++++++++++++++ 3 files changed, 973 insertions(+) create mode 100644 excess_pv_boiler/CLAUDE.md create mode 100644 excess_pv_boiler/README.md create mode 100644 excess_pv_boiler/use_excess_pv_in_boiler.yaml diff --git a/excess_pv_boiler/CLAUDE.md b/excess_pv_boiler/CLAUDE.md new file mode 100644 index 0000000..9ba5d78 --- /dev/null +++ b/excess_pv_boiler/CLAUDE.md @@ -0,0 +1,195 @@ +# CLAUDE.md - Development Context for Excess PV Boiler Control + +## Project Purpose + +This Home Assistant package controls an auxiliary electric heater installed in a DHW (Domestic Hot Water) boiler. It works alongside a heat pump to provide: +- **Preset-based temperature control** with user-adjustable temperatures per preset +- **PV excess utilization** to use surplus solar power instead of exporting +- **Bath boost** with configurable timer for rapid hot water +- **Manual override** for emergency/testing scenarios + +## Architecture + +``` +[Solar Inverter] --> sensor.deye_12_external_ct*_power (3-phase grid power) + | + [binary_sensor.dhw_pv_power_enough_for_aux_heater] + | + [automation: DHW Manage PV Thermostat] + | + [climate.dhw_pv_excess_heating] (shadow thermostat) + | + [binary_sensor.dhw_use_boiler_aux_heater] <-- [manual override] + | <-- [boost modes] + [automation: DHW Boiler Heater Relay] + | + [switch.boiler_heater_relay_switch_0] (physical relay) + +[input_select.dhw_boiler_preset] --> [automation: DHW Boiler Preset Manager] +[input_number.dhw_boiler_temp_*] | + v + [climate.boiler_temperature] (main thermostat) + +[script.dhw_start_bath_boost] --> [timer.bath_time] --> [automation: DHW Bath Time] +[input_number.dhw_bath_boost_duration] | + v + [input_boolean.dhw_bath_boost] + [switch.acm_pump_switch] +``` + +## Key Entities + +### Input Booleans (Modes/Toggles) +| Entity | Purpose | +|--------|---------| +| `input_boolean.dhw_aux_heater_manual_override` | Force heater ON regardless of conditions | +| `input_boolean.dhw_allow_aux_heater_usage` | Master enable for aux heater | +| `input_boolean.dhw_use_excess_pv_for_aux_heater` | Enable PV excess mode | +| `input_boolean.dhw_allow_aux_heater_in_all_modes` | Allow boost in normal thermostat mode | +| `input_boolean.boiler_pv_dummy_heater` | Virtual switch for shadow thermostat | +| `input_boolean.dhw_bath_boost` | Bath boost active flag (managed by automations) | + +### Input Select (Presets) +| Entity | Purpose | +|--------|---------| +| `input_select.dhw_boiler_preset` | Active boiler preset: Normal, Eco, Boost, Sleep, Away, Off | + +### Timer +| Entity | Purpose | +|--------|---------| +| `timer.bath_time` | Countdown timer for bath boost duration | + +### Input Numbers (Thresholds) +| Entity | Purpose | Range | +|--------|---------|-------| +| `input_number.dhw_aux_heater_cut_off_temperature_threshold` | Max temp before heater stops | 50-85°C | +| `input_number.dhw_aux_heater_temperature_threshold` | Hysteresis threshold | 1-15°C | +| `input_number.dhw_pv_target_temperature` | Target temp for PV heating | 40-70°C | +| `input_number.dhw_pv_excess_usage_buffer` | Buffer power before triggering | 0-1000W | +| `input_number.dhw_aux_heater_power` | Heater power rating | 500-9000W | +| `input_number.dhw_pv_excess_usage_start_delay` | Delay before starting PV mode | 1-300s | +| `input_number.dhw_pv_excess_usage_stop_delay` | Delay before stopping PV mode | 1-300s | + +### Input Numbers (Preset Temperatures) +| Entity | Purpose | Range | +|--------|---------|-------| +| `input_number.dhw_boiler_temp_normal` | Normal preset target temperature | 30-65°C | +| `input_number.dhw_boiler_temp_eco` | Eco preset target temperature | 30-60°C | +| `input_number.dhw_boiler_temp_boost` | Boost preset target temperature | 40-70°C | +| `input_number.dhw_boiler_temp_sleep` | Sleep preset target temperature | 25-55°C | +| `input_number.dhw_boiler_temp_away` | Away preset target temperature | 20-50°C | +| `input_number.dhw_bath_boost_duration` | Duration for bath boost timer | 5-120 min | + +### Scripts +| Entity | Purpose | +|--------|---------| +| `script.dhw_start_bath_boost` | Starts `timer.bath_time` with duration from `dhw_bath_boost_duration` | + +### Climate (Generic Thermostats) +| Entity | Purpose | +|--------|---------| +| `climate.dhw_pv_excess_heating` | Shadow thermostat for PV excess mode | +| `climate.boiler_temperature` | Main boiler thermostat (target set by preset manager) | + +### Automations +| Entity | Purpose | +|--------|---------| +| `DHW Boiler Heater Relay Automation` | Switches physical relay based on decision sensor | +| `DHW Manage PV Thermostat` | Controls shadow thermostat based on PV availability | +| `DHW Boiler Preset Manager` | Syncs preset selection + temperatures to thermostat, toggles bath boost | +| `DHW Bath Time` | Manages bath boost lifecycle: pump + boost on/off with timer | + +### External Entities (Not Defined in Package) +These must exist in your HA instance from other integrations or manual UI setup: + +| Entity | Source | Purpose | Fallback if Unavailable | +|--------|--------|---------|------------------------| +| `sensor.boiler_temp` | Heat pump / temperature probe | Boiler water temperature | 100 (prevents running) | +| `sensor.deye_12_external_ct1_power` | Deye inverter integration | Phase 1 grid power (negative = export) | 0 | +| `sensor.deye_12_external_ct2_power` | Deye inverter integration | Phase 2 grid power | 0 | +| `sensor.deye_12_external_ct3_power` | Deye inverter integration | Phase 3 grid power | 0 | +| `sensor.heat_pump_auxiliary_heater` | Heat pump integration | HP aux heater state | treated as 'off' | +| `switch.boiler_heater_relay_switch_0` | Relay device (Shelly, etc.) | Physical heater control | N/A | +| `switch.acm_pump_switch` | Pump relay/smart plug | DHW circulation pump | N/A | +| `switch.schedule_f403a3` | Scheduler integration | Pump schedule to restore after boost | N/A | + +## Decision Logic + +### binary_sensor.dhw_use_boiler_aux_heater +This is the main decision sensor. It turns ON when: +1. **Manual override** is ON, OR +2. **All conditions met**: + - Heat pump aux heater is OFF + - Boiler aux usage is allowed + - Boiler temp is below cut-off threshold + - AND one of: + - PV excess mode active AND shadow thermostat is heating + - Bath boost active AND main thermostat is heating + - All-modes boost enabled AND main thermostat is heating + +### binary_sensor.dhw_pv_power_enough_for_aux_heater +Determines if there's enough solar export to run the heater: +- **When heater is OFF**: All 3 phases must export > (buffer + heater_power) / 3 +- **When heater is ON**: All 3 phases must still be exporting (<=0W import) + +### Preset Manager Flow +1. User selects preset from `input_select.dhw_boiler_preset` +2. Automation reads corresponding `input_number.dhw_boiler_temp_` value +3. Sets `climate.boiler_temperature` to that target + heat mode (or off for "Off" preset) +4. Toggles `input_boolean.dhw_bath_boost` on/off based on whether Boost is selected +5. If user changes a preset temperature input_number, automation re-applies current preset + +### Bath Boost Flow +1. User calls `script.dhw_start_bath_boost` (e.g., from a dashboard button) +2. Script starts `timer.bath_time` with duration from `input_number.dhw_bath_boost_duration` +3. `DHW Bath Time` automation detects timer active: turns on pump + bath boost +4. Timer finishes: automation restores pump schedule + turns off boost + +## Common Modifications + +### Changing Preset Temperatures +Adjust via dashboard sliders at runtime (no YAML edit needed). +The `input_number.dhw_boiler_temp_*` entities store each preset's temperature. + +### Adding New Presets +1. Add option to `input_select.dhw_boiler_preset` +2. Add corresponding `input_number.dhw_boiler_temp_` (name must be lowercase match) +3. The preset manager automation uses dynamic entity resolution, so no automation changes needed + +### Changing Power Thresholds +Adjust via dashboard at runtime: +- `dhw_pv_excess_usage_buffer`: Increase for more conservative PV triggering +- `dhw_aux_heater_power`: Match to actual heater rating + +### Adjusting Timing +Adjust via dashboard at runtime: +- `dhw_pv_excess_usage_start_delay`: Increase to avoid rapid cycling +- `dhw_pv_excess_usage_stop_delay`: Increase to ride through clouds +- `dhw_bath_boost_duration`: Duration of bath boost timer + +### Adding New Heating Modes +Edit template section, add new condition in `binary_sensor.dhw_use_boiler_aux_heater` alongside `pv_excess`, `thermostat_activity_boost`, etc. + +## Testing/Validation + +1. **YAML Syntax**: Run `yamllint *.yaml` or use HA's configuration check +2. **Entity References**: Ensure all `states()` calls reference defined entities +3. **Default Fallbacks**: Verify all `float()` filters have appropriate defaults: + - Temperature sensors: `float(100)` (fail-safe: heater OFF) + - Power sensors: `float(0)` (fail-safe: no export detected) + - Input numbers: `float()` + +## File Structure + +| File | Purpose | +|------|---------| +| `use_excess_pv_in_boiler.yaml` | **Main package file** - install this in HA packages directory | +| `CLAUDE.md` | Development context for AI assistants | +| `README.md` | User-facing documentation | + +## Safety Considerations + +1. **Never run both heaters**: Template checks `sensor.heat_pump_auxiliary_heater != 'on'` +2. **Temperature cut-off**: Hard limit prevents overheating +3. **Unavailable sensors**: Default to safe values (temp=100, power=0) +4. **Manual override**: Bypasses all checks - use with caution +5. **Bath boost timer**: Auto-disables boost when timer expires \ No newline at end of file diff --git a/excess_pv_boiler/README.md b/excess_pv_boiler/README.md new file mode 100644 index 0000000..2b9b22a --- /dev/null +++ b/excess_pv_boiler/README.md @@ -0,0 +1,258 @@ +# Excess PV Boiler Auxiliary Heater Control + +Home Assistant package for controlling an auxiliary electric heater in a DHW (Domestic Hot Water) boiler, designed to work alongside a heat pump system. + +## Features + +- **Preset-based temperature control**: Normal, Eco, Boost, Sleep, Away, Off - with user-adjustable temperatures per preset via dashboard sliders +- **PV Excess Utilization**: Automatically uses surplus solar power to heat water instead of exporting to grid +- **Bath Boost with Timer**: Timed rapid hot water heating with configurable duration +- **Manual Override**: Emergency/testing control +- **Safety Interlocks**: Prevents running both heat pump and boiler auxiliary heaters simultaneously +- **Energy Tracking**: Runtime and energy consumption stats split by PV vs grid + +## System Architecture + +``` + SOLAR INVERTER + | + sensor.deye_12_external_ct1/2/3_power + (3-phase grid power monitoring) + | + v + binary_sensor.dhw_pv_power_enough_for_aux_heater + Checks: All 3 phases exporting enough? + | + v + automation: DHW Manage PV Thermostat + (with configurable start/stop delays) + | + v + climate.dhw_pv_excess_heating + (shadow thermostat for PV mode) + | + v + binary_sensor.dhw_use_boiler_aux_heater + MAIN DECISION: manual OR (allowed AND + (pv_excess OR bath_boost OR normal_boost)) + | + v + automation: DHW Boiler Heater Relay + | + v + switch.boiler_heater_relay_switch_0 + (PHYSICAL RELAY - heater element) + + + PRESET SYSTEM BATH BOOST + -------------- ---------- + input_select --> Preset script.dhw_start_bath_boost + dhw_boiler_preset Manager | + input_number --> | timer.bath_time + dhw_boiler_temp_* | | + v v + climate.boiler_temperature DHW Bath Time automation + (main thermostat) (pump + boost on/off) +``` + +## Installation + +1. Copy `use_excess_pv_in_boiler.yaml` to your Home Assistant `packages` directory +2. Enable packages in `configuration.yaml`: + ```yaml + homeassistant: + packages: !include_dir_named packages + ``` +3. Ensure all external entities exist (see [External Dependencies](#external-dependencies)) +4. Restart Home Assistant +5. Configure preset temperatures and thresholds via the UI + +## External Dependencies + +These entities must already exist in your Home Assistant instance from other integrations or devices. They are **not** created by this package. + +### Sensors (from device integrations) + +| Entity | Source | Purpose | +|--------|--------|---------| +| `sensor.boiler_temp` | Heat pump / temperature probe | Boiler water temperature | +| `sensor.deye_12_external_ct1_power` | Deye inverter integration | Phase 1 grid power (negative = export) | +| `sensor.deye_12_external_ct2_power` | Deye inverter integration | Phase 2 grid power | +| `sensor.deye_12_external_ct3_power` | Deye inverter integration | Phase 3 grid power | +| `sensor.heat_pump_auxiliary_heater` | Heat pump integration | HP aux heater state (interlock) | + +### Switches (from device integrations) + +| Entity | Source | Purpose | +|--------|--------|---------| +| `switch.boiler_heater_relay_switch_0` | Relay device (Shelly, etc.) | Physical heater control | +| `switch.acm_pump_switch` | Pump relay / smart plug | DHW circulation pump (used by bath boost) | + +### Scheduler (optional integration) + +| Entity | Source | Purpose | +|--------|--------|---------| +| `switch.schedule_f403a3` | Scheduler integration | Pump schedule restored after bath boost ends | + +> **Note**: If you don't use the Scheduler integration, remove the `scheduler.run_action` call from the DHW Bath Time automation. + +## Configuration + +### Boiler Temperature Presets + +The preset system uses an `input_select` for mode selection and `input_number` entities for each preset's temperature. Users can adjust all temperatures from the dashboard without editing YAML. + +| Preset | Entity | Range | Intended Use | +|--------|--------|-------|-------------| +| **Normal** | `input_number.dhw_boiler_temp_normal` | 30-65°C | Everyday hot water | +| **Eco** | `input_number.dhw_boiler_temp_eco` | 30-60°C | Energy saving mode | +| **Boost** | `input_number.dhw_boiler_temp_boost` | 40-70°C | Rapid heating (also enables aux heater) | +| **Sleep** | `input_number.dhw_boiler_temp_sleep` | 25-55°C | Nighttime lower temperature | +| **Away** | `input_number.dhw_boiler_temp_away` | 20-50°C | Away from home | +| **Off** | — | — | Turns off the boiler thermostat | + +Selecting **Boost** also enables `input_boolean.dhw_bath_boost`, which allows the auxiliary heater to run (through the decision logic). All other presets disable it. + +### Bath Boost Timer + +| Entity | Purpose | Range | +|--------|---------|-------| +| `input_number.dhw_bath_boost_duration` | Timer duration | 5-120 min (step: 5) | +| `script.dhw_start_bath_boost` | Call to start the boost timer | — | +| `timer.bath_time` | Active countdown (shows remaining time) | — | + +**How it works**: Call `script.dhw_start_bath_boost` from a dashboard button. The timer starts, the automation turns on the circulation pump (`switch.acm_pump_switch`) and enables bath boost. When the timer expires, both are turned off and the pump schedule is restored. + +### Mode Toggles + +| Entity | Description | +|--------|-------------| +| `input_boolean.dhw_aux_heater_manual_override` | Forces heater ON regardless of all other conditions | +| `input_boolean.dhw_allow_aux_heater_usage` | Master enable switch. Must be ON for any automatic operation | +| `input_boolean.dhw_use_excess_pv_for_aux_heater` | Enables PV excess utilization mode | +| `input_boolean.dhw_allow_aux_heater_in_all_modes` | Aux heater runs whenever main thermostat calls for heat (any preset) | + +### PV Excess Thresholds + +| Entity | Description | Range | +|--------|-------------|-------| +| `input_number.dhw_aux_heater_cut_off_temperature_threshold` | Maximum temperature before heater stops | 50-85°C | +| `input_number.dhw_pv_target_temperature` | Target temperature when using PV excess | 40-70°C | +| `input_number.dhw_pv_excess_usage_buffer` | Extra export power required as safety margin | 0-1000W | +| `input_number.dhw_aux_heater_power` | Rated power of your heater element | 500-9000W | +| `input_number.dhw_pv_excess_usage_start_delay` | Seconds of stable export before starting | 1-300s | +| `input_number.dhw_pv_excess_usage_stop_delay` | Seconds of insufficient export before stopping | 1-300s | + +## Usage Modes + +### 1. Preset-Based Heating + +Select a preset from `input_select.dhw_boiler_preset`. The thermostat target temperature is set automatically from the corresponding `input_number`. Adjust temperatures anytime via dashboard sliders. + +### 2. PV Excess Mode + +Automatically heats water when solar production exceeds consumption. + +**Enable**: Turn ON `input_boolean.dhw_use_excess_pv_for_aux_heater` + +**Behavior**: +- Monitors 3-phase grid power (CT sensors) +- Waits for `start_delay` seconds of sufficient export +- Heats to `dhw_pv_target_temperature` +- Stops after `stop_delay` seconds of insufficient export + +### 3. Bath Boost (Timed) + +Rapid heating with automatic timeout. + +**Trigger**: Call `script.dhw_start_bath_boost` (e.g., from a dashboard button) + +**Behavior**: +- Starts timer for configured duration +- Turns on circulation pump +- Enables aux heater boost +- Auto-disables everything when timer expires +- Restores pump schedule + +### 4. Normal Boost Mode + +Aux heater supplements heat pump during any thermostat heating call. + +**Enable**: Turn ON `input_boolean.dhw_allow_aux_heater_in_all_modes` + +### 5. Manual Override + +Direct control for testing or emergencies. + +**Enable**: Turn ON `input_boolean.dhw_aux_heater_manual_override` + +**Warning**: Bypasses all safety checks except physical relay. Use with caution. + +## Energy Tracking + +The package includes sensors for monitoring heater usage: + +| Sensor | Purpose | +|--------|---------| +| `sensor.boiler_resistance_power` | Current power draw (0 or rated power) | +| `sensor.boiler_resistance_pv_power` | Power when running on PV excess | +| `sensor.boiler_resistance_grid_power` | Power when running on grid | +| `sensor.boiler_resistance_total_energy` | Cumulative total energy (kWh) | +| `sensor.boiler_resistance_pv_energy` | Cumulative PV energy (kWh) | +| `sensor.boiler_resistance_grid_energy` | Cumulative grid energy (kWh) | + +Runtime utility meters are provided with daily, weekly, and monthly cycles for both PV and grid usage. + +## Troubleshooting + +### Heater not turning on + +1. Check `binary_sensor.dhw_use_boiler_aux_heater` state in Developer Tools +2. Verify `input_boolean.dhw_allow_aux_heater_usage` is ON +3. Check `sensor.heat_pump_auxiliary_heater` is not ON (interlock) +4. Verify `sensor.boiler_temp` is below cut-off threshold +5. Check automation trace in Automations panel + +### PV mode not activating + +1. Check `binary_sensor.dhw_pv_power_enough_for_aux_heater` state +2. Verify all CT sensors show negative values (export) +3. Check if export exceeds `(buffer + heater_power) / 3` per phase +4. Wait for `start_delay` seconds + +### Preset not applying + +1. Verify `input_select.dhw_boiler_preset` has the expected value +2. Check that the corresponding `input_number.dhw_boiler_temp_*` entity exists and has a value +3. Check `DHW Boiler Preset Manager` automation trace + +### Heater cycling rapidly + +1. Increase `dhw_pv_excess_usage_stop_delay` to ride through clouds +2. Increase `dhw_pv_excess_usage_buffer` for more margin +3. Check thermostat tolerance settings + +### Sensor unavailable errors + +The templates include safe defaults: +- Temperature sensors default to 100°C (heater stays OFF) +- Power sensors default to 0W (no export detected) + +## File Structure + +``` +excess_pv_boiler/ +├── use_excess_pv_in_boiler.yaml # Main package file (install this) +├── CLAUDE.md # Development context for AI assistants +└── README.md # This file +``` + +## Related Documentation + +- [Home Assistant Generic Thermostat](https://www.home-assistant.io/integrations/generic_thermostat/) +- [Home Assistant Packages](https://www.home-assistant.io/docs/configuration/packages/) +- [Home Assistant Automations](https://www.home-assistant.io/docs/automation/) +- [Home Assistant Scripts](https://www.home-assistant.io/integrations/script/) +- [Home Assistant Timer](https://www.home-assistant.io/integrations/timer/) +- [Input Select](https://www.home-assistant.io/integrations/input_select/) +- [Input Number](https://www.home-assistant.io/integrations/input_number/) \ No newline at end of file diff --git a/excess_pv_boiler/use_excess_pv_in_boiler.yaml b/excess_pv_boiler/use_excess_pv_in_boiler.yaml new file mode 100644 index 0000000..6608e1c --- /dev/null +++ b/excess_pv_boiler/use_excess_pv_in_boiler.yaml @@ -0,0 +1,520 @@ +# Excess PV Boiler Auxiliary Heater Control Package +# See README.md for documentation + +input_boolean: + dhw_aux_heater_manual_override: + name: "DHW Aux Heater Manual Override" + icon: mdi:water-boiler + + dhw_allow_aux_heater_usage: + name: "DHW Allow Aux Heater Usage" + icon: mdi:check-circle + + dhw_use_excess_pv_for_aux_heater: + name: "DHW Use Excess PV for Aux Heater" + icon: mdi:solar-power + + dhw_allow_aux_heater_in_all_modes: + name: "DHW Allow Aux Heater in All Modes" + icon: mdi:thermostat + + # Dummy switch for shadow thermostat + boiler_pv_dummy_heater: + name: "Boiler PV Dummy Heater" + icon: mdi:flash + + dhw_bath_boost: + name: "DHW Bath Boost" + icon: mdi:bath + +input_select: + dhw_boiler_preset: + name: "DHW Boiler Preset" + icon: mdi:thermostat + options: + - "Normal" + - "Eco" + - "Boost" + - "Sleep" + - "Away" + - "Off" + initial: "Normal" + +timer: + bath_time: + name: "Bath Time" + icon: mdi:timer-outline + +input_number: + dhw_aux_heater_cut_off_temperature_threshold: + name: "DHW Aux Heater Cut-off Temperature Threshold" + min: 50 + max: 85 + step: 1 + unit_of_measurement: "°C" + icon: mdi:thermometer-high + + dhw_aux_heater_temperature_threshold: + name: "DHW Aux Heater Temperature Threshold" + min: 1 + max: 15 + step: 0.5 + unit_of_measurement: "°C" + icon: mdi:thermometer-lines + + dhw_pv_target_temperature: + name: "DHW PV Target Temperature" + min: 40 + max: 70 + step: 1 + unit_of_measurement: "°C" + icon: mdi:solar-power + + dhw_pv_excess_usage_buffer: + name: "DHW PV Excess Usage Buffer" + min: 0 + max: 1000 + step: 50 + unit_of_measurement: "W" + icon: mdi:buffer + + dhw_aux_heater_power: + name: "DHW Aux Heater Power" + min: 500 + max: 9000 + step: 100 + unit_of_measurement: "W" + icon: mdi:lightning-bolt + + dhw_pv_excess_usage_start_delay: + name: "DHW PV Excess Start Delay" + min: 1 + max: 300 + step: 1 + unit_of_measurement: "s" + icon: mdi:timer-play + + dhw_pv_excess_usage_stop_delay: + name: "DHW PV Excess Stop Delay" + min: 1 + max: 300 + step: 1 + unit_of_measurement: "s" + icon: mdi:timer-stop + + dhw_boiler_temp_normal: + name: "DHW Boiler Normal Temperature" + min: 30 + max: 65 + step: 1 + unit_of_measurement: "°C" + icon: mdi:thermometer + + dhw_boiler_temp_eco: + name: "DHW Boiler Eco Temperature" + min: 30 + max: 60 + step: 1 + unit_of_measurement: "°C" + icon: mdi:leaf + + dhw_boiler_temp_boost: + name: "DHW Boiler Boost Temperature" + min: 40 + max: 70 + step: 1 + unit_of_measurement: "°C" + icon: mdi:flash + + dhw_boiler_temp_sleep: + name: "DHW Boiler Sleep Temperature" + min: 25 + max: 55 + step: 1 + unit_of_measurement: "°C" + icon: mdi:sleep + + dhw_boiler_temp_away: + name: "DHW Boiler Away Temperature" + min: 20 + max: 50 + step: 1 + unit_of_measurement: "°C" + icon: mdi:home-export-outline + + dhw_bath_boost_duration: + name: "DHW Bath Boost Duration" + min: 5 + max: 120 + step: 5 + unit_of_measurement: "min" + icon: mdi:timer-sand + +climate: + - platform: generic_thermostat + name: "DHW PV Excess Heating" + heater: input_boolean.boiler_pv_dummy_heater + target_sensor: sensor.boiler_temp + min_temp: 10 + max_temp: 70 + cold_tolerance: 1 + hot_tolerance: 0.5 + min_cycle_duration: + minutes: 2 + initial_hvac_mode: "off" + precision: 0.1 + + - platform: generic_thermostat + name: "Boiler Temperature" + heater: input_boolean.boiler_pv_dummy_heater + target_sensor: sensor.boiler_temp + min_temp: 10 + max_temp: 70 + cold_tolerance: 4.0 + hot_tolerance: 0 + min_cycle_duration: + minutes: 2 + +template: + - binary_sensor: + - name: "DHW: Use Boiler Aux Heater" + unique_id: "dhw_config_use_boiler_aux_heater" + state: > + {% set manual_on = states('input_boolean.dhw_aux_heater_manual_override') == 'on' %} + {% set hp_aux_state = states('sensor.heat_pump_auxiliary_heater') %} + {% set hp_aux_off = hp_aux_state in ['off', 'unavailable', 'unknown'] or hp_aux_state != 'on' %} + {% set boiler_aux_allowed = states('input_boolean.dhw_allow_aux_heater_usage') == 'on' %} + {% set boiler_temp = states('sensor.boiler_temp') | float(100) %} + {% set cut_off_temp = states('input_number.dhw_aux_heater_cut_off_temperature_threshold') | float(60) %} + {% set boiler_temp_ok = boiler_temp < cut_off_temp %} + {# allowed checks if the resistance is permitted to run, mostly to check we're not running both boiler and HP resistance at the same time #} + {% set allowed = hp_aux_off and boiler_aux_allowed and boiler_temp_ok %} + {# here go various other conditions that influence the decision to run the boiler auxiliary heater #} + {# PV Excess to boiler - now using shadow thermostat #} + {% set pv_excess = states('input_boolean.dhw_use_excess_pv_for_aux_heater') == 'on' and + state_attr('climate.dhw_pv_excess_heating', 'hvac_action') == 'heating' %} + {% set thermostat_activity_boost = states('input_boolean.dhw_bath_boost') == 'on' and + state_attr('climate.boiler_temperature','hvac_action') == 'heating'%} + {% set thermostat_normal_boost = states('input_boolean.dhw_allow_aux_heater_in_all_modes') == 'on' and + state_attr('climate.boiler_temperature','hvac_action') == 'heating'%} + {{ manual_on or + (allowed and ( + pv_excess or + thermostat_activity_boost or + thermostat_normal_boost + )) }} + + - name: "DHW: PV Power Enough for Aux Heater" + unique_id: "dhw_pv_power_enough_for_aux_heater" + state: > + {% set phase_buffer = states('input_number.dhw_pv_excess_usage_buffer') | float(200) / 3 %} + {% set phase_heater_power = states('input_number.dhw_aux_heater_power') | float(3000) / 3 %} + {% set turn_on_threshold = -1 * (phase_buffer + phase_heater_power) %} + {% set ct1_power = states('sensor.deye_12_external_ct1_power') | float(0) %} + {% set ct2_power = states('sensor.deye_12_external_ct2_power') | float(0) %} + {% set ct3_power = states('sensor.deye_12_external_ct3_power') | float(0) %} + {% if is_state('switch.boiler_heater_relay_switch_0', 'on') %} + {{ ct1_power <= 0 and ct2_power <= 0 and ct3_power <= 0 }} + {% else %} + {{ ct1_power < turn_on_threshold and ct2_power < turn_on_threshold and ct3_power < turn_on_threshold }} + {% endif %} + device_class: power + + - name: "DHW: Aux Heater Running on PV" + unique_id: "dhw_aux_heater_running_on_pv" + state: > + {{ is_state('switch.boiler_heater_relay_switch_0', 'on') and + is_state('binary_sensor.dhw_pv_power_enough_for_aux_heater', 'on') }} + + - name: "DHW: Aux Heater Running on Grid" + unique_id: "dhw_aux_heater_running_on_grid" + state: > + {{ is_state('switch.boiler_heater_relay_switch_0', 'on') and + is_state('binary_sensor.dhw_pv_power_enough_for_aux_heater', 'off') }} + + - sensor: + - name: "Boiler Resistance Power" + unique_id: "boiler_resistance_power" + unit_of_measurement: "W" + device_class: power + state_class: measurement + state: > + {% if is_state('switch.boiler_heater_relay_switch_0', 'on') %} + {{ states('input_number.dhw_aux_heater_power') | float(0) }} + {% else %} + 0 + {% endif %} + + - name: "Boiler Resistance PV Power" + unique_id: "boiler_resistance_pv_power" + unit_of_measurement: "W" + device_class: power + state_class: measurement + state: > + {% if is_state('binary_sensor.dhw_aux_heater_running_on_pv', 'on') %} + {{ states('input_number.dhw_aux_heater_power') | float(0) }} + {% else %} + 0 + {% endif %} + + - name: "Boiler Resistance Grid Power" + unique_id: "boiler_resistance_grid_power" + unit_of_measurement: "W" + device_class: power + state_class: measurement + state: > + {% if is_state('binary_sensor.dhw_aux_heater_running_on_grid', 'on') %} + {{ states('input_number.dhw_aux_heater_power') | float(0) }} + {% else %} + 0 + {% endif %} + +sensor: + - platform: history_stats + name: "Boiler Resistance Total Runtime" + entity_id: switch.boiler_heater_relay_switch_0 + state: "on" + type: time + start: "{{ 0 }}" + end: "{{ now() }}" + + - platform: history_stats + name: "Boiler Resistance PV Runtime" + entity_id: binary_sensor.dhw_aux_heater_running_on_pv + state: "on" + type: time + start: "{{ 0 }}" + end: "{{ now() }}" + + - platform: history_stats + name: "Boiler Resistance Grid Runtime" + entity_id: binary_sensor.dhw_aux_heater_running_on_grid + state: "on" + type: time + start: "{{ 0 }}" + end: "{{ now() }}" + + - platform: integration + name: "Boiler Resistance Total Energy" + source: sensor.boiler_resistance_power + unit_prefix: k + unit_time: h + method: left + + - platform: integration + name: "Boiler Resistance PV Energy" + source: sensor.boiler_resistance_pv_power + unit_prefix: k + unit_time: h + method: left + + - platform: integration + name: "Boiler Resistance Grid Energy" + source: sensor.boiler_resistance_grid_power + unit_prefix: k + unit_time: h + method: left + +utility_meter: + boiler_resistance_pv_runtime_daily: + source: sensor.boiler_resistance_pv_runtime + name: "Boiler Resistance PV Runtime Daily" + cycle: daily + + boiler_resistance_pv_runtime_weekly: + source: sensor.boiler_resistance_pv_runtime + name: "Boiler Resistance PV Runtime Weekly" + cycle: weekly + + boiler_resistance_pv_runtime_monthly: + source: sensor.boiler_resistance_pv_runtime + name: "Boiler Resistance PV Runtime Monthly" + cycle: monthly + + boiler_resistance_grid_runtime_daily: + source: sensor.boiler_resistance_grid_runtime + name: "Boiler Resistance Grid Runtime Daily" + cycle: daily + + boiler_resistance_grid_runtime_weekly: + source: sensor.boiler_resistance_grid_runtime + name: "Boiler Resistance Grid Runtime Weekly" + cycle: weekly + + boiler_resistance_grid_runtime_monthly: + source: sensor.boiler_resistance_grid_runtime + name: "Boiler Resistance Grid Runtime Monthly" + cycle: monthly + +script: + dhw_start_bath_boost: + alias: "DHW Start Bath Boost" + description: "Starts the bath boost timer with the configured duration" + icon: mdi:bath + sequence: + - action: timer.start + target: + entity_id: timer.bath_time + data: + duration: "{{ (states('input_number.dhw_bath_boost_duration') | int(30)) * 60 }}" + +automation: + - alias: DHW Boiler Heater Relay Automation + description: >- + This automation makes sure the boiler auxiliary heater only works when the + boost is required and the heatpump aux heater is not on + triggers: + - trigger: state + entity_id: + - binary_sensor.dhw_use_boiler_aux_heater + conditions: [] + actions: + - if: + - condition: state + entity_id: binary_sensor.dhw_use_boiler_aux_heater + state: "on" + then: + - action: switch.turn_on + metadata: { } + target: + entity_id: switch.boiler_heater_relay_switch_0 + data: { } + else: + - action: switch.turn_off + metadata: { } + target: + entity_id: switch.boiler_heater_relay_switch_0 + data: { } + mode: single + + - alias: DHW Manage PV Thermostat + description: Controls shadow thermostat based on PV excess availability + mode: restart + trigger: + # Trigger when PV power becomes sufficient (with delay) + - platform: state + entity_id: binary_sensor.dhw_pv_power_enough_for_aux_heater + to: "on" + for: + seconds: "{{ states('input_number.dhw_pv_excess_usage_start_delay') | int(60) }}" + id: "turn_on" + + # Trigger when PV power becomes insufficient (with delay) + - platform: state + entity_id: binary_sensor.dhw_pv_power_enough_for_aux_heater + to: "off" + for: + seconds: "{{ states('input_number.dhw_pv_excess_usage_stop_delay') | int(60) }}" + id: "turn_off" + action: + - choose: + - conditions: + - condition: state + entity_id: input_boolean.dhw_use_excess_pv_for_aux_heater + state: "on" + - condition: trigger + id: "turn_on" + sequence: + - service: climate.set_temperature + target: + entity_id: climate.dhw_pv_excess_heating + data: + temperature: "{{ states('input_number.dhw_pv_target_temperature') | float }}" + hvac_mode: "heat" + + - conditions: + - condition: trigger + id: "turn_off" + sequence: + - service: climate.set_hvac_mode + target: + entity_id: climate.dhw_pv_excess_heating + data: + hvac_mode: "off" + + - alias: DHW Boiler Preset Manager + description: >- + Sets the boiler thermostat temperature based on the selected preset + and the user-configurable temperature for that preset. + Also toggles dhw_bath_boost when Boost preset is selected. + mode: restart + triggers: + - trigger: state + entity_id: + - input_select.dhw_boiler_preset + - trigger: state + entity_id: + - input_number.dhw_boiler_temp_normal + - input_number.dhw_boiler_temp_eco + - input_number.dhw_boiler_temp_boost + - input_number.dhw_boiler_temp_sleep + - input_number.dhw_boiler_temp_away + actions: + - choose: + - conditions: + - condition: state + entity_id: input_select.dhw_boiler_preset + state: "Off" + sequence: + - action: climate.set_hvac_mode + target: + entity_id: climate.boiler_temperature + data: + hvac_mode: "off" + - action: input_boolean.turn_off + target: + entity_id: input_boolean.dhw_bath_boost + default: + - action: climate.set_temperature + target: + entity_id: climate.boiler_temperature + data: + temperature: > + {% set preset = states('input_select.dhw_boiler_preset') | lower %} + {{ states('input_number.dhw_boiler_temp_' ~ preset) | float(50) }} + hvac_mode: "heat" + - if: + - condition: state + entity_id: input_select.dhw_boiler_preset + state: "Boost" + then: + - action: input_boolean.turn_on + target: + entity_id: input_boolean.dhw_bath_boost + else: + - action: input_boolean.turn_off + target: + entity_id: input_boolean.dhw_bath_boost + + - alias: DHW Bath Time + description: >- + Manages bath boost lifecycle: enables boost + ACM pump when timer starts, + restores schedule and disables both when timer finishes. + triggers: + - trigger: state + entity_id: + - timer.bath_time + conditions: [] + actions: + - if: + - condition: state + entity_id: timer.bath_time + state: active + then: + - action: switch.turn_on + target: + entity_id: switch.acm_pump_switch + - action: input_boolean.turn_on + target: + entity_id: input_boolean.dhw_bath_boost + else: + - action: scheduler.run_action + data: + entity_id: switch.schedule_f403a3 + - action: switch.turn_off + target: + entity_id: switch.acm_pump_switch + - action: input_boolean.turn_off + target: + entity_id: input_boolean.dhw_bath_boost + mode: single \ No newline at end of file