Hey Folks!
Inspired by custom component https://github.com/Home-Is-Where-You-Hang-Your-Hack/sensor.goveetemp_bt_hci I wanted to use these awesome sensors throughout my house but I have sections of the house I knew the BLE advertisements would not be able to reach my PC that is running home assistant so I wanted to see if it would be possible to use ESP32 bluetooth capability to read these advertisements. There’s already multiple ESPHome components that do something similar but I am a n00b at C++ and it was quite daunting trying to start writing my own component for esphome. Luckily, we dont have to do that as ESPHome has a built in feature/callback that can parse such messages with a lambda function.
Relevant ESP Home config:
esp32_ble_tracker:
on_ble_manufacturer_data_advertise:
- mac_address: A4:C1:38:11:22:33 #update to your govee device mac address
manufacturer_id: '0001'
then:
- lambda: |-
int basenum = (int16_t(x[2]) << 16) + (int16_t(x[3]) << 8) + int16_t(x[4]);
ESP_LOGD("ble_adv", "goveesensor basenum: (%d)", basenum);
bool is_negative = false;
if (basenum & 0x800000) {
is_negative = true;
basenum = basenum ^ 0x800000;
}
float temperature = basenum / 10000.0f;
float humidity = (basenum % 1000) / 10.0f;
float battery_level = uint16_t(x[5]) / 1.0f;
if (is_negative) {
temperature = -temperature;
}
ESP_LOGD("ble_adv", " Temperature: %.2f°C", temperature);
ESP_LOGD("ble_adv", " Humidity: %.2f", humidity);
ESP_LOGD("ble_adv", " Battery Level: %.0f percent", battery_level);
id(govee1_temp).publish_state(temperature);
id(govee1_humidity).publish_state(humidity);
id(govee1_battery).publish_state(battery_level);
#use this section to determine manufacturer id(mine was '0001'), can be commented out after initial discovery
on_ble_advertise:
- mac_address: A4:C1:38:11:22:33 #update to your govee device mac address
then:
- lambda: |-
ESP_LOGD("ble_adv", "New BLE device");
ESP_LOGD("ble_adv", " address: %s", x.address_str().c_str());
ESP_LOGD("ble_adv", " name: %s", x.get_name().c_str());
ESP_LOGD("ble_adv", " Advertised service UUIDs:");
for (auto uuid : x.get_service_uuids()) {
ESP_LOGD("ble_adv", " service uuid %s", uuid.to_string().c_str());
}
ESP_LOGD("ble_adv", " Advertised service data:");
for (auto data : x.get_service_datas()) {
ESP_LOGD("ble_adv", " service data uuid - %s: (length %i)", data.uuid.to_string().c_str(), data.data.size());
}
ESP_LOGD("ble_adv", " Advertised manufacturer data:");
for (auto data : x.get_manufacturer_datas()) {
ESP_LOGD("ble_adv", " mfg data uuid %s: (length %i)", data.uuid.to_string().c_str(), data.data.size());
}
sensor:
- platform: template
name: "Master Bath Temperature"
id: govee1_temp
unit_of_measurement: "°C"
accuracy_decimals: 2
- platform: template
name: "Master Bath Humidity"
id: govee1_humidity
unit_of_measurement: '%'
accuracy_decimals: 2
- platform: template
name: "Master Bath Sensor Battery Level"
id: govee1_battery
unit_of_measurement: '%'
accuracy_decimals: 0
Note(s):
I’ve confirmed this works with Govee H5101 model, which based on the lovely work by @Thrilleratplay should also work with a slight change in message format for Govee models 5102 and 5072 as well other models should be fairly straightforward to adapt, assuming they use similar structure.
Be sure to comment with your code if you find a new model working with a similar method!