Read Govee Temperature Humidity BLE Advertisements with esp32 and esphome!

I have a c language program that has the decodes for the following units, code is a bit ragged but perhaps it will give you some ideas:

//  1 = Xiaomi LYWSD03MMC-ATC   https://github.com/atc1441/ATC_MiThermometer
//  2 = Govee H5052 (type 4 advertising packets)
//  3 = Govee H5072
//  4 = Govee H5102
//  5 = Govee H5075
//  6 = Govee H5074 (type 4 advertising packets)
// 99 = Display raw type 0 and type 4 advertising packets for this BLE MAC address

Has anyone tried this integration with a B5178? It is a dual indoor and outdoor thermometer and humidity sensor. It uses Bluetooth so I would think it would be similar but the packets might be a little different. Here is a link https://www.amazon.com/gp/product/B0872ZPQSJ to the one I purchased. It communicates over 433 between the base unit and the outdoor sensor but the communication to the phone is BLE.

For thirty bucks you can get 10 Xiaomi LYWSD03MMC units that you can have working in 30 minutes. Or 5 of them and a six pack of IPA s :wink: Only benny I can see of this unit is the 433 mhz, if you needed to have a sensor a long distance away. Assuming that the range of this 433 mhz device is good and better than you could get with a BLE device.

The reason I liked the B5178 is because it has an outdoor module that has no screen. It is just a module with a battery. Do you know how the Xiaomi LYWSD03MMC does outdoors?

I read through some of the Q&A section for the product on Amazon, you might want to do the same… vendors response on using it outside : ‘Please protect it from the weather.’ :wink:

My Xiaomi has been outside 7x24 for six months inside two ziplock sandwich bags. If you want to go 1st class, get one of the mobile phone waterproof bags for a couple bucks.

Rain, hail wind and temps from 28F to 140F recorded so far (it is not completely shaded from sun). The biggest issue with all of these outdoor sensors is there humidity readings after rain. You end up with water all around the sensor until the sun evaporates it, so you end up with inaccurate humidity reading for a considerable period after rain or other significant moisture.

Battery at 64% after six months:

'Is the outdoor sensor waterproof? I want to place it outside in my garden area. Do I need to protect it from the weather in some way?
Answer:The outdoor sensor is not totally waterproof. Please protect it from the weather.
By Govee US SELLER  on March 30, 2021'

OK. Thanks. I ordered some Xiaomi LYWSD03MMC as I found a outdoor wall mount for it on thingiverse that I can print. I bought a backup one in case it gets fried. I will take into account the humidity delay after a rain.

With the ziplocs how do you handle letting air in so it can measure humidity?

The bags are not really airtight. I could probably get more accurate reading if I just stuck the unit on the wall exposed. As long as you keep it out of direct moisture I think it will be fine. And again, for 4 bucks…

And if you have Nabu Casa and Google Home, Alexa or Siir it is kind of nice to just ask what the backyard temperature is …

I didn’t see the H5102 details mentioned yet, so I’ll add the version of the ESP Home BLE tracker that worked for me on that version of the sensor. Should be the right version for H5101 or H5102, which is actually very close to the H5072/H5075, with the data location just off by a byte.

esp32_ble_tracker:
  on_ble_manufacturer_data_advertise:
    - mac_address: A4:C1:38:xx:xx:xx # Office Govee 5102
      manufacturer_id: '0001'
      then:
        - lambda: |-
            const int basenum = (int16_t(x[2]) << 16) + (int16_t(x[3]) << 8) + int16_t(x[4]);
            const float temperature = (basenum / 10000.0f)*9.0/5.0 + 32.0;
            const float humidity = (basenum % 1000) / 10.0f;
            const float battery_level = uint16_t(x[5]) / 1.0f;
            id(office_humidity).publish_state(humidity);
            id(office_temperature).publish_state(temperature);
            id(office_battery).publish_state(battery_level);
2 Likes

I am coming late to this discussion. I have read through the whole post. What I did not understand is where I should be putting this. I have H5075s downstairs and they do not reach my upstairs system. I have esphome and esp32 boards, just not sure what to do with the above.

