Блог

EBUS-контроллер котла My Heat. Интеграция в Home Assistant (часть 2)

В первой части этого блога я рассказывал о приобретении контроллера My Heat Smart, который управляет котлом отопления по шине EBUS, и которым неплохо было бы научиться управлять из-под Home Assistant'а, благо, что от производителя имеется какое-никаке описание функций API (вернее, не "какое-никакое описание", а "какого-никакого API", поскольку функционал этого API весьма беден).

Итак, первое, что нам для работы нужно получить от контроллера - это его идентификатор. Напомню, что "облачный" сервис My Heat запросы типа POST в формате JSON, а затем возвращает ответ - также в формате JSON. Запрос должен в обязательном порядке включать в себя логин облачного клиента и его пароль ключ API, который нужно предварительно получить, зайдя в веб-интерфейс администрирования:

Чтобы получить список контроллеров, закрепленных на нашим логином, мы посылаем на адреc "https://my2.myheat.net/api/request/" вот такой запрос обратите внимание - здесь и далее логин и ключ API указаны из примеров в документации, предоставленной производителем. Я лично проверял - на практике они не работают.

{ "action":"getDevices", "login":"lenino", "key":"f11f45d5-5e3a827467cd14-02276894" }

В ответ мы должны получить нечто вроде этого (снова пример из документации):

{ "data":{ "devices":[ { "id":12, "name":"У Моста", "city":"Новошешминск", "severity":1, "severityDesc":"Система работает нормально." }, { "id":10, "name":"Хорошее место", "city":"Новошешминск", "severity":1, "severityDesc":"Система работает нормально." } ] }, "err":0, "refreshPage":false }

А теперь попробуем реализовать этот запрос с помощью механизмов Home Assistant'а. Для этого создадим (ручками, ручками) сенсор типа "REST". Вот такой:

sensor: - platform: rest name: "mh_getdevices" resource: https://my2.myheat.net/api/request/ method: POST json_attributes_path: "$.data" json_attributes: - devices headers: Content-type: "application/json" Accept: "text/plain" Content-Encoding: "utf-8" payload: '{"action":"getDevices","login":"mylogin","key":"xxxxxxxx-yyyyyyyyyyyyyyyy-zzzzzzzz"}' verify_ssl: false value_template: '{{ value_json.err == 0 }}'

В интерфейсе Home Assistant'а идем в "Панель разработчика", на закладке "Состояния" вбиваем в поле объект: sensor.mh_getdevices, и в поле атрибутов видим следующее:

devices: - id: 12 name: У моста city: Новошешминск severity: 1 severityDesc: Система работает нормально. - id: 10 name: Хорошее место city: Новошешминск severity: 1 severityDesc: Система работает нормально. friendly_name: mh_getdevices

Следующий этап: получение информации об устройствах, "прицепленных" к контроллеру. Сразу оговорюсь - для каждого контроллера придется создавать свой отдельный сенсор, указывая в запросе идентификатор нужного нам контроллера. Приведенный ниже пример показывает процесс получения данных для контроллера с идентификатором 12 (id = 12). Сначала текст в POST-запросе, как рекомендует нам документация по API. Обратите внимание: Значение идентификатора контроллера указывается явным образом ("deviceId":12):

{ "action":"getDeviceInfo", "deviceId":12, "login":"lenino", "key":"f11f45d5-5e3a827467cd14-02276894" }

Получаем ответ:

{ "data":{ "heaters":[ { "id":13, "name":"Vaillant правый", "disabled":false, "flowTemp":56, "returnTemp":56, "pressure":2.223, "targetTemp":0, "burnerHeating":false, "burnerWater":false, "modulation":0 }, { "id":37, "name":"Vaillant левый", "disabled":false, "flowTemp":56, "returnTemp":57, "pressure":2.436, "targetTemp":0, "burnerHeating":false, "burnerWater":false, "modulation":0 } ], "envs":[ { "id":21, "type":"boiler_temperature", "name":"Бойлер", "value":46.687, "target":45, "demand":false, "severity":1, "severityDesc":"Нормальное состояние." }, { "id":22, "type":"room_temperature", "name":"Кафе", "value":24.812, "target":23, "demand":false, "severity":1, "severityDesc":"Нормальное состояние." }, { "id":24, "type":"circuit_temperature", "name":"Контур отопления", "value":56, "target":null, "demand":false, "severity":1, "severityDesc":"Нормальное состояние." }, { "id":23, "type":"room_temperature", "name":"Магазин", "value":24.187, "target":23, "demand":false, "severity":1, "severityDesc":"Нормальное состояние." }, { "id":20, "type":"room_temperature", "name":"Бухгалтерия", "value":29.812, "target":null, "demand":false, "severity":1, "severityDesc":"Нормальное состояние." }, { "id":19, "type":"room_temperature", "name":"Котельная", "value":27.25, "target":null, "demand":false, "severity":1, "severityDesc":"Нормальное состояние." } ], "engs":[ { "id":40, "type":"pump", "name":"Насос магазин", "turnedOn":false, "severity":1, "severityDesc":"Насос работает исправно." }, { "id":41, "type":"pump", "name":"Насос бойлер", "turnedOn":false, "severity":1, "severityDesc":"Насос работает исправно." }, { "id":38, "type":"pump", "name":"Насос кафе", "turnedOn":false, "severity":1, "severityDesc":"Насос работает исправно." }, { "id":39, "type":"pump", "name":"Насос бухгалтерия", "turnedOn":false, "severity":1, "severityDesc":"Насос работает исправно." } ], "alarms":{ }, "dataActual":true, "severity":1, "severityDesc":"Система работает нормально.", "weatherTemp":"-6.78999999999996", "city":"Новошешминск" }, "err":0, "refreshPage":false }

