After a very interesting (German) toot about a CO₂ sensor I also purchased such a sensor (TFA Dostman AIRCO₂NTROL MINI) and of course my goal was to have it as sensor within Home Assistant. Luckily, there already is a project to collect the sensor data via MQTT, called CO2MqttSensor. Unfortunately at first, while it’s possible to get it running via shell in TrueNAS, it is not recommended, since it would require to install a system service to stay running. But there is a solution via a Docker app!
This is where I created my first own Docker container. And I admit: I used Google Gemini for it. And while I don’t like AI in my day-to-day job, especially when it comes to building new stuff you don’t know anything about yet, it may be a good guidance at the beginning. And so it was for me.
Structure
The structure of the app looks like this:
drwxr-xr-x 4 root root 15 Nov 12 21:50 CO2MqttSensor
-rw-r--r-- 1 root root 947 Nov 12 22:07 Dockerfile
-rw-r--r-- 1 root root 722 Nov 12 21:45 config.json
-rw-r--r-- 1 root root 392 Nov 12 22:02 docker-compose.ymlCode language: CSS (css)
I’ll guide you in the setup steps on how to get it.
Setup
Home Assistant
- Install the MQTT integration in Home Assistant.
- Go to Settings > Add-ons and install the add-on “Mosquitto broker”. Leave all settings by their defaults for an easier setup.
- Go to Settings > People > Users and create a new user, e.g.
mosquitto. This will later be used to connect to the Mosquitto MQTT broker.
TrueNAS
First, create the directory where you want to run the app on your TrueNAS via the command line and go into this directory. In my case, it’s /mnt/SSData/apps/co2mqtt.
CO2MqttSensor
Then, clone the CO2MqttSensor project:
git clone https://github.com/irimitenkan/CO2MqttSensor.gitCode language: PHP (php)
USB handling
Since Docker does not run as root, we need to adjust the UDEV-rules as described in CO2MqttSensor’s readme:
Create and open the file /etc/udev/rules.d/99-hidraw-permissions.rules and paste the following content into it:
SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d9", ATTRS{idProduct}=="a052", GROUP="plugdev", MODE="0660"Code language: JavaScript (javascript)
Then, restart UDEV with this command: udevadm control --reload-rules
If you already plugged in the sensor USB device, disconnect and connect it again so that the rules can apply to the device.
Now, we need to find the sensor USB device (it needs to be plugged in).
lsusb | grep 04d9:a052
The output looks like this:
Bus 003 Device 008: ID 04d9:a052 Holtek Semiconductor, Inc. USB-zyTempCode language: CSS (css)
Here, the two first 3-character digits are important: 003 and 008. They will be referred to later as XXX (for 003 here) and YYY (for 008 here) in the docker-compose.yml.
Dockerfile
Paste the following code in the Dockerfile:
# Use a slim Python 3.11 image based on Debian Trixie
# This provides a minimal OS environment with Python pre-installed.
FROM python:3.11-slim-trixie
# Set up the environment for a non-interactive installation
ENV DEBIAN_FRONTEND=noninteractive
# Install necessary system dependencies for building Python packages (like pyusb/pyserial)
# and for device interaction.
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
libusb-1.0-0-dev \
libhidapi-dev \
# Clean up to minimize image size
&& rm -rf /var/lib/apt/lists/*
# Set the working directory inside the container
WORKDIR /app
RUN pip install paho-mqtt==1.6.1 hidapi
COPY config.json /app/config.json
# Set the default command to run the application with the config file
# The configuration file will be mounted via Docker Compose.
CMD ["python", "co2sensor.py", "-c", "/app/config.json"]Code language: Dockerfile (dockerfile)
config.json
You can find an example config.json in the CO2MqttSensor project: https://github.com/irimitenkan/CO2MqttSensor/blob/main/config.json
As host, use the hostname of your Home Assistant system, e.g. its IP address, and as username and password the credentials you’ve created the user with in Home Assistant. Leave the rest for now as is, since it already uses the default of the Mosquitto broker we installed in Home Assistant before. If you changed settings there, you need to adjust your config.json accordingly.
docker-compose.yml
The docker-compose.yml looks like this:
services:
co2sensor:
build:
context: .
dockerfile: Dockerfile
network: host
container_name: co2mqttsensor
hostname: tfa-airco2ntrol-mini
volumes:
- /mnt/SSData/apps/co2mqtt/CO2MqttSensor:/app
- /mnt/SSData/apps/co2mqtt/config.json:/app/config.json
devices:
- /dev/bus/usb/XXX/YYY:/dev/bus/usb/XXX/YYY
restart: unless-stoppedCode language: YAML (yaml)
Here, adjust the volumes path according to your requirements and especially all the XXX and YYY under devices. Usually, it’s recommended to use the /dev/hdiraw*, but these are not available in TrueNAS and within a quick search, I couldn’t find a solution.
Create the app
As final step, create the app in TrueNAS via Apps > Discover Apps > Three vertical dots in the upper right corner > Install via YAML and add the following custom config:
include:
- /mnt/SSData/apps/co2mqtt/docker-compose.yml
services: {}Code language: YAML (yaml)
Adjust the path according to your setup. Of course, you can also paste the content of the docker-compose.yml directly into this editor field, if you like that more.
Give it a unique name, e.g. co2mqtt and press Save to start it. It should now automatically start and be in a running state.

Verify in Home Assistant
In the MQTT integration in Home Assistant, a new device should now be added automatically with the name co2sensor.tfa-airco2ntrol-mini (the tfa-airco2ntrol-mini is defined in the docker-compose.yml as hostname) and it should automatically show all collected data from the device.


Regarding the USB device path
I’m not sure if the path to the device will persist over reboots. Probably not, as the second number (YYY) did update after re-plugging in the device another time, while XXX should stay persistent if the same USB port is used. So maybe it’s the best way to check it after a reboot, use these values (coming from lsusb | grep 04d9:a052) and never touching this USB port again or disconnecting the device.
If anyone has a solution for it, I’d be very happy if you share it. 🙂
Also, I’m not sure whether the file /etc/udev/rules.d/99-hidraw-permissions.rules persists. Reboots: probably. System updates: unlikely.
Leave a Reply