the_badluck - If you have a functional esphome running, you’d need to edit that esphome code, adding some sensor definitions and a corresponding “esp32_ble_tracker” section which defines how to get at the specific data values for those sensors. Maybe start with John.McDowell’s example but swap in the H5075 specific section from mwildrick (adjusting the names of the locations and the MAC address to match your usage).

I have to say thanks for all those that contributed code here. I got a couple 5075s on Amazon and they were up and running in about 15 minutes thanks to all the code snippets here!

Has anyone tackled the H5179? I have the following data from the tracker:

[15:54:00][VV][esp32_ble_tracker:493]: Parse Result:
[15:54:00][VV][esp32_ble_tracker:510]:   Address: E3:8C:81:93:80:7A (PUBLIC)
[15:54:00][VV][esp32_ble_tracker:512]:   RSSI: -65
[15:54:00][VV][esp32_ble_tracker:513]:   Name: 'Govee_H5179_807A'
[15:54:00][VV][esp32_ble_tracker:521]:   Ad Flag: 6
[15:54:00][VV][esp32_ble_tracker:524]:   Service UUID: 0x180A
[15:54:00][VV][esp32_ble_tracker:524]:   Service UUID: 0xFEF5
[15:54:00][VV][esp32_ble_tracker:524]:   Service UUID: 0xEC88
[15:54:00][VV][esp32_ble_tracker:527]:   Manufacturer data: EC.00.01.01.3E.08.B4.0A.64 (9)
[15:54:00][VV][esp32_ble_tracker:543]: Adv data: 02.01.06.07.03.0A.18.F5.FE.88.EC.11.09.47.6F.76.65.65.5F.48.35.31.37.39.5F.38.30.37.41.0C.FF.01.88.EC.00.01.01.3E.08.B4.0A.64 (42)

I’ve tried a couple of the lambda’s for anything that has a length of 9 for the manufacturer data and I’m not having any luck.

Has anyone else already tackled the H5179 and can share their lambda setup?

To add some more clarity - in the example above the 3E hex value (5th byte in manf. adv.) seems to change with temp and the B4 value (7 in manf. adv.) changes with humidity.

The problem is that whenever I convert these to integer it never relates to an accurate temp. or humidity. I’ve tried 2 pair and 3 pair values with divisors and modulus with what prior examples in this thread.

I’ve also looked at other examples which seem to point to a message payload that is 13 bytes long - none of the messages that broadcast when the verbose logging is enabled show this…they are all 9 bytes for the manf. and 42 bytes for the service data.

Am I just missing something here? In the example posted above the temp should be around 20.1C and humidity would be around 35.5%…

Is there a way to display the entire message payload with esp_ble_tracker? I’ve created lambda’s that convert x[?] to display each position but the decoding always gives a result (whether 16 bit or 8 bit) that’s not accurate…

More detail - here’s an example of a python decode:

elif self.check_is_gvh5179():
                temp, hum, batt = unpack_from("<HHB", self.mfg_data, 6)
                self.packet = hex(temp)[2:] + hex(hum)[2:]
                # Negative temperature stored an two's complement
                self.temperature = float(twos_complement(temp) / 100.0)
                self.humidity = float(hum / 100.0)
                self.battery = int(batt)
                self.model = "Govee H5179"

Along with the check function:

def check_is_gvh5179(self) -> bool:
        """Check if mfg data is that of Govee H5179."""
        return self._mfg_data_check(11, 6) and self._mfg_data_id_check("0188")

And the twos compliment:

def twos_complement(n: int, w: int = 16) -> int:
    """Two's complement integer conversion."""
    # Adapted from: https://stackoverflow.com/a/33716541.
    if n & (1 << (w - 1)):
        n = n - (1 << w)
    return n

This code is located here:

Can anyone interpret this and take a stab at a lambda that I could test?

Bought some 5075s but still can’t get them running after days. Can you please share the code you used to get it working in 15mins? thanks!

thanks to you i got my 5075 to work, I have 4 of them running on on ESP32…

Thanks guys I have 4 Govee 5075 working on this script that i put together from code posted in here… Here is mine that works… you can keep adding more as as needed see comments in code

