Home Assistant, Protherm, My Heat - очень много букв

28 февраля 2021, 21:18

Вкратце обрисую предлагаемое решение.

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

А задача, если кратко, состоит в том, чтобы заставить котел отопления, рассчитанный изначально на поддержание заданной температуры воздуха в  одном помещении* (так называемый "одноконтурный" котёл), поддерживать разную температуру в нескольких разных помещениях* (то есть, обслуживать несколько контуров).

Исходный состав оборудования (на своём собственном примере, но возможны и другие варианты):

  • Система отопления водяного типа (батареи, теплые полы), состоящая из нескольких контуров**.
  • Электрокотёл Protherm Скат с управлением по шине EBUS.
  • Локальная сеть с возможностью доступа по WiFi (оптимально - с выходом в Интернет).
  • Контроллер котла My Heat Smart.
  • Микроконтроллерное устройство (плата) на чипе ESP8266.
  • Комплект дистанционно управляемых кранов  для перекрытия подачи теплоносителя в контуры***.
  • Home Assistant.
  • MQTT- брокер.

* Помещение - это не обязательно одно физическое помещение (например, комната). Под помещением мы понимаем совокупность пространств, отапливаемых одним физическим контуром отопления, а температура в таком помещении со стороны системы отопления контролируется по одному термодатчику. Например, это может быть этаж небольшого дома.

** Контур отопления - это сопокупность трубопроводов, радиаторов и прочего оборудования, имеющих один общий трубопропод подачи теплоносителя и один общий трубопровод возврата теплоносителя. 

*** Включая контроллер, который приводит в действие краны и управляется со стороны Home Assistant'а.

Суть решения

Контроллер My Heat (впрочем, как и любой другой) переключает режимы работы котла, исходя из необходимости поддержания заданной температуры в помещении. Так как котел одноконтурный, то и термодатчик, с которого считывается текущее значение температуры, всего один. Поэтому при разветвлении теплоподачи на несколько физических контуров (помещений, этажей и т.д.) заданная температура по факту будет поддерживаться только в том помещении, в котором установлен термодатчик. В остальных же помещениях с высокой долей вероятности будет иметь место либо недогрев, либо перегрев.

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

Этап 1. Создаём виртуальный термодатчик.

В качестве термодатчика, по показаниям которого будет поддерживаться заданная температура, контроллер My Heat позволяет использовать термодатчики, работающие по протоколу 1-Wire (One Wire). К таким относится, например, весьма популярный и недорогой датчик DS18B20. Датчик подключается к контроллеру по трем проводам - VCC ( 5 В), GND (масса) и DATA (передача данных). Вместо такого физического датчика мы подключим к контроллеру виртуальный датчик, который будет сообщать контроллеру не фактическую температуру, а ту температуру, которую мы захотим. Физическая основа виртуального датчика - плата на чипе ESP8266. Сгодятся варианты ESP01 (самый дешевый), NodeMCU, Wemos D1 Mini и прочие. Плата подключается к контроллеру по тем же самым трем проводам, что были описаны выше, и будет питаться прямо от контроллера. Единственная оговорка - платы ESP8266 питаются не от 5 вольт, а от 3,3, поэтому нужно позаботиться о наличии понижающего преобразователя. У таких плат как NodeMCU или Wemos D1 Mini такие "понижатели" встроены, поэтому можно смело подключать выход " 5 В" контроллера к пину "VIN", а если вы используете ESP01, то рекомендую воспользоваться копеечным переходником типа такого: 

1600x_image.png?1614509253

Через этот переходник можно питать ESP01 от 5 вольт. Поскольку я для себя использовал именно ESP01 и именно с таким переходником, то далее буду описывать всё именно для этого варианта.

Для программирования ESP01 нам понадобится скетч, который использует библиотеки OneWireHub (для эмуляции датчика One Wire) и EspMQTTClient (для получения текущего значения температуры, которое нужно сообщить контроллеру).

Вот текст скетча:

#include <EspMQTTClient.h>
#include <ArduinoJson.h>

#define WLAN_SSID       "YourWiFi_AccesPoint"
#define WLAN_PASS       "YourWiFi_Password"
#define MQTT_BROKER     "YourMQTT_IP_address"
#define MQTT_USER       "YourMQTT_login"
#define MQTT_PASS       "YourMQTT_password"
#define MQTT_CLIENT     "YourMQTT_ClientName"
#define MQTT_PORT       YourMQTT_Port_without_quotes
#define MQTT_TOPIC      "YourMQTT_topic"

