Skip to content

Instantly share code, notes, and snippets.

@mkjanke
Last active July 17, 2023 21:29
Show Gist options
  • Save mkjanke/8ceb9b40ecdaceb5fe33719832b26f8f to your computer and use it in GitHub Desktop.
Save mkjanke/8ceb9b40ecdaceb5fe33719832b26f8f to your computer and use it in GitHub Desktop.
Govee 5074 Temperature & Humidity Monitor Decoding Notes
#Govee 5074 decode notes
Notes on passively monitoring Govee BLE 5074 temperature sensor using and ESP32
Reference: https://github.com/Thrilleratplay/GoveeWatcher
##Govee 5074 Advertising Packet (NimBLE getPayload():
```
Byte: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
-----------------------------------------------------------------------------------------------------------
Data: 02 01 06 03 03 88 ec 11 09 47 6f 76 65 65 5f 48 35 30 37 34 5f 46 37 31 41 0a ff 88 ec 00 58 0a e6 11 64 02
Data: 02 01 06 03 03 88 ec 11 09 47 6f 76 65 65 5f 48 35 30 37 34 5f 46 37 31 41 0a ff 88 ec 00 b7 09 a0 12 64 02
----- ----------------------------------------------- ----- ----- ----- --
Mfg Id G o v e e _ H 5 0 7 4 _ F 7 1 A Mfg Id TempC Humid Bat
```
##Mfg. Data Field (NimBLE getManufacturerData().data())
```
88 ec 00 f8 09 cf 11 64 02
----- ----- ----- --
Mfg Id TempC Humid Bat
```
###Example Mfg. data:
```
88ec00580ae6116402
```
Temperature (C): `580a`
Convert to int: `data[3] << 0) | (data[4]) << 8 = 2648`
Divide by 100 = 26.48 deg. C
Humidity: `e611`
Convert to int: `data[5] << 0) | (data[6]) << 8 = 4582`
Divide by 100 = 45.82 %
Battery Pct: 64 = 64 hex = 100%
##Sample Code
Reference: https://github.com/h2zero/NimBLE-Arduino/tree/release/1.4/examples/NimBLE_Scan_Continuous
```
#include <Arduino.h>
#include "NimBLEDevice.h"
NimBLEScan* pBLEScan;
//Govee 5074 serivice UUID
NimBLEUUID serviceUuid("ec88");
class MyAdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
if (advertisedDevice->getServiceUUID() == serviceUuid){
// Serial.printf("Advertised Device: %s \n", advertisedDevice->toString().c_str());
// Desired advert will have 9 byte mfg. data length & leading bytes 0x88 0xec
if ((advertisedDevice->getManufacturerData().length() == 9) &&
((byte)advertisedDevice->getManufacturerData().data()[0] == 0x88) &&
((byte)advertisedDevice->getManufacturerData().data()[1] == 0xec)) {
char* payloaddata = NimBLEUtils::buildHexData(NULL, (uint8_t*)advertisedDevice->getPayload(), advertisedDevice->getPayloadLength());
Serial.println(payloaddata);
if (payloaddata != NULL) {
free(payloaddata);
}
std::string output = advertisedDevice->getName() + " " + advertisedDevice->getAddress().toString() + " ";
Serial.print(output.c_str());
char* manufacturerdata = NimBLEUtils::buildHexData(NULL, (uint8_t*)advertisedDevice->getManufacturerData().data(), advertisedDevice->getManufacturerData().length());
Serial.print(manufacturerdata);
if (manufacturerdata != NULL) {
free(manufacturerdata);
}
uint8_t* MFRdata;
MFRdata = (uint8_t*)advertisedDevice->getManufacturerData().data();
float tempInC = ((float)((uint16_t)((MFRdata[3] << 0) | (MFRdata[4]) << 8)))/100;
float humPct = ((float)((uint16_t)((MFRdata[5] << 0) | (MFRdata[6]) << 8)))/100;
uint8_t battPct = (uint8_t)MFRdata[7];
Serial.printf(" %4.2f %4.2f %d\n", tempInC, humPct, battPct);
}
}
}
};
void setup() {
Serial.begin(115200);
NimBLEDevice::init("");
pBLEScan = NimBLEDevice::getScan(); //create new scan
// Set the callback for when devices are discovered, include duplicates.
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), true);
pBLEScan->setActiveScan(true); // Set active scanning, this will get more data from the advertiser.
// Values taken from NimBLE examples
pBLEScan->setInterval(97); // How often the scan occurs / switches channels; in milliseconds,
pBLEScan->setWindow(37); // How long to scan during the interval; in milliseconds.
pBLEScan->setMaxResults(0); // do not store the scan results, use callback only.
}
void loop() {
// If an error occurs that stops the scan, it will be restarted here.
if(pBLEScan->isScanning() == false) {
// Start scan with: duration = 0 seconds(forever), no scan end callback, not a continuation of a previous scan.
pBLEScan->start(0, nullptr, false);
}
delay(2000);
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment