Last active
July 17, 2023 21:29
-
-
Save mkjanke/8ceb9b40ecdaceb5fe33719832b26f8f to your computer and use it in GitHub Desktop.
Govee 5074 Temperature & Humidity Monitor Decoding Notes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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