esphome:
  # Name Is From When you Setup The ESP32
  name: esp-govee

esp32:
  board: esp32dev
  framework:
    type: arduino
    
sensor:
# GOVEE Sensor1 CHANGE NAMES AS NEEDED here and in Lamda Section
  - platform: template
    name: "govee1 Humidity"
    id: govee1_humidity
    unit_of_measurement: '%'
    icon: "mdi:water-percent"
  - platform: template
    name: "govee1 Temperature"
    id: govee1_temperature
    unit_of_measurement: '° F'
    icon: "mdi:thermometer"
  - platform: template
    name: "govee1 Battery"
    id: govee1_battery
    unit_of_measurement: '%'
    icon: "mdi:battery"
# GOVEE Sensor2 CHANGE NAMES AS NEEDED here and in Lamda Section   
  - platform: template
    name: "govee2 Humidity"
    id: govee2_humidity
    unit_of_measurement: '%'
    icon: "mdi:water-percent"
  - platform: template
    name: "govee2 Temperature"
    id: govee2_temperature
    unit_of_measurement: '° F'
    icon: "mdi:thermometer"
  - platform: template
    name: "govee2 Battery"
    id: govee2_battery
    unit_of_measurement: '%'
    icon: "mdi:battery"
# GOVEE Sensor3 CHANGE NAMES AS NEEDED here and in Lamda Section
  - platform: template
    name: "govee3 Humidity"
    id: govee3_humidity
    unit_of_measurement: '%'
    icon: "mdi:water-percent"
  - platform: template
    name: "govee3 Temperature"
    id: govee3_temperature
    unit_of_measurement: '° F'
    icon: "mdi:thermometer"
  - platform: template
    name: "govee3 Battery"
    id: govee3_battery
    unit_of_measurement: '%'
    icon: "mdi:battery"
# GOVEE Sensor4 CHANGE NAMES AS NEEDED here and in Lamda Section
  - platform: template
    name: "govee4 Humidity"
    id: govee4_humidity
    unit_of_measurement: '%'
    icon: "mdi:water-percent"
  - platform: template
    name: "govee4 Temperature"
    id: govee4_temperature
    unit_of_measurement: '° F'
    icon: "mdi:thermometer"
  - platform: template
    name: "govee4 Battery"
    id: govee4_battery
    unit_of_measurement: '%'
    icon: "mdi:battery"

    

# Enable logging
logger:

# Enable Home Assistant API
api:

# Your Over The Air Password
ota:
  password: "861291xx35895xx43ea2xxxx80b12"

# Wifi login and Password 
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password


# Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esp-Govee Fallback Hotspot"
    password: "z3nfxBoGdDub"

# Script For The First 5075 Govee Themometer/Humidity Sensor    
esp32_ble_tracker:
  on_ble_advertise:
    - mac_address: A4:C1:38:xx:xx:xx #MAC Adress of First Sensor
      then:
        - lambda: |-
            for (auto data : x.get_manufacturer_datas()) {
              if(data.data.size()==6) {
                const int basenum = (int16_t(data.data[1]) << 16) + (int16_t(data.data[2]) << 8) + int16_t(data.data[3]);
                const float temperature = ((basenum / 10000.0f)*9.0/5.0 + 32.0);
                const float humidity = (basenum % 1000) / 10.0f;
                const float battery_level = uint16_t(data.data[4]) / 1.0f;
                int16_t rssi=x.get_rssi();
                id(govee1_humidity).publish_state(humidity);
                id(govee1_temperature).publish_state(temperature);
                id(govee1_battery).publish_state(battery_level);
              } 
            }
            
 
# Script For The Second 5075 Govee Themometer/Humidity Sensor     
    - mac_address: A4:C1:38:xx:xx:xx #MAC Adress of Second Sensor
      then:
        - lambda: |-
            for (auto data : x.get_manufacturer_datas()) {
              if(data.data.size()==6) {
                const int basenum = (int16_t(data.data[1]) << 16) + (int16_t(data.data[2]) << 8) + int16_t(data.data[3]);
                const float temperature = ((basenum / 10000.0f)*9.0/5.0 + 32.0);
                const float humidity = (basenum % 1000) / 10.0f;
                const float battery_level = uint16_t(data.data[4]) / 1.0f;
                int16_t rssi=x.get_rssi();
                id(govee2_humidity).publish_state(humidity);
                id(govee2_temperature).publish_state(temperature);
                id(govee2_battery).publish_state(battery_level);
              } 
            }
              
 
