Govee H5075 and H5074, Bluetooth Low Energy, and MRTG

I have been wanting a method of keeping track of temperatures for a long time. Last week I acquired a Govee H5075 Bluetooth Thermometer Hygrometer. It communicates with an app from Govee on my iPhone using Bluetooth Low Energy (BLE).

I’ve now learned some details on BLE, and have written a program that listens for BLE advertisements from either type of thermometer and logs the temperature and humidity in a text file. The code for my project is available on GitHub. https://github.com/wcbonner/GoveeBTTempLogger

The same program can also be called to get the last value from the log and produce output compatible with MRTG. MRTG is not the best method for graphing these temperatures, because all graphs start with zero on the Y axis, and neither the temperature or humidity is likely to be near zero.

MRTG graph of Temperature and Relative Humidity

My program seems to receive advertisements from each thermometer about every ten seconds. I’ve had a friend running the code in his location with a different set of thermometers and it doesn’t get advertisements nearly as frequently. I don’t know if that’s just because environment is different, or if there’s something else going on.

16 thoughts on “Govee H5075 and H5074, Bluetooth Low Energy, and MRTG

  1. Pingback: GoveeBTTempLogger as a Debian Package | WimsWorld

  2. Cool little utility! I just picked up one of the Govee thermometers, and wanted to see if I could come up with a more hands-off logging solution. My environment is slightly different from yours, though: I’m compiling / running this on a desktop Ubuntu box, rather than an arm-based system like a Raspberry Pi.

    One change that I had to make in order to get this to compile: in the makefile I had to move -lbluetooth to the end of the g++ command line, as for whatever reason it refused to find the library when I tried to compile with it as-is in your distribution.

    I’ve tinkered with other BLE devices in the past, and was planning to have to write my own tool. I still may, but for now your little utility is awesome.

    Thanks!

    • Thanks. I figure simple procedural C++ code is always nice as a reference starting point for personal projects.

      If you figure out how to download the data log from the device, let me know. I was playing with a set of thermometers at my sisters home and don’t see the announcements nearly as frequently as I do at my home.

      • I’m seeing the announcements pretty infrequently. I’ve only been playing with it for about an hour, but it seems to only announce every 8-10 minutes. I thought it was due to distance from the linux box (I initially set it all up from across the house) but even with the thermometer sitting right on top of the computer, the announcement interval has not changed. Also, connecting from the Govee app on my iPhone does not seem to have any effect on announcement interval.

        For reference: I have model H5075 with firmware version 1.00.02.

        I do have a bluetooth scanning/debugging tool on my Mac (BlueSee) that shows 2 different services advertised by this thing. The first service (00010203-0405-0607-0809-0A0B0C0D1912) has 1 single characteristic which can be written to (00010203-0405-0607-0809-0A0B0C0D2B12), but I don’t have any good way of determining what to write to it.

        The second service (494E5445-4C4C-495F-524F-434B535F4857) advertises 3 characteristics, all of which can be subscribed to for updates:

        494E5445-4C4C-495F-524F-434B535F2011
        494E5445-4C4C-495F-524F-434B535F2012
        494E5445-4C4C-495F-524F-434B535F2013

        However, once I connect with BlueSee I only get a few seconds before the device hangs up on me.

        Here is a log of a recent session. I connected, subscribed to the 3 announcement characteristics, then started writing 01, 02, 03 etc to the other characteristic. Then the device hangs up on me.

        It does not matter if I try to interact with it at all or not – I just get a few seconds, then it hangs up.

        Here’s a session log, if you are interested:

        ———————————————————————————-
        User initiated device connection.
        13:19:30.9470: connected in underlying BLE layer.
        13:19:30.9480: discovered services: (
        “Device Information”,
        EC88,
        “00010203-0405-0607-0809-0A0B0C0D1912”,
        “494E5445-4C4C-495F-524F-434B535F4857”
        )
        13:19:31.0600: discovered characteristics for service 180A: (
        “PnP ID”
        )
        13:19:31.2260: discovered characteristics for service 494E5445-4C4C-495F-524F-434B535F4857: (
        “494E5445-4C4C-495F-524F-434B535F2011”,
        “494E5445-4C4C-495F-524F-434B535F2012”,
        “494E5445-4C4C-495F-524F-434B535F2013”
        )
        13:19:31.2860: discovered characteristics for service 00010203-0405-0607-0809-0A0B0C0D1912: (
        “00010203-0405-0607-0809-0A0B0C0D2B12”
        )
        13:19:31.2870: state changed to ‘Connected’.
        13:19:31.4950: received update from characteristic 00010203-0405-0607-0809-0A0B0C0D2B12___00010203-0405-0607-0809-0A0B0C0D1912:
        13:19:31.5250: received update from characteristic 00010203-0405-0607-0809-0A0B0C0D2B12___00010203-0405-0607-0809-0A0B0C0D1912:
        13:19:31.5550: received update from characteristic 00010203-0405-0607-0809-0A0B0C0D2B12___00010203-0405-0607-0809-0A0B0C0D1912:
        13:19:31.5860: received update from characteristic 00010203-0405-0607-0809-0A0B0C0D2B12___00010203-0405-0607-0809-0A0B0C0D1912:
        13:19:35.8700: received update from characteristic 494E5445-4C4C-495F-524F-434B535F2011___494E5445-4C4C-495F-524F-434B535F4857:
        13:19:35.9000: received update from characteristic 494E5445-4C4C-495F-524F-434B535F2012___494E5445-4C4C-495F-524F-434B535F4857:
        13:19:35.9300: received update from characteristic 494E5445-4C4C-495F-524F-434B535F2013___494E5445-4C4C-495F-524F-434B535F4857:
        13:19:35.9600: received update from characteristic 494E5445-4C4C-495F-524F-434B535F2011___494E5445-4C4C-495F-524F-434B535F4857:
        13:19:35.9900: received update from characteristic 494E5445-4C4C-495F-524F-434B535F2012___494E5445-4C4C-495F-524F-434B535F4857:
        13:19:36.0200: received update from characteristic 494E5445-4C4C-495F-524F-434B535F2013___494E5445-4C4C-495F-524F-434B535F4857:
        13:19:37.5340: updated subscription state for characteristic 494E5445-4C4C-495F-524F-434B535F2011___494E5445-4C4C-495F-524F-434B535F4857: subscribed
        13:19:38.2540: updated subscription state for characteristic 494E5445-4C4C-495F-524F-434B535F2012___494E5445-4C4C-495F-524F-434B535F4857: subscribed
        13:19:38.9440: updated subscription state for characteristic 494E5445-4C4C-495F-524F-434B535F2013___494E5445-4C4C-495F-524F-434B535F4857: subscribed
        13:19:42.2970: wrote to characteristic 00010203-0405-0607-0809-0A0B0C0D2B12:
        13:19:44.0280: wrote to characteristic 00010203-0405-0607-0809-0A0B0C0D2B12:
        13:19:46.3530: wrote to characteristic 00010203-0405-0607-0809-0A0B0C0D2B12:
        13:19:46.3680: disconnected in underlying BLE layer with error: Error Domain=CBErrorDomain Code=6 “The connection has timed out unexpectedly.” UserInfo={NSLocalizedDescription=The connection has timed out unexpectedly.}
        13:19:46.3680: state changed to ‘Disconnected’ with error: The connection has timed out unexpectedly.
        ———————————————————————————————–

        If I can figure out how to read the device logs, I’ll let you know.

      • At home I was seeing multiple announcements per minute. My sisters I might only see one an hour. It’s a low priority Labor Day weekend project. πŸ˜€

  3. Finally got it to compile on my Raspberry Pi. Had to add flag for C++11 on the C++ line (g++ -std=c++11. My make file has this line:
    g++ -O3 -std=c++11 goveebttemplogger.cpp -o GoveeBTTempLogger/usr/local/bin/goveebttemplogger -lbluetooth

    • I’ve updated the makefile in github to use your options. they seemed to not make a difference on my current Raspian Buster installation. (Raspberry Pi reference 2020-05-27)

  4. Hello fellow BLE debuggers πŸ™‚ and thank you Wim for posting this !

    I have several Govee H5074 (vs the 5075’s w display you worked with) and wanted to share what I have found – and a question.

    Using Arduino BLE code (library from Neil Kolban for ESP32) I am finding that the H5074s emit 3 types of BLE packets, with different lengths (namely, 40, 56, and 29)

    The length 40 packets are the ones that contain temperature, humidity and battery level data.
    The other two do not (details below)
    The 29 packets seem to be emitted every second. After a long break from scanning, I appear to randomly get some 40 and 56 packets but following the first scan, only receiving 29 packets any more. This is frustrating since those don’t actually contain any data πŸ™‚
    I tried this with active and passive scanning, and with various scan periods, windows etc.
    Perhaps someone else can shed light on this or compare w their experiences.

    I am just learning about BLE and the various types of interactions between BLE servers (like the H5074) and clients like the ESP32 I am using for scanning.
    Based on Wims post here and others I assumed I could just “listen” ie passively scan and filter out packets with temp data from the ether. Doesn’t seem that simple.

    After a long time of not scanning (eg ESP32 turned off) I might get a couple of data packets with actual temp but after that I only ever get length 29 “keepalive” type packets that do not contain temp data.

    There seems to be something stateful to the scanning, ie. my scans influence what the H5074 emits subsequently, at least for a period of time.

    So, questions:

    – is anyone else seeing this “only length 29, not data containing packets” subsequent to initial scan behavior ? Or is everyone able to periodically (what period ?) fish out length 40 data containing packets out of the air ?

    – does the H5074 require active scanning (connecting to H5074 explicitly, asking for temp data) ?

    More details on the packets
    ——————————————————————
    Length 40 packet
    all : Name: Govee_H5074_C0A6,
    Address: e3:8e:c8:c1:c0:a6,
    manufacturer data: 88ec002f0941176402,
    serviceUUID: 0000180a-0000-1000-8000-00805f9b34fb

    raw data (for each data item: byte 1=len, byte 2=type, byte 3+=value)
    02 01 06
    07 03 0A 18 F5 FE 88 EC
    11 09 47 6F 76 65 65 5F 48 35 30 37 34 5F 43 30 41 36
    0A FF 88 EC 00 2F 09 41 17 64 02

    Decoded data
    length[ 1] type[ 1 = flags] 06 .
    length[ 6] type[ 3 = BLEUUIDs of services available] 0A 18 F5 FE 88 EC ……
    length[16] type[ 9 = full device name] 47 6F 76 65 65 5F 48 35 30 37 34 5F 43 30 41 36 Govee_H5074_C0A6
    length[ 9] type[255 = mfg specific data] 88 EC 00 2F 09 41 17 64 02 …/.A.d.

    Interpretation
    BLEUUIDs of services available:
    0x180A device information
    0xFEF5 ??
    0xEC88 sensor readings (temp, humidity, battery) eg this packet

    mfg specific data item:
    0x88EC = tmp/humidity/battery data follows
    0x092F = temperature = 2351 decimal / 100 ➟ 23.51 degrees C
    0x1741 = humidity = 5953 decimal / 100 ➟ 59.53 % relative humidity
    0x64 = battery level = 100 decimal ➟ 100% battery level

    ——————————————————————
    Length 56 packets

    all : Name: Govee_H5074_C0A6
    Address: e3:8e:c8:c1:c0:a6
    manufacturer data: 4c000215494e54454c4c495f524f434b535f48575074a6c0c2
    serviceUUID: 0000180a-0000-1000-8000-00805f9b34fb
    decoded data:
    length[ 1] type[ 1=flags] 06 .
    length[ 6] type[ 3=services] 0A 18 F5 FE 88 EC ……
    length[16] type[ 9=device name] 47 6F 76 65 65 5F 48 35 30 37 34 5F 43 30 41 36 Govee_H5074_C0A6
    length[25] type[255=mfg specific data] 4C 00 02 15 49 4E 54 45 4C 4C 49 5F 52 4F 43 4B 53 5F 48 57 50 74 A6 C0 C2 L…INTELLI_ROCKS_HWPt…

    Interpretation
    0x004C type of Govee data packet, mfg data follows ?
    0x0215 ???
    0x4E…50 INTELLI_ROCKS_HWP Intelli_rocks is the name of the mfg of the Govee devices. This data seems constant
    0x74 ?
    0xC0A6 last 4 of device name Govee_H5074_C0A6
    0xC2 ???

    This packet type doesn’t appear to have enough bytes for device specific data for all hw, firmware versions, serial etc.

    ——————————————————————
    Length 29 packets

    all : Name: Govee_H5074_C0A6
    Address: e3:8e:c8:c1:c0:a6
    serviceUUID: 0000180a-0000-1000-8000-00805f9b34fb
    length[ 1] type[ 1] 06 .
    length[ 6] type[ 3] 0A 18 F5 FE 88 EC ……
    length[16] type[ 9] 47 6F 76 65 65 5F 48 35 30 37 34 5F 43 30 41 36 Govee_H5074_C0A6

    Interpretation
    same flag value (6) and BLEUUIDs for services and device name
    Just a “heartbeat” to signal the device is online ? Once per second seems very frequent for a low power device. Perhaps triggered by scanning

    ———————————

    I assume Govee has some more packet types with additional information which I have not seen documented anywhere yet:

    fetch batch data (the Govee app uses that to fetch a whole batch of temp/humidity data at a time. Presumably this involves a multi step handshake w the client asking for data starting from a particular date etc.)

    query for device information (such as hw serial, hw version, firmware version etc.) and possibly there is a firmware update mechanism as well, I don’t know that though.

  5. Good timing of your response.. This past weekend I came back to this code, hoping to figure out how to download the stored data on the device via a connection as opposed to my existing code that only listens to advertisements.

    My apartment is in a multistory building with plenty of other units and lots of Bluetooth devices beyond my own broadcasting. I seem to see very frequent report from my own devices. I have worked with a friend in a house with very few devices broadcasting and his thermometers broadcasts are received with significantly less frequency. I don’t know if that is because the thermometers broadcast less when there’s less noise, or if its just that the receivers and transmitters align on the same frequency more often when there’s more noise.

    With my existing program, I listened to broadcasts just now and saw this data on the console:

    [2020-09-21T19:24:53] 26 [E3:5E:CC:21:5C:0F] (Manu) 88EC00A408F21A6402 (Temp) 71.816Β°F (Humidity) 68.98% (Battery) 100%
    [2020-09-21T19:24:54] 44 [E3:5E:CC:21:5C:0F] (Flags) 06 (UUID) 0A18F5FE88EC (Name) Govee_H5074_5C0F
    [2020-09-21T19:24:54] 42 [E3:5E:CC:21:5C:0F] (Manu) 4C000215494E54454C4C495F524F434B535F485750740F5CC2 (Apple) (UUID) 494E54454C4C495F524F434B535F48 (Major) 5750 (Minor) 740F (RSSI) 5C

    That was running with the -v 1 option. The number between the date and the Bluetooth id is the packet size, including the Bluetooth id. From the h5074 I seem to receive three advertisements.

    The one matching your manufacturer data 4c00 is the Apple iBeacon format message. (the third in my output)

    https://youtu.be/gCQ3iSy6R-U has been my starting point in my reverse engineering. I dug an old Nexus 7 tablet running Android 6 out of the closet and captured a Bluetooth btsnoop_hci.log of downloading data from both an h5074 and h5075 device. I’m currently staring at data in wireshark and trying to understand what needs to be done to download the data in my C program.

  6. Hi Wim – just looking through your console output…I think your major/minor parsing is off by one byte. Ie device name is Govee_H5074_5C0F, major should be 5074, minor 5C0F.

    • Thanks, It’ll get updated next time I push code. Still trying to understand Bluetooth programming to be able to stop scanning, connect to the device, and download the stored data.

      • After the offset fix, the Major matches up with the model number, but the Minor only matches the BT Address on the 5074, not the 5075.

        [2020-09-24T20:15:47] 42 [E3:5E:CC:21:5C:0F] (Manu) 4C000215494E54454C4C495F524F434B535F485750740F5CC2 (Apple) (UUID) 494E54454C4C495F524F434B535F4857 (Major) 5074 (Minor) 0F5C (RSSI) C2
        [2020-09-24T20:15:48] 42 [A4:C1:38:13:AE:36] (Manu) 4C000215494E54454C4C495F524F434B535F48575075F2FFC2 (Apple) (UUID) 494E54454C4C495F524F434B535F4857 (Major) 5075 (Minor) F2FF (RSSI) C2
        [2020-09-24T20:15:48] 42 [A4:C1:38:EC:0B:03] (Manu) 4C000215494E54454C4C495F524F434B535F48575075F2FFC2 (Apple) (UUID) 494E54454C4C495F524F434B535F4857 (Major) 5075 (Minor) F2FF (RSSI) C2

  7. some more Govee H5074 research data from two IOS BLE scanner apps (nRF Connect and BLE Scanner). Tedious because the 5074 disconnects just a few seconds after every connection, making at most one value readable before it disconnects…

    Both apps show three service IDs:
    180A ➟ full UUID 0000180A-0000-1000-8000-00805f9b34fb
    FEF5 ➟ full UUID 0000FEF5-0000-1000-8000-00805f9b34fb
    494E5445-4C4C-495F-524F-434B535F4857

    And now the characteristic UUIDs and values to the extent I was able to get them:

    BLE characteristic UUIDs for 180A service:
    UUID 2A24 -> MODEL NUMBER STRING “IR”
    UUID 2A29 -> MFG NAME STRING “Intelli_Rocks”
    UUID 2A50 -> PNP ID 0x01 D2 00 80 05 00 01
    UUID 2A23 -> SYSTEM ID 0xA6 C0 C1 C8 8E E3
    UUID 2A28 -> SW REV STRING 1.01.00
    UUID 2A26 -> FW REV STRING 1.00.01

    BLE characteristic UUIDs for FEF5 service:
    5F78DF94-798C-46F5-990A-B3EB6A065C88 ➟ value returned was 0 (length 1)
    42C3DFDD-77BE-4D9C-8454-8F875267FB3B ➟ value returned was F4 00 (length 2)
    64B4E8B5-0DE5-401B-A21D-ACC8DB3B913A ➟ value returned was 0D (length 1)
    B7DE1EEA-823D-43BB-A3AF-C4903DFCE23C ➟ value returned was F7 00 (length 2)
    there are more (9 total) custom characteristics with no helpful metadata in this service

    BLE characteristic UUIDs for 494E5445-4C4C-495F-524F-434B535F4857 service:
    494E5445-4C4C-495F-524F-434B535F2011 -> protocol 0xAA0E00..more zeroes…000A4
    494E5445-4C4C-495F-524F-434B535F2012 -> humi_cmd 0xAA01000..more zeroes..000AB
    494E5445-4C4C-495F-524F-434B535F2013 -> humi_data 0
    494E5445-4C4C-495F-524F-434B535F2014 -> heart_beat 1

  8. Looking at yet another scanner app (IOS: BLE Hero)…
    Just looking continuously at the advertising packets, ie not connecting at all: only SOME advertising packets contain the characteristic payload for sensor data (something like 88 EC 00 2F 09 41 17 64 02) and others do not.

    I suspect in my ESP32 raw code and Neil Kolban BLE_scan sketches, the lower levels of code filter out “duplicate” advertising packets from the same device during a scan, and only show whatever they caught first in the scan.

    If the smaller, non payload containing length 29 packets are sent much more frequently, they have a higher probability of being picked up first. Solution would be to go deeper and manually inspect each packet as it flies by to see whether it contains juicy payload data (length 40) Will pull on that thread a little more….

  9. Yep I think the ESP32 IDF SDK bluetooth stack is buggy. I do see advertisement packets cruise by every 900+ milliseconds or so but the stack reports them all as length 29 packets which is bogus. Rats…

    • My current code is on GitHub. The function ConnectAndDownload() at line 452 has the beginning of my routine to download historical data. It successfully connects to devices, but I’ve not yet learned how to take the next step of connecting to the GATT service and initiating the transfer of data.

      If anyone can point me to the API call to complete it, I would be very happy.

      I don’t want to try to reinvent the entire process using the DBUS API at this point. (If it was well documented I might consider it, but switching from one poorly documented interface to another is not an interesting prospect)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s