Тепловой насос на отдельной линии: что он стоит и как автоматизировать его в HA

  • Проверено на прошивке v1.1.4
  • Средний уровень

Написано для прошивки v1.1.4. Актуальный релиз — v1.2.1, поэтому некоторые детали могут отличаться.

Часть 3 из 3 · Home Assistant recipes

Тепловой насос — обычно самая крупная отдельная нагрузка в доме, и его стоимость труднее всего предугадать. Он работает, когда того требует погода, а не когда вы, и при дневном и ночном тарифе счёт зависит от часов, которые вы не выбирали. Измерение на отдельной цепи отвечает на первый вопрос — что он на самом деле стоит, — а когда Home Assistant знает, в какой тарифной зоне находится хаб, можно что-то сделать и со вторым.

Что понадобится:

  • хаб RBgrid, на котором цепь теплового насоса измеряется как отдельная точка;
  • тарифный план, введённый в хаб; если вы этого ещё не сделали, начните с вашего собственного многотарифного учёта;
  • хаб настроен на ваш часовой пояс, а его часы синхронизированы: каждая граница зоны в этом руководстве определяется по часам хаба, а не ваших (какой часовой пояс выбрать для хаба);
  • MQTT-брокер, и Home Assistant подключён к хабу. Это руководство начинается с того места, где всё это уже работает. Если ещё нет, Измеритель мощности для Home Assistant проведёт вас по шагам — брокер, форма Настройки → Home Assistant на хабе и первые сущности, — а потом возвращайтесь сюда.

Монтаж и подбор токовых клещей, а также трёхфазная сборка описаны в сколько стоят тепловой насос и электромобиль — там тепловой насос разобран от начала до конца.

Безопасность. Любые работы внутри электрощитка поручайте квалифицированному электрику.

1. Выделите тепловому насосу отдельную точку

В Управление → Точки привяжите канал теплового насоса и задайте его Роль: Отопление/охлаждение. Роль сообщает приложению, что это нагрузка со своим расписанием: например, карточка тихого потребления сначала исключает линии отопления и зарядки электромобиля из базовой нагрузки дома и только потом оценивает, что работает постоянно, — ведь насос, который работает в 03:00, не находится в режиме ожидания.

Назовите точку до того, как она попадёт в Home Assistant. Это важнее, чем кажется, — см. §3.

Однофазный насос — это одна точка. Трёхфазный — это по одним токовым клещам на каждый проводник, каждые на модуле BASIC своей фазы, привязанные как три точки и объединённые в группу; трёхфазное руководство проведёт вас через это.

2. Что показывает приложение

Мониторинг → Экономика с выбранным тепловым насосом показывает его энергию и стоимость для часа, сегодня, вчера, 7 дней, этого месяца, прошлого месяца или этого года. Стоимость — та, которую хаб рассчитал в момент потребления энергии: каждые 15 минут по цене зоны, действовавшей в тот момент, и она хранится вместе с почасовой записью. Позже ничего не пересчитывается, поэтому, когда поставщик меняет тариф, то, что насос стоил прошлой зимой, так и остаётся его стоимостью.

История с показателем в деньгах ставит его рядом с другими вашими цепями за тот же период, а Скачать CSV позволяет забрать цифры с собой.

Что касается стоимости по зонам: в разделе «Экономика» есть такая разбивка, но читать её нужно как есть — это накопленная сумма с последнего перезапуска хаба, которая не следует за выбором периода. Она отвечает на вопрос «как распределяется сейчас», а не «сколько насос стоил мне в ночной зоне в октябре». Помесячного вида стоимости по зонам нет; для месяца используйте выбор периода и берите итог.

И прежде чем сами считать это по CSV: в сохранённых записях есть энергия и деньги за период, но поля зоны нет — разбивка хранится только в этой накопленной сумме. Так что сравнение ночи и дня за месяц — это не вид, которого вам не хватает, а показатель, который хаб не хранит.

3. Передайте данные в Home Assistant