# Script For The Third 5075 Govee Themometer/Humidity Sensor    
    - mac_address: A4:C1:38:xx:xx:xx #MAC Adress of Third Sensor
      then:
        - lambda: |-
            for (auto data : x.get_manufacturer_datas()) {
              if(data.data.size()==6) {
                const int basenum = (int16_t(data.data[1]) << 16) + (int16_t(data.data[2]) << 8) + int16_t(data.data[3]);
                const float temperature = ((basenum / 10000.0f)*9.0/5.0 + 32.0);
                const float humidity = (basenum % 1000) / 10.0f;
                const float battery_level = uint16_t(data.data[4]) / 1.0f;
                int16_t rssi=x.get_rssi();
                id(govee3_humidity).publish_state(humidity);
                id(govee3_temperature).publish_state(temperature);
                id(govee3_battery).publish_state(battery_level);
              } 
            }
              
 
# Script For The Forth 5075 Govee Themometer/Humidity Sensor    
    - mac_address: A4:C1:38:xx:xx:xx #MAC Adress of Forth Sensor
      then:
        - lambda: |-
            for (auto data : x.get_manufacturer_datas()) {
              if(data.data.size()==6) {
                const int basenum = (int16_t(data.data[1]) << 16) + (int16_t(data.data[2]) << 8) + int16_t(data.data[3]);
                const float temperature = ((basenum / 10000.0f)*9.0/5.0 + 32.0);
                const float humidity = (basenum % 1000) / 10.0f;
                const float battery_level = uint16_t(data.data[4]) / 1.0f;
                int16_t rssi=x.get_rssi();
                id(govee4_humidity).publish_state(humidity);
                id(govee4_temperature).publish_state(temperature);
                id(govee4_battery).publish_state(battery_level);
              } 
            }

I posted my code that works for 5075 and you can keep adding more as needed

FYI
Here is my code for the Govee 5183 meat thermometer.
If the probe is not connected or the target temp is not set then I show a number to big to be right.
Also, currently, the only way to set the target temp is with the app.
Not sure how to send a BLE or what that message would look like.
I left some debug code.

esp32_ble_tracker:
 on_ble_advertise:
    - mac_address: A4:C1:xx:xx:xx:xx
      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", "    - %s", uuid.to_string().c_str());
            }
            ESP_LOGD("ble_adv", "  Advertised service data:");
            for (auto data : x.get_service_datas()) {
                ESP_LOGD("ble_adv", "    - %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", "    - %s: (length %i)", data.uuid.to_string().c_str(), data.data.size());
                if (data.data.size() == 14){
                  for (int i=0;i<14;i++){
                    ESP_LOGD("ble_adv", "-%i", data.data[i]);
                  }
                  if (data.data[8] == 255 && data.data[9] == 255){
                    id(meat_tempture).publish_state(99999999.00);            
                  } else{
                    int temp_lsb = (data.data[8] * 256) + data.data[9];
                    float temperature = float(temp_lsb)/100*9.0/5.0 + 32.0;
                    id(meat_tempture).publish_state(temperature);            
                  }
                  if (data.data[10] == 255 && data.data[11] == 255){
                    id(meat_taget_tempture).publish_state(99999999.00);            
                  } else{
                    int temp_lsb = (data.data[10] * 256) + data.data[11];
                    float temperature = float(temp_lsb)/100*9.0/5.0 + 32.0;
                    id(meat_taget_tempture).publish_state(temperature);            
                  }
                }
            }
            
sensor:
  - platform: template
    name: "Meat Tempture"
    id: meat_tempture
  - platform: template
    name: "Meat Traget Tempture"
    id: meat_taget_tempture

Did you manage to get H5179 working with ESP32 ?