This project uses any android phone to read Temperature and Humidity from the low cost BLE (Bluetooth Low energy) Mijia senor and send MQTT to Home Assistant.
I have three of these Xiaomi Mijia high precision temperature sensors, which give the temperature and air humidity. These devices should work with the Home Assistant mitemp_bt integration but I and many others have problems with the readings dropping out. There is a special custom component ( see here ) but people still report having errors.
In addition, I run Home assistant on Termux which can’t directly read bluetooth data. Installation of HASS on termux is covered here.
Part 1 BLE Gateway
I found a Playstore android app ( BLE Gateway ) that reads in BLE (Bluetooth low energy) signals and sends the data onto your MQTT server. Some apps I looked at were really geeky, this one is simple and obvious to set up; you add your BLE devices ( which show up as MJ_HT_V1) and set your MQTT broker and topic.
The app then scans and sends the raw sensor data to your MQTT server which can be read by a Home Assistant MQTT template sensor ( see part 3).
Part 2 Keep Android awake
This was most difficult; Android phones insist on killing applications to save power even when the phone is plugged in!
I found that solving this can be done using the Playstore “Automate” app. I used a very simple infinite loop that waits a while, restarts the BLEgateway, & cleans up some trash directories. You can find it here.
Part 3 Home Assistant MQTT sensor
The sent data can be read into Home Assistant mqtt sensors. The RawData advertisement needs to be parsed to get the Temperature and Relative Humidity values. I looked here to get the general idea, followed by a great deal of trial and error to get the following MQTT sensor configuration. I have included comments to help understand the logic.
I have put XXXXXXX above the two places where the config needs to be customised. Firstly, the MAC address of the sensor to be checked. Secondly, if one of the messages does not contain the device, the name of the sensor is used to report the last value rather than a blank.
This is for the temperature
- platform: mqtt
name: "Arr Salon Temp"
unit_of_measurement: '°C'
state_topic: "androdro/ble2"
value_template: >
{# set a namespace to check if new value found #}
{% set ns = namespace(found=false) %}
{# loop through all BLE devices #}
{% for dev in value_json.BleDevice %}
{# Check MAC is the device for this sensor #}
{# Config here. XX XX XX XX XX XX #}
{% if dev.MAC == '4C:65:A8:DB:CC:18' %}
{% set val = dev.RawData %}
{# Check if data has Temperature value #}
{% if (val[36:38] == "04") or (val[36:38] == "0d") %}
{# set new value found true #}
{% set ns.found = true %}
{# Convert data from big endian hex #}
{% set p = 42 %}
{{ ((val[p+2]~val[p+3]~val[p]~val[p+1])|int(base=16))/10 }}
{% endif %}
{% endif %}
{% endfor %}
{# if no new value found, keep old value #}
{% if not(ns.found) %}
{# Config here XXXXXXXXXXX #}
{{ states('sensor.arr_salon_temp') }}
{% endif %}
( old check yaml identing as my cut & paste was weird)
This is for relative humidity.
- platform: mqtt
name: "Arr Salon RH"
unit_of_measurement: '%'
state_topic: "androdro/ble2"
value_template: >
{% set ns = namespace(found=false) %}
{% for dev in value_json.BleDevice %}
{% if dev.MAC == '4C:65:A8:DB:CC:18' %}
{% set val= dev.RawData%}
{% if (val[36:38] == "06") %}
{% set ns.found = true %}
{% set p = 42 %}
{{ ((val[p+2]~val[p+3]~val[p]~val[p+1])|int(base=16))/10 }}
{% elif (val[36:38] == "0d") %}
{% set ns.found = true %}
{% set p = 46 %}
{{ ((val[p+2]~val[p+3]~val[p]~val[p+1])|int(base=16))/10 }}
{% endif %}
{% endif %}
{% endfor %}
{% if not(ns.found) %}
{{ states('sensor.arr_salon_RH') }}
{% endif %}
That’s it. I hope you it useful.