These units do work with negative (freezing) temps, correct decoding algorithm
eharris opened this issue · 5 comments
I tested with a unit and have verified that these do work and read negative temps. According to their marketing materials, they only claim the device supports 0-50 degrees C, but the mobile app shows the range as -20C to 60C. I have personally verified that my unit reads sub-freezing temps (although I didn't have a way to test all the way down to -20C).
The decoding algorithm description could use updating to be less complicated and more accurate. Converting to a binary string isn't needed. The algorithm I used is (pseudocode):
Join the 3 data bytes together and convert to an integer, then:
if (val & 0x800000) {
is_negative = true;
val = val ^ 0x800000;
}
humidity = (val % 1000) / 10;
temp = int(val / 1000) / 10;
if (is_negative) {
temp = 0 - temp;
}
# If desire Farenheit
temp = temp * 9 / 5 + 32;
The official operating temperature range, according to Govee, for the H5075 is 0°C - 50°C (32°F - 122°F). It may display and send negative temperatures but I would be suspicious of those values. Also standard LCDs do not do well in freezing temperatures.
I see that there has bee some discussion about negative temperature... the below seems to work for me and reports pretty accurately in tests with my fridge & freezer...
- 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]);
float temperature = (basenum / 10000.0f);
ESP_LOGD("custom", "Govee Two Reported Temp: %f", temperature);
if(temperature>=839.0) {
temperature = temperature-839;
temperature = -temperature * 9.0/5.0 + 32.0;
} else {
temperature = temperature * 9.0/5.0 + 32.0;
}
}
@JZ-SmartThings Thanks! This seems to work for me. But what's with the 839 number? Where does this magic number come from?
(I have corroborated that number being best for me to, just figuring it out empirically .... I just want to know the meaning of that number)
@landonsilla I'm going to try my best to explain where the 839
comes from and hopefully I get correct.
The data received is three octets, FF FF FF
, but to represent a 32bit integer 4 octets are needed. Simple, we pad it with zeros, but because BLE is little endian, they are padded on the end to be FF FF FF 00
. However, a signed 32bit integer has an upper bound of 2,147,483,647 using a two's compliment representation. In hex, the four octets that represent this is 0x7FFFFFFF
.
Anything beyond 0x7F FF FF FF
is considered negative in two's compliment. Meaning 0x80000000
is equal to -1
. To figure this out based on the data received we need to take the value, subtract the upper bound of 0x7FFFFFFF
and multiply by negative 1. As we cannot store anything beyond the limit of signed integer, we have to use an unsigned int. What is 0x80000000
as an unsigned integer, 8,388,608
. Remember we need to divided the values provided by 10,000
,
This leaves us with 838.8608
, rounding or casting to an int gives us 839
.
I am trying to do this from memory and quick Googling, so I apologize if this is still confusing or if the terminology is off.
That is super great! I love it! This takes me back to my college days.