Когда MQTT подключён, каждая привязанная точка появляется как отдельное устройство с восемью датчиками: ток, мощность, реактивная мощность, коэффициент мощности, а также энергия на входе и выходе — и как счётчик за всё время, и как счётчик за день. Энергия попадает в панель энергии в разделе Отдельные устройства напрямую — без utility_meter и без шаблонного датчика. Используйте счётчик за всё время Energy In, а не (Day): счётчики за день сбрасываются в местную полночь хаба, а суммы за всё время гарантированно не уменьшаются и переживают перезагрузку или обновление прошивки, так как хранятся в памяти самого хаба. Сброс до заводских настроек их обнуляет, и удаление точки тоже.

Две вещи, которые сэкономят вам вечер:

  • Идентификатор сущности фиксируется при первом обнаружении. Если потом переименовать точку в приложении, меняется только отображаемое имя: точка, впервые обнаруженная как «UI7 I2», сохраняет sensor.rbgrid_ui7_i2_power. Сущности можно переименовать в Home Assistant, так что это не навсегда — просто работу, которой можно избежать. Назовите точку до подключения брокера или переименуйте сущности в HA один раз.
  • Роль не передаётся. «Отопление/охлаждение» — понятие приложения; в Home Assistant устройство теплового насоса выглядит точно так же, как любая другая точка. Что бы вы ни хотели сделать с ролью, делайте это на стороне RBgrid.

4. Покажите тарифную зону в HA

Хаб публикует текущую тарифную зону, но не как обнаруженную сущность: обнаружение охватывает измерения, а не тариф. Зона находится в телеметрическом кадре хаба, который публикуется каждые три секунды и не сохраняется (без retained-флага). Один датчик MQTT забирает её. <MAC> — это двенадцать шестнадцатеричных символов хаба в нижнем регистре: темы чувствительны к регистру, а префикс rbgrid/ фиксирован:

yaml
mqtt:
  sensor:
    - name: "Tariff Zone"
      unique_id: ha_rbgrid_<MAC>_tariff_zone
      default_entity_id: sensor.rbgrid_tariff_zone
      state_topic: "rbgrid/<MAC>/telemetry"
      value_template: >-
        {% set t = value_json.get('system', {}).get('tariff') or {} %}
        {{ t.zone if t.zone is defined else None }}
      expire_after: 30
      availability:
        - topic: "rbgrid/<MAC>/status"
          payload_available: "online"
          payload_not_available: "offline"
      json_attributes_topic: "rbgrid/<MAC>/telemetry"
      json_attributes_template: >-
        {% set t = value_json.get('system', {}).get('tariff') or {} %}
        {{ {'plan_active': t.zone is defined,
            'time_src': value_json.get('time_src'),
            'buy_rate': t.get('buy_rate'), 'sell_rate': t.get('sell_rate'),
            'currency': t.get('currency'),
            'placeholder': t.get('placeholder', false)} | tojson }}
      device:
        identifiers: ["<MAC>"]
    - name: "Tariff Buy Rate"
      unique_id: ha_rbgrid_<MAC>_tariff_buy_rate
      default_entity_id: sensor.rbgrid_tariff_buy_rate
      state_topic: "rbgrid/<MAC>/telemetry"
      value_template: >-
        {% set t = value_json.get('system', {}).get('tariff') or {} %}
        {{ t.buy_rate if t.buy_rate is defined else None }}
      unit_of_measurement: "EUR/kWh"
      expire_after: 30
      availability:
        - topic: "rbgrid/<MAC>/status"
          payload_available: "online"
          payload_not_available: "offline"
      device:
        identifiers: ["<MAC>"]

В этом коде три детали, которые не случайны.

Шаблоны защищены, и так и должно быть. Поля тарифа отсутствуют в кадре, пока на хабе нет плана, — а подключить брокер до ввода тарифа вполне нормальный порядок работы. Незащищённый value_json.system.tariff.zone выдаст ошибку на отсутствующем ключе, а Home Assistant ничего не запишет в журнал: MQTT молча проглатывает ошибки шаблонов. Хуже того, датчик перезапускает expire_after до вычисления шаблона, поэтому хаб без плана держит датчик «живым» на последнем значении бесконечно — устаревшая зона, которая выглядит совершенно исправно. Защищённая версия вместо этого сообщает unknown — это состояние, на которое ваша автоматизация может отказаться реагировать.

