ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
ruuvi_ble.cpp
Go to the documentation of this file.
1#include "ruuvi_ble.h"
3#include "esphome/core/log.h"
4
6
7ESPHOME_LOG_TAG(TAG, "ruuvi_ble");
8
10 const uint8_t data_type = adv_data[0];
11 const auto *data = &adv_data[1];
12 switch (data_type) {
13 case 0x03: { // RAWv1
14 if (adv_data.size() != 14)
15 return false;
16
17 const uint8_t temp_sign = (data[1] >> 7) & 1;
18 const float temp_val = (data[1] & 0x7F) + (data[2] / 100.0f);
19 const float temperature = temp_sign == 0 ? temp_val : -1 * temp_val;
20
21 const float humidity = data[0] * 0.5f;
22 const float pressure = (encode_uint16(data[3], data[4]) + 50000.0f) / 100.0f;
23 const float acceleration_x = encode_value<int16_t>(&data[5]) / 1000.0f;
24 const float acceleration_y = encode_value<int16_t>(&data[7]) / 1000.0f;
25 const float acceleration_z = encode_value<int16_t>(&data[9]) / 1000.0f;
26 const float battery_voltage = encode_uint16(data[11], data[12]) / 1000.0f;
27
28 result.humidity = humidity;
29 result.temperature = temperature;
30 result.pressure = pressure;
31 result.acceleration_x = acceleration_x;
32 result.acceleration_y = acceleration_y;
33 result.acceleration_z = acceleration_z;
34 result.acceleration =
35 sqrtf(acceleration_x * acceleration_x + acceleration_y * acceleration_y + acceleration_z * acceleration_z);
36 result.battery_voltage = battery_voltage;
37
38 return true;
39 }
40 case 0x05: { // RAWv2
41 if (adv_data.size() != 24)
42 return false;
43
44 const float temperature = encode_value<int16_t>(data) * 0.005f;
45 const float humidity = encode_uint16(data[2], data[3]) / 400.0f;
46 const float pressure = (encode_uint16(data[4], data[5]) + 50000.0f) / 100.0f;
47 const float acceleration_x = encode_value<int16_t>(&data[6]) / 1000.0f;
48 const float acceleration_y = encode_value<int16_t>(&data[8]) / 1000.0f;
49 const float acceleration_z = encode_value<int16_t>(&data[10]) / 1000.0f;
50
51 const uint16_t power_info = encode_uint16(data[12], data[13]);
52 const float battery_voltage = ((power_info >> 5) + 1600.0f) / 1000.0f;
53 const float tx_power = ((power_info & 0x1F) * 2.0f) - 40.0f;
54
55 const float movement_counter = float(data[14]);
56 const float measurement_sequence_number = float(encode_uint16(data[15], data[16]));
57
58 result.temperature = data[0] == 0x7F && data[1] == 0xFF ? NAN : temperature;
59 result.humidity = data[2] == 0xFF && data[3] == 0xFF ? NAN : humidity;
60 result.pressure = data[4] == 0xFF && data[5] == 0xFF ? NAN : pressure;
61 result.acceleration_x = data[6] == 0xFF && data[7] == 0xFF ? NAN : acceleration_x;
62 result.acceleration_y = data[8] == 0xFF && data[9] == 0xFF ? NAN : acceleration_y;
63 result.acceleration_z = data[10] == 0xFF && data[11] == 0xFF ? NAN : acceleration_z;
64 if ((data[6] != 0xFF || data[7] != 0xFF) && (data[8] != 0xFF || data[9] != 0xFF) &&
65 (data[10] != 0xFF || data[11] != 0xFF)) {
66 result.acceleration =
67 sqrtf(acceleration_x * acceleration_x + acceleration_y * acceleration_y + acceleration_z * acceleration_z);
68 } else {
69 result.acceleration = NAN;
70 }
71 result.battery_voltage = (power_info >> 5) == 0x7FF ? NAN : battery_voltage;
72 result.tx_power = (power_info & 0x1F) == 0x1F ? NAN : tx_power;
73 result.movement_counter = movement_counter;
74 result.measurement_sequence_number = measurement_sequence_number;
75
76 return true;
77 }
78 default:
79 return false;
80 }
81}
82optional<RuuviParseResult> parse_ruuvi(const ble_device_base::ESPBTDevice &device) {
83 bool success = false;
84 RuuviParseResult result{};
85 for (auto &it : device.get_manufacturer_datas()) {
86 bool is_ruuvi = it.uuid.contains(0x99, 0x04);
87 if (!is_ruuvi)
88 continue;
89
90 if (parse_ruuvi_data_byte(it.data, result))
91 success = true;
92 }
93 if (!success)
94 return {};
95 return result;
96}
97
99 auto res = parse_ruuvi(device);
100 if (!res.has_value())
101 return false;
102
103 char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
104 ESP_LOGD(TAG, "Got RuuviTag (%s):", device.address_str_to(addr_buf));
105
106 if (res->humidity.has_value()) {
107 ESP_LOGD(TAG, " Humidity: %.2f%%", *res->humidity);
108 }
109 if (res->temperature.has_value()) {
110 ESP_LOGD(TAG, " Temperature: %.2f°C", *res->temperature);
111 }
112 if (res->pressure.has_value()) {
113 ESP_LOGD(TAG, " Pressure: %.2fhPa", *res->pressure);
114 }
115 if (res->acceleration.has_value()) {
116 ESP_LOGD(TAG, " Acceleration: %.3fG", *res->acceleration);
117 }
118 if (res->acceleration_x.has_value()) {
119 ESP_LOGD(TAG, " Acceleration X: %.3fG", *res->acceleration_x);
120 }
121 if (res->acceleration_y.has_value()) {
122 ESP_LOGD(TAG, " Acceleration Y: %.3fG", *res->acceleration_y);
123 }
124 if (res->acceleration_z.has_value()) {
125 ESP_LOGD(TAG, " Acceleration Z: %.3fG", *res->acceleration_z);
126 }
127 if (res->battery_voltage.has_value()) {
128 ESP_LOGD(TAG, " Battery Voltage: %.3fV", *res->battery_voltage);
129 }
130 if (res->tx_power.has_value()) {
131 ESP_LOGD(TAG, " TX Power: %.0fdBm", *res->tx_power);
132 }
133 if (res->movement_counter.has_value()) {
134 ESP_LOGD(TAG, " Movement Counter: %.0f", *res->movement_counter);
135 }
136 if (res->measurement_sequence_number.has_value()) {
137 ESP_LOGD(TAG, " Measurement Sequence Number: %.0f", *res->measurement_sequence_number);
138 }
139
140 return true;
141}
142
143} // namespace esphome::ruuvi_ble
ESPDEPRECATED("Use address_str_to() instead. Removed in 2027.2.0.", "2026.8.0") std const char * address_str_to(char *buf) const
Return MAC as "XX:XX:XX:XX:XX:XX" string.
const std::vector< ServiceData > & get_manufacturer_datas() const
Definition ble_device.h:224
bool parse_device(const ble_device_base::ESPBTDevice &device) override
Definition ruuvi_ble.cpp:98
std::vector< uint8_t > adv_data_t
Definition ble_device.h:38
ESPHOME_LOG_TAG(TAG, "ruuvi_ble")
optional< RuuviParseResult > parse_ruuvi(const ble_device_base::ESPBTDevice &device)
Definition ruuvi_ble.cpp:82
bool parse_ruuvi_data_byte(const ble_device_base::adv_data_t &adv_data, RuuviParseResult &result)
Definition ruuvi_ble.cpp:9
constexpr T encode_value(const uint8_t *bytes)
Encode a value from its constituent bytes (from most to least significant) in an array with length si...
Definition helpers.h:1036
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:1015
optional< float > measurement_sequence_number
Definition ruuvi_ble.h:19
uint16_t temperature
Definition sun_gtil2.cpp:12
uint8_t pressure
Definition tt21100.cpp:7