После приобретения пылесоса 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.Примечание: для понимания структуры папок и файлов в НА привожу пример конфигурации как сделано у меня.
# 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/automationtemplate: !include_dir_merge_list includes/templates
Сначала я так же, как в упомянутой статье, создал для каждой комнаты input boolean, и объединил их в группу:
#input_boolean.yamlis_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
Затем создал два сенсора
#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:
# Автоматизация# 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.yamlmark_unmark_selected_rooms_in_the_list:
alias: Отметить/снять отметку выбранных комнат
sequence:
- service: input_boolean.toggle
target:
entity_id: input_boolean.{{ bool_name }}
А дальше, собственно, сама автоматизация включения пылесоса по кнопке Начать уборку
# Автоматизация#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.yamlmessage_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.yamlzone_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-пусто
Собственно, этого кода достаточно для выполнения поставленной задачи. Вынесение некоторых операций в отдельные скрипты оправдано тем, что я их переиспользую в других задачах (уборка по расписанию, уборка по кнопке из браузера и тп.), ничего не мешает их встроить в автоматизации. Листинг некоторых скриптов я не показал, так как они решают задачи выходящие за рамки данной статьи. Если интересно, расскажу о них в следующих статьях.
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]]}"'
Почему-то скрипт подставляет одинарные кавычки. Как от них можно избавиться? Спасибо