Второй датчик — текущая цена, и есть причина уточнить это. Панель энергии Home Assistant может взять сущность как текущую цену для источника, поэтому buy_rate хаба даёт вашей панели правильное число для зоны, в которой вы находитесь прямо сейчас, — так стоимость считается на стороне Home Assistant по вашему собственному тарифу для всего, что у вас там уже есть. RBgrid хранит деньги по каждой цепи; HA сохраняет общую картину дома, которая у него и была.

plan_active — ваш единственный признак. Поскольку в журнале ничего не появляется, именно этот атрибут показывает, есть ли у хаба тариф на самом деле. Стоит вывести его на панель, если вы собираетесь на это полагаться.

default_entity_id закрепляет идентификатор сущности. Сущности MQTT берут идентификатор из имени устройства плюс имени сущности, так что без него этот датчик окажется в sensor.rbgrid_system_tariff_zone, и каждая автоматизация ниже тихо будет следить за пустотой. (object_id выполнял ту же задачу, но устарел начиная с HA 2025.12.) Префикс ha_ в unique_id держит его подальше от пространства имён прошивки, так что если будущая версия сама обнаружит сущность зоны, они будут сосуществовать, и вы удалите этот блок.

expire_after: 30 всё ещё важен: кадр не сохраняется, поэтому, если хаб замолчит, датчик станет недоступным, а не будет держать зону, которая, возможно, уже не соответствует действительности.

Тема доступности тоже делает реальную работу: хаб публикует online с retained-флагом при каждом подключении и регистрирует MQTT last will, чтобы брокер опубликовал offline, если хаб отвалится без прощания. Поэтому перезапущенный Home Assistant сразу узнаёт состояние хаба, а не ждёт кадра. А если перезапускается ваш брокер и теряет сохранённые сообщения, хаб при переподключении заново публикует весь свой набор обнаружения, так что ваши сущности точек не остаются без владельца.

Одна ловушка, прежде чем что-то строить на этом. time_src показывает sntp только после того, как хаб достучался до сервера NTP. Часы, которые вы выставили вручную из браузера, по-прежнему показывают none, хотя и верны, — поэтому на хабе без доступа в интернет условие в следующем разделе никогда не выполняется, и автоматизация никогда не срабатывает, молча и навсегда. Если time_src остаётся none, искать нужно путь хаба к серверу времени, а не автоматизацию.

Датчик показывает одно из восьми значений — NIGHT, MORNING_PEAK, DAY, EVENING_PEAK, LATE_EVENING, WEEKEND, HOLIDAY, CRITICAL_PEAK — именно в таком написании. Это тип активной зоны, а не имя, которое вы ей дали, поэтому две зоны разных типов с одинаковой ценой всё равно читаются по-разному. Если на хабе нет тарифного плана, поля нет в кадре вовсе, и защищённый датчик показывает unknown с plan_active: false.

Признак того, что всё работает: в Инструменты разработчика → Состояния новый датчик показывает название зоны, например NIGHT, а среди его атрибутов есть plan_active: true, time_src: sntp и placeholder: false. Если он застрял на unknown, тема или путь шаблона для вашего хаба неверны: подпишитесь на rbgrid/# в любом клиенте MQTT и сравните реальный кадр с шаблоном.

Атрибуты приходят не просто так, и причина серьёзнее, чем кажется. Хаб определяет зону по своим часам, даже если они ещё не синхронизированы — после загрузки без SNTP они показывают около 1970 года плюс время работы, так что зона, которую он сообщает, и цена, которую он берёт, могут быть просто неверными. Пока часы не синхронизированы, он не скрывает поле. По time_src это видно, и следующий раздел отказывается действовать, пока там не появится sntp.

