Esse tutorial tem a ideia de mostrar como é feito a integração entre um ROBOCK XIAOMI dos modelos S4 a S7 + Node Red + Alexa Action.
Primeiro de tudo temos que ter seu Robock configurado no aplicativo oficial da Xiaomi.
PASSO 1
Integra-lo ao Home Assistant via Xiaomi Miio
OBS: O ponto aqui é configurar ele de forma manual, para que possamos extrair o mapa dele.
Usuário → E-mail do APP
Senha → Senha do APP
País → Entrar no link disponível no pop-up para ver o código do país. Caso esteja no Brasil o código é US
IP → IP do equipamento que está na sua rede 162.168.X.X
Token da API → Seguir o passo a passo do link do Pop-up ou acessar esse repositório que tem um executável para gerar o Token API.
OBS: Salve o seu token pois vamos utilizar ele em outro momento.
PASSO 2
Instalar o Map extractor via HACS para o home assistant ter acesso ao mapa do RoboRock.
repositório do Map Extractor
Abrir seu arquivo configuration.yaml e adicionar uma câmera.
camera:
- platform: xiaomi_cloud_map_extractor
host: !secret xiaomi_vacuum_host
token: !secret xiaomi_vacuum_token
username: !secret xiaomi_cloud_username
password: !secret xiaomi_cloud_password
draw: ['all']
attributes:
- calibration_points
OBS: Lembra do token que salvamos no passo anterior?
O meu está extenso pois eu li toda a documentação e apliquei de acordo com as minhas necessidades.
Para mais informações aqui está o repositório
Realizar um restart no home assistant:
Criar um painel com a câmera xiaomi_cloud_map_extractor:
Pronto passo 2 finalizado.
Passo 3
Mapeando sua residência:
Para mapear a sua residência primeiro faça o RoboRock (Na minha casa eu coloquei o apelido de Judite, para casos futuros vou colocar Judite… rs)
Depois que a Judite fez o mapeando da sua casa, a câmera vai estar com todos os cômodos.
Edite sua câmera e coloque a flag DEBUG: true e salve as alterações.
Clique no ícone de +, e redimensione para a área de limpeza e clique no Play, isso fara um alerta com as coordenadas do seu cômodo.
Os dados do JSON que nos importa é o ZONE.
Salve todos as “zonas” em algum lugar.
Pronto passo 3 finalizado.
Passo 4
Melhorando sua SKILL no Alexa Action:
Não vou postar toda minha skill aqui, pois estou criando ela para fins comerciais.
A ideia é que você acione a Judite via alexa para limpar um cômodo X vezes.
Realizar integrações e customizações com a Alexa no Home Assistant as vezes é uma tarefa bem árdua.
Neste passo vamos evoluir a Alexa Actions que existe em muitos tutorias na internet.
Caso não tenha a skill Alexa Actions segue o link com um tutorial bem completo que tem no YouTube.
Para evoluir a skill recomendo ter uma noção de desenvolvimento e entendimento da biblioteca da Amazona Alexa.
Pré-requisito para essa integração:
Ter o Media Player Alexa
Links matérias de apoio para quem não tem nenhuma dessas integrações:
Continuando o passo a passo.
Abra seu Developer Console e vá até sua skill.
Vá até SlotTypes, e nesse passo é necessário criar 3 novos Slots.
Acao (Ação que a Judite irá realizar é o “Limpar” a única obrigatória no cadastro de vocês)
Modo de trabalho (Velocidade é tipo de limpeza que a Judite irá fazer)
Cômodo da Casa (Insira todos os cômodos da sua casa)
Clique em BUILD MODEL
Após a criação dos Slot Types, vamos criar uma intenção para a Alexa, ou seja, a frase que a Alexa irá interpretar ao acionarmos nossa Skill.
Para isso acesse o menu Interaction Model => Intents.
Crie uma intenção (Intents) chamado TextoComplexo
{Acao} {ComodoCasa} {Qtd} vez
{Acao} {ComodoCasa} no modo {ModoTrabalho} {Qtd} vez
{Acao} {ComodoCasa} no modo {ModoTrabalho} {Qtd} vezes
{Acao} {ComodoCasa} {Qtd} vezes
Clique em BUILD MODEL
Pronto agora vamos a parte da codificação, clique em CODE acesse o lambda_function.py
Insira a função abaixo:
class TextoComplexoHandler(AbstractRequestHandler):
"""Handler for TextoComplexo Intent."""
def can_handle(self, handler_input):
return (ask_utils.is_intent_name("TextoComplexo")(handler_input))
def handle(self, handler_input):
home_assistant_object = HomeAssistant(handler_input)
acao = home_assistant_object.get_value_for_slot("Acao")
comodo = home_assistant_object.get_value_for_slot("ComodoCasa")
qtd = ask_utils.get_slot_value(handler_input, "Qtd")
modotrabalho = ask_utils.get_slot_value(handler_input, "ModoTrabalho")
if modotrabalho:
selection = acao + "-" + comodo + "-" + qtd + "-" + modotrabalho
else:
selection = acao + "-" + comodo + "-" + qtd
if selection:
home_assistant_object.post_ha_event(selection, RESPONSE_SELECT)
data = handler_input.attributes_manager.request_attributes["_"]
speak_output = data[prompts.STOP_MESSAGE]
else:
raise
return (
handler_input.response_builder
.speak(speak_output)
.response
)
Adicione a linha no final do arquivo onde todas as intenções são acopladas na Skill.
sb.add_request_handler(TextoComplexoHandler())
UFA tamo quase lá bora passo 5.
Passo 5
Node Red
Aqui está meu Workflow, porém coloquei um pequeno cenário de template para importarmos no NodeRed e entendermos melhor o flow.
[{"id":"ce1025655096ab75","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"52716ff8f5b1c259","type":"switch","z":"ce1025655096ab75","name":"Tipo","property":"payload_acao_judite","propertyType":"msg","rules":[{"t":"eq","v":"Comodo1","vt":"str"},{"t":"eq","v":"Comodo2","vt":"str"},{"t":"eq","v":"Comodo3","vt":"str"},{"t":"eq","v":"Comodo4","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":810,"y":260,"wires":[["561df9f1affd233f"],["6d1b61c187ecc2fe"],["dc236d37e751e25a"],["03e5e7826cf774eb"]]},{"id":"af0293a2d46ecbf6","type":"function","z":"ce1025655096ab75","name":"","func":"const arrayMsg = msg.payload.event.event_response.split(\"-\");\nif (arrayMsg.length == 3){\n switch (arrayMsg[0]) {\n case \"Limpar\":\n msg.payload_acao_judite = arrayMsg[1];\n msg.payload_qtd_repeats_judite = parseInt(arrayMsg[2]);\n msg.payload_set_fan_speed = \"Silent\";\n break;\n default:\n }\n}\n\nif (arrayMsg.length == 4) {\n switch (arrayMsg[0]) {\n case \"Limpar\":\n msg.payload_acao_judite = arrayMsg[1];\n msg.payload_qtd_repeats_judite = parseInt(arrayMsg[2]);\n msg.payload_set_fan_speed = tratarMododeTrabalho(arrayMsg[3]);\n break;\n default:\n }\n}\n\n\nreturn msg;\n\n/**\n* @param {any} valor\n*/\nfunction tratarMododeTrabalho(valor){\n let retorno;\n switch (valor) {\n case \"passar pano\":\n retorno = \"Gentle\"\n break;\n case \"normal\":\n retorno = \"Standard\"\n break;\n case \"médio\":\n retorno = \"Medium\"\n break;\n case \"máximo\":\n retorno = \"Turbo\"\n break;\n default:\n retorno = \"Silent\"\n break;\n }\n\n return retorno;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":260,"wires":[["c104d04c20373522"]]},{"id":"3933aef1598810df","type":"comment","z":"ce1025655096ab75","name":"Alexa me escute para o apirador","info":"Alexa me escute SKILL DESENVOLVIDA","x":210,"y":180,"wires":[]},{"id":"c104d04c20373522","type":"api-call-service","z":"ce1025655096ab75","name":"Modo de limpeza","server":"9f230d2c.1e00d","version":5,"debugenabled":false,"domain":"vacuum","service":"set_fan_speed","areaId":[],"deviceId":[],"entityId":["vacuum.roborock_vacuum_a15"],"data":"{\"fan_speed\":\"{{payload_set_fan_speed}}\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":590,"y":260,"wires":[["52716ff8f5b1c259"]]},{"id":"8a8b0987cc188eea","type":"api-call-service","z":"ce1025655096ab75","name":"Limpeza","server":"9f230d2c.1e00d","version":5,"debugenabled":false,"domain":"xiaomi_miio","service":"vacuum_remote_control_start","areaId":[],"deviceId":[],"entityId":["vacuum.roborock_vacuum_a15"],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1220,"y":500,"wires":[[]]},{"id":"0d62b97256ed3f25","type":"api-call-service","z":"ce1025655096ab75","name":"Modo de limpeza","server":"9f230d2c.1e00d","version":5,"debugenabled":false,"domain":"vacuum","service":"set_fan_speed","areaId":[],"deviceId":[],"entityId":["vacuum.roborock_vacuum_a15"],"data":"{\"fan_speed\":\"Turbo\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":990,"y":500,"wires":[["8a8b0987cc188eea"]]},{"id":"588f639902ad6b26","type":"switch","z":"ce1025655096ab75","name":"Tipo","property":"payload.event.event_response","propertyType":"msg","rules":[{"t":"eq","v":"fazer faxina","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":814,"y":442,"wires":[["0d62b97256ed3f25"]]},{"id":"9f6bd2b49b8185ef","type":"switch","z":"ce1025655096ab75","name":"Resposta diferente de NONE","property":"payload.event.event_response","propertyType":"msg","rules":[{"t":"neq","v":"ResponseNone","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":400,"y":440,"wires":[["af0293a2d46ecbf6","588f639902ad6b26"]]},{"id":"cb2250f0cfe34351","type":"server-events","z":"ce1025655096ab75","name":"Evento Alexa me escute","server":"9f230d2c.1e00d","version":1,"event_type":"alexa_actionable_notification","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"waitForRunning":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"$outputData(\"eventData\").event_type","valueType":"jsonata"},{"property":"event_type","propertyType":"msg","value":"$outputData(\"eventData\").event_type","valueType":"str"}],"x":140,"y":440,"wires":[["9f6bd2b49b8185ef"]]},{"id":"561df9f1affd233f","type":"api-call-service","z":"ce1025655096ab75","name":"Limpar Comodo1","server":"9f230d2c.1e00d","version":5,"debugenabled":false,"domain":"xiaomi_miio","service":"vacuum_clean_zone","areaId":[],"deviceId":[],"entityId":["vacuum.roborock_vacuum_a15"],"data":"{\t \"zone\":[[23539,19729,27035,23610]],\t \"repeats\":$number(payload_qtd_repeats_judite)\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1030,"y":200,"wires":[[]]},{"id":"6d1b61c187ecc2fe","type":"api-call-service","z":"ce1025655096ab75","name":"Limpar Escritorio","server":"9f230d2c.1e00d","version":5,"debugenabled":false,"domain":"xiaomi_miio","service":"vacuum_clean_zone","areaId":[],"deviceId":[],"entityId":["vacuum.roborock_vacuum_a15"],"data":"{\t \"zone\":[[23509,23688,26948,28214]],\t \"repeats\":$number(payload_qtd_repeats_judite)\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1030,"y":240,"wires":[[]]},{"id":"dc236d37e751e25a","type":"api-call-service","z":"ce1025655096ab75","name":"Limpar Cozinha","server":"9f230d2c.1e00d","version":5,"debugenabled":false,"domain":"xiaomi_miio","service":"vacuum_clean_zone","areaId":[],"deviceId":[],"entityId":["vacuum.roborock_vacuum_a15"],"data":"{\t \"zone\": [\t [\t 23607,\t 16607,\t 26487,\t 19554 \t ] \t ],\t \"repeats\":$number(payload_qtd_repeats_judite)\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1020,"y":280,"wires":[[]]},{"id":"03e5e7826cf774eb","type":"api-call-service","z":"ce1025655096ab75","name":"Limpar Corredor","server":"9f230d2c.1e00d","version":5,"debugenabled":false,"domain":"xiaomi_miio","service":"vacuum_clean_zone","areaId":[],"deviceId":[],"entityId":["vacuum.roborock_vacuum_a15"],"data":"{\t \"zone\":[[23633,11640,24513,16853]],\t \"repeats\":$number(payload_qtd_repeats_judite)\t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1010,"y":320,"wires":[[]]},{"id":"9f230d2c.1e00d","type":"server","name":"Home Assistant","version":4,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m"}]
Aqui está um video pequeno do funcionamento completo da minha skill com a Judite.
Espero que tenha ajudado alguem, não sou de entrar muito aqui para postar as coisas , mais esse forum vem me ajudando muito com minhas automações malucas.