Garage door, Shelly 1 and CarPlay

There is plenty of documentation around about how to wire up a Shelly 1 relay module to automate a garage door. It’s conceptually simple: the relay is wired in to the manual door open button.

The Gen 4 modules from Shelly also support Matter, which means they can be adopted straight into HomeKit. Awesome!

Except…

Despite being able to configure what the Shelly is used for (you can define the “appliance type” to be lighting, entertainment, heating and cooling - there’s a whole bunch of them, including “garage door”), this doesn’t actually change how it identifies itself over Matter. It always shows up as a switch.

In the Apple ecosystem, HomeKit allows it to be displayed within the Home app as an outlet, a light or a fan. This is all functional, but is missing some key functionality:

  • A garage door will change its icon to show if it is open or closed. States for a switch are on or off, which kind of works but not really.
  • A garage door will automatically appear on a CarPlay dashboard as you approach your house, so you can open it with a quick tap.

Don’t get me wrong, missing these is absolutely a first world problem. However, I live in the first world, and I want my CarPlay icon.

For reasons, I also have a Home Assistant installation. I was pretty sure I’d be able to use a “helper” entitiy to change the switch into something else (like, a garage door!), but alas: I could only get a cover (which HomeKit thinks is a curtain or blind) or a lock. Close - would show me the open/closed state (kind of), but still wouldn’t show on CarPlay.

It turns out that Home Assistant actually did provide the solution, but I had to do some manual config work rather than rely on the GUI. I added this to my configuration.yaml:

# Define the virtual state helper
input_boolean:
  garage_door_open:
    name: Garage Door State
    initial: false

# The template cover configuration
template:
  - cover:
      - name: "Garage Door"
        unique_id: garage_door_cover
        device_class: garage
        state: >-
          {% if is_state('input_boolean.garage_door_open', 'on') %}
            open
          {% else %}
            closed
          {% endif %}
        open_cover:
          - action: switch.turn_on
            target:
              entity_id: switch.id.goes.here
          - action: input_boolean.turn_on
            target:
              entity_id: input_boolean.garage_door_open
        close_cover:
          - action: switch.turn_on
            target:
              entity_id: switch.id.goes.here
          - action: input_boolean.turn_off
            target:
              entity_id: input_boolean.garage_door_open
        icon: >-
          {% if is_state('input_boolean.garage_door_open', 'on') %}
            mdi:garage-open
          {% else %}
            mdi:garage-variant
          {% endif %}

I’m just testing this setup, so I don’t have the I/O module and reed sensor installed on the Shelly, so it doesn’t have any way to report if the door is open or closed. I’m faking it by using an internal variable to hold the door state - that’s what the boolean value for Garage Door State is for. No, it’s not ideal, and yes it could potentially get out of sync, but for now it’s good enough.

The real work is in the next section. Basically, what it does is specific type of cover (i.e. a garage door), uses the variable to report the state, and then ties the open and close actions to turning on the relay. The Shelly relay is configured to turn itself off after half a second, to simulate a button being pressed, so the action for both open and close is to turn it on.

It then also applies a custom icon so that in the Home Assistant dashboards it will show the open/closed state on the icon.

Then it’s a simple task to add the new “cover” to a HomeKit bridge, and bingo! It magically appeared in HomeKit as a garage door.