⚠️ После любого перезапуска заново сохраните тариф, прежде чем доверять этим цифрам или позволять им что-то запускать. В v1.1.4 хаб, который перезагрузился, возвращается на встроенный пробный план Test Day/Night, пока вы не откроете Тарифы и не нажмёте Сохранить (руководство по тарифам — там подробности). Подвох для этой статьи: пока это так, зона по-прежнему показывает вполне правдоподобный NIGHT, а time_src по-прежнему показывает sntp, поэтому проверка в следующем разделе проходит, и ваша автоматизация управляет тепловым насосом по границам пробного плана. Представьте себе отключение электричества в 02:00.

5. Автоматизация — в Home Assistant, по уставке

RBgrid измеряет и сообщает. Он ничего не переключает: ни реле, ни контактора, никаких выходов вообще. Всё, что ниже, работает на стороне Home Assistant, с уже имеющейся у вас климатической сущностью.

yaml
automation:
  - alias: "Heat pump: follow tariff zone (reconcile)"
    mode: single
    max_exceeded: silent
    triggers:
      - trigger: state
        entity_id: sensor.rbgrid_tariff_zone
        to: ~
      - trigger: state
        entity_id: sensor.rbgrid_tariff_zone
        attribute: placeholder
      - trigger: homeassistant
        event: start
      - trigger: time_pattern
        minutes: "/15"
    conditions:
      - condition: state
        entity_id: sensor.rbgrid_tariff_zone
        state: ["NIGHT", "DAY"]
      - condition: template
        value_template: "{{ state_attr('sensor.rbgrid_tariff_zone', 'time_src') == 'sntp' }}"
      - condition: template
        value_template: "{{ state_attr('sensor.rbgrid_tariff_zone', 'placeholder') is sameas false }}"
    actions:
      - variables:
          target: "{{ 21 if is_state('sensor.rbgrid_tariff_zone', 'NIGHT') else 19 }}"
      - condition: template
        value_template: "{{ (state_attr('climate.heat_pump', 'temperature') | float(0)) != (target | float) }}"
      - action: climate.set_temperature
        target: { entity_id: climate.heat_pump }
        data: { temperature: "{{ target }}" }
  - alias: "RBGrid: placeholder tariff plan active"
    mode: single
    triggers:
      - trigger: state
        entity_id: sensor.rbgrid_tariff_zone
        attribute: placeholder
        to: true
    actions:
      - action: persistent_notification.create
        data:
          notification_id: rbgrid_placeholder_plan
          title: "RBGrid: placeholder tariff plan"
          message: >-
            The hub is running the built-in Test Day/Night plan. Re-save your tariff
            plan in the RBgrid app; zone automations stay paused until then.

Защита от пробного плана — третье условие, и о нём думают реже всего. Хаб, который перезагрузился на v1.1.4, возвращается на встроенный план Test Day/Night, пока вы не сохраните свой заново, — и пока это так, зона выглядит правдоподобно, а часы показывают синхронизацию, так что очевидные проверки проходят. Действуя по нему, вы управляли бы тепловым насосом по тестовым ценам.

Впрочем, хаб об этом скажет, если спросить: пока работает встроенный план, телеметрия несёт placeholder: true, а после сохранения собственного плана ключа просто нет. Условие намеренно строгое — оно срабатывает только на явное false, но никогда на отсутствующий атрибут, — так что датчик, который не может сообщить, обрабатывается так же, как хаб на тестовом плане.

Вторая автоматизация делает только одно — сообщает, почему всё стихло. А поскольку автоматизация сверки тоже срабатывает на этот атрибут, как только вы пересохраните план в приложении, уставка догоняет сразу, а не ждёт следующего пятнадцатиминутного периода.

Направьте это на комнатный термостат и сначала проверьте. climate.set_temperature предполагает сущность с заданием комнатной температуры в °C. Многие интеграции тепловых насосов показывают что-то другое: температуру подачи или воды, кривую погодозависимого регулирования, где задание ничего не делает, сущность только с пресетами без задаваемой температуры — или бак горячей воды. Установка 21 на сущности температуры подачи — это не подталкивание; на баке ГВС это холодный бойлер и цикл против легионеллы, которого вы не планировали.

