initial commit
This commit is contained in:
295
README.md
Normal file
295
README.md
Normal file
@@ -0,0 +1,295 @@
|
||||
# HAMeter
|
||||
|
||||
Read utility meters (electric, gas, water) via SDR and publish to Home Assistant over MQTT.
|
||||
|
||||
HAMeter uses an RTL-SDR dongle to receive wireless transmissions from ERT-equipped utility meters, decodes them with [rtlamr](https://github.com/bemasher/rtlamr), and publishes readings to Home Assistant via MQTT auto-discovery.
|
||||
|
||||
## Features
|
||||
|
||||
- Reads SCM, SCM+, IDM, and R900 (Neptune) meter protocols
|
||||
- Built-in calibration multiplier per meter
|
||||
- Home Assistant MQTT auto-discovery — sensors appear automatically
|
||||
- Three HA sensors per meter: calibrated reading, raw reading, last seen
|
||||
- Discovery mode to find nearby meter IDs
|
||||
- Fully configurable via Docker environment variables — no config files needed
|
||||
- Smart defaults based on meter type (energy, gas, water)
|
||||
- Supports up to 9 meters simultaneously
|
||||
|
||||
## Requirements
|
||||
|
||||
- RTL-SDR dongle (tested with Nooelec RTL-SDR v5)
|
||||
- 915 MHz antenna (or telescopic whip at ~8 cm for 900 MHz band)
|
||||
- Docker host with USB access (tested on Unraid)
|
||||
- MQTT broker (e.g., Mosquitto)
|
||||
- Home Assistant with MQTT integration
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Install Mosquitto MQTT Broker
|
||||
|
||||
Install via your Docker host's app store or:
|
||||
|
||||
```bash
|
||||
docker run -d --name mosquitto -p 1883:1883 eclipse-mosquitto
|
||||
```
|
||||
|
||||
### 2. Add MQTT Integration to Home Assistant
|
||||
|
||||
**Settings → Devices & Services → Add Integration → MQTT**
|
||||
|
||||
- Broker: your Docker host IP
|
||||
- Port: 1883
|
||||
|
||||
### 3. Connect the SDR Dongle
|
||||
|
||||
Plug the RTL-SDR into a **USB 2.0 port** (USB 3.0 can cause interference).
|
||||
|
||||
Blacklist the kernel DVB driver so it doesn't claim the device:
|
||||
|
||||
```bash
|
||||
# On Unraid (persists across reboots):
|
||||
mkdir -p /boot/config/modprobe.d
|
||||
echo "blacklist dvb_usb_rtl28xxu" >> /boot/config/modprobe.d/rtlsdr.conf
|
||||
rmmod dvb_usb_rtl28xxu 2>/dev/null
|
||||
|
||||
# On other Linux:
|
||||
echo "blacklist dvb_usb_rtl28xxu" | sudo tee /etc/modprobe.d/rtlsdr.conf
|
||||
sudo rmmod dvb_usb_rtl28xxu 2>/dev/null
|
||||
```
|
||||
|
||||
### 4. Run HAMeter
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name hameter \
|
||||
--restart unless-stopped \
|
||||
--device=/dev/bus/usb \
|
||||
-e MQTT_HOST=192.168.1.74 \
|
||||
-e METER_1_ID=23040293 \
|
||||
-e METER_1_PROTOCOL=scm \
|
||||
-e METER_1_NAME="Electric Meter" \
|
||||
-e METER_1_DEVICE_CLASS=energy \
|
||||
-e METER_1_MULTIPLIER=1.0 \
|
||||
hameter:latest
|
||||
```
|
||||
|
||||
Your meter should appear in Home Assistant within a minute.
|
||||
|
||||
## Configuration
|
||||
|
||||
All configuration is done via environment variables. No config file needed.
|
||||
|
||||
### Required Variables
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `MQTT_HOST` | MQTT broker IP address |
|
||||
| `METER_1_ID` | Meter radio serial number (ERT ID, not the billing number) |
|
||||
| `METER_1_PROTOCOL` | Protocol: `scm`, `scm+`, `idm`, `r900`, `r900bcd`, `netidm` |
|
||||
|
||||
### Optional Variables
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `MQTT_PORT` | `1883` | MQTT broker port |
|
||||
| `MQTT_USER` | *(empty)* | MQTT username |
|
||||
| `MQTT_PASSWORD` | *(empty)* | MQTT password |
|
||||
| `MQTT_BASE_TOPIC` | `hameter` | Base MQTT topic |
|
||||
| `METER_1_NAME` | `Electric Meter` | Friendly name in HA |
|
||||
| `METER_1_MULTIPLIER` | `1.0` | Calibration multiplier (see below) |
|
||||
| `METER_1_DEVICE_CLASS` | `energy` | HA device class — sets smart defaults |
|
||||
| `METER_1_UNIT` | *(auto)* | Unit of measurement |
|
||||
| `METER_1_ICON` | *(auto)* | HA icon |
|
||||
| `METER_1_STATE_CLASS` | `total_increasing` | HA state class |
|
||||
| `SDR_DEVICE_ID` | `0` | RTL-SDR device index |
|
||||
| `LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
||||
|
||||
### Smart Defaults by Device Class
|
||||
|
||||
When you set `METER_1_DEVICE_CLASS`, the icon and unit are set automatically:
|
||||
|
||||
| Device Class | Icon | Unit |
|
||||
|-------------|------|------|
|
||||
| `energy` | `mdi:flash` | `kWh` |
|
||||
| `gas` | `mdi:fire` | `ft³` |
|
||||
| `water` | `mdi:water` | `gal` |
|
||||
|
||||
You can override any of these with the explicit `METER_1_ICON` or `METER_1_UNIT` variables.
|
||||
|
||||
### Multiple Meters
|
||||
|
||||
Add meters using `METER_2_*`, `METER_3_*`, etc. (up to `METER_9_*`):
|
||||
|
||||
```bash
|
||||
-e METER_1_ID=23040293 \
|
||||
-e METER_1_PROTOCOL=scm \
|
||||
-e METER_1_NAME="Electric Meter" \
|
||||
-e METER_1_DEVICE_CLASS=energy \
|
||||
-e METER_2_ID=55512345 \
|
||||
-e METER_2_PROTOCOL=r900 \
|
||||
-e METER_2_NAME="Water Meter" \
|
||||
-e METER_2_DEVICE_CLASS=water \
|
||||
```
|
||||
|
||||
Gaps are fine (e.g., meter 1 and 3 without 2).
|
||||
|
||||
## Finding Your Meter ID
|
||||
|
||||
Your meter has two numbers:
|
||||
- **Billing number** — printed on the faceplate (e.g., `2698881`). **Don't use this.**
|
||||
- **Radio serial number (ERT ID)** — transmitted over RF (e.g., `23040293`). **Use this one.**
|
||||
|
||||
To find the ERT ID, run HAMeter in discovery mode:
|
||||
|
||||
```bash
|
||||
docker run --rm \
|
||||
--device=/dev/bus/usb \
|
||||
-e MQTT_HOST=localhost \
|
||||
-e METER_1_ID=0 \
|
||||
-e METER_1_PROTOCOL=scm \
|
||||
hameter:latest --discover --discover-duration 120
|
||||
```
|
||||
|
||||
This listens for all nearby meter transmissions for 2 minutes and prints a summary:
|
||||
|
||||
```
|
||||
DISCOVERY SUMMARY — 12 unique meters found
|
||||
============================================================
|
||||
Meter ID Protocol Count Last Reading
|
||||
--------------------------------------------------
|
||||
23040293 SCM 8 519161
|
||||
55512345 R900 3 12345678
|
||||
...
|
||||
```
|
||||
|
||||
Cross-reference the IDs with your physical meters to identify which is yours. Your meter will likely be the one with the highest count (since it's closest).
|
||||
|
||||
## Calibration
|
||||
|
||||
The raw value from the meter's radio does not directly equal the reading on the meter display. You need a calibration multiplier to convert raw values to actual units (kWh, gallons, etc.).
|
||||
|
||||
### How to Calibrate
|
||||
|
||||
**Step 1: Read your physical meter**
|
||||
|
||||
Go to the meter and write down the display reading. For example: `59,669 kWh`
|
||||
|
||||
**Step 2: Get the raw reading from HA**
|
||||
|
||||
In Home Assistant, go to **Developer Tools → States** and find your meter's raw reading sensor. For example: `sensor.electric_meter_raw_reading` shows `516,030`
|
||||
|
||||
Take both readings at roughly the same time so they correspond.
|
||||
|
||||
**Step 3: Calculate the multiplier**
|
||||
|
||||
Divide the physical reading by the raw reading:
|
||||
|
||||
```
|
||||
multiplier = physical_reading / raw_reading
|
||||
multiplier = 59669 / 516030
|
||||
multiplier = 0.1156
|
||||
```
|
||||
|
||||
**Step 4: Set the multiplier**
|
||||
|
||||
Set `METER_1_MULTIPLIER=0.1156` in your Docker environment variables and restart the container.
|
||||
|
||||
### Verifying Calibration
|
||||
|
||||
After setting the multiplier, the **Reading** sensor in HA should closely match your physical meter display. If it drifts over time, repeat the process to recalculate.
|
||||
|
||||
The **Raw Reading** sensor (shown as a diagnostic entity in HA) always shows the unconverted value, so you can recalibrate at any time without removing the multiplier first.
|
||||
|
||||
### Why Is Calibration Needed?
|
||||
|
||||
ERT meters transmit a raw register value, not the displayed reading. The relationship between the two depends on the meter's internal configuration (Kh factor, register multiplier, number of dials). The multiplier accounts for all of these.
|
||||
|
||||
## Home Assistant Sensors
|
||||
|
||||
Each configured meter creates three sensors in HA:
|
||||
|
||||
| Sensor | Example Entity | Description |
|
||||
|--------|---------------|-------------|
|
||||
| **Reading** | `sensor.electric_meter_reading` | Calibrated value (e.g., `59,669 kWh`) |
|
||||
| **Raw Reading** | `sensor.electric_meter_raw_reading` | Unconverted register value (diagnostic) |
|
||||
| **Last Seen** | `sensor.electric_meter_last_seen` | Timestamp of last received transmission |
|
||||
|
||||
All three are grouped under a single device in HA with the manufacturer shown as "HAMeter".
|
||||
|
||||
### Energy Dashboard
|
||||
|
||||
To add your electric meter to the HA Energy Dashboard:
|
||||
|
||||
1. Go to **Settings → Dashboards → Energy**
|
||||
2. Under **Electricity Grid**, click **Add Consumption**
|
||||
3. Select `sensor.electric_meter_reading`
|
||||
4. Optionally set a cost per kWh
|
||||
|
||||
## Building from Source
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-username/HAMeter.git
|
||||
cd HAMeter
|
||||
docker build -t hameter:latest .
|
||||
```
|
||||
|
||||
The Dockerfile is a multi-stage build:
|
||||
1. **Go** — compiles `rtlamr` from source
|
||||
2. **C** — compiles `rtl-sdr` (librtlsdr + rtl_tcp) from source
|
||||
3. **Python** — runtime with `paho-mqtt` and `pyyaml`
|
||||
|
||||
## Unraid Setup
|
||||
|
||||
### Via Docker UI
|
||||
|
||||
1. Go to **Docker → Add Container**
|
||||
2. Set **Repository** to `hameter:latest`
|
||||
3. Set **Network** to Host
|
||||
4. Set **Extra Parameters** to `--device=/dev/bus/usb`
|
||||
5. Add environment variables for `MQTT_HOST`, `METER_1_ID`, `METER_1_PROTOCOL`, etc.
|
||||
6. Start the container
|
||||
|
||||
### USB Passthrough
|
||||
|
||||
The SDR dongle must be accessible inside the container. Use `--device=/dev/bus/usb` to pass the entire USB bus (simplest and most reliable across reboots).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No readings appearing
|
||||
- Verify the SDR dongle is on a **USB 2.0 port** (USB 3.0 causes interference)
|
||||
- Check that the antenna is attached
|
||||
- Run discovery mode to confirm the SDR is receiving signals
|
||||
- Check logs: `docker logs hameter`
|
||||
|
||||
### "usb_open error -3"
|
||||
The kernel DVB driver is claiming the device:
|
||||
```bash
|
||||
rmmod dvb_usb_rtl28xxu
|
||||
```
|
||||
|
||||
### MQTT connection refused
|
||||
- Verify Mosquitto is running: `docker ps | grep mosquitto`
|
||||
- Check `MQTT_HOST` and `MQTT_PORT` are correct
|
||||
- If using Docker bridge networking, use the host IP (not `127.0.0.1`)
|
||||
|
||||
### Sensors not appearing in HA
|
||||
- Verify the MQTT integration is configured in HA
|
||||
- In HA, go to **Developer Tools → MQTT → Listen** and subscribe to `hameter/#` to check if messages are arriving
|
||||
- Restart HA if sensors don't appear after the first discovery publish
|
||||
|
||||
## Supported Meters
|
||||
|
||||
HAMeter supports any ERT meter that transmits on the 900 MHz ISM band:
|
||||
|
||||
| Protocol | Typical Manufacturer | Meter Type |
|
||||
|----------|---------------------|------------|
|
||||
| SCM | Itron | Electric, Gas |
|
||||
| SCM+ | Itron | Electric, Gas |
|
||||
| IDM | Itron | Electric (with interval data) |
|
||||
| R900 | Neptune | Water |
|
||||
| R900BCD | Neptune | Water |
|
||||
| NetIDM | Itron | Electric (net metering) |
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Reference in New Issue
Block a user