#include "OneWireHub.h"
#include "DS18B20.h"  // Digital Thermometer, 12bit

#define pin_onewire 1 //TXD

auto hub    = OneWireHub(pin_onewire);
auto ds18b20 = DS18B20(DS18B20::family_code, 0x00, 0x00, 0xB2, 0x18, 0xDA, 0x00);
bool blinking(void);

float temperature;
String temperatureString;

//********************************************************
EspMQTTClient mqttClient(
  WLAN_SSID,
  WLAN_PASS,
  MQTT_BROKER,    // MQTT Broker server ip
  MQTT_USER,      // Can be omitted if not needed
  MQTT_PASS,      // Can be omitted if not needed
  MQTT_CLIENT,    // Client name that uniquely identify your device
  MQTT_PORT       // The MQTT port, default to 1883. this line can be omitted
);
//********************************************************
void setup()
{
    hub.attach(ds18b20);
    mqttClient.enableHTTPWebUpdater(); // Enable the web updater. 
                                       // User and password default to values of MQTTUsername and MQTTPassword. 
                                       // These can be overrited with enableHTTPWebUpdater("user", "password").
}
//*************************************************************
void onConnectionEstablished()
{
  mqttClient.subscribe(MQTT_TOPIC, [](const String & payload) {
    temperatureString = payload;
  });
}
//********************************************************
void loop()
{
    mqttClient.loop();
    hub.poll();
    if (hub.hasError()) hub.printError();
    if (blinking())
    {
        temperature = temperatureString.toFloat();
        ds18b20.setTemperature(temperature);
    }
}
//****************************************************
bool blinking(void)
{
    constexpr  uint32_t interval    = 1000;          // interval at which to blink (milliseconds)
    static uint32_t nextMillis  = millis();     // will store next time LED will updated

    if (millis() > nextMillis)
    {
        nextMillis  = interval;             // save the next time you blinked the LED
        static uint8_t ledState = LOW;      // ledState used to set the LED
        if (ledState == LOW)    ledState = HIGH;
        else                    ledState = LOW;
//        digitalWrite(pin_led, ledState);
        return 1;
    }
    return 0;
}

Небольшое уточнение. Поскольку у адаптера ESP01, кроме выводов питания, только два логических вывода - TXD и RXD, то мне было удобнее в качестве пина передачи данных использовать именно один из них (я использую TXD). Если вы используете другую плату, то можете назначить для этого другой пин, который вам покажется более удобным.

И еще. В скетче имеется строчка :

    mqttClient.enableHTTPWebUpdater();

