Hello, community! I would like to share my solution, which significantly reduced energy consumption (by 30-40%, according to my calculations) when using a duct heater (2.5 kW) in a DHW system with a recuperator. Instead of a primitive On/Off thermostat, I developed an autonomous PID controller based on the ESP32, which: Provides a stable target temperature (5°C) with an accuracy of $\pm 0.3^\circ C$ at the recuperator inlet, regardless of the frost outside (down to -20°C). Smooth power control (via a dimmer on the SSR) eliminates temperature surges and increases comfort in the home. Includes a strict safety system (only turns on when the fan is running) to prevent overheating. This is a complete, ready-to-use device, integrated with Home Assistant for monitoring and control.
# =================================================================
# --- 1. Основная конфигурация устройства (ПЛАТА И СЕТЬ) ---
# =================================================================
esphome:
name: nagrev-pritoka-20
friendly_name: nagrev_pritoka_2.0
esp32:
board: esp32dev
framework:
type: arduino
logger:
api:
encryption:
key: "06RAujzMZGvHtNURcFPc7zJxjfgM4npzwkqcF/6OR7Y="
reboot_timeout: 5min
ota:
- platform: esphome
password: "de5857967d95527f7dab10acaf66f437"
wifi:
ssid:
password:
manual_ip:
static_ip:
gateway:
subnet:
ap:
ssid: "Nagrev-Pritoka-13"
password: "jLRjYrAoNgOg"
captive_portal:
web_server:
port: 80
# --- Конфигурация интерфейсов ---
uart:
tx_pin: GPIO17
rx_pin: GPIO16
baud_rate: 9600
one_wire:
- platform: gpio
pin: GPIO13
# =================================================================
# --- 2. SENSORS (Датчики: Dallas Temp & PZEM-004T) ---
# =================================================================
sensor:
- platform: dallas_temp
address: 0xb9020491770ed528
name: "Улица/перед нагревателем"
id: outdoor_temperature
update_interval: 55s
- platform: dallas_temp
address: 0xd9000000b3d1bd28
name: "Темп после нагревателя"
id: heater_temperature
filters:
# Защитные фильтры оставлены, чтобы убрать невалидные показания
- timeout: 30s
- filter_out: -127.0
- filter_out: 85.0
update_interval: 5s
- platform: dallas_temp
address: 0xa3020891777a5f28
name: "Темп после рекупа"
id: temperature_posle_rekupa
update_interval: 65s
- platform: dallas_temp
address: 0xf5000000b3b49e28
name: "Вытяжка перед рекупом"
id: vytazhka_temp_pered_rekupom
update_interval: 2min
- platform: dallas_temp
address: 0xfb0204917729d028
name: "Вытяжка после рекупа"
id: vytazhka_temp_posle_rekupa
update_interval: 90s
- platform: pzemac
address: 5
current:
name: "Канальный нагреватель амперы"
id: load_current
power:
name: "Канальный нагреватель нагрузка"
power_factor:
name: "Канальный нагреватель Power Factor"
update_interval: 4s
- platform: wifi_signal
name: "WiFi Signal Nagrev"
update_interval: 60s
# =================================================================
# --- 3. OUTPUTS & SWITCHES (Диммер и Реле) ---
# =================================================================
output:
- platform: ac_dimmer
id: ac_dimmer_physical
gate_pin: GPIO27
zero_cross_pin:
number: GPIO14
mode:
input: true
pullup: true
inverted: no
min_power: 0.1
switch:
- platform: gpio
pin: GPIO26
id: master_relay_switch
name: "Мастер-реле нагревателя"
restore_mode: ALWAYS_OFF
# 🔴 ИСПРАВЛЕНИЕ: Делаем реле внутренним для предотвращения ручного управления
# internal: true
# --- Переключатель для АВТОМАТИЧЕСКОГО ОБОГРЕВА ---
- platform: template
id: auto_mode_switch
name: "Включить/Выключить Автоматический Обогрев"
lambda: 'return id(pid_heater).mode == climate::CLIMATE_MODE_HEAT;'
turn_on_action:
- if:
condition:
# Разрешаем включение, только если главный блокиратор активен
binary_sensor.is_on: heating_allowed
then:
- switch.turn_on: master_relay_switch # Включаем физическое питание
- climate.control: { id: pid_heater, mode: 'HEAT' }
turn_off_action:
- switch.turn_off: master_relay_switch # Выключаем физическое питание
- climate.control: { id: pid_heater, mode: 'OFF' }
# =================================================================
# --- 4. Виртуальный Сенсор (Home Assistant Fan Status) ---
# =================================================================
binary_sensor:
# --- 4.1. Сенсор состояния вентилятора ---
- platform: homeassistant
id: virtual_indicator
name: "Виртуальный Сенсор-Индикатор"
# !!! ВАЖНО: ЗАМЕНИТЕ entity_id НА ID ВАШЕГО ВЕНТИЛЯТОРА В HOME ASSISTANT !!!
entity_id: light.pritochka2025_sonoff_d1_dimmer
# Этот сенсор будет ON, только если Home Assistant сообщает "on".
# В любом другом случае (off, unknown, unavailable) он будет OFF.
- platform: template
name: "Статус Вентилятора Притока (HA)" # Имя вашего целевого виртуального сенсора
id: virtual_indicator2
lambda: |-
// Возвращает TRUE (ВКЛ) или FALSE (ВЫКЛ) в зависимости от состояния вентилятора в HA
return id(virtual_indicator).state;
# --- 4.2. Сенсор логики (T_улица < T_уставка - 0.3) ---
- platform: template
id: outdoor_temp_too_low
name: "T Улица Ниже Уставки (Требуется Нагрев)"
lambda: 'return id(outdoor_temperature).state < id(pid_heater).target_temperature - 0.3;'
# --- 4.3. Сезонный блокиратор (Т улицы ниже 10C) ---
- platform: template
id: seasonal_blocking
name: "Сезонный Блокиратор (Т улица < 10C)"
# Нагрев нужен только если на улице температура ниже 10°C (порог, когда рекуператор не справляется)
lambda: 'return id(outdoor_temperature).state < 10.0;'
# --- 4.4. ГЛАВНЫЙ СЕНСОР АКТИВАЦИИ (Вентилятор И Холод) ---
- platform: template
id: heating_allowed
name: "Разрешение на Обогрев (Финальный Блокиратор)"
# Сенсор включен только если ОБА сенсора ON (Вентилятор ON И Улица Холодно ON)
lambda: 'return id(virtual_indicator).state && id(outdoor_temp_too_low).state && id(seasonal_blocking).state;'
# 🔴 КРИТИЧЕСКАЯ ЗАЩИТА: Мгновенное отключение при блокировке
on_state:
- if:
condition:
# Если сенсор перешел в состояние OFF (т.е. вентилятор или температура блокируют нагрев)
not:
binary_sensor.is_on: heating_allowed
then:
- switch.turn_off: master_relay_switch # Обесточить нагреватель
- climate.control: { id: pid_heater, mode: 'OFF' }
# 🟢 РЕЖИМ ОЖИДАНИЯ: Запускает систему, как только разрешено, если тумблер 'auto_mode_switch' включен
- if:
condition:
# Проверяем, что пользователь ранее включил главный тумблер
switch.is_on: auto_mode_switch
then:
- switch.turn_on: master_relay_switch # ➡️ Включаем физическое питание
- climate.control: { id: pid_heater, mode: 'HEAT' } # ➡️ Запускаем PID
# ----------------- CLIMATE CONTROL (PID) -----------------
climate:
- platform: pid
visual:
min_temperature: 0
max_temperature: 20 # Установлен лимит 20°C по запросу
temperature_step: 0.1
id: pid_heater
name: "PID Нагреватель"
sensor: heater_temperature
default_target_temperature: 5.0
heat_output: ac_dimmer_physical
control_parameters:
kp: 0.16
ki: 0.001
kd: 0.0
output_averaging_samples: 5 # Сглаживание выхода диммера
derivative_averaging_samples: 10 # Сглаживание входа Kd
deadband_parameters:
threshold_high: 0.1°C
threshold_low: -0.1°C