Painel de controle da casa inteligente mostrando a interface do Home Assistant com automações visíveis

Boas práticas para automações no Home Assistant

Nos últimos meses, revisei uma a uma as automações da minha casa. O Home Assistant começou pequeno, com poucas luzes e um sensor aqui e outro ali, e foi crescendo até virar um sistema que controla luzes, tomadas, a geladeira, a TV e os botões espalhados pelos cômodos. Nesse caminho, dei de cara com dois tipos de problema que se repetiam.

O primeiro era abrir uma automação que eu mesmo tinha escrito e não entender mais o que ela fazia, nem por que tinha aquela condição estranha no meio. O segundo era mais irritante: luzes que ficavam acesas depois de um reinício do HA, ou que não voltavam ao estado certo quando um dispositivo Zigbee caía e voltava.

Cada problema virou uma regra, e hoje toda automação da casa segue as duas. É o que eu compartilho aqui:

  • Nome e estrutura: escrever a automação de um jeito que você, ou outra pessoa, entenda o que ela faz daqui a seis meses.
  • Gatilhos de ressincronização: fazer a automação se recuperar sozinha depois de um reinício, de uma edição ou da queda de um dispositivo.

Nome e estrutura

Toda automação da casa segue o mesmo esqueleto. Com 10 automações, qualquer nome serve. Com 80, a lista vira uma sopa de “Automação nova”, “Luz sala 2” e “teste final agora vai”. Um padrão fixo faz com que qualquer automação seja lida do mesmo jeito, seja ela a mais simples ou a mais complicada da casa.

  • Nome no formato Ambiente/Dispositivo | Função, por exemplo Luz Cozinha | Acionamento ou Geladeira | Retomada Após Queda de Energia. Assim a lista de automações fica agrupada por ambiente, e você acha o que procura em segundos.
  • Uma descrição que explica o porquê das decisões menos óbvias. Aquele for: 30 s ou aquela condição esquisita existem por um motivo que você descobriu depois de horas olhando traces. Se ninguém escrever o motivo, o “você do futuro” apaga a linha achando que é sujeira, e o bug volta.
  • Um id legível em cada gatilho, no seu idioma e em snake_case: tudo em minúsculas, sem acentos nem espaços, com as palavras separadas por sublinhado (movimento, porta_aberta, tv_desligou). Esse formato é o padrão do Home Assistant para identificadores (é o mesmo dos entity_id) e evita problemas com espaços e caracteres especiais no YAML. Com IDs assim, um condition: trigger com id: movimento se lê como uma frase. Com um id: "2", você precisa subir no YAML e contar os gatilhos.
  • Um único choose com um alias claro em cada ramo, e o default cuidando do estado oposto. Com isso, o trace mostra “Ligar Luz Por Movimento” em vez de “Option 2”, e fica claro o que acontece quando nenhum ramo se aplica.
  • Modo restart, para que o evento mais recente sempre vença. Se a automação está esperando 30 segundos para apagar a luz e alguém entra no cômodo, o HA cancela a execução antiga e a nova assume. No modo padrão (single), o novo evento seria ignorado.

Veja a diferença na prática, com a mesma automação escrita das duas formas.

Antes:

alias: Automação nova
description: ""
triggers:
  - trigger: state
    entity_id: binary_sensor.presenca_corredor
    to: "on"
  - trigger: state
    entity_id: binary_sensor.presenca_corredor
    to: "off"
    for:
      seconds: 30
actions:
  - choose:
      - conditions:
          - condition: state
            entity_id: binary_sensor.presenca_corredor
            state: "on"
        sequence:
          - action: light.turn_on
            target:
              entity_id: light.corredor
      - conditions:
          - condition: state
            entity_id: binary_sensor.presenca_corredor
            state: "off"
        sequence:
          - action: light.turn_off
            target:
              entity_id: light.corredor
mode: single

Depois:

alias: Luz Corredor | Acionamento
description: >-
  Acende com presença e apaga 30 s depois que a presença some.
  Os 30 s evitam que a luz pisque quando o sensor perde por um
  instante uma pessoa parada.
