ESPHome  2024.3.1
ruuvi_ble.cpp
Go to the documentation of this file.
1 #include "ruuvi_ble.h"
2 #include "esphome/core/log.h"
3 
4 #ifdef USE_ESP32
5 
6 namespace esphome {
7 namespace ruuvi_ble {
8 
9 static const char *const TAG = "ruuvi_ble";
10 
12  const uint8_t data_type = adv_data[0];
13  const auto *data = &adv_data[1];
14  switch (data_type) {
15  case 0x03: { // RAWv1
16  if (adv_data.size() != 14)
17  return false;
18 
19  const uint8_t temp_sign = (data[1] >> 7) & 1;
20  const float temp_val = (data[1] & 0x7F) + (data[2] / 100.0f);
21  const float temperature = temp_sign == 0 ? temp_val : -1 * temp_val;
22 
23  const float humidity = data[0] * 0.5f;
24  const float pressure = (uint16_t(data[3] << 8) + uint16_t(data[4]) + 50000.0f) / 100.0f;
25  const float acceleration_x = (int16_t(data[5] << 8) + int16_t(data[6])) / 1000.0f;
26  const float acceleration_y = (int16_t(data[7] << 8) + int16_t(data[8])) / 1000.0f;
27  const float acceleration_z = (int16_t(data[9] << 8) + int16_t(data[10])) / 1000.0f;
28  const float battery_voltage = (uint16_t(data[11] << 8) + uint16_t(data[12])) / 1000.0f;
29 
30  result.humidity = humidity;
31  result.temperature = temperature;
32  result.pressure = pressure;
33  result.acceleration_x = acceleration_x;
34  result.acceleration_y = acceleration_y;
35  result.acceleration_z = acceleration_z;
36  result.acceleration =
37  sqrtf(acceleration_x * acceleration_x + acceleration_y * acceleration_y + acceleration_z * acceleration_z);
38  result.battery_voltage = battery_voltage;
39 
40  return true;
41  }
42  case 0x05: { // RAWv2
43  if (adv_data.size() != 24)
44  return false;
45 
46  const float temperature = (int16_t(data[0] << 8) + int16_t(data[1])) * 0.005f;
47  const float humidity = (uint16_t(data[2] << 8) | uint16_t(data[3])) / 400.0f;
48  const float pressure = ((uint16_t(data[4] << 8) | uint16_t(data[5])) + 50000.0f) / 100.0f;
49  const float acceleration_x = (int16_t(data[6] << 8) + int16_t(data[7])) / 1000.0f;
50  const float acceleration_y = (int16_t(data[8] << 8) + int16_t(data[9])) / 1000.0f;
51  const float acceleration_z = (int16_t(data[10] << 8) + int16_t(data[11])) / 1000.0f;
52 
53  const uint16_t power_info = (uint16_t(data[12] << 8) | data[13]);
54  const float battery_voltage = ((power_info >> 5) + 1600.0f) / 1000.0f;
55  const float tx_power = ((power_info & 0x1F) * 2.0f) - 40.0f;
56 
57  const float movement_counter = float(data[14]);
58  const float measurement_sequence_number = float(uint16_t(data[15] << 8) | uint16_t(data[16]));
59 
60  result.temperature = data[0] == 0x7F && data[1] == 0xFF ? NAN : temperature;
61  result.humidity = data[2] == 0xFF && data[3] == 0xFF ? NAN : humidity;
62  result.pressure = data[4] == 0xFF && data[5] == 0xFF ? NAN : pressure;
63  result.acceleration_x = data[6] == 0xFF && data[7] == 0xFF ? NAN : acceleration_x;
64  result.acceleration_y = data[8] == 0xFF && data[9] == 0xFF ? NAN : acceleration_y;
65  result.acceleration_z = data[10] == 0xFF && data[11] == 0xFF ? NAN : acceleration_z;
66  result.acceleration = result.acceleration_x == NAN || result.acceleration_y == NAN || result.acceleration_z == NAN
67  ? NAN
68  : sqrtf(acceleration_x * acceleration_x + acceleration_y * acceleration_y +
69  acceleration_z * acceleration_z);
70  result.battery_voltage = (power_info >> 5) == 0x7FF ? NAN : battery_voltage;
71  result.tx_power = (power_info & 0x1F) == 0x1F ? NAN : tx_power;
72  result.movement_counter = movement_counter;
73  result.measurement_sequence_number = measurement_sequence_number;
74 
75  return true;
76  }
77  default:
78  return false;
79  }
80 }
82  bool success = false;
83  RuuviParseResult result{};
84  for (auto &it : device.get_manufacturer_datas()) {
85  bool is_ruuvi = it.uuid.contains(0x99, 0x04);
86  if (!is_ruuvi)
87  continue;
88 
89  if (parse_ruuvi_data_byte(it.data, result))
90  success = true;
91  }
92  if (!success)
93  return {};
94  return result;
95 }
96 
98  auto res = parse_ruuvi(device);
99  if (!res.has_value())
100  return false;
101 
102  ESP_LOGD(TAG, "Got RuuviTag (%s):", device.address_str().c_str());
103 
104  if (res->humidity.has_value()) {
105  ESP_LOGD(TAG, " Humidity: %.2f%%", *res->humidity);
106  }
107  if (res->temperature.has_value()) {
108  ESP_LOGD(TAG, " Temperature: %.2f°C", *res->temperature);
109  }
110  if (res->pressure.has_value()) {
111  ESP_LOGD(TAG, " Pressure: %.2fhPa", *res->pressure);
112  }
113  if (res->acceleration.has_value()) {
114  ESP_LOGD(TAG, " Acceleration: %.3fG", *res->acceleration);
115  }
116  if (res->acceleration_x.has_value()) {
117  ESP_LOGD(TAG, " Acceleration X: %.3fG", *res->acceleration_x);
118  }
119  if (res->acceleration_y.has_value()) {
120  ESP_LOGD(TAG, " Acceleration Y: %.3fG", *res->acceleration_y);
121  }
122  if (res->acceleration_z.has_value()) {
123  ESP_LOGD(TAG, " Acceleration Z: %.3fG", *res->acceleration_z);
124  }
125  if (res->battery_voltage.has_value()) {
126  ESP_LOGD(TAG, " Battery Voltage: %.3fV", *res->battery_voltage);
127  }
128  if (res->tx_power.has_value()) {
129  ESP_LOGD(TAG, " TX Power: %.0fdBm", *res->tx_power);
130  }
131  if (res->movement_counter.has_value()) {
132  ESP_LOGD(TAG, " Movement Counter: %.0f", *res->movement_counter);
133  }
134  if (res->measurement_sequence_number.has_value()) {
135  ESP_LOGD(TAG, " Measurement Sequence Number: %.0f", *res->measurement_sequence_number);
136  }
137 
138  return true;
139 }
140 
141 } // namespace ruuvi_ble
142 } // namespace esphome
143 
144 #endif
optional< float > movement_counter
Definition: ruuvi_ble.h:21
optional< float > battery_voltage
Definition: ruuvi_ble.h:19
uint8_t pressure
Definition: tt21100.cpp:19
float temperature
Definition: qmp6988.h:71
optional< float > acceleration_x
Definition: ruuvi_ble.h:16
const std::vector< ServiceData > & get_manufacturer_datas() const
optional< float > acceleration_y
Definition: ruuvi_ble.h:17
optional< float > acceleration_z
Definition: ruuvi_ble.h:18
optional< float > measurement_sequence_number
Definition: ruuvi_ble.h:22
optional< RuuviParseResult > parse_ruuvi(const esp32_ble_tracker::ESPBTDevice &device)
Definition: ruuvi_ble.cpp:81
std::vector< uint8_t > adv_data_t
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override
Definition: ruuvi_ble.cpp:97
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
bool parse_ruuvi_data_byte(const esp32_ble_tracker::adv_data_t &adv_data, RuuviParseResult &result)
Definition: ruuvi_ble.cpp:11