Откройте Инструменты разработчика → Состояния, найдите свою климатическую сущность и убедитесь, что у неё есть атрибут temperature в ожидаемом диапазоне, прежде чем позволять чему-либо в неё писать.

Добавьте парную зеркальную автоматизацию для дневной зоны, которая задаёт температуру на один-два градуса ниже, или climate.set_preset_mode: eco, если в вашем устройстве есть такой режим.

Проверьте, что NIGHT — действительно ваша дешёвая зона. Датчик сообщает тип зоны, а не имя, которое вы ей дали, и именно тип определяет, что произойдёт:

  • Если в вашем плане есть зона Выходные, она имеет приоритет над ночью в дни своего действия, а WEEKEND нет в условии выше — поэтому с момента начала этой зоны автоматизация перестаёт что-либо решать. Она не откатывается к дневной цели: уставка сохраняет последнее заданное значение, так что если ночь пятницы задала ночную цель, дом держит её до конца выходной зоны. Подходит ли это вам, зависит от вашей цены в выходные, которую название зоны не говорит — см. ниже.
  • Если дешёвый тариф идёт двумя окнами — дешёвая ночь и дешёвая середина дня, что очень подходит тепловому насосу, — второе окно приходит как другой тип, например LATE_EVENING, и ему нужен собственный триггер. Два дешёвых окна в день объясняет, как строится такой план.
  • На трёхзонном тарифе «дневная зона» может быть DAY, MORNING_PEAK или EVENING_PEAK, и для каждой понадобится свой триггер.

Наблюдайте за датчиком день, прежде чем доверять какому-либо значению to:.

Зона выходных требует решения, а не значения по умолчанию. WEEKEND — это тип зоны; он ничего не говорит о том, сколько вы платите. Выведите датчик Tariff Buy Rate из §4 на панель, посмотрите на него в субботу, а затем добавьте "WEEKEND" в список state:, чтобы автоматизация действовала по выходным, а не молчала. Дальнейший путь — одна строка. Как есть, шаблон target считает каждую зону, кроме NIGHT, дневной целью, поэтому выходные по полной цене получают дневную уставку — что вам и нужно. Добавьте or is_state('sensor.rbgrid_tariff_zone', 'WEEKEND') в эту строку, и дешёвые выходные получат ночную уставку:

yaml
conditions:
      - condition: state
        entity_id: sensor.rbgrid_tariff_zone
        state: ["NIGHT", "DAY", "WEEKEND"]            # add WEEKEND here → the automation also acts at weekends
    actions:
      - variables:
          # a full-price weekend: leave this line exactly as it is in the automation above — WEEKEND then gets 19
          # a cheap weekend: add the second is_state(), as below — WEEKEND then gets 21
          target: "{{ 21 if is_state('sensor.rbgrid_tariff_zone', 'NIGHT') or is_state('sensor.rbgrid_tariff_zone', 'WEEKEND') else 19 }}"

Оба варианта проверены на живой зоне WEEKEND, и делают именно это; защиты time_src и placeholder выше не тронуты и действуют в любом случае. По умолчанию автоматизация действует на две зоны, потому что хаб может сообщить тип зоны и её цену, но не то, по какой зоне хочет жить ваш дом.

Сначала отключите любое расписание, которое уже работает с этой сущностью. Если и временная автоматизация, и эта пишут уставку, они начнут конфликтовать, и побеждает тот, кто записал последним, — а это не то свойство, которое вы хотите, чтобы определяло ваше отопление.

Хаб заново определяет зону каждые три секунды и публикует по собственному таймеру на три секунды, так что смена зоны появляется в худшем случае примерно через шесть секунд, обычно раньше, плюс собственная задержка Home Assistant. Для уставки этого достаточно; не стройте ничего, что требует границы с точностью до секунды.