Её наличие позволяет вам обращаться к ESP через браузер (http://ip-address) для залития прошивки. Очень удобно.

Подведем промежуточный итог. Теперь мы можем "подставлять" контролеру My Heat в качестве текущей любую температуру, которую захотим. Для этого нам нужно записывать в заданный MQTT-топик нужное значение.

Этап 2. Записываем в MQTT-брокер нужное показание температуры

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

Например, на первом этаже у нас прихожая, кухня и гостиная. Здесь мы принимаем пищу и проводим вечерний семейный досуг. Но ночью на первом этаже никого нет (только коты бродят). Поэтому имеет смысл в дневное время поддерживать здесь, скажем, 21 градус, а ночью - не более 19. Ну, еще утром перед завтраком прогреть часовым "толчком" до 22 градусов.

Второй этаж. Здесь расположены спальни. Тут всё наоборот - днём сюда мало, кто заходит (поэтому будет достаточно днём здесь поддеживать 21 градус), а ночью во время сна хочется тепла - поэтому ночью здесь выставим 23 градуса.

Третий этаж - это мансардное помещение, используемое под кладовку. Тут никто не живёт, здесь хранится сезонная одежда на вешалках, лежат коробки с обувью, старые журналы и прочий хлам, "нажитый непосильным трудом". Поэтому для третьего этажа вполне хватит и круглосуточных 19 градусов.

Итак, мы пришли к выводу, что при переключении контуров котла нужно заодно еще и менять не только текущую температуру помещения, но еще и заданную. Но если для подстановки текущей температуры нам нужно всего лишь отправить в MQTT-брокер другое значение, то чтобы заменить заданную температуру, придется общаться уже с настройками самого контроллера. Это, хоть и возможно, но, во-первых, достаточно сложно (нужно отсылать REST-запрос на облако, через которое управляется контроллер), а во-вторых, чревато непредсказуемыми последствиями - ведь непонятно, как себя поведет логика контроллера, если каждые несколько минут будет возникать требование поддерживать другую заданную температуру. Ну и опять же - чем больше операций, тем меньше надёжность.

Поэтому я решил реализовать это дело по-другому, а именно:

  1. Заданная температура будет постоянной. Желательно, чтобы она была заведомо выше всех температур для всех помещений - как текущих, так и задаваемых. Например, 25 градусов.
  2. В качестве текущей мы будем оправлять  MQTT-брокеру (и в конечном итоге - контроллеру котла) не истинную текущую температуру в таком-то помещении (в нашем случае - на таком-то этаже), а приведённую (или фейковую - как хотите, так и называйте).

Что такое (в нашем случае) приведённая текущая температура? Поясню на примере. Допустим, в настоящее время для второго этажа требуется поддержание 22 градусов, а по факту там сейчас 20,5 градусов. Значит, требуется нагрев на (22 - 20,5) = 1,5 градуса. Вычитаем эту "дельту" из неизменной целевой температуры, заданной в настройках контроллера (т.е., 25 градусов) и получаем (25 - 1,5) = 23,5 градуса. Именно это показание мы отправляем на MQTT-брокер. При этом мы по сути полагаем, что для котла нагреть воздух что с 20,5 до 22 градусов, что с 23,5 до 25 градусов - это одна и та же работа. Ну, конечно, тонкие знатоки термодинамики могут сказать, что это не так. Конечно, не так, но в пересчете на энергию там получится разница в какие-то микроскопические доли джоуля, которыми можно пренебречь.

Кстати, такой подход позволяет в качестве "полезной побочки" решить одну небольшую проблему. Дело в том, что разработчики контроллера My Heat почему-то подумали, что целевую температуру нужно задавать с точностью в один градус. Тут сказывается отсутствие у этих разработчиков практики в предметной области (то есть, жизни в доме, отоплением которого управляешь сам). А практика показывает, что для реальных систем отопления градус Цельсия - это очень грубо. Желательно иметь возможность задавать температуру с точностью ну хотя бы до половины гнрадуса. А в идеале - до одной десятой. И наша "побочка" состоит как раз в том, что как бы сохраняя выставленную на контроллере заданную температуру в те же 25 градусов, по факту мы можем настраивать заданную температуру практически с любой точностью - но однако в реальности нам хватит, пожалуй, и одного знака после запятой.

Переходим к делу. В Home Assistant'е создаем вспомогательные элементы типа "число" по количеству наших контуров (этажей). Даем им интуитивно понятные имена...

  • input_number.goal_temp_floor_1
  • input_number.goal_temp_floor_2
  • input_number.goal_temp_floor_3

... и в опциях указываем минимальное (например, 5) и максимальное (например, 30) значения, а также тип представления (мне понравился "слайдер"), шаг (допустим, 0.1) и единицу измерения (°C).

Создадим в Lovelace карточку типа "Entities" и поместим туда наши свежесозданные объекты. В этой карточке мы сможем, двигая ползунками, выставлять для каждого этажа свою заданную температуру. Для начала вручную, а потом, может быть, и автоматизацию какую-нибудь напишем.

Карточка может выглядеть примерно так. Тут я конечно, немного поспешил и показал, что в ту же карточку можно поместить значения реальных температур на этажах, а также значения фейковых (приведённых) текущих температур, вычисленных по принципу, изложенному ранее в этом документе.

1600x_image.png?1614514272

Предполагается, что сенсоры для отображения истинных текущих температур на каждом этаже, у нас уже есть (а как иначе?). Они могут у вас по-разному называться, но у меня называются так:

  • sensor.temperature_floor_3
  • sensor.temperature_floor_2
  • sensor.temperature_floor_1

 Следующее, что нам нужно сделать в Home Assistant'е - это создать переменные (в нотации HA - сенсоры) для приведённых (фейковых) значений текущей температуры по каждому этажу. Для этого воспользуемся механизмом создания шаблонных сенсоров (Template Sensors).

Отступление: чуть не забыл. Я же не рассказал, как получить значение текущей и заданной температур с контроллера My Heat. Долго писать здесь не буду - всё описано здесь. Отмечу только что сенсоры, получающие эти два значения температуры с контроллера, называются у меня так:

  • sensor. mh_virt_temp_temperature
  • sensor.mh_virt_temp_target_temperature

При этом мы договорились, что целевая температура для нашего виртуально-фейкового термодатчика будет постоянной и равной 25 градусам. Таковой мы ее зададим средствами веб-администрирования контроллера (ну, или через REST-запрос со стороны HA, но зачем городить этот запрос, если операцию нужно выполнить всего один раз?).

Итак, создаем шаблонные сенсоры для отображения приведённых (фейковых)  текущих температур по каждому этажу (на примере 3-го этажа):

sensor:
  - platform: template
    sensors: 
      fake_temp_3:
        friendly_name: "Фейк: t° 3-го этажа"
        unit_of_measurement: "°C"
        value_template: "{{ ((states('sensor.mh_virt_temp_target_temperature')|float) - ((states('input_number.goal_temp_floor_3')|float) - (states('sensor.temperature_floor_3')|float))|round(2)) }}"

Далее нам (чисто для удобства) необходимо будет создать по числу контуров двоичные сенсоры (binary sensors), которые будут нам показывать, нуждается ли тот или иной контур (этаж) в настоящий момент в обогреве. Принцип тут простой - если разница между истинными значениями заданной и текущей температуры положительная, то значит данный контур нуждается в обогреве. Ну, или разница между значениями заданной температуры виртуального датчика и приведёнными (фейковыми) значениями текущей температуры на разных этажах - что по сути одно и то же:

binary_sensor:
  - platform: template
    sensors:
      need_to_heat_3:
        friendly_name: "3-й этаж нуждается в обогреве"
        value_template: "{{ (states('sensor.mh_virt_temp_target_temperature')|float - states('sensor.fake_temp_3')|float)|float > 0 }}"
      need_to_heat_2:
        friendly_name: "2-й этаж нуждается в обогреве"
        value_template: "{{ (states('sensor.mh_virt_temp_target_temperature')|float - states('sensor.fake_temp_2')|float)|float > 0 }}"
      need_to_heat_1:
        friendly_name: "1-й этаж нуждается в обогреве"
        value_template: "{{ (states('sensor.mh_virt_temp_target_temperature')|float - states('sensor.fake_temp_1')|float)|float > 0 }}"

Теперь начинается интересное. Допустим, в текущий момент времени в обогреве нуждается не один этаж, а сразу два (или даже все три). Какую из фейковых температур передавать в MQTT и далее на контроллер? Логически предположить, что надо выбрать меньшую (потому что чем больше разница между заданной и текущей температурами, тем бо́льшую мощность разовьет котёл отопления - в этом и состоит, в частности, логика "умного" управления котлом по цифровой шине) . А как её выбрать? Да вот так:

sensor:
  - platform: min_max
    type: min
    name: min_fake_temp
    entity_ids:
      - sensor.fake_temp_3
      - sensor.fake_temp_2
      - sensor.fake_temp_1

Теперь мы знаем, что контроллеру в качестве текущей температуры нужно передать значение вот этого сенсора:

sensor.min_fake_temp

Это можно сделать с помощью созданной специально для этого в Home Assistant'е автоматизации. Но здесь возникает вопрос - а что будет являться триггером для срабатывания этой автоматизации? Рассуждая логически, триггером должно быть изменение значения сенсора sensor.min_fake_temp. Но к великому сожалению, в автоматизациях Home Assistant'а нельзя назначить триггером "просто изменение" значения сенора. Нужно обязательно указывать (причём, жёстко - т.е., в виде определенного числа) пороговое значение. Например, если температура поднялась выше 19 градусов. И триггер сработает именно в момент перехода температуры через эти 19 градусов. Получается, что для того, чтобы отрабатывать любые колебания температуры в диапазоне, скажем, от 18 до 20 градусов с точностью до одной десятой градуса, нам потребуется создать 20 (двадцать, Карл!) триггеров. А если в диапазоне от 16 до 26 градусов? А если нужны триггеры не только на повышение температуры, а еще и на понижение? В-общем, "это не наш метод".

Поэтому "пойдем другим путём" и назначим триггер типа "шаблон времени". Такой тип триггера позволяет запускать автоматизацию, как говорится, без видимых причин, а просто через равные промежутки времени (в нашем примере - каждые 10 секунд):

- id: 'mqtt_send_fake_temp'
  alias: 'Автоотопление: подстановка температуры'
  trigger:
  - platform: time_pattern
    seconds: /10
  condition: []
  action:
  - service: mqtt.publish
    data:
      topic: homeassistant/thermometer/myheat
      payload_template: "{{ states('sensor.min_fake_temp') }}"
      retain: 'yes'
  mode: single

Как видно выше, мы не стали усложнять себе жизнь, создавая payload в формате JSON (как нынче модно). Мы просто тупо забиваем в топик значение температуры (например, 20,38), оставляя его там храниться (retain: 'yes'), чтобы наш виртуальный термодатчик всегда смог прочитать оттуда это значение и сообщить контроллеру котла, что, мол, контролируемая температура такая-то.

Но это еще не всё...

Этап 3. Управляем кранами

Текст стал настолько длинным, что некоторые, возможно, успели подзабыть, о каких кранах идёт речь. А речь идёт о том, что на выходе из котла отопления эта самая выходящая (или в терминологии профильных специалистов - подающая) линия разветвляется на несколько контуров (например, батареи 1-го этажа, 2-го этажа и 3-го этажа), и после разветвления на линии каждого контура стоит кран, который имеет два положения - открыт или закрыт. Если кран открыт, то теплоноситель (вода или что там у вас залито в систему - антифриз, тосол, рыбий жир, томатный сок, лимонад "Буратино") попадает в контур, прогревает его батареи и охлажденный возвращается в котёл для нового подогрева. Если кран закрыт, то в контур вода не поступает, и его батареи начинают потихоньку охлаждаться. Вместе с ними охлаждается и воздух в помещении, обслуживаемом контуром, термометр в помещении начинает выдавать все более низкое начение температуры и т.д., и т.п.

О "физике" кранов я говорить не буду.  Краны бывают разные.  Есть электроприводы, непосредственно крутящие шаровую заслонку, а есть приводы, крутящие ручку обычного крана. Есть приводы, работающие на постоянном токе напряжением 12 вольт (и направление их работы - на открытие или на закрытие - обеспечивается сменой полярности подаваемого питания), а есть и работающие от бытовой сети переменного тока 230 вольт (да-да, не 220, а 230 - читайте новые стандарты) - и они управляются попеременной подачей "фазы" то на один контакт, то на другой, при условии, что на третий контакт всё время подается "ноль".

Для управления такими кранами можно использовать как "полуготовый" контроллер (например, Sonoff 4CH), так и самодельное (и более дешёвое) решение - например, на плате NodeMCU с прошивкой Tasmota в совокупности с блоком реле. В "особо тяжёлых" случаях иногда приходится ставить еще и дополнительные (промежуточные) реле - например, типа РЭК77 или РЭК78. Эти реле коммутируют (в зависимости от конкретной модели) от двух до четырех наборов "сухих" перекидных контактов, что позволяет (на нашем примере) одновременно с переключением электроприводного крана задействовать еще какие-то функции. Ну, не знаю - может лампочку включать во время перекладки крана. Или сирену. Или насос прокачки, если он имеется во включаемом контуре. Если у вас краны со сменой полярности, то без такого промежуточного реле вы точно не обойдётесь.

В-общем, не буду здесь описывать реализацию контроллера управления кранами. Скажу только то, что в итоге мы должны создать в Home Assistant'е  несколько (по числу контуров отопления - в нашем случае это 3) объектов типа switch (а с точки зрения Tasmota, если вы будете использовать эту прошивку, это будут объекты типа Relay). Назовем их, например,  так:

  • switch.vcran_3
  • switch.vcran_2
  • switch.vcran_1

Например, если мы хотим открыть кран контура 1-го этажа, то присваиваем переключателю switch.vcran_1 значение on. А если надо закрыть кран 3-го тажа, то переключателю switch.vcran_3 присваиваем значение off.  И так далее.

Осталось решить довольно сложную задачу - создать логику открытия и закрытия трёх кранов в зависимости от потребностей того или иного этажа в обогреве. Плюс еще учесть маленький, но очень важный момент - в любой произвольный момент времени должен быть открыт хотя бы один кран. Для чего? Да чисто из соображений безопасности - чтобы не "запирать" котел и его насос, оставляя ему выход для прокачивания воды.

Для удобства создадим в Home Assistant'е еще несколько (в нашем случае - снова три) бинарных сенсора, основанных на шаблонах. Каждый сенсор может принимать значение 1 (true) или 0 (false)  в зависимости от того, нуждается ли закрепленный за ним контур (этаж) в отоплении в данный момент. Сама эта "нуждаемость" вычисляется простой разницей температур - заданной и текущей. Если текущая меньше заданной, то топить нужно, если равна или больше - то не нужно:

binary_sensor:
  - platform: template
    sensors:
      need_to_heat_3:
        friendly_name: "3-й этаж нуждается в обогреве"
        value_template: "{{ (states('sensor.mh_virt_temp_target_temperature')|float - states('sensor.fake_temp_3')|float)|float > 0 }}"
      need_to_heat_2:
        friendly_name: "2-й этаж нуждается в обогреве"
        value_template: "{{ (states('sensor.mh_virt_temp_target_temperature')|float - states('sensor.fake_temp_2')|float)|float > 0 }}"
      need_to_heat_1:
        friendly_name: "1-й этаж нуждается в обогреве"
        value_template: "{{ (states('sensor.mh_virt_temp_target_temperature')|float - states('sensor.fake_temp_1')|float)|float > 0 }}"

Ещё нам понадобится создать три группы , в каждую из которых мы включим по два вышеупомянутых бинарных сенсора:

group:
 need_to_heat_12:
    name: 'Потребность в отоплении 12'
    entities:
      - input_boolean.vcran_1  
      - input_boolean.vcran_2 
  need_to_heat_13:
    name: 'Потребность в отоплении 13'
    entities:
      - input_boolean.vcran_1  
      - input_boolean.vcran_3
  need_to_heat_23:
    name: 'Потребность в отоплении 23'
    entities:
      - input_boolean.vcran_2 
      - input_boolean.vcran_3

Как видим выше, в каждой группе "не хватает" по одному из трёх сенсоров. Особенность группы состот в том, что она принимает значение 1 (true), если хотя бы один из входящих в неё сенсоров имеет значение 1, и принимает значение 0, если значение 0 имеют все входящие в неё сенсоры. С помощью этих групп мы будем перед закрытием каждого крана проверять, не является ли он последним открытым краном. И если так, то мы не будем его закрывать.

Пишем сразу 3 (три) однотипных автоматизации для управления каждым из трёх кранов. Пояснения я помещу прямо в текст автоматизации (пример для крана 1 этажа):

alias: 'Автоотопление: переключение крана 1 этажа'
description: ''
trigger: 
# Триггерами у нас являются переходы виртуального сенсора "1-й этаж нуждается в обогреве"
# из состояния "вкл" в состояние "выкл" и обратно 
  - platform: state
    entity_id: binary_sensor.need_to_heat_1
# чисто в целях отладки я указал здесь таймаут в 1 секунду.
# на практике рекомендуется указывать время, на 3-5 секунд превышающее 
# засечённое секундомером время полной перекладки электропривода крана (обычно порядка 15-20 секунд)
    for: '00:00:01'
    to: 'off'
    from: 'on'
  - platform: state
    entity_id: binary_sensor.need_to_heat_1
    for: '00:00:01'
    to: 'on'
    from: 'off'
condition: []
action:
# тут у нас будут варианты
  - choose:
# вариант 1. 
# условие   
      - conditions:
          - condition: state
# если 1-й этаж нуждается в обогреве           
            entity_id: binary_sensor.need_to_heat_1
            state: 'on'
            for: '00:00:01'
# то выполняем следующие действия            
        sequence:
# вызываем службу "включить переключатель"        
          - service: switch.turn_on
            data: {}
# для крана 1-го этажа (то есть, открываем кран)            
            entity_id: switch.vcran_1
# после этого проверяем еще одно условие             
          - condition: state
# нуждается ли 2-й этаж в данное время в обогреве?          
            entity_id: binary_sensor.need_to_heat_2
            state: 'off'
            for: '00:00:01'
# и если не нуждается, то закрываем кран 2-го этажа
# (даже если он и был уже закрыт, то от повторного закрытия хуже не станет)
          - service: switch.turn_off
            data: {}
            entity_id: switch.vcran_2
# аналогично проверяем 3-й этаж и при необходимости закрыаем его кран            
          - condition: state
            entity_id: binary_sensor.need_to_heat_3
            state: 'off'
            for: '00:00:01'
          - service: input_boolean.turn_off
            data: {}
            entity_id: input_boolean.vcran_3
# а вот и 2 вариант            
      - conditions:
# его условие - 1-й этаж НЕ нуждается в обогреве      
          - condition: state
            entity_id: binary_sensor.need_to_heat_1
            state: 'off'
            for: '00:00:01'
# мы не можем закрыть ПОСЛЕДНИЙ кран - надо котлу оставить хотя бы один открытый
# поэтому мы проверяем, нуждается ли в отоплении хотя бы какой-то из оставшихся
# этажей (2-й и/или 3-й). И если да (т.е., какой-то из оставшихся кранов открыт)
          - condition: state
            entity_id: group.need_to_heat_23
            state: 'on'
            for: '00:00:01'
# то смело закрываем кран 1-го этажа в уверенности, что котел не лопнет            
        sequence:
          - service: switch.turn_off
            data: {}
            entity_id: switch.vcran_1
    default: []
mode: single

Автоматизации для кранов 2-го и 3-го этажа создаём методом "копипаста", заменив нужные цифры в именах объектов.

Вот, собственно говоря, и всё. Буду признателен, если кто-то найдёт ошибки (в том числе, ошибки логики самого решения) и укажет на них, а также предложит как-то оптимизировать это решение (я и сам вижу. что развёл тут "виртуальнно-шаблонных" объектов в непотребном количестве - наверное, можно часть из них как-то сократить).

Подводя итог, ещё раз попробую изложить "на пальцах" логику работы.

Примем за исходное следующее состояние - все этажи прогреты до заданных температур, виртуальный термодатчик контроллера показывает, что текущая температура не ниже заданной, котел не топит, один или несколько кранов контуров открыты.

Если какой-то (N-ый) этаж остывает ниже заданной температуры, то происходит следующее:

  1. Термодатчик N-го этажа начинает выдавать температуру ниже заданной.
  2. N-ый этаж получает статус "нуждается в обогреве".
  3. Вычисленное значение виртуальной (фейковой) температуры N-го этажа объявляется минимальной виртуальной температурой среди всех этажей и передается в MQTT-брокер.
  4. Виртуальный термодатчик контроллера котла получает значение температуры из MQTT-брокера.
  5. Контроллер понимает, что текущая температура опустилась ниже заданной и включает "топку" котла.
  6. Так как N-й этаж имеет статус "нуждается в обогреве" (см. п. 2 выше), то открывается кран его контура, и этаж начинает обогреваться.

Вся остальная логика рассчитана на ситуации, когда в обогреве одновременно нуждается больше одного этажа.

Вот теперь всё. Спасибо всем, кто смог дочитать до конца.


Все новости мира умных домов - t.me/SprutAI_News или Instagram
Остались вопросы? Мы в Telegram - @SprutAI

Хочешь умный дом но нет времени разбираться?
Посмотри примеры работ и выбери себе интегратора.
К списку блогов

Скидки для сообщества

Z-Wave Ukraine

+380 68 641 9670
Промокод:
Sprut-UA
Размер скидки:
15%

Тематические чаты

Похожие записи

12 сентября 2020, 20:51
Создание при помощи бесплатной программы Sweet Home 3D интерактивного плана помещения для Home Assistant.
16 июля 2020, 15:13
Удобная настройка Home Assistant с помощью packages.
20 января 2019, 17:39
Создание очень бюджетной автоматизации рулонных штор
13 февраля 2019, 22:00
Подключение радио на Xiaomi Gateway к Home Assistant c дальнейшим использованием в автоматизациях
19 апреля 2019, 20:53
Требуется ваше мнение!
06 февраля 2019, 12:02
Автоматизированное открытие/закрытие окна
31 марта 2019, 11:37
Нативный HomeKit датчик температуры и влажности своими руками самый бюджетный вариант.
04 апреля 2019, 12:45
Самое важное из апдейта Home Assistant 0.91-0.91.4 от 03.04.19.
21 марта 2019, 11:59
Самое важное из апдейта Home Assistant 0.9 от 20.03.19.