question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Support for Thermoplus / ThermoBeacon hydrometers

See original GitHub issue

I built a BLE custom component for Thermoplus hydrometers a while ago, but having found this component which is much more feature rich, I think it makes sense to get the support in here instead of my limited implementation: https://github.com/araines/homeassistant-thermoplus-ble

In terms of how these work, the code above seems to mostly work, but here are some details:

The sensors appear to broadcast three different messages, one which identifies the sensor as a “ThermoBeacon”, one which contains the temp, humidity & battery data, and another one which I have not determined the purpose of it.

As an example, here is one of my sensors:

# hcitool lescan
LE Scan ...
9B:B0:00:00:02:60 (unknown)
9B:B0:00:00:02:60 ThermoBeacon

Then from the HCI dump:

# cat dump.txt | grep '60 02 00 00 B0 9B'
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 28 0B 64 01 9E 03 9A
> 04 3E 2B 02 01 00 00 60 02 00 00 B0 9B 1F 02 01 06 03 02 F0
  FF 17 FF 11 00 00 00 60 02 00 00 B0 9B 95 01 1B 45 0D 00 11
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 30 0B 64 01 9E 03 9C
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 30 0B 64 01 9E 03 9D
> 04 3E 2B 02 01 00 00 60 02 00 00 B0 9B 1F 02 01 06 03 02 F0
  FF 17 FF 11 00 00 00 60 02 00 00 B0 9B 95 01 1B 45 0D 00 11
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 2D 0B 64 01 9E 03 9F
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 2D 0B 64 01 9E 03 A0
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 2D 0B 64 01 9E 03 A0
> 04 3E 2B 02 01 00 00 60 02 00 00 B0 9B 1F 02 01 06 03 02 F0
  FF 17 FF 11 00 00 00 60 02 00 00 B0 9B 95 01 1B 45 0D 00 11
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 2F 0B 64 01 9E 03 A2
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 2F 0B 64 01 9E 03 A3
> 04 3E 2B 02 01 00 00 60 02 00 00 B0 9B 1F 02 01 06 03 02 F0
  FF 17 FF 11 00 00 00 60 02 00 00 B0 9B 95 01 1B 45 0D 00 11
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 2F 0B 64 01 9E 03 A5
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 2F 0B 64 01 9E 03 A5
> 04 3E 2B 02 01 00 00 60 02 00 00 B0 9B 1F 02 01 06 03 02 F0
  FF 17 FF 11 00 00 00 60 02 00 00 B0 9B 95 01 1B 45 0D 00 11
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 31 0B 64 01 9E 03 A9
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 31 0B 64 01 9E 03 AB
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 2F 0B 64 01 9E 03 AB
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 2F 0B 64 01 9E 03 AC
> 04 3E 2B 02 01 00 00 60 02 00 00 B0 9B 1F 02 01 06 03 02 F0
  FF 17 FF 11 00 00 00 60 02 00 00 B0 9B 95 01 1B 45 0D 00 11
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 30 0B 64 01 9E 03 AE
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 30 0B 64 01 9E 03 AF
> 04 3E 2B 02 01 00 00 60 02 00 00 B0 9B 1F 02 01 06 03 02 F0
  FF 17 FF 11 00 00 00 60 02 00 00 B0 9B 95 01 1B 45 0D 00 11
> 04 3E 2B 02 01 00 00 60 02 00 00 B0 9B 1F 02 01 06 03 02 F0
  FF 17 FF 11 00 00 00 60 02 00 00 B0 9B 95 01 1B 45 0D 00 11
> 04 3E 29 02 01 00 00 60 02 00 00 B0 9B 1D 02 01 06 03 02 F0
  FF 15 FF 11 00 00 00 60 02 00 00 B0 9B 2F 0B 64 01 9E 03 B2
> 04 3E 2B 02 01 00 00 60 02 00 00 B0 9B 1F 02 01 06 03 02 F0
  FF 17 FF 11 00 00 00 60 02 00 00 B0 9B 95 01 1B 45 0D 00 11

Approximately at the time of the above dump the sensor read close to: 22.3C 57% humidity.

This test file shows basically how the decoding works: https://github.com/araines/homeassistant-thermoplus-ble/blob/master/test.py Giving this output:

RAW1 (Med packet - 44 bytes)
('06:88:00:00:16:27',)
[{'data_type': b'\x01', 'length': 2, 'value': b'\x06'}, {'data_type': b'\x02', 'length': 3, 'value': b'\xf0\xff'}, {'data_type': b'\xff', 'length': 21, 'value': b"\x11\x00\x00\x00'\x16\x00\x00\x88\x06<\x0c\x8f\x01\xa1\x03\xb9\xd7\x03"}]
mac: 06:88:00:00:16:27
Payload: 3132 24.94 58.06 -56

RAW2 (Long packet - 46 bytes)
('06:88:00:00:16:27',)
[{'data_type': b'\x01', 'length': 2, 'value': b'\x06'}, {'data_type': b'\x02', 'length': 3, 'value': b'\xf0\xff'}, {'data_type': b'\xff', 'length': 23, 'value': b"\x11\x00\x00\x00'\x16\x00\x00\x88\x06\xfa\x01\x98\x17\x00\x00T\x01Ns\x02"}]

RAW3 (Short packet - 38 bytes)
('06:88:00:00:16:27',)
[{'data_type': b'\t', 'length': 13, 'value': b'ThermoBeacon'}, {'data_type': b'\x12', 'length': 5, 'value': b'\x18\x008\x01'}, {'data_type': b'\n', 'length': 2, 'value': b''}]
ThermoBeacon

Noting here that the medium length message has the payload:

3132 - Battery voltage in mV
24.94 - Temperature in C
58.06 - Humidity %
-56 - Signal strength (RSSI)

According to the reverse-engineered app code, the battery voltage is interpreted as such:

Voltage Level
>=3000 100%
>=2800 80%
>=2600 60%
>=2500 40%
>=2450 20%
<2450 0%

The temperature and humidity values are the raw value divided by 16 to get the true values (details in the code).

For auto-discovery my implementation looks for sensors emitting the ThermoBeacon identifier, then remembers those MAC addresses. Any subsequent messages emitted from those MAC addresses are analysed to find the correct (medium length) message and then decoded to get the associated data.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:37

github_iconTop GitHub Comments

1reaction
arainescommented, Jun 8, 2021

Same - all looking good to me now! Thanks for everything 😃

1reaction
ACrazyConceptcommented, Jun 8, 2021

Yup that did the trick. Thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

ThermoPlus - Home Assistant
Connect and control your ThermoPlus devices using the ThermoBeacon integration. ... Support for devices by ThermoPlus in Home Assistant is provided by the ......
Read more >
Scan BLE passive thermometers and send data through mqtt
I created a script that collects temperature/humidity from ThermoBeacon (ThermoPlus, Bifri, Oria) based on this project: ...
Read more >
Integrari - Be Tech
Integrations · Home Assistant Alerts · Developers · Data Science · Community Forum · Contact (no support!) · Security Vulnerabilities · Privacy ·...
Read more >
How do I read manufacturer data from a thermobeacon BLE ...
I am trying to receive the temperature and humidity that is sent out in the manufacturer data field as part of the BLE...
Read more >
Untitled
... Moat Qingping Thermobeacon Thermopro / Sensorpro ThermoPlus SensorPush Tilt ... I hope Govee will support Google Home by updating the app some...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found