Статья

Управление пылесосом Xiaomi Robot Vacuum-Mop 2C из telegram_bot через Home Assistant

После приобретения пылесоса Xiaomi Robot Vacuum MOP C2 Robot Cleaner оказалось, что он произведен для региона Сингапур. Отказался регистрироваться в приложении Mi Home в регионах Китай и Россия. Что, собственно, меня не очень устроило. Пользоваться кнопками на корпусе пылесоса тоже не очень интересно, тем более, что поселили мы его под шкафом. Сами понимаете, что залазить под шкаф для активации уборки не очень удобно. В итоге решил поискать возможности интеграции данного пылесоса в систему, уже имеющегося у меня "умного дома" на базе Home Assistant (НА). НА у меня уже около года, начал использовать его после того, как перестали приходить уведомления от датчиков протечки Aqara в Mi Home. Вернее приходить как им вздумается. Поиски решения этой проблемы привели меня к локальной системе управления умного дома. Выбор пал на НА, потому что прочитал, что есть кастомная интеграция Xiaomi Gateway 3 for Home Assistant для которой не нужно перепрошивать хаб Xiaomi Gateway (EU).  Но и управлять пылесосом только из интерфейса НА мне тоже не очень хотелось, поэтому решил для управления использовать telegram_bot Home Assistant.   

Задача поставлена - организовать основные кнопки управления в telegram (старт, стоп, пауза) и, раз уж пылесос может строить карты, сделать выбор помещений для уборки. Для подключения пылесоса к НА использовал  интеграцию Xiaomi Miot For HomeAssistant. Подключить его не составило труда, в итоге стало доступно 1 устройство (собственно сам пылесос) и 10 объектов (сенсоров). По поиску в гугле пришел на статью Аз Алексея (AlexAz),где как раз было написано как подключить пылесос и, главное, как сделать автоматизацию зональной уборки с выбором помещений. Опыт написания конфигов в yaml у меня не большой, поэтому изначально взяв примеры из статьи, я их адаптировал к моей задаче, управлению уборкой через telegram.Примечание: для понимания структуры папок и файлов в НА привожу пример конфигурации как сделано у меня.    

yaml
Копировать
# configuration.yaml

# Вынос в файлы scene: !include scenes.yaml telegram_bot: !include includes/telegram.yaml notify: !include includes/notify.yaml input_number: !include includes/input_number.yaml input_text: !include includes/input_text.yaml input_datetime: !include includes/input_datetime.yaml input_boolean: !include includes/input_boolean.yaml group: !include includes/groups.yaml # Вынос во внешние папки script: !include_dir_merge_named includes/script sensor: !include_dir_merge_list includes/sensor automation: !include_dir_merge_list includes/automation
template: !include_dir_merge_list includes/templates

Сначала я так же, как в упомянутой статье, создал для каждой комнаты input boolean, и объединил их в группу:

yaml
Копировать
#input_boolean.yaml
is_bedroom_vacuum_manual:
name: manual cleaning the bedroom with a vacuum cleaner initial: false is_hallway_vacuum_manual: name: manual cleaning the hallway with a vacuum cleaner initial: false is_childrensroom_vacuum_manual: name: manual cleaning the childrensroom with a vacuum cleaner initial: false is_kitchen_vacuum_manual: name: manual cleaning the kitchen with a vacuum cleaner initial: false

# Флаг активного задания на уборку помещений
is_started_manual_zone_cleaning_vacuum:
name: started manual cleaning the vacuum cleaner initial: false

#grousp.yaml
# Группа для немедленной уборки по кнопке в телеграм
all_rooms_for_manual_vacuum_clean:
name: All rooms for manual vacuum clean entities: - input_boolean.is_kitchen_vacuum_manual - input_boolean.is_hallway_vacuum_manual - input_boolean.is_bedroom_vacuum_manual - input_boolean.is_childrensroom_vacuum_manual

Затем создал два сенсора

yaml
Копировать
#vacuum_sensor.yaml
- sensor:
- name: "select_rooms_for_manual_clean" unique_id: "Выбранные комнаты для ручной уборки пылесосом, скрипт" state: > {%- set dfg = expand('group.all_rooms_for_manual_vacuum_clean') | selectattr('state', 'eq', 'on') | map(attribute='entity_id') | list | join(',') | replace('input_boolean.is_hallway_vacuum_manual','[1,1,1,0,1]') | replace('input_boolean.is_childrensroom_vacuum_manual','[2,1,1,0,1]') | replace('input_boolean.is_kitchen_vacuum_manual','[3,1,1,0,1]') | replace('input_boolean.is_bedroom_vacuum_manual','[4,1,1,0,1]') %} {{dfg}} - name: "select_friendly_name_rooms_for_manual_clean" unique_id: "Выбранные комнаты для ручной уборки пылесосом, дисплей" state: > {%- set dfg = expand('group.all_rooms_for_manual_vacuum_clean') | selectattr('state', 'eq', 'on') | map(attribute='entity_id') | list | join(', ') | replace('input_boolean.is_hallway_vacuum_manual','Прихожая') | replace('input_boolean.is_childrensroom_vacuum_manual','Детская') | replace('input_boolean.is_kitchen_vacuum_manual','Кухня') | replace('input_boolean.is_bedroom_vacuum_manual','Спальня') %} [ {{ dfg }} ]

