A while ago, I’ve set up Traefik to be able to publicly expose some of the services on my TrueNAS, and for the Crowdsec middleware to work with Home Assistant, I needed to feed it HA logs to detect bruteforce attempts. Problem? My Home Assistant was in a virtual machine, thus no direct access to the filesystem. I really did not want to set up a convoluted method of ssh-ing into it and tailing the logs to the host, so I switched to the container installation. I’ve been running it for a month or so and am quite happy with how the migration turned out.
Per @kris ’ suggestion on Youtube, here is a write up of how I did it.
Btw, since this was discussed on the T3 podcast - Home Assistant Supervised does not support LXC/Incus containers nor will it install inside one, it will just error out.
Prerequisites:
- TrueNAS Electric Eel (or newer
)
- An ESP32 (Wroom-32) board and a cable for it
- (Optional) Installed Dockge app
- (Optional) 3D-printed case for ESP32, for example https://www.printables.com/model/726600-esp32-wroom-32-usb-c-box-with-lid-trimmed
- Home Assistant Container
I really did not want to run the container that will face the internet as privilleged and root with mounts to to system’s internals like the official guide wants you to (Linux - Home Assistant), nor did I really like the app from Truenas catalog as it’s also running as root, so I opted for using the image from linuxserver.io.
I’m also used to editing Home Assistant config through a web editor, so I set it up together with a code server container, also from linuxserver.io.
Here is the compose config that I used in Dockge:
services:
homeassistant:
image: linuxserver/homeassistant:latest
container_name: homeassistant
security_opt:
- no-new-privileges:true
volumes:
- type: bind
source: ${apps_storage}/homeassistant/config
target: /config
- type: bind
source: ${apps_storage}/homeassistant/ssh
target: /config/ssh
- type: bind
source: ${apps_storage}/homeassistant/secrets/secrets.yaml
target: /config/secrets.yaml
- type: bind
source: ${apps_storage}/homeassistant/backups
target: /config/backups
network_mode: host
environment:
- PUID=${USER_ID}
- PGID=${USER_ID}
- TZ=${timezone}
restart: unless-stopped
code-server:
image: linuxserver/code-server:latest
container_name: code-server
security_opt:
- no-new-privileges:true
environment:
- PUID=${USER_ID}
- PGID=${USER_ID}
- HASHED_PASSWORD=${HASHED_PASSWORD}
- TZ=${timezone}
- DEFAULT_WORKSPACE=/homeassistant
volumes:
- type: bind
source: ${apps_storage}/homeassistant/code-server
target: /config
- type: bind
source: ${apps_storage}/homeassistant/config
target: /homeassistant
- type: bind
source: ${apps_storage}/homeassistant/secrets/secrets.yaml
target: /homeassistant/secrets.yaml
- type: bind
source: ${apps_storage}/homeassistant/backups
target: /homeassistant/backups
ports:
- 8124:8443
restart: unless-stopped
networks: {}
Pay attention to the ${variables}, you will want to specify them in .env in Dockge.
Note that I chose to use the bind mounts because I wanted each mount to be its own ZFS dataset, as volume mounts will happily create the source directory if it doesn’t already exist (in case you mess something up), which I didn’t really want.
Secrets file is in a separate secrets
dataset because I had to mount whole config
dataset for Crowdsec for it to read Home Assistant’s logs, and I didn’t want it to have access to the secrets file too.
Backup dataset is separate because that’s where my HAOS VM used to save its backups over SMB, so I decided to keep that dataset but just as a bind mount.
Also, if you want working mDNS discovery, in TrueNAS Web UI, you will need to go to Network - Global Configuration and uncheck the mDNS Service Announcement:
- Zigbee
For zigbee, I’m using zigbee2mqtt and mosquitto, which are both available in the TrueNAS Apps Catalog, as I didn’t want to give HA container privilleged access to USB devices.
I’ve been using zigbee2mqtt before I switched from the VM due to its better compatibility with zigbee devices, but if you are coming from ZHA (Home Assistant’s builtin Zigbee integration), last time I checked (which was a while ago), you basically need to start from scratch and manually re-add all your zigbee devices to a fresh zigbe2mqtt-created network.
Devices get exposed to Home Assistant via the “MQTT” integration.
I won’t go into detail on how to set those 2 containers up other than to suggest to read the tooltip for the port field in the zigbee2mqtt configuration, but if you have a question, leave a comment.
- Bluetooth
As there is, to me knowledge, no equivalent to zigbee2mqtt for bluetooth, I decided to instead opt for an ESP32 bluetooth proxy.
Setting those up is easy - buy a generic ESP-32 board, which cost a few dollars, plug it into your computer, flash it with Bluetooth Proxy firmware by visiting this page in a Chromium-based browser Ready-Made Projects — ESPHome, give it credentials to your 2.4GHz Wi-Fi network, add it to your Home Assistant via the ESPHome integration, and you are good to go.
- ESPHome Device Builder
Only needed if you have devices that require custom compiled ESPHome firmware. You don’t need this for bluetooth proxy or Voice PE, as they get their firmware updates from Home Assistant servers.
ESPHome is available as a docker container, which I’ve installed through Dockge, although it is available in the App Catalog. But again, I want to run it as non-root, so I’m going the compose route.
services:
esphome:
container_name: esphome
image: ghcr.io/esphome/esphome
security_opt:
- no-new-privileges:true
user: ${USER_ID}:${USER_ID}
ports:
- 6052:6052
volumes:
- type: bind
source: ${apps_storage}/esphome/config
target: /config
- type: bind
source: ${apps_storage}/esphome/cache
target: /.cache
restart: unless-stopped
environment:
- TZ=${timezone}
- ESPHOME_DASHBOARD_USE_PING=true
- USERNAME=admin
- PASSWORD=${password}
- PLATFORMIO_CORE_DIR=/config/.esphome/.platformio
- PLATFORMIO_GLOBALLIB_DIR=/config/.esphome/piolibs
networks: {}
I couldn’t get mDNS discovery working with this one, so I had to assign static DHCP leases to my ESPHome devices in the router, as well add this to configuration for ESPHome devices:
use_address: DEVICE_IP_HERE
which goes under the wi-fi section.
It will look something like this:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
use_address: 192.168.0.123
You also won’t get notifications in Home Assistant itself every time new ESPHome version comes out, but it’s not a big deal to me as it’s rare I need to update the firmware version at all.
- Wyoming Piper for Text to Speech
If you use Home Assistant’s voice assistant satellites, such as Voice PE, then Wyoming Piper for local TTS is available as a docker container: https://hub.docker.com/r/rhasspy/wyoming-piper
Again, it’s nothing hard to set up, you can just convert the example command from the docker hub page to compose on the home page of Dockge, although you may want to change the default voice option to something nicer, like en_GB-alba-medium
.
- Whisper.cpp for local Speech to Text with GPU acceleration
I have an Intel Arc A380 in my TrueNAS box mainly for Jellyfin transcoding, but since that uses only Media Engine part of the chip, I’ve set it up to do some compute by running local speech to text.
Speed is quite good, accuracy too, especially in noisy environments, takes only a second to process a simple request with the large-v2
model, less than a second with large-v3-turbo
.
Compose config and stuff is available here: GitHub - tannisroot/wyoming-whisper-cpp-intel-gpu-docker: Run an Intel GPU-accelerated Wyoming protocol speech-to-text service for your Home Asssistant in Docker
I wrote this somewhat in a haste, so if I missed something or you have any questions, feel free to leave a comment.
Update: I was able to bypass the need for running home assistant in host networking mode by using the macvlan
network driver.
This allowed me to re-enable mDNS discovery in TrueNAS and still have auto-discovery in Home Assistant.
I removed:
network_mode: host
and added
services:
homeassistant:
...
networks:
homeassistant:
ipv4_address: 192.168.0.242
...
networks:
homeassistant:
driver: macvlan
driver_opts:
parent: br0
ipam:
config:
- subnet: 192.168.0.0/24
ip_range: 192.168.0.240/29
gateway: 192.168.0.1
aux_addresses:
host: 192.168.0.241
(to use br0 you need to have a bridge interface configured on TrueNAS)
To be able to access services on the host, create and configure a macvlan by running these commands on the host:
ip link add ha-host-shim link br0 type macvlan mode bridge
ip addr add 192.168.0.241/32 dev ha-host-shim
ip link set ha-host-shim up
ip route add 192.168.0.240/29 dev ha-host-shim
Change the subnet to the one used in your local network of course.