Реализация сенсора в Home Assistant'е. Текст сенсора:

- platform: rest name: "mh_getdeviceinfo" resource: https://my2.myheat.net/api/request/ method: POST json_attributes_path: "$.data" json_attributes: - heaters - envs - engs - alarms - dataActual - severity - severityDesc - weatherTemp - city headers: Content-type: "application/json" Accept: "text/plain" Content-Encoding: "utf-8" payload: '{"action":"getDeviceInfo","deviceId":"12","login":"mylogin","key":"xxxxxxxx-yyyyyyyyyyyyyy-zzzzzzzz"}' verify_ssl: false value_template: '{{ value_json.err == 0 }}'

Значение (состояние) сенсора:

heaters: - id: 13, name: Vaillant правый disabled: false, flowTemp: 56, returnTemp: 56, pressure: 2.223, targetTemp: 0, burnerHeating: false, burnerWater: false, modulation: 0 - id: 37, name: Vaillant левый disabled: false, flowTemp: 56, returnTemp: 57, pressure: 2.436, targetTemp: 0, burnerHeating: false, burnerWater: false, modulation: 0 envs: - id: 21, type: boiler_temperature name: Бойлер value: 46.687, target: 45, demand: false, severity: 1, severityDesc: Нормальное состояние. - id: 22, type: room_temperature name: Кафе value: 24.812, target: 23, demand: false, severity: 1, severityDesc: Нормальное состояние. - id: 24, type: circuit_temperature name: Контур отопления value: 56, target: null, demand: false, severity: 1, severityDesc: Нормальное состояние. - id: 23, type: room_temperature name: Магазин value: 24.187, target: 23, demand: false, severity: 1, severityDesc: Нормальное состояние. - id: 20, type: room_temperature name: Бухгалтерия value: 29.812, target: null, demand: false, severity: 1, severityDesc: Нормальное состояние. - id: 19, type: room_temperature name: Котельная value: 27.25, target: null, demand: false, severity: 1, severityDesc: Нормальное состояние. engs: - id: 40, type: pump name: Насос магазин turnedOn: false, severity: 1, severityDesc: Насос работает исправно. - id: 41, type: pump name: Насос бойлер turnedOn: false, severity: 1, severityDesc: Насос работает исправно. - id: 38, type: pump name: Насос кафе turnedOn: false, severity: 1, severityDesc: Насос работает исправно. - id: 39, type: pump name: Насос бухгалтерия turnedOn: false, severity: 1, severityDesc: Насос работает исправно. alarms: [] dataActual: true, severity: 1, severityDesc: Система работает нормально. weatherTemp: -6.78999999999996 city: Новошешминск

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

Например, сенсор для получения местоположения (населенного пункта) установки контроллера с идентификатором 12

- platform: template sensors: mh_city: friendly_name: "Местоположение" value_template: "{{ (state_attr('sensor.mh_getdevices', 'devices')|selectattr('id','eq',12)|first).city }}"

Сенсор для получения температуры подачи отопительного котла с идентификатором 13:

- platform: template sensors: mh_heater_flow_temperature: friendly_name: "Температура подачи" unit_of_measurement: "°С" value_template: "{{ (state_attr('sensor.mh_getdeviceinfo', 'heaters')|selectattr('id','eq',13)|first).flowTemp | round(2) }}"

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

Хочется выразить благодарность коллегам 470258 и a005 с форума 4пда за неоценимую помощь в грамотном написании сенсоров.

P.S. Описанный здесь способ взаимодействия Home Assistant'а с контроллером My Heat весьма далёк от совершенства.

В частности, мне пока не удалось решить следующие вопросы:

  • Как избежать явного указания логина и ключа API в тексте сенсоров? Я хотел их заменить на подставные переменные, но у меня не получилось.
  • Идентификаторы устройств и объектов назначаются облачным софтом без вашего участия. Вы создаете объект, а идентификатор ему присваивается автоматически. Более того - если вы удалите объект, а затем создатите точно такой же вместо него - с тем же именем и теми же параметрами - его идентификатор будет уже другой, и вам придется переписывать значения в файле конфигурации сенсоров.
  • Все взаимодействие основано на указании в запросах (читай - в конфигурации сенсоров) конкретных идентификаторов. Было бы очень здорово каким-то образом полученные по запросу getDevices идентификаторы контроллеров автоматически использовать в запросах getDeviceInfo, затем полученные идентификаторы объектов группировать по типам оборудования и в конце концов получать сформированный автоматически набор "конечных" сенсоров для использования в интерфейсах Home Assistant'а. Чутьё мне подсказывает, что надо каким-то образом JSON-отклики "облака" пересылать на MQTT, а там уже реализовывать (опять же - непонятно, каким образом) механизм "discovery".

В-общем, моих знаний для решения вышеуказанных вопросов, пока маловато. Буду признателен, если кто-то изложит подсказки в комментариях. Спасибо!

0

Вернуться назад
Вернуться назад