Написал автоматизацию выбора помещений для уборки в telegram:

yaml
Копировать
# Автоматизация
# vacuum_poll_list_rooms.yaml

- id: Клавиатура выбора помещений для ручной зональной уборки alias: ctrl_panels_rooms_4_manual_zone_cleaning_vacuum initial_state: true trigger: - platform: event event_type: telegram_callback event_data: data: '/roomCleaning' action: - service: telegram_bot.send_message data_template: message_id: 'last' chat_id: '{{ trigger.event.data.chat_id }}' title: '{{ "\U0001F916" }} Робот пылесос сообщает:' data: message: | - Выберите помещения для зональной уборки: inline_keyboard: &ctrlBtnRooms [ [ ["{{ '☑️' if bool(states('input_boolean.is_kitchen_vacuum_manual'), false) else '⬜️' }} Кухня", "/rooms is_kitchen_vacuum_manual"], ["{{ '☑️' if bool(states('input_boolean.is_hallway_vacuum_manual'), false) else '⬜️' }} Прихожая", "/rooms is_hallway_vacuum_manual"] ], [ ["{{ '☑️' if bool(states('input_boolean.is_bedroom_vacuum_manual'), false) else '⬜️' }} Спальня", "/rooms is_bedroom_vacuum_manual"], ["{{ '☑️' if bool(states('input_boolean.is_childrensroom_vacuum_manual'), false) else '⬜️' }} Детская", "/rooms is_childrensroom_vacuum_manual"] ], [ ["️ Начать уборку", "/startManualClean"] ], [ ["{{ '\U0001F916' }} Управ. пылесосом", "/controlPanelVacuum"], ["{{ '\u21a9\ufe0f' }} Глав. панель управ.", "/start"] ] ] - id: Клавиатура отметки выбора помещений для ручной зональной уборки alias: ctrl_panels_ONOFF_rooms_4_manual_zone_cleaning_vacuum initial_state: true trigger: - platform: event event_type: telegram_callback event_data: command: '/rooms' action: - service: script.mark_unmark_selected_rooms_in_the_list data: bool_name: "{{ trigger.event.data['args'][0] }}" - service: telegram_bot.edit_replymarkup data: message_id: 'last' chat_id: '{{ trigger.event.data.chat_id }}' inline_keyboard: *ctrlBtnRooms
# Скрипт
# script_poll_list_rooms.yaml
mark_unmark_selected_rooms_in_the_list:
alias: Отметить/снять отметку выбранных комнат sequence: - service: input_boolean.toggle target: entity_id: input_boolean.{{ bool_name }}
Вот так это выглядит в telegram

А дальше, собственно, сама автоматизация включения пылесоса по кнопке Начать уборку

yaml
Копировать
# Автоматизация
#vacuum_zone_clean_teleg.yaml
- id: Запуск зональной уборки робота пылесоса из телеграм alias: manual_zone_cleaning_start_vacuum_cleaner initial_state: true trigger: - platform: event event_type: telegram_callback event_data: data: '/startManualClean' condition: # Защита от повторного запуска, если is_started_..._cleaning_vacuum ON, старта не будет - condition: state entity_id: input_boolean.is_started_manual_zone_cleaning_vacuum state: "off" action: - service: script.turn_on target: entity_id: > {%- if not bool(states('group.all_rooms_for_manual_vacuum_clean'), false) %} script.message_about_uncomplete_task {%- else %} script.zone_autostart_and_message_complete_task {%- endif %} data: variables: > {%- if not bool(states('group.all_rooms_for_manual_vacuum_clean'), false) %} { "command": "Начать уборку помещений немедленно", "valid_state": "Выбрано одно или несколько помещений для уборки", "current_state": "Нет выбранных помещений", "joke": "А счастье было так близко... :=)" } {%- else %} { "type_clean": "ручная", "friendly_name_rooms": "{{states('sensor.select_friendly_name_rooms_for_manual_clean')}}", "bool_name": "is_started_manual_zone_cleaning_vacuum", "select_rooms": "{{ states('sensor.select_rooms_for_manual_clean') }}" } {%- endif %}

