Repository navigation
Installing with Docker
Use this route for Home Assistant Container, or a receiver on a separate Linux computer. Docker runs the receiver in its own software container. Home Assistant OS users should follow the add-on guide. Existing Core users can also use this route; Core is a legacy HA installation method.
These instructions target receiver 0.3.0. The historical hardware test used 0.2.1; it does not establish field verification of every 0.3.0 feature. The 2 November 2026 hardware test used Debian 13, Docker 26 + Compose v2, an RTL-SDR Blog V4 passed through to a VM, Home Assistant 2026.10.4 Container and Mosquitto 2. Only the same single Gladstone transmitter was tested. Ubuntu commands and the authenticated broker recipe below are not additional radio field tests.
You'll need a Linux amd64 or arm64/aarch64 computer, the USB receiver and antenna, a running Home Assistant installation with an administrator account, and a reachable MQTT broker. A VM needs USB passthrough. Stop any other SDR software using this receiver.
Run Linux commands in a terminal on the receiver's host, not in Home Assistant's YAML editor.
Already running Home Assistant Container? Keep your Docker installation. Check:
docker --version
docker compose versionIf both work and Compose reports v2, skip package installation. If Compose is missing (docker: 'compose' is not a docker command), install it for your existing Docker package source using the official Docker instructions. Do not replace a working engine with another package source. Ensure git and nano are installed before cloning.
For a new Docker installation, use the commands for your distribution. These use distribution packages:
Debian 13 (the tested distribution):
sudo apt update
sudo apt install -y docker.io docker-compose git nanoUbuntu 24.04 (not field-tested here):
sudo apt update
sudo apt install -y docker.io docker-compose-v2 git nanoFor other releases, use the Docker installation selector and ensure Compose v2 works. If you need Docker access without sudo:
sudo usermod -aG docker "$USER"Log out and back in, then check docker compose version before continuing.
Get the release's files:
git clone https://github.com/Spicynostalgia/ha-taggle.git
cd ha-taggle
git checkout --detach v0.3.0
cp config.example.json config.json
mkdir -p data
chmod 700 data
chmod 600 config.json
nano docker-compose.ymlChange the receiver image: line to ghcr.io/spicynostalgia/ha-taggle:0.3.0. In nano, press Ctrl+O, Enter to save, then Ctrl+X to exit. All later commands run from this cloned ha-taggle directory unless stated otherwise.
nano config.jsonEdit the copied file, keeping the outer braces and other settings:
- Replace the number in
"meter_ids": [123456]with your transmitter ID. Fictional123456must not stay configured. If the label is unreadable, use"meter_ids": []for the scan in Step 3; normal mode needs your confirmed ID. - Set
"timezone": "Australia/Brisbane"to Home Assistant's named timezone, for exampleAustralia/Sydney,Australia/AdelaideorAustralia/Perth. Brisbane is not an Australia-wide default; daylight saving differs. This setting controls “today”. Compose'sTZ: UTCdoes not override it. - Change
hostinside the existing"mqtt": { ... }block to the broker computer's LAN IP, then set itsport,usernameandpassword. Do not add a literalmqtt.hostkey. Follow the address and broker instructions below if needed. - Keep
"data_dir": "/data"; Compose maps it to./dataon the host. - Keep
"sample_rate": 2400000; only that rate is supported. - Keep
"litres_per_count": {}for guided calibration. Do not copy an example litres-per-pulse value. -
Neighbourhood comparison is on by default. It publishes group statistics with assumed litres per pulse, not individual neighbour IDs/usage. To disable collection before starting, set
"neighbourhood": false. Read its assumptions and privacy exceptions.
JSON needs double quotes, commas between entries, no comments and no trailing comma. Save and exit nano with Ctrl+O → Enter → Ctrl+X. chmod 600 above keeps the broker password readable only by your host user. See Configuration reference for defaults, ranges and setting formats. Never add add-on-only scan_minutes to standalone JSON.
Use the broker computer's address on your home network, without a URL scheme, port or network prefix length. On Debian/Ubuntu, run this on the broker host:
ip -br addressFictional address example:
enp1s0 UP 192.168.1.50/24
Here you would use 192.168.1.50, without /24. Choose the active Ethernet or Wi-Fi LAN interface; ignore lo, docker0 and br-… bridge addresses. Your address will differ. Reserving it for this computer in your router avoids later address changes.
Even if the broker runs on this same computer, do not use localhost inside the receiver container: it means that container itself. The copied example's "mqtt" hostname works only when a matching service/hostname exists on the same network. It does not resolve automatically between the separate Compose projects here.
Skip this if you already have a broker. This creates a separate broker; it does not replace your Home Assistant Container configuration. Keep it on your trusted LAN and do not forward port 1883 to the internet.
From the cloned receiver directory:
mkdir -p mosquitto
chmod 755 mosquitto
nano mosquitto/mosquitto.confEnter:
listener 1883
allow_anonymous false
password_file /mosquitto/config/passwords
Save and exit. Create a password for the dedicated username taggle. This prompts interactively; the password is not included in command history:
docker run --rm -it --user 0:0 --entrypoint sh \
-v "$PWD/mosquitto:/mosquitto/config" eclipse-mosquitto:2 \
-c 'mosquitto_passwd -c /mosquitto/config/passwords taggle && chown 1883:1883 /mosquitto/config/passwords && chmod 600 /mosquitto/config/passwords'Use this creation command only for a new password file: -c overwrites an existing file. For a later password change, omit -c. The image's Mosquitto user is UID/GID 1883; the ownership and permissions let that user read the password file while keeping other host users out.
Create the broker's Compose file:
nano mosquitto/compose.yamlEnter:
services:
mosquitto:
image: eclipse-mosquitto:2
user: "1883:1883"
restart: unless-stopped
ports: ["1883:1883"]
volumes:
- "./mosquitto.conf:/mosquitto/config/mosquitto.conf:ro"
- "./passwords:/mosquitto/config/passwords:ro"Save and exit, then start and check the broker:
docker compose -f mosquitto/compose.yaml up -d
docker compose -f mosquitto/compose.yaml ps
docker compose -f mosquitto/compose.yaml logs --tail=50The service should stay running, with a log saying it is opening a listen socket on port 1883. Fix password-file, bind-port or restart-loop errors before continuing. The paths in this Compose file are relative to the mosquitto directory, so keep this layout. Put the same username taggle and your chosen password in the receiver's mqtt block and in Home Assistant's MQTT setup below. Do not share the password file.
After changing broker config or passwords, apply it with:
docker compose -f mosquitto/compose.yaml restart mosquittoThe Eclipse Mosquitto documentation explains password-file authentication in more detail.
A running broker alone is not enough. In HA, open Settings → Devices & services → Add integration → MQTT. Enter the broker computer's LAN IP, port 1883, username taggle and the password you chose (or your existing broker credentials). If MQTT is already configured, check it uses the same broker. Keep MQTT discovery enabled.
Scanning is useful if you need to find your ID. Stop normal reception first, even if you are returning here from a working installation:
docker compose pull taggle
docker compose stop taggle
docker compose run --rm taggle --config /config/options.json --scan 65Look for receiver detection and Reading samples in async mode... before waiting. Scanning prints decoded IDs and signal details, with no MQTT or saved state/log files. Ctrl+C stops the foreground scan early. Once startup is healthy, allow 65 minutes to cover a typical hourly transmission opportunity; reception is not guaranteed. In 0.3.0 scans include sample-derived UTC timestamps and one-decimal signal measurements, but no normal-mode heartbeat. Counts appear only for configured IDs with clear frames.
If you started with empty meter_ids, identify a candidate from your label or the water-use check, then edit config.json. Keep only your own confirmed ID in normal use. A scan must end before normal reception can use the same USB receiver.
docker compose up -d taggle
docker compose ps taggle
docker compose logs -f taggleNormal startup on the tested V4 included:
RTL-SDR Blog V4 Detected
Reading samples in async mode...
Check the selected image with docker compose images taggle; the device page also reports the receiver software version. The container should stay running. Fix USB/startup errors now. In 0.3.0, look for Listening on 922.2 MHz for meter(s): 1 configured; first reading can take up to an hour and MQTT connected in normal mode. A listening summary appears every 15 minutes, counting other meters without listing their IDs. It does not prove your own meter was heard; see startup and heartbeat examples.
Once MQTT connects, open Settings → Devices & services → MQTT → Devices. Taggle 123456 (your ID) and the enabled Taggle neighbourhood device should appear before a radio reading. If absent, check broker connectivity, configured IDs, discovery and scan mode; waiting for a transmission does not fix discovery.
Leave the receiver running for up to an hour. On your Taggle device, check Last seen under Diagnostics and Last hour pulses. Neighbourhood values remain unknown until their separate groups qualify. Ctrl+C in logs -f only closes the log viewer; the detached receiver keeps running.
Next: check ownership using a household tap, then optionally add the dashboard card. In card 0.3.0, a new card says “Waiting for first reading (can take up to an hour)”. A previously working meter losing usage needs Troubleshooting.
The supplied docker-compose.yml uses ghcr.io/spicynostalgia/ha-taggle:0.3.0 for amd64/aarch64. The steps above pin :0.3.0 so the receiver matches this guide. A commented build block enables local builds. It maps /dev/bus/usb:/dev/bus/usb on Linux, mounts config.json read-only at /config/options.json, mounts ./data for persistent state, and restarts with unless-stopped. device can be an RTL index or its USB serial. The image includes the RTL-SDR Blog driver; no host driver installation or transmit software is needed.
The receiver retries a working SDR disconnect after two seconds and reanchors incoming samples to wall time. If no samples arrive, retry delay grows to 60 seconds with a clear reminder every ten minutes; see no-SDR backoff. Memory queues are bounded. Input backpressure can still lose samples; raw unsigned IQ cannot measure that loss.
Back up config.json and ./data, especially state.json and neighbourhood.salt; keep them private. Manual factor/offset pins live in config; cumulative totals, entered dial readings, selected unit and the automatic solution live in state. Restarts preserve them. Deleting state loses the baseline and does not repair reception. Keep the same persistent mount when recreating the container.
Linux may load a DVB TV driver for the USB receiver. In the Debian VM test the image detached it automatically; no blacklist was needed. If you get “device busy”, also check for another SDR app/container, and confirm USB passthrough on a VM.
If the driver still prevents access, run on the host, not in the container:
lsmod | grep dvb_usb_rtl28xxu
sudo rmmod dvb_usb_rtl28xxu
# Optional permanent blacklist if needed:
echo 'blacklist dvb_usb_rtl28xxu' | sudo tee --append /etc/modprobe.d/blacklist-dvb_usb_rtl28xxu.confThen unplug/replug the USB receiver or reboot. The quick start guide and V4 guide explain the blacklist. On a NAS, USB access is still required; some NAS kernels have no DVB module, while others may need host-specific changes.
-
Stop the receiver with
docker compose stop tagglebefore copyingconfig.jsonand the privatedatadirectory to your backup location. -
Select the released version you intend to use in
docker-compose.yml. This guide covers 0.3.0. Review its release notes before changing versions. -
Run the commands below from the same receiver directory, keeping the existing data mount:
docker compose pull taggle docker compose up -d taggle docker compose logs -f taggle
Update the card separately if needed and check its version too. Do not reinstall with an empty data directory to troubleshoot reception.
ha-taggle is experimental, receive-only and unofficial. It is not affiliated with Taggle Systems or any council or utility. Only receive your own meter, and never touch the utility's equipment. All IDs in this wiki are fictional. · Repository · Report an issue · Glossary
Start here
- Home
- Getting started
- Check your meter
- Finding your meter
- Meter types and pulse sizes
- Hardware and antennas
- Tested hardware
Setup
Using it
Reference and optional background
- Entities reference
- Configuration reference
- How it works
- Protocol
- Privacy and legal
- Glossary
- AI disclosure
Help