I made a few updates based on my own use case (of course) this afternoon. It’s a little hacky, I’ll try to clean it up a bit if I get a chance. The gist is that I was using balda’s awesome ruuvitag-discovery addon previously, which has really neat features like friendly names and the ability to perform math on the metrics (i.e. convert temps to F because the US is stuck in the middle ages). I also have a few tags running old firmware that are hard to reach, so I have a mix of format type 3 and type 5. Here’s the script I’m using now, works perfectly on my system. Many thanks for sharing, I never would have been able to do this in a couple of hours without your original script to work from.
from ruuvi_decoders import Df3Decoder, Df5Decoder
from json import dumps
MQTT_TOPIC_PREFIX = "ruuvi"
TEMPERATURE_UNITS = "F" # C for Celsius or F for Fahrenheit
DECIMAL_PLACES = 2
BATTERY_RANGE = {"min":2500,"max":3000}
SENSOR_FRIENDLY_NAMES = {"f33c5fc10393":"Living Room",
"dc757bb86337":"Middle Bedroom",
"f9fd6a322a01":"Front Bedroom",
"dc2c241a4b24":"Kitchen",
"ef336477a31a":"Back Bedroom"}
MEASUREMENT_CONFIG = {"temperature": {"stat_t":"homeassistant/sensor/<MAC_ADDRESS>/temperature/state",
"json_attr_t":"homeassistant/sensor/<MAC_ADDRESS>/temperature/attributes",
"name":"<SENSOR_FRIENDLY_NAME> Temperature",
"unit_of_meas":f"°{TEMPERATURE_UNITS}",
"dev_cla":"temperature",
"uniq_id":"ruuvitag_<MAC_ADDRESS>_temperature",
"device":{"ids":"ruuvitag-<MAC_ADDRESS>",
"mf":"Ruuvi Innovations Ltd",
"mdl": "RuuviTag",
"name": "<SENSOR_FRIENDLY_NAME>"}},
"humidity": {"stat_t":"homeassistant/sensor/<MAC_ADDRESS>/humidity/state",
"json_attr_t":"homeassistant/sensor/<MAC_ADDRESS>/humidity/attributes",
"name":"<SENSOR_FRIENDLY_NAME> Humidity",
"unit_of_meas":"%",
"dev_cla":"humidity",
"uniq_id":"ruuvitag_<MAC_ADDRESS>_humidity",
"device":{"ids":"ruuvitag-<MAC_ADDRESS>",
"mf":"Ruuvi Innovations Ltd",
"mdl": "RuuviTag",
"name": "<SENSOR_FRIENDLY_NAME>"}},
"battery_level": {"stat_t":"homeassistant/sensor/<MAC_ADDRESS>/battery_level/state",
"json_attr_t":"homeassistant/sensor/<MAC_ADDRESS>/battery_level/attributes",
"name":"<SENSOR_FRIENDLY_NAME> Battery Level",
"unit_of_meas":"%",
"dev_cla":"battery",
"uniq_id":"ruuvitag_<MAC_ADDRESS>_battery",
"device":{"ids":"ruuvitag-<MAC_ADDRESS>",
"mf":"Ruuvi Innovations Ltd",
"mdl": "RuuviTag",
"name": "<SENSOR_FRIENDLY_NAME>"}}
}
def sensor_exists(mac):
try:
sensor = f"sensor.{mac}"
return state.get(sensor) != "unavailable"
except (NameError):
return False
@mqtt_trigger(f"{MQTT_TOPIC_PREFIX}/#")
def mqtt_msg(topic=None, payload=None, payload_obj=None):
if payload_obj.get("data") is not None:
try:
raw_data = payload_obj.get("data")
clean_data = raw_data.split("FF9904")[1]
# decode the data based on the format field
format = clean_data[0:2]
data = {}
if format == "03":
decoder = Df3Decoder()
data = decoder.decode_data(clean_data)
else:
decoder = Df5Decoder()
data = decoder.decode_data(clean_data)
# get the mac from the topic (data format 3 doesn't include the mac)
raw_mac = topic.split('/')[-1]
mac = raw_mac.lower().replace(':','')
measurements = {}
if "temperature" in MEASUREMENT_CONFIG:
# get the temperature
temperature = round(data.get("temperature"), DECIMAL_PLACES)
if TEMPERATURE_UNITS == "F":
temperature = (temperature * (9/5) + 32)
measurements["temperature"] = round(temperature, DECIMAL_PLACES)
if "humidity" in MEASUREMENT_CONFIG:
# get the humidity
measurements["humidity"] = round(data.get("humidity"), DECIMAL_PLACES)
if "battery_level" in MEASUREMENT_CONFIG:
# get the battery and convert it to a percentage
battery_level = round((data.get("battery") - BATTERY_RANGE["min"]) * 100 / (BATTERY_RANGE["max"] - BATTERY_RANGE["min"]))
battery_level = max(1, battery_level)
battery_level = min(100, battery_level)
measurements["battery_level"] = round(battery_level, DECIMAL_PLACES)
for measurement,value in measurements.items():
if not sensor_exists(mac):
config_topic = f"homeassistant/sensor/{mac}/{measurement}/config"
config_payload = dumps(MEASUREMENT_CONFIG[measurement]).replace("<MAC_ADDRESS>",mac)
config_payload = config_payload.replace("<SENSOR_FRIENDLY_NAME>",SENSOR_FRIENDLY_NAMES[mac])
mqtt.publish(topic=config_topic, payload=config_payload, retain='True')
state_topic = f"homeassistant/sensor/{mac}/{measurement}/state"
mqtt.publish(topic=state_topic, payload=measurements[measurement], retain='True')
except (AttributeError, ValueError, TypeError):
log.warning(f'Error --> {payload}')