17 How to integrate rtl_433 sensors into openHAB via MQTT
Bjorn Helgaas edited this page 2020-02-29 20:09:59 -06:00

Integrate rtl_433 sensors into openHAB via MQTT

Since rtl_433 now has the ability to directly publish sensor data to a MQTT broker, it's reasonably easy to integrate with MQTT-enabled automation solutions.

This HowTo could serve as a blueprint for integrating two different types of sensors into home automation solution openHAB

We focus here on the rtl_433 side and assume you are familiar with openHAB and its basic concepts (Things, Channels, Items ...) and that you have a MQTT broker (preferably Mosquitto) running.

1. Getting the devices received by rtl_433

When starting with rtl_433 the first thing to check is whether the device is already "known" to rtl_433 and has a dedicated decoder implemented. If so, we can simply read values from this device by specifying the right protocol.

As an example of this kind of devices we use a Globaltronic GT-WT02, a simple temperature/humidity transmitter sold with different weather stations. To gather data from it, we can simply start rtl_433 while specifying the right protocol to receive - -R 25 in this case:

# rtl_433 -R 25
<---OUTPUT OMITTED---->
Tuner gain set to Auto.
Tuned to 433.920MHz.
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time      : 2019-08-30 13:48:12
model     : GT-WT02      ID Code   : 215
Channel   : 1            Battery   : OK            Button    : 0             Temperature: 26.3 C       Humidity  : 54 %          Integrity : CHECKSUM
^CSignal caught, exiting!

The second type of device is not directly supported by the rtl_433 and has no built-in decoder yet. Fortunately, many such devices can be decoded by a so-called "flex decoder".

Our example here is a cheap EV1527-base motion detector. To get notifications from it, we specify a flex decoder specification like this:

-R 0 -X n=EV1527-PIR,m=OOK_PWM,s=400,l=1200,g=1500,r=12000,repeats>=4,rows=25,unique

# rtl_433 -R 0 -X "n=EV1527-PIR,m=OOK_PWM,s=400,l=1200,g=1500,r=12000,repeats>=4,rows=25,unique"
<---OUTPUT OMITTED>
Tuner gain set to Auto.
Tuned to 433.920MHz.
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time      : 2019-08-30 14:00:30
model     : EV1527-PIR count     : 25           num_rows  : 25            len       : 25            data      : 1234567
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time      : 2019-08-30 14:00:39
model     : EV1527-PIR count     : 25           num_rows  : 25            len       : 25            data      : 1234567
^CSignal caught, exiting!

Good. Messages from "unsupported" motion detector can be received too.

2. Publish output to MQTT

MQTT is the "swiss army knife" to integrate IoT components via simple attribute/value peers ("topics"). These topics are published to an "MQTT broker".

Clients interested in these topics can subscribe to them.

We choose the MQTT output by the -F mqtt://.... option, e.g.:

-F mqtt://localhost:1883,retain=0,devices=sensors/rtl_433/

and check whether the output is sent to the broker:

#rtl_433 -R 0 -X "n=EV1527-PIR,m=OOK_PWM,s=400,l=1200,g=1500,r=12000,repeats>=4,rows=25,unique" -F mqtt://localhost:1883,retain=0,devices=sensors/rtl_433/
<---OUTPUT OMITTED--->
Tuner gain set to Auto.
Tuned to 433.920MHz.
MQTT Connected...
MQTT Connection established.

On a second terminal screen we subscribe to sensors/# to observe incoming topics starting with "sensors/":

# mosquitto_sub -v -t sensors/#
sensors/rtl_433//time 2019-08-30 14:14:38
sensors/rtl_433//count 25
sensors/rtl_433//num_rows 25
sensors/rtl_433//len 25
sensors/rtl_433//data 1234567

Well - works too. We get topics created for our motion sensor....

3. Prettifying the output

To simplify the consumption of the published content by openHAB (as well as by other MQTT clients) it helps a lot if we slightly modify or format the topics:

-F mqtt://localhost:1883,retain=0,devices=sensors/rtl_433/P[protocol:255]/C[channel:0] -M newmodel -M protocol -M time:iso

This does the following:

-M newmodel ... use revised model names and MQTT topics (will become default some day)

-M protocol ... outputs the protocol number along with the other output

[protocol:255]... placeholder for the protocol number if defined, otherwise set to "255"

[channel:0]... placeholder for the channel ID if defined, otherwise set to "0"

-M time:iso ... generate time topics which can be directly sent to openHAB's DateTimeitems

Putting this all together in one command line gives us:

rtl_433 -R 25 -X "n=EV1527-PIR,m=OOK_PWM,s=400,l=1200,g=1500,r=12000,repeats>=4,rows=25,unique" -F mqtt://localhost:1883,retain=0,devices=sensors/rtl_433/P[protocol:255]/C[channel:0] -M newmodel -M protocol -M time:iso

which generates these pretty topics at the broker:

# mosquitto_sub -v -t sensors/#
sensors/rtl_433/P25/C3/time 2019-08-30T14:23:25
sensors/rtl_433/P25/C3/protocol 25
sensors/rtl_433/P25/C3/id 20
sensors/rtl_433/P25/C3/channel 3
sensors/rtl_433/P25/C3/battery_ok 1
sensors/rtl_433/P25/C3/button 0
sensors/rtl_433/P25/C3/temperature_C 28.400000
sensors/rtl_433/P25/C3/humidity 38.000000
sensors/rtl_433/P25/C3/mic CHECKSUM
sensors/rtl_433/P255/C0/time 2019-08-30T14:23:25
sensors/rtl_433/P255/C0/count 25
sensors/rtl_433/P255/C0/num_rows 25
sensors/rtl_433/P255/C0/len 1
sensors/rtl_433/P255/C0/data 8
sensors/rtl_433/P255/C0/time 2019-08-30T14:23:26
sensors/rtl_433/P255/C0/count 25
sensors/rtl_433/P255/C0/num_rows 25
sensors/rtl_433/P255/C0/len 25
sensors/rtl_433/P255/C0/data 1234567

