Integrating an AppleTV via MQTT

My Home Assistant install spans multiple VLANs (one per physical building). Home Assistant itself has an IP in each of the subnets and for the most part everything works exactly how you’d hope it would for device discovery and network device integrations. Unfortunately, Apple TV support loses its mind in this environment, a fundamental limitation of both the pyatv library and Apple’s protocols themselves. I’ve never found a way to get the native appletv media player integration to actually work.

I finally found a good workaround via MQTT. There’s still room for improvement, but it’s working well enough for me that I thought there might be some value to posting the configuration in case anyone else is facing a similar challenge. I don’t expect either Apple or the pyatv maintainers to prioritize this issue.

I found pyatv-mqtt-bridge on GitHub recently. Coupled with MQTT Sensor and MQTT Binary Sensor I can at least get a device and some useful entities that track what’s going on with the Apple TV.

You’ll need a way to run the pyatv-mqtt-bridge service (node npm or there’s a docker container) in the same subnet where the Apple TV lives. I spun up a VM and I’m running the bridge in docker inside the VM which is in the correct VLAN. My firewall allows this VM to talk to my MQTT server (Mosquitto Broker add-on in my case).

I used the pyatv atvremote wizard which pairs with the Apple TV and then gives you the protocol credentials it negotiated with the device.

You’ll need those AirPlay credentials and whichever Identifier matches the format of the one in the config file. Also make note of Apple TV’s MAC address as reported by this tool, you’ll need it later.

Username and password are embedded into the broker URL and are the credentials needed to connect to your MQTT server. If you’re using the Mosquitto broker add-on in Home Assistant, then this will be any person or user you’ve added to your Home Assistant server in Settings>People.

My config.json looks like this:

{
    "broker": "mqtts://username:[email protected]:8883",
    "devices": [
        {
            "name": "Theater AppleTV",
            "topic": "house/theater/appletv",
            "host": "10.0.0.42",
            "id": "123A456B-7CD8-9E97-FAB8-9012C345DE6F",
            "airplayCredentials": "giant:string:of:linenoise"
        }
    ]
}

Unless you run it with --debug, pyatv-mqtt-bridge gives no indication or logging that it’s working. If it doesn’t crash/exit immediately, then it’s probably connected to the Apple TV and sending MQTT messages to the configured topic.

A tool like MQTT Explorer can be really helpful for debugging at this point. You can use it to connect to your MQTT server and see what messages show up on a topic.

Next we need to do something with those messages on the Home Assistant side.

This is what I added to my configuration.yaml:

mqtt:
  binary_sensor:
    - name: "Power State"
      state_topic: house/theater/appletv/powerState
      object_id: theater_appletv_powerstate
      unique_id: theater_appletv_powerstate
      payload_off: "off"
      payload_on: "on"
      device:
        name: "Theater Apple TV"
        manufacturer: "Apple"
        model: "Apple TV 4K"
        model_id: "A2843"
        identifiers:
          - "theater_appletv"
        connections:
          - ["mac", "1c:b3:c9:22:be:43"]
  sensor:
    - name: "Device State"
      state_topic: house/theater/appletv/deviceState
      object_id: theater_appletv_devicestate
      unique_id: theater_appletv_devicestate
      device:
        name: "Theater AppleTV"
        identifiers:
          - "theater_appletv"

Some of those items are optional and some are purely cosmetic, but I figure we’re in this deep already, why not?

Also, there are many more topics available which you can add as additional sensor: items following the the form of the deviceState topic sensor above (powerState deviceState host name mediaType title app appId position totalTime shuffle repeat although support varies by app).

There’s enough there that I can start do so some fun automations, like turning the lights off when mediaState changes to playing and back on when it changes to paused or idle.

It’s nowhere near as nice as a proper media player device, but I’ll take it. Hope this is helpful to someone. I’ll keep up the thread as I continue to refine my setup here.

5 Likes

Awesome idea! I found an issue with flickering power state on turning on, but I think it’s related with HDMI activation.

This is very timely for me… I recently decided to set up Zigbee remotes to switch between apps on one of my Apple TVs so that family members have a quick way to navigate between what they want.

My roadblock was the native Apple TV integration relies on mDNS, which can be difficult to get working on rootless containers. This MQTT integration seems like a pretty straightforward way for me to get the app launching I need. Thank you for sharing!