# Скрипты
# script_alert_fail_task.yaml
message_about_uncomplete_task: alias: Сообщение о невозможности выполнить задание sequence: - service: telegram_bot.send_message data: message: | {{"\U0001F916"}} Робот пылесос сообщает: - Я не могу выполнить команду! - Для команды [ {{ command }} ] я должен быть в состоянии: [ {{ valid_state }} ] - А я сейчас в состоянии: [ {{ current_state }} ] ================= - {{ joke }} [ {{ states('sensor.time_date') }} ] inline_keyboard: - '{{ "\U0001F52E" }} Узнать как дела у пылесоса:/reportStateVacuum' - '{{ "\U0001F916" }} Панель управления пылесосом:/controlPanelVacuum'

# script_zone_clean.yaml
zone_autostart_and_message_complete_task: alias: Сообщение о запуске автостарта зональной уборки sequence: - service: telegram_bot.send_message data: message: | {{ "\U0001F916" }} Робот пылесос сообщает: Внимание, через 10 секунд начинается {{ type_clean }} зональная уборка. Убедитесь, что помещения {{ friendly_name_rooms }} готовы к моей работе. При необходимости завершите уборку вручную. Для этого зайдите в Панель управления пылесосом и нажмите кнопку Стоп ⏹️. [ {{ states('sensor.time_date') }} ] inline_keyboard: - '{{ "\U0001F52E" }} Узнать как дела у Чудика:/reportStateVacuum' - '{{ "\U0001F916" }} Панель управления пылесосом:/controlPanelVacuum' - delay: 00:00:10 - service: script.turn_on target: entity_id: script.start_zone_cleaning_robot_vacuum_cleaner data: variables: rooms_list: "{{ select_rooms }}" # Включение булевой переменной начала зональной автоуборки - service: input_boolean.turn_on target: entity_id: input_boolean.{{ bool_name }}

start_zone_cleaning_robot_vacuum_cleaner: alias: Старт зональной уборки sequence: - service: xiaomi_miot.call_action data: entity_id: vacuum.dreame_md1808_8c1e_robot_cleaner #Здесь должен быть id пылесоса siid: 18 aiid: 1 params: >- [ { "piid": 1, "value": 18 }, { "piid": 21, "value": "{\"selects\":[{{ rooms_list }}]}" } ] force_params: true # Включение автоматизации отчета о результатах уборки last_data_status_vacuum_cleaner - service: automation.turn_on entity_id: automation.last_data_status_vacuum_cleaner mode: single
# Разбор строки по позициям цифр # '{ "selects":[[3,1,1,0,1]] }' [1]3-ном.ком.,[2]1-пусто,[3]1-сила всасывания(0-3),[4]0-сила полива(0-3),[5]1-пусто
Пример вывода сообщения в telegram о начале уборки
Пример вывода сообщения о невозможности начать уборку

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


Не подскажите по скриптам? Я делаю уборку по комнатам и столкнулся с проблемой написания скрипта.
params:
- piid: 1
value: 18
- piid: 21
value: >-
{% set ids = [] %} {% if is_state('input_boolean.kitchen_vacuum',
'on') %} {% set ids = ids + [[5,1,1,2,1]] %} {% endif %} {% if
is_state('input_boolean.prihojaya_vacuum', 'on') %} {% set ids = ids +
[[3,1,1,2,1]] %} {% endif %} {% if
is_state('input_boolean.koridor_vacuum', 'on') %} {% set ids = ids +
[[8,1,1,2,1]] %} {% endif %} {% if
is_state('input_boolean.myroom_vacuum', 'on') %} {% set ids = ids +
[[1,1,1,2,1]] %} {% endif %} {% if
is_state('input_boolean.spalnya_vacuum', 'on') %} {% set ids = ids +
[[4,1,1,2,1]] %} {% endif %} {% if is_state('input_boolean.zal_vacuum',
'on') %} {% set ids = ids + [[2,1,1,2,1]] %} {% endif %} {% if
is_state('input_boolean.tiolet_vacuum', 'on') %} {% set ids = ids +
[[7,1,1,2,1]] %} {% endif %} {% if
is_state('input_boolean.bathroom_vacuum', 'on') %} {% set ids = ids +
[[6,1,1,2,1]] %} {% endif %} "{\"selects\":{{ ids }}}"
Вот таким скриптом я набиваю переменную ids значениями комнат которые будут убираться, а в трассировке потом получаю значение
value: '"{\"selects\":[[3, 1, 1, 2, 1], [8, 1, 1, 2, 1]]}"'
Почему-то скрипт подставляет одинарные кавычки. Как от них можно избавиться? Спасибо
Добрый вечер! Подскажите как вообще у вас дела с пылесосом, стоит заморачиваться?

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