I just started out with Home Assistant and this was one of my first real projects to get set up. Everyone’s information here and a few other places were invaluable in getting this working. However, it seemed a bit piecemeal where I was grabbing bits of information from different comments and pages trying to put it all together. So hopefully I can assemble it a little bit for someone else like me who’s not as familiar with the individual parts of getting something like this running.
My setup has Home Assistant and all of the relevant services running in docker-compose, so I don’t have access to any of the add-ons. I picked up the Nooelec NESDR Mini 2+ RTL-SDR dongle and 10 of the Govee water sensors.
My first hurdle was getting rtl_433 running so I could receive the messages from the devices. As I mentioned, I have no access to add-ons which seems to be where most suggestions lead to. Exploring that and a few others that seemed like they added some unnecessary complexity for docker, I discovered GitHub - hertzg/rtl_433_docker: Repository containing multiarch docker images definitions of rtl_4 which just builds and runs the binary with no special logic or fluff, since I found out rtl_433 already supports MQTT. The doc suggests using the specific usb bus but that can change, so I just gave the whole thing.
#docker-compose
rtl-433-mqtt:
image: hertzg/rtl_433
restart: unless-stopped
volumes:
- /host/path/to/rtl-433-mqtt:/etc/rtl_433
devices:
- /dev/bus/usb:/dev/bus/usb
environment:
- TZ=America/New_York
Note: as of writing, the latest image is missing a library. I’m using tag alpine-3.13-21.05
until it’s fixed.
#rtl_433.conf
#config_file
config_file /etc/rtl_433/govee_rm433.conf
report_meta level
report_meta noise
report_meta stats
report_meta time:iso:usec:utc:tz
report_meta protocol
output mqtt://mosquitto:1883,user=USER,pass=PASS,retain=1,events=rtl_433[/model][/id][/subtype]
convert si
The important parts are the link to the second config file and the output, which defines the MQTT broker and the topic. Subtype is one of the few variables supported for value expansion for the topic, and it’s what I use for grouping the messages as one of sensor, battery, or heartbeat.
#govee_rm433.conf
decoder {
name=Govee_H5054,
modulation=OOK_PWM,
short=440,
long=940,
reset=9000,
gap=900,
bits=48,
get=id:@0:{16},
get=subtype:@16:{16}:[1285:sensor 1028:sensor 1022:battery 999:battery 997:battery 950:battery 956:battery 964:battery 923:battery 514:heartbeat],
get=event:@16:{16}:[ 1285:button 1028:leak_detected 1022:empty 999:25_percent 997:50_percent 950:75_percent 956:75_percent 964:75_percent 923:full 514:heartbeat],
unique
}
I got this decoder from this comment on the rtl_433 github, but modified it so that I could use retain and have the values saved individually on separate topics. So my entities’ values would survive restart.
Now on the home assistant side I made two entities for each of my physical sensors, a binary_sensor and a battery sensor.
#binary_sensors.yaml
- platform: mqtt
name: "Water Heater Water Sensor"
state_topic: "rtl_433/Govee_H5054/ID/sensor"
unique_id: "Govee_H5054_ID"
icon: mdi:water
payload_on: "leak_detected"
payload_off: "button"
value_template: "{{ value_json.event }}"
json_attributes_topic: "rtl_433/Govee_H5054/ID/+"
json_attributes_template: >
{
"id": "{{ value_json.id }}",
"model": "{{ value_json.model }}",
{%- if value_json.subtype == "heartbeat" %}
"heartbeat": "{{ as_timestamp(value_json.time) | timestamp_custom("%Y-%m-%d %H:%M:%S.%f") }}",
{%- endif %}
"time": "{{ as_timestamp(value_json.time) | timestamp_custom("%Y-%m-%d %H:%M:%S.%f") }}"
}
Like others, I use the button to turn it off instead of a timeout. I want to make sure someone goes and checks on it. I like having the id and model as attributes for if I need to reference things in the future. Also, I plan on making an automation to send a notification to check on the device if time is older than a month. I haven’t seen any heartbeat messages so I probably won’t be able to rely on that.
#sensors.yaml
- platform: mqtt
name: "Water Heater Water Sensor Battery"
state_topic: "rtl_433/Govee_H5054/ID/battery"
unique_id: "Govee_H5054_ID"
device_class: battery
unit_of_measurement: '%'
value_template: >
{%- if value_json.event == "full" -%}
100
{%- elif value_json.event == "75_percent" -%}
75
{%- elif value_json.event == "50_percent" -%}
50
{%- elif value_json.event == "25_percent" -%}
25
{%- elif value_json.event == "empty" -%}
0
{%- endif %}
json_attributes_topic: "rtl_433/Govee_H5054/ID/+"
json_attributes_template: >
{
"id": "{{ value_json.id }}",
"model": "{{ value_json.model }}",
{%- if value_json.subtype == "heartbeat" %}
"heartbeat": "{{ as_timestamp(value_json.time) | timestamp_custom("%Y-%m-%d %H:%M:%S.%f") }}",
{%- endif %}
"time": "{{ as_timestamp(value_json.time) | timestamp_custom("%Y-%m-%d %H:%M:%S.%f") }}"
}
Then I set up a simple automation to watch for any of them turning on.
#automation
alias: Water Sensor Alarm
description: ''
trigger:
- platform: state
entity_id:
- binary_sensor.water_shutoff_water_sensor
- binary_sensor.water_heater_water_sensor
to: 'on'
from: 'off'
condition: []
action:
- service: script.emergency_alarm
data:
title: Water Detected
message: >-
Water was detected by the {{ state_attr(trigger.entity_id,
'friendly_name') }}
mode: single
This calls a script I set up for any emergency messages, which sends TTS and an alarm to my wife and I.
#script
alias: Emergency Alarm
description: Send an emergency alert notification to all devices and TTS the message
mode: queued
max: 10
icon: mdi:alert
fields:
title:
description: Title of the notification
example: Alarm!
message:
description: The message content
example: The house is on fire!
sequence:
- service: notify.all_devices
data:
title: '{{ message }}'
message: TTS
data:
ttl: 0
priority: high
channel: alarm_stream_max
- service: notify.all_devices
data:
title: '{{ title }}'
message: '{{ message }}'
data:
ttl: 0
priority: high
channel: alarm_stream_max
I don’t know if that was all overly verbose, but hopefully it saves someone else a bit of time.