-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
680e1e5
commit 2ee2913
Showing
10 changed files
with
884 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,318 @@ | ||
#!/usr/bin/env python | ||
# coding=utf-8 | ||
|
||
"""MQTT Home Assistant auto discovery for rtl_433 events.""" | ||
|
||
# It is strongly recommended to run rtl_433 with "-C si" and "-M newmodel". | ||
|
||
# Needs Paho-MQTT https://pypi.python.org/pypi/paho-mqtt | ||
|
||
# Option: PEP 3143 - Standard daemon process library | ||
# (use Python 3.x or pip install python-daemon) | ||
# import daemon | ||
|
||
from __future__ import print_function | ||
from __future__ import with_statement | ||
|
||
import socket | ||
import time | ||
import json | ||
import paho.mqtt.client as mqtt | ||
|
||
MQTT_HOST = "127.0.0.1" | ||
MQTT_PORT = 1883 | ||
MQTT_TOPIC = "rtl_433/+/events" | ||
DISCOVERY_PREFIX = "homeassistant" | ||
DISCOVERY_INTERVAL = 600 # Seconds before refreshing the discovery | ||
|
||
discovery_timeouts = {} | ||
|
||
mappings = { | ||
"temperature_C": { | ||
"device_type": "sensor", | ||
"object_suffix": "T", | ||
"config": { | ||
"device_class": "temperature", | ||
"name": "Temperature", | ||
"unit_of_measurement": "°C", | ||
"value_template": "{{ value_json.temperature_C }}" | ||
} | ||
}, | ||
"temperature_1_C": { | ||
"device_type": "sensor", | ||
"object_suffix": "T1", | ||
"config": { | ||
"device_class": "temperature", | ||
"name": "Temperature 1", | ||
"unit_of_measurement": "°C", | ||
"value_template": "{{ value_json.temperature_1_C }}" | ||
} | ||
}, | ||
"temperature_2_C": { | ||
"device_type": "sensor", | ||
"object_suffix": "T2", | ||
"config": { | ||
"device_class": "temperature", | ||
"name": "Temperature 2", | ||
"unit_of_measurement": "°C", | ||
"value_template": "{{ value_json.temperature_2_C }}" | ||
} | ||
}, | ||
"temperature_F": { | ||
"device_type": "sensor", | ||
"object_suffix": "F", | ||
"config": { | ||
"device_class": "temperature", | ||
"name": "Temperature", | ||
"unit_of_measurement": "°F", | ||
"value_template": "{{ value_json.temperature_F }}" | ||
} | ||
}, | ||
|
||
"battery_ok": { | ||
"device_type": "sensor", | ||
"object_suffix": "B", | ||
"config": { | ||
"device_class": "battery", | ||
"name": "Battery", | ||
"unit_of_measurement": "%", | ||
"value_template": "{{ float(value_json.battery_ok) * 99 + 1 }}" | ||
} | ||
}, | ||
|
||
"humidity": { | ||
"device_type": "sensor", | ||
"object_suffix": "H", | ||
"config": { | ||
"device_class": "humidity", | ||
"name": "Humidity", | ||
"unit_of_measurement": "%", | ||
"value_template": "{{ value_json.humidity }}" | ||
} | ||
}, | ||
|
||
"moisture": { | ||
"device_type": "sensor", | ||
"object_suffix": "H", | ||
"config": { | ||
"device_class": "moisture", | ||
"name": "Moisture", | ||
"unit_of_measurement": "%", | ||
"value_template": "{{ value_json.moisture }}" | ||
} | ||
}, | ||
|
||
"pressure_hPa": { | ||
"device_type": "sensor", | ||
"object_suffix": "P", | ||
"config": { | ||
"device_class": "pressure", | ||
"name": "Pressure", | ||
"unit_of_measurement": "hPa", | ||
"value_template": "{{ value_json.pressure_hPa }}" | ||
} | ||
}, | ||
|
||
"wind_speed_km_h": { | ||
"device_type": "sensor", | ||
"object_suffix": "WS", | ||
"config": { | ||
"device_class": "weather", | ||
"name": "Wind Speed", | ||
"unit_of_measurement": "km/h", | ||
"value_template": "{{ value_json.wind_speed_km_h }}" | ||
} | ||
}, | ||
|
||
"wind_speed_m_s": { | ||
"device_type": "sensor", | ||
"object_suffix": "WS", | ||
"config": { | ||
"device_class": "weather", | ||
"name": "Wind Speed", | ||
"unit_of_measurement": "km/h", | ||
"value_template": "{{ float(value_json.wind_speed_m_s) * 3.6 }}" | ||
} | ||
}, | ||
|
||
"gust_speed_km_h": { | ||
"device_type": "sensor", | ||
"object_suffix": "GS", | ||
"config": { | ||
"device_class": "weather", | ||
"name": "Gust Speed", | ||
"unit_of_measurement": "km/h", | ||
"value_template": "{{ value_json.gust_speed_km_h }}" | ||
} | ||
}, | ||
|
||
"gust_speed_m_s": { | ||
"device_type": "sensor", | ||
"object_suffix": "GS", | ||
"config": { | ||
"device_class": "weather", | ||
"name": "Gust Speed", | ||
"unit_of_measurement": "km/h", | ||
"value_template": "{{ float(value_json.gust_speed_m_s) * 3.6 }}" | ||
} | ||
}, | ||
|
||
"wind_dir_deg": { | ||
"device_type": "sensor", | ||
"object_suffix": "WD", | ||
"config": { | ||
"device_class": "weather", | ||
"name": "Wind Direction", | ||
"unit_of_measurement": "°", | ||
"value_template": "{{ value_json.wind_dir_deg }}" | ||
} | ||
}, | ||
|
||
"rain_mm": { | ||
"device_type": "sensor", | ||
"object_suffix": "RT", | ||
"config": { | ||
"device_class": "weather", | ||
"name": "Rain Total", | ||
"unit_of_measurement": "mm", | ||
"value_template": "{{ value_json.rain_mm }}" | ||
} | ||
}, | ||
|
||
"rain_mm_h": { | ||
"device_type": "sensor", | ||
"object_suffix": "RR", | ||
"config": { | ||
"device_class": "weather", | ||
"name": "Rain Rate", | ||
"unit_of_measurement": "mm/h", | ||
"value_template": "{{ value_json.rain_mm_h }}" | ||
} | ||
}, | ||
|
||
# motion... | ||
|
||
# switches... | ||
|
||
"depth_cm": { | ||
"device_type": "sensor", | ||
"object_suffix": "D", | ||
"config": { | ||
"device_class": "depth", | ||
"name": "Depth", | ||
"unit_of_measurement": "cm", | ||
"value_template": "{{ value_json.depth_cm }}" | ||
} | ||
}, | ||
} | ||
|
||
|
||
def mqtt_connect(client, userdata, flags, rc): | ||
"""Callback for MQTT connects.""" | ||
print("MQTT connected: " + mqtt.connack_string(rc)) | ||
if rc != 0: | ||
print("Could not connect. Error: " + str(rc)) | ||
else: | ||
client.subscribe(MQTT_TOPIC) | ||
|
||
|
||
def mqtt_disconnect(client, userdata, rc): | ||
"""Callback for MQTT disconnects.""" | ||
print("MQTT disconnected: " + mqtt.connack_string(rc)) | ||
|
||
|
||
def mqtt_message(client, userdata, msg): | ||
"""Callback for MQTT message PUBLISH.""" | ||
try: | ||
# Decode JSON payload | ||
data = json.loads(msg.payload.decode()) | ||
bridge_event_to_hass(client, msg.topic, data) | ||
|
||
except json.decoder.JSONDecodeError: | ||
print("JSON decode error: " + msg.payload.decode()) | ||
return | ||
|
||
|
||
def sanitize(text): | ||
"""Sanitize a name for Graphite/MQTT use.""" | ||
return (text | ||
.replace(" ", "_") | ||
.replace("/", "_") | ||
.replace(".", "_") | ||
.replace("&", "")) | ||
|
||
|
||
def publish_config(mqttc, topic, model, instance, mapping): | ||
"""Publish Home Assistant auto discovery data.""" | ||
global discovery_timeouts | ||
|
||
device_type = mapping["device_type"] | ||
object_suffix = mapping["object_suffix"] | ||
object_id = "-".join([model, instance, object_suffix]) | ||
|
||
path = "/".join([DISCOVERY_PREFIX, device_type, object_id, "config"]) | ||
|
||
# check timeout | ||
now = time.time() | ||
if path in discovery_timeouts: | ||
if discovery_timeouts[path] > now: | ||
return | ||
|
||
discovery_timeouts[path] = now + DISCOVERY_INTERVAL | ||
|
||
config = mapping["config"].copy() | ||
config["state_topic"] = topic | ||
|
||
mqttc.publish(path, json.dumps(config)) | ||
print(path, " : ", json.dumps(config)) | ||
|
||
|
||
def bridge_event_to_hass(mqttc, topic, data): | ||
"""Translate some rtl_433 sensor data to Home Assistant auto discovery.""" | ||
|
||
if "model" not in data: | ||
# not a device event | ||
return | ||
model = sanitize(data["model"]) | ||
|
||
if "channel" in data: | ||
channel = str(data["channel"]) | ||
instance = channel | ||
elif "id" in data: | ||
device_id = str(data["id"]) | ||
instance = device_id | ||
if not instance: | ||
# no unique device identifier | ||
return | ||
|
||
# detect known attributes | ||
for key in data.keys(): | ||
if key in mappings: | ||
publish_config(mqttc, topic, model, instance, mappings[key]) | ||
|
||
|
||
def rtl_433_bridge(): | ||
"""Run a MQTT Home Assistant auto discovery bridge for rtl_433.""" | ||
mqttc = mqtt.Client() | ||
mqttc.on_connect = mqtt_connect | ||
mqttc.on_disconnect = mqtt_disconnect | ||
mqttc.on_message = mqtt_message | ||
mqttc.connect_async(MQTT_HOST, MQTT_PORT, 60) | ||
mqttc.loop_start() | ||
|
||
while True: | ||
time.sleep(1) | ||
|
||
|
||
def run(): | ||
"""Run main or daemon.""" | ||
# with daemon.DaemonContext(files_preserve=[sock]): | ||
# detach_process=True | ||
# uid | ||
# gid | ||
# working_directory | ||
rtl_433_bridge() | ||
|
||
|
||
if __name__ == "__main__": | ||
run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/** @file | ||
MQTT output for rtl_433 events | ||
Copyright (C) 2019 Christian Zuckschwerdt | ||
This program is free software; you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation; either version 2 of the License, or | ||
(at your option) any later version. | ||
*/ | ||
|
||
#ifndef INCLUDE_OUTPUT_MQTT_H_ | ||
#define INCLUDE_OUTPUT_MQTT_H_ | ||
|
||
#include "data.h" | ||
|
||
struct data_output *data_output_mqtt_create(char const *host, char const *port, char *opts, char const *dev_hint); | ||
|
||
#endif /* INCLUDE_OUTPUT_MQTT_H_ */ |
Oops, something went wrong.