triggers:
  - trigger: state
    entity_id: binary_sensor.presenca_corredor
    to: "on"
    id: movimento
  - trigger: state
    entity_id: binary_sensor.presenca_corredor
    to: "off"
    for:
      seconds: 30
    id: sem_movimento
actions:
  - choose:
      - alias: Ligar Luz Por Movimento
        conditions:
          - condition: trigger
            id: movimento
        sequence:
          - action: light.turn_on
            target:
              entity_id: light.corredor
    default:
      - alias: Desligar Luz Após 30s Sem Movimento
        action: light.turn_off
        target:
          entity_id: light.corredor
mode: restart

As duas fazem a mesma coisa, mas só a segunda explica a si mesma.

Gatilhos de ressincronização

As automações do Home Assistant reagem a mudanças: se nada muda, nada acontece. O problema aparece quando a mudança acontece enquanto ninguém está ouvindo. Imagine que você está no corredor, com a luz acesa, e o HA reinicia por causa de uma atualização. Nesse meio-tempo você sai, e o sensor vai para off. Quando o HA volta, o sensor já está em off, então a transição “on → off por 30 s” não acontece mais. A luz fica acesa até alguém passar pelo corredor de novo.

A solução é dar a toda automação que mantém um estado alguns gatilhos extras, cuja única função é mandar a automação olhar para a casa agora e colocar tudo no estado certo.

  • Gatilho inicio (homeassistant → start), que reavalia tudo quando o HA termina de iniciar. Ele cobre o caso do corredor: tudo o que mudou durante o reinício é corrigido assim que o sistema volta.
  • Gatilho ativacao (a própria automação indo para on), que reavalia tudo quando você reativa a automação. Isso resolve o caso clássico de desativar a automação para testar algo, mexer nas luzes na mão e esquecer que o mundo mudou. Além disso, cada edição recarrega a automação, que passa de unavailable para on. Ou seja, a lógica nova é testada no instante em que você salva.
  • Gatilho reconectou, listando todos os dispositivos envolvidos, e não só a luz: sensores, atuadores e, se a automação depende dela, a TV. Quando um dispositivo cai e volta, o estado dele pode ser diferente do que a automação imagina, e qualquer um deles pode ser a peça que mudou.
  • from em lista ([unavailable, unknown]) combinado com not_to com os mesmos valores. Dispositivos do Zigbee2MQTT costumam voltar em duas etapas: unavailable → unknown → estado real. Só com from: unavailable, o gatilho dispara na etapa unknown, quando o estado ainda não serve para nada, e não dispara de novo quando o estado real chega. Com a lista e o not_to, ele dispara uma única vez, no momento certo.
  • Ramos idempotentes, que conferem o estado atual em vez de confiar só no gatilho. Idempotente é uma palavra difícil para uma ideia simples: o ramo aplica o estado correto, não importa quantas vezes rode. “Se o gatilho foi movimento, acenda” não serve para ressincronizar, porque no inicio não houve movimento nenhum. “Se tem alguém aqui agora, acenda; senão, apague” serve.
  • Ressincronização de acordo com o tipo da automação, porque colocar os três gatilhos em tudo cria problemas novos (aprendi isso errando):
    • Mantém estado (luz, tomada): inicio + ativacao + reconectou, porque existe um estado “certo” a recalcular.
    • Notificação de condição (“porta aberta há 10 min”, falta de energia): só inicio + ativacao, com um input_boolean do tipo “já avisado” para não mandar o mesmo aviso duas vezes. Sem reconectou, porque a reconexão de um sensor não é o problema que você quer avisar.
    • Evento puro (botão, campainha): nenhuma ressincronização, porque não há estado a recalcular. Um toggle disparado no inicio inverteria a luz de alguém às 3 da manhã. Se o botão usa uma entidade event.* ou um gatilho de estado, adicione not_from: [unavailable, unknown], para que a volta do dispositivo não pareça um clique. Aqui em casa os botões Zigbee usam um gatilho mqtt no tópico zigbee2mqtt/<botão>/action com um payload fixo. Esse tópico só recebe mensagem quando alguém aperta o botão, então o problema nem existe.

