[Guide] HomeKit Bridge on Home Assistant in Docker (NanoPi R6S, FriendlyWrt... possibly OpenWrt)

[Guide] HomeKit Bridge on Home Assistant in Docker (NanoPi R6S, FriendlyWrt… possibly OpenWrt)

Hey all,

I had a really rough time getting the Home Assistant running in a Docker container with a physical Zigbee device and specifically HomeKit bridge, so I wanted to share what finally worked for me.

Hopefully, this will be helpful for others, but please proceed with caution—some of these configuration steps could be destructive if you’re not careful.

Note:
If you have Home Assistant installed and running in a docker container in host mode, skip down to the HomeKit Bridge Discovery Trick section, as this was the only part that I did not find explicitly documented. TL;DR: Disable multicast on WAN interface and enable multicast on local interface(s) in Network settings.

Hardware/Software Setup

  • Device: NanoPi R6S
  • OS: FriendlyWRT with Docker support
  • Zigbee: Using Conbee II from deCONZ (Dresden Elektronik)
  • Storage: eMMC, not SD card (SD card seemed to have a bottleneck during the Docker pull. It pulls in a few minutes on eMMC, but hanged after ~45 minutes on SD card)

Due to the SD card issue, I ended up flashing the FriendlyWRT binary onto the eMMC using the web tool (instructions here).

The restore backup functionality DID NOT work, so I had to untar the backup and move some of the files over myself. Note as well you can set opkg to use OpenWrt’s packages with this command as noted in /etc/opkg/distfeeds.conf:

sed -i -e 's/mirrors.ustc.edu.cn\/openwrt/downloads.openwrt.org/g' /etc/opkg/distfeeds.conf
opkg update

Partition Information

I had to ensure the partition was formatted as ext4 (since /mnt/data appears to be used by an overlay filesystem, which caused issues).

I had to use the Luci web interface (System > Mount Points > Mount Points section), as the “normal” linux CLI approach wasn’t sufficient and gave me some really weird issues.

Here’s a look at my partition setup:

root@FriendlyWrt:~# lsblk -f
NAME         FSTYPE FSVER LABEL  UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
mmcblk2                                                                              
├─mmcblk2p1                                                                          
├─mmcblk2p2                                                                          
├─mmcblk2p3                                                                          
├─mmcblk2p4                                                                          
├─mmcblk2p5                                                                          
├─mmcblk2p6                                                                          
├─mmcblk2p7                                                                          
├─mmcblk2p8  ext4         rootfs ce0a...de806d4                
└─mmcblk2p9  ext4                9330...31fc249   22.7G    12% /mnt/userdata/docker
                                                                                         /mnt/userdata
root@FriendlyWrt:~# df -Th
Filesystem     Type     Size  Used Avail Use% Mounted on
/dev/mmcblk2p9 ext4      28G  3.3G   23G  13% /mnt/userdata
overlay        overlay   28G  3.3G   23G  13% /mnt/userdata/docker/overlay2/...

I mounted my custom partition to /mnt/userdata to avoid conflicts, as /mnt/data was being used by the overlay filesystem.

Directories Layout

Next, I created two directories:

  • /mnt/userdata/homeassistant-config: where the HomeAssistant container will place all of the config files, like config.yml, scenes.yml, etc.
  • /mnt/userdata/homeassistant-docker: where I placed docker-compose.yml

Docker Configuration

I also set up Docker to use the /mnt/userdata partition so that docker layers would go directly to the eMMC. I modified /etc/config/dockerd like this:

root@FriendlyWrt:~# cat /etc/config/dockerd
config globals 'globals'
	option data_root '/mnt/userdata/docker'

(You can also rm -r the old directory to free up space, or mv them to the new location)

Then I created /mnt/userdata/homeassistant-docker/docker-compose.yml:

version: '3.9'

services:
  homeassistant:
    container_name: home-assistant
    image: homeassistant/home-assistant:stable
#    privileged: true  # I had this enabled during configuration, but it does not seem necessary, so it is now disabled
    restart: unless-stopped
    network_mode: "host"
    volumes:
      - /mnt/userdata/homeassistant-config:/config
    devices:
      - /dev/ttyACM0:/dev/ttyACM0  # This is my conbee II
    environment:
      - TZ=America/Los_Angeles

networks:
  default:
    driver: bridge

Network Configuration

I initially ran into an issue where avahi-daemon was using the same port as HomeKit bridge, so I disabled it temporarily:

/etc/init.d/avahi-daemon stop

Then I restarted the Home Assistant Docker container. Once I had the HomeKit bridge configured, avahi-daemon restarted itself, and I didn’t encounter any further issues.

Failed Attempt at Macvlan

I also gave the macvlan network approach a try since it seemed like a cleaner setup. Unfortunately, I couldn’t get it to work properly, but in the process I enabled Avahi Reflector Mode. I did this by editing /etc/avahi/avahi-daemon.conf:

[server]
enable-reflector=yes

This shouldn’t be necessary for this approach, but it would be for the docker bridge or macvlan. I believe that enabling it will also enable auto-discovery from Home Assistant of other docker containers that would otherwise be “Add-Ons” that aren’t running in host mode with supported Integrations (e.g., ESP-Home, Scrypted, etc.).

HomeKit Bridge Setup

I had switched to the manual configuration trying to get this to work, but I believe the UI will work too. In any case, here are my settings:

In /mnt/userdata/homeassistant-config/configuration.yaml on its own line

homekit: !include homekit.yaml

Then I created the homekit.yaml file:

# /mnt/userdata/homeassistant-config/homekit.yaml : 
- name: HASS Bridge
  advertise_ip: 192.168.2.1 # This is the IP of the docker host
  port: 21064  # Any port should be fine
  filter:
    include_entities:
      # Covers
      - cover.ikea_of_sweden_praktlysing_cellular_blind_cover
      # add your devices by name per 

The advertise_ip setting shouldn’t be necessary in this setup, but it was when I was using the macvlan approach (set to the actual IP of the container, but I digress).

HomeKit Bridge Discovery Trick

The key to getting HomeKit discovery to work was enabling advanced mode in Home Assistant and modifying the network interface settings to multicast on the local interface.

First, enable advanced mode. For me it’s a toggle here: http://192.168.2.1:8123/profile/general

This will unhide the Network settings. Then,

  1. Go to Settings > System > Network.
  2. Uncheck the WAN interface (eth1 in my case).
  3. Check the boxes for your local network (br-lan) and (optional) Docker network interface (docker0).

This ensures Home Assistant advertises itself correctly via mDNS aka Avahi aka Bonjour aka Zeroconf on the correct interfaces. HomeKit must be able to see the advertisement messages on mDNS for the HomeKit bridge to be detected. If the wrong interfaces are selected, HomeKit device discovery will fail.

Related reading:

Conclusion

After much trial and error, I got this setup working. Hopefully, this will help others, but again, proceed with caution—some of these steps (like disabling services or modifying partitions) could be destructive. If you have any questions, feel free to ask!

1 Like

Why

Somewhere on this forum I have a detailed explanation with examples. If I find it I will add link to this post