Enhancing Home Assistant with custom automation

Enhancing Home Assistant with custom automation

I tend to write these after breaking something a few times, which is usually the fastest way to find the rough edges. Home Assistant gets much easier to live with once the automations are repeatable, readable and not doing pointless work every second.

Start with the difference between scenes, automations and blueprints. A scene sets device states, for example lights on at 30 per cent and the thermostat to a setpoint. An automation reacts to triggers and runs actions, for example motion detected then turn on a grouped light. A blueprint is a reusable automation template you can share or import. Use the GUI for quick experiments. Switch to YAML when you want repeatable configs and version control. Put YAML files under config/automations.yaml or split them into config/automations/ if you prefer a directory. Save blueprints under config/blueprints/automation/<author>/name.yaml. For triggers, use device_trigger where you can rather than state polling. Device triggers from Z-Wave JS, Zigbee integrations or MQTT are a lot lighter than template checks running every second. For a simple evening lights automation, a compact example looks like this:

alias: Evening lights on arrival
description: Turn on hall and lounge when I arrive after sunset
trigger:
  - platform: zone
    entity_id: person.jamie
    zone: zone.home
    event: enter
condition:
  - condition: sun
    after: sunset
action:
  - service: scene.turn_on
    target:
      entity_id:
        - scene.hall_evening
        - scene.lounge_dim
mode: single

For reusability, turn that into a blueprint. Create config/blueprints/automation/lab53/arrival_lights.yaml and use inputs so you can pick the person, zone and scenes without editing YAML each time. A usable blueprint snippet:

blueprint:
  name: Arrival lights with sunset
  description: Turn scenes on when a person enters a zone after sunset
  domain: automation
  input:
    person:
      name: Person entity
      selector:
        entity:
          domain: person
    zone:
      name: Zone
      selector:
        entity:
          domain: zone
    scenes:
      name: Scenes to activate
      selector:
        target:
          entity:
            domain: scene
trigger:
  - platform: zone
    entity_id: !input person
    zone: !input zone
    event: enter
condition:
  - condition: sun
    after: sunset
action:
  - service: scene.turn_on
    target: !input scenes
mode: single

Save it, reload blueprints from Configuration, then create automations from that blueprint. That cuts down on copy and paste mistakes. When I build blueprints I test with a synthetic trigger first. Use Developer Tools → Services and call the automation.trigger service. Watch the trace in the automation UI to see each step and the values passed to the blueprint inputs.

Device integration is where a lot of these projects bog down. Pick a radio stack early. I use Z-Wave JS for Z-Wave, Zigbee2MQTT for many Zigbee sticks, and ESPHome for DIY sensors. MQTT is useful for bespoke hardware. Use unique entity_id names when you add devices; change names in the integration UI rather than editing core.entity_registry unless you know what you are doing. Make use of helpers: input_booleans, input_selects and input_numbers let you turn awkward flows into simple conditions passed to blueprints. For devices with local APIs, prefer local integrations. They are quicker and keep automations running if the cloud is down. If a device keeps flapping, switch its state handling to a binary_sensor or add a small condition with a for: value so it does not retrigger constantly.

Performance starts to matter once you have more than a handful of automations. Keep template sensors minimal and move repeated calculations into one template sensor instead of copying the same template into multiple automations. Use device triggers and binary_sensors as cheap, event-driven sources. Set automation mode with intent: single prevents overlaps, queued runs them one after another, parallel allows concurrency if the actions are independent. I set long-running automations to mode: queued with max: 2 so they do not pile up. When calling heavy services such as cloud TTS, push them into a script and mark the script as background. That keeps the automation quick to return and avoids blocking other logic.

When automations misbehave, use the trace and logger. Turn on debug for an integration in Configuration → Logs or by adding a logger entry in configuration.yaml like this:

logger:
  default: info
  logs:
    homeassistant.core: debug
    homeassistant.components.mqtt: debug

Use the automation trace to inspect variables, conditions and timing. Check Developer Tools → States to confirm entity IDs have not changed after a device reconfigure. If a blueprint fails for multiple people, try the same inputs on a local test person or entity. Keep all configurations in Git. Tag working releases before major changes so you can roll back with a single git checkout. Back up the config directory regularly, and keep secrets.yaml somewhere encrypted if you need to.

My takeaways are fairly boring, which usually means they work. Put inputs on any blueprint value that changes between rooms. Use device triggers and binary_sensors to keep CPU use down. Test each automation with the trace tool and keep configs in Git so a bad change is easy to undo.

Related posts

Weekly Tech Digest | 06 Jul 2026

Stay updated with the latest in tech! This digest covers AI ethics, auto industry shifts, and the impact of politics on technology, exploring today's pressing issues.

wolfCOSE zero-allocation parsing in embedded C

wolfCOSE looks sensible only if you care about what your firmware actually has to carry. I like that, because on small targets the wrong crypto feature can cost more than the message itself, and there...

restic | v0.19.1

restic v0 19 1: safer FUSE mounts and mountpoint checks, robust backup source and exclude handling, clearer CLI JSON output, Windows SFTP deletion fixes