Она сходится, а не реагирует. Это та часть, которую стоит понять, прежде чем адаптировать. Автоматизация, которая срабатывает только на переход в зону, имеет сбой, который вы не заметите: если Home Assistant перезапускается, или брокер моргнул, или хаб молчит в момент 23:00, переход пропущен, и уставка так и не восстанавливается. Насос остаётся на дневной цели — и ничто в доме вам не скажет об этом, пока не похолодает.

Поэтому триггер — не «началась ночная зона», а «что-то изменилось, или мы перезапустились, или прошло пятнадцать минут». Действие затем выясняет, чего требует текущая зона, и отправляет это, только если тепловой насос ещё не там. Это идемпотентно, поэтому запуск после перезапуска — правильное поведение, а не то, что нужно подавлять, а пропущенная граница исправляется сама в следующем пятнадцатиминутном периоде не позднее.

Безопасность обеспечивают условия, а не триггер: зона должна быть реальным значением (unknown и unavailable отсеиваются), часы хаба должны быть синхронизированы, и тарифный план должен быть подтверждён. Если что-то из этого не выполнено, ничего не отправляется, и тепловой насос продолжает работать по собственной программе.

Подталкивайте уставку, а не перекрывайте питание. Держать насос выключенным до начала дешёвой зоны — очевидная идея и неверная: компрессорам нужен собственный цикл, а также размораживание и циклы против легионеллы.

Собственный вход сигнала сети устройства — SG Ready, в большей части Европы — может его заблокировать, включая жёсткую блокировку до двух часов, и контакты блокировки от энергокомпании на тепловых тарифах — обычное дело. Разница в том, что контроллер производителя во время блокировки всё ещё ведает размораживанием и расписанием против легионеллы и знает, когда вмешаться. Умная розетка в линии питания не отвечает ни за что из этого. Поэтому: уставка, пресет или режим — через собственный интерфейс устройства, но никогда не через питание.

Сделайте «нет данных» безопасным состоянием — и знайте, что это оставляет после себя. Если хаб уходит в офлайн, датчик становится недоступным, условия не выполняются и ничего не отправляется, так что тепловой насос продолжает работать по своей программе. Для прибора это правильное поведение.

Но важно понимать, чем это не является: если дневная автоматизация уже понизила вашу уставку, пока хаб отсутствует, её ничто не восстановит. Тишина защищает машину, а не ваш комфорт. Именно поэтому важен принцип сверки — как только хаб вернётся, следующий такт поставит уставку туда, где её должна держать текущая зона, без ваших действий.

Сначала запустите как уведомление. День-два замените действие climate.set_temperature на

yaml
- action: persistent_notification.create
        data:
          title: "Tariff zone"
          message: "Would set the heat pump to {{ target }} °C"

и посмотрите, когда оно бы сработало. Это ничего не стоит, и так вы узнаете, что граница вашей зоны не там, где вы думали, или что ваша климатическая сущность — не та, которую вы предполагали.

Если в Home Assistant нет климатической сущности, пропустите этот раздел целиком. Измерение и картина стоимости по зонам самостоятельны, а автоматизация, которой вы не можете управлять правильно, хуже её отсутствия.

Чего это не делает

  • RBgrid ничего не переключает. У него нет выходов. Каждое действие в этом руководстве — это Home Assistant, управляющий вашим собственным оборудованием.
  • Стоимость по каждой цепи остаётся в приложении. Home Assistant получает энергию теплового насоса, а не её стоимость.
  • Нет стоимости по зонам за период. Разбивка по зонам — это накопленная сумма с последнего перезапуска хаба.
  • Роль не видна в HA, поэтому автоматизация не может отличить точку отопления от любой другой.
  • Хаб с несинхронизированными часами всё равно сообщает зону и всё равно назначает цену энергии по тому времени, которое он считает текущим. Поэтому автоматизация выше проверяет time_src, и поэтому первые цифры после свежей загрузки заслуживают повторной проверки.
  • RBgrid показывает, сколько стоила энергия насоса по вашим тарифам. Он не сверяет счёт поставщика и не утверждает, сколько вы сэкономите.

Далее