So for the GT-WT-02 we get for example:

sensors/rtl_433/P25/C3/temperature_C 28.400000

Protocol==25

Channel == 3 (set by the tiny switch at the back of the sensor)

Temperature == 28.4 degree celsius

4. Convert the settings to a configuration file

The command line got pretty long meanwhile. This is neither easy to read nor to change if needed.

Luckily we can put all that configuration stuff into a configuration file. A sample is provided along with the rtl_433.

Rtl_433 looks for it (rtl_433.conf) by default in different locations. If we put our configfile in one of these default locations, we don't even need to specify the file at launch, rtl_433 will honor it. If you store it somewhere else or use a different name you can pass it by the -c <path/configfile>.

Let's copy the sample config file to /etc/rtl_433/rtl_433.conf :

cp conf/rtl_433.example.conf /etc/rtl_433/rtl_433.conf

and add, uncomment and/or modify the following lines:

# to get the "protocol"-token available in output and set the time output to ISO
report_meta protocol
report_meta time:iso

# specify MQTT output and formatting
output mqtt://localhost:1883,retain=0,devices=sensors/rtl_433/P[protocol:255]/C[channel:0]

# enable the needed protocol (25 in our example)
protocol 25  # GT-WT-02 Sensor

# create the flex decoder specification
decoder {
        n=EV1527-PIR,
        m=OOK_PWM,
        s=400,
        l=1200,
        g=1500,
        r=12000,
        repeats>=4,
        rows=25,
        get=@0:{25}:channel:[1234567:10 2345678:20],
        get=@0:{1}:command:[0:OPEN 1:OPEN],
        unique
}

You may have noticed the two get= statements in the flex decoder which have been added compared to the former command line. This is the idea behind:

get=@0:{25}:channel:[1234567:10 2345678:20] sets a channel-token to 10 or 20 based on the unique EV1527-ID in the data

get=@0:{1}:command:[0:OPEN 1:OPEN] adds a command-topic with value always set to OPEN to assist openHAB integration

7. Make rtl_433 controlled by systemd

You certainly want to have rtl_433 starting automatically every time your system boots. Systemd can do this for us...

Create the /etc/systemd/system/rtl_433-mqtt.service with this content:

# more /etc/systemd/system/rtl_433-mqtt.service
[Unit]
Description=rtl_433 to MQTT publisher
After=network.target
[Service]
ExecStart=/usr/local/bin/rtl_433
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target

Make it automatically start at system start:

#systemctl enable rtl_433-mqtt.service

Start the service:

#systemctl start rtl_433-mqtt.service

6. Create your openHAB MQTT things

In the openHAB thing configuration folder, we create a MQTT bridge definition along with channels matching our MQTT topics from above:

/etc/openhab2/things/mqtt.things:

Bridge mqtt:broker:MY-MQTT "MQTT Broker" @ "Central functions" [
  host="192.168.x.y",
  secure=false,
  port=1883,
  qos=0,
  retain=false,
  clientid="Oh2Mqtt2Thing",
  keep_alive_time=30000,
  reconnect_time=60000
]
{
    Thing topic RTL_433 "433MHz receiver" @ "Central functions"  {
      Channels:
          Type number : temp  	       [ stateTopic="sensors/rtl_433/P25/C3/temperature_C" ]
          Type number : hum   	       [ stateTopic="sensors/rtl_433/P25/C3/humidity" ]
          Type switch : batt  	       [ stateTopic="sensors/rtl_433/P25/C3/battery_ok"]
          Type contact: motion1        [ stateTopic="sensors/rtl_433/P255/C10/command" ]
          Type datetime: motion1_time  [ stateTopic="sensors/rtl_433/P255/C10/time" ]
    }
}

Now you likely see why we publish a command==OPEN when motion is detected:

The motion1-channel is of type contact which supports just the two states OPEN and CLOSED. Directly sending OPEN makes it easy to configure without any further logic to translate (see: transformations) other values to OPEN.

You might need to restart the MQTT binding at this point.

7. Configure the matching openHAB items

Now we are going to link the configured channels to the real items which we can use in rules or UIs:

Number Temp1 	"Temperature [%.1f °C]" <temperature>   { channel="mqtt:topic:MY-MQTT:RTL_433:temp"}
Number Hum1 	"Humidity [%d %%rH]"  	<humidity> 	{ channel="mqtt:topic:MY-MQTT:RTL_433:hum"}
Switch Bat1 	"Battery o.k."  			{ channel="mqtt:topic:MY-MQTT:RTL_433:batt"}

Contact Motion1 "Motion" 		<lock>		{ channel="mqtt:topic:MY-MQTT:RTL_433:motion1", expire="10s, state=CLOSED" }
DateTime Motion1_time "last detection"  <motion>        { channel="mqtt:topic:OGV-MQTT:RTL_433:motion1_time" }

8. Observe the log

Start the openHAB logviewer and look for the just created items getting populated:

2019-08-30 15:17:23.895 [vent.ItemStateChangedEvent] - Temp1 changed from UNDEF to 26.600000
2019-08-30 15:17:23.903 [vent.ItemStateChangedEvent] - Hum1 changed from UNDEF to 52.000000
2019-08-30 15:18:00.555 [vent.ItemStateChangedEvent] - Motion1 changed from CLOSED to OPEN
2019-08-30 15:18:11.470 [vent.ItemStateChangedEvent] - Motion1 changed from OPEN to CLOSED

Have fun ;-)