Veja como fica a automação do corredor com essas regras aplicadas.

Antes (já organizada, mas sem ressincronização):

alias: Luz Corredor | Acionamento
description: >-
  Acende com presença e apaga 30 s depois que a presença some.
  Os 30 s evitam que a luz pisque quando o sensor perde por um
  instante uma pessoa parada.
triggers:
  - trigger: state
    entity_id: binary_sensor.presenca_corredor
    to: "on"
    id: movimento
  - trigger: state
    entity_id: binary_sensor.presenca_corredor
    to: "off"
    for:
      seconds: 30
    id: sem_movimento
actions:
  - choose:
      - alias: Ligar Luz Por Movimento
        conditions:
          - condition: trigger
            id: movimento
        sequence:
          - action: light.turn_on
            target:
              entity_id: light.corredor
    default:
      - alias: Desligar Luz Após 30s Sem Movimento
        action: light.turn_off
        target:
          entity_id: light.corredor
mode: restart

Depois:

alias: Luz Corredor | Acionamento
description: >-
  Acende com presença e apaga 30 s depois que a presença some.
  Os 30 s evitam que a luz pisque quando o sensor perde por um
  instante uma pessoa parada. Os gatilhos inicio, ativacao e reconectou
  reavaliam o estado depois de um reinício, de uma edição ou da queda
  de um dispositivo.
triggers:
  # Funcionais
  - trigger: state
    entity_id: binary_sensor.presenca_corredor
    to: "on"
    id: movimento
  - trigger: state
    entity_id: binary_sensor.presenca_corredor
    to: "off"
    for:
      seconds: 30
    id: sem_movimento
  # Ressincronização
  - trigger: homeassistant
    event: start
    id: inicio
  - trigger: state
    entity_id: automation.luz_corredor_acionamento
    to: "on"
    id: ativacao
  - trigger: state
    entity_id:
      - binary_sensor.presenca_corredor
      - light.corredor
    from: [unavailable, unknown]
    not_to: [unavailable, unknown]
    id: reconectou
actions:
  - choose:
      - alias: Ligar Luz Por Movimento Ou Ressincronização Com Presença
        conditions:
          - condition: trigger
            id: [movimento, inicio, ativacao, reconectou]
          - condition: state
            entity_id: binary_sensor.presenca_corredor
            state: "on"
        sequence:
          - action: light.turn_on
            target:
              entity_id: light.corredor
    default:
      - alias: Desligar Luz Sem Presença
        action: light.turn_off
        target:
          entity_id: light.corredor
mode: restart

O ramo de “ligar” agora também responde aos gatilhos de ressincronização, mas só acende se o sensor confirmar presença. Se o HA reinicia com o corredor vazio, o default apaga a luz. Rodar isso uma vez ou dez vezes dá sempre o mesmo resultado.

Checklist para levar

Ao criar ou revisar uma automação, confira:

  • ☐ O nome segue Ambiente/Dispositivo | Função?
  • ☐ A descrição explica as decisões que não são óbvias?
  • ☐ Todo gatilho tem um id legível, em snake_case?
  • ☐ Os ramos do choose têm alias, e o default cuida do estado oposto?
  • ☐ O modo é restart?
  • ☐ Os gatilhos de ressincronização combinam com o tipo da automação (estado, notificação ou evento)?
  • ☐ O reconectou lista todos os dispositivos envolvidos, com from em lista e not_to?
  • ☐ Os ramos que respondem a inicio, ativacao e reconectou conferem o estado atual, em vez de confiar só no gatilho?
  • ☐ Você abriu o trace depois de salvar? A própria edição dispara o ativacao, então o primeiro teste já aconteceu.

Resumindo

Nome e estrutura deixam a automação fácil de entender. Gatilhos de ressincronização deixam a automação difícil de quebrar. Nenhuma das duas práticas custa muito: são algumas linhas de YAML e um pouco de disciplina. Em troca, você não acorda mais com a luz do corredor acesa e perde o medo de abrir uma automação antiga.

Se você tem uma prática que funciona na sua casa, me conta nos comentários!

Posts Similares

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *