-
-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial support for GVH5074 #21
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
02e576d
Initial 5074 testing
b42f9fa
Fixed decimal rounding issue
94717e6
Adding refrence material
36cf1fd
Now using geti for two's complement
a64269b
Updated notes for new temperature method
7b126a6
Fixed internal anchor link
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
def handle_GVH5074(value, trigger, msg) | ||
if trigger == details_trigger | ||
var this_device = device_config[value['mac']] | ||
var p = bytes(value['p']) | ||
var i = 0 | ||
var adv_len = 0 | ||
var adv_data = bytes('') | ||
var adv_type = 0 | ||
|
||
while i < size(p) | ||
adv_len = p.get(i,1) | ||
adv_type = p.get(i+1,1) | ||
adv_data = p[i+2..i+adv_len] | ||
if (adv_type == 0xFF) && (adv_len == 0x0A) | ||
var last_data = this_device['last_p'] | ||
if adv_data == last_data | ||
return 0 | ||
else | ||
device_config[value['mac']]['last_p'] = adv_data | ||
end | ||
|
||
if this_device['discovery'] && !this_device['done_disc'] | ||
publish_sensor_discovery(value['mac'], 'Temperature', 'temperature', '°C') | ||
publish_sensor_discovery(value['mac'], 'Humidity', 'humidity', '%') | ||
publish_sensor_discovery(value['mac'], 'DewPoint', 'temperature', '°C') | ||
publish_sensor_discovery(value['mac'], 'Battery', 'battery', '%') | ||
publish_sensor_discovery(value['mac'], 'RSSI', 'signal_strength', 'dB') | ||
device_config[value['mac']]['done_disc'] = true | ||
end | ||
|
||
var output_map = {} | ||
output_map['Time'] = tasmota.time_str(tasmota.rtc()['local']) | ||
output_map['alias'] = this_device['alias'] | ||
output_map['mac'] = value['mac'] | ||
output_map['via_device'] = device_topic | ||
output_map['RSSI'] = value['RSSI'] | ||
if this_device['via_pubs'] | ||
output_map['Time_via_' + device_topic] = output_map['Time'] | ||
output_map['RSSI_via_' + device_topic] = output_map['RSSI'] | ||
end | ||
|
||
output_map['Battery'] = adv_data.geti(7, 1) | ||
# .geti() will take the two's complement when it extracts data | ||
output_map['Temperature'] = adv_data.geti(3,2) / 100.0 | ||
output_map['Humidity'] = adv_data.get(5, 2) / 100.0 | ||
|
||
output_map['DewPoint'] = round(get_dewpoint(output_map['Temperature'], output_map['Humidity']), this_device['temp_precision']) | ||
output_map['Temperature'] = round(output_map['Temperature'], this_device['temp_precision']) | ||
output_map['Humidity'] = round(output_map['Humidity'], this_device['humi_precision']) | ||
var this_topic = base_topic + '/' + this_device['alias'] | ||
tasmota.publish(this_topic, json.dump(output_map), this_device['sensor_retain']) | ||
|
||
if this_device['publish_attributes'] | ||
for output_key:output_map.keys() | ||
tasmota.publish(this_topic + '/' + output_key, string.format('%s', output_map[output_key]), this_device['sensor_retain']) | ||
end | ||
end | ||
|
||
end | ||
i = i + adv_len + 1 | ||
end | ||
end | ||
end | ||
|
||
# map function into handles array | ||
device_handles['GVH5074'] = handle_GVH5074 | ||
require_active['GVH5074'] = true |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Notes for GVH7074 | ||
|
||
https://github.com/w1gx/govee-ble-scanner/wiki/Sniffing-BLE-advertising-packets was helpful in decoding the GVH5074 | ||
|
||
Full 'p' strings captured from ESP32 serial monitor | ||
``` | ||
02010607030A18F5FE88EC1109476F7665655F48353037345F414141410AFF88EC00650775126402 | ||
02010607030A18F5FE88EC1109476F7665655F48353037345F414141410AFF88EC00650769126402 | ||
02010607030A18F5FE88EC1109476F7665655F48353037345F414141410AFF88EC0069075C126402 | ||
``` | ||
|
||
## Flags | ||
`02 01 06` | ||
|
||
`02` - two bytes | ||
|
||
`01` - Type = Flags | ||
|
||
`06` - Value (bitwise - 00000110) Bit 1 : "LE General Discoverable Mode", Bit 2: "BR/EDR Not Supported." | ||
|
||
## Service Class | ||
`07 03 0A 18 F5 FE 88 EC` | ||
|
||
`07` - 7 bytes | ||
|
||
`03` - Type = Service Class | ||
|
||
`0A 18` -> 18 0A (little endian) - Device Information | ||
|
||
`F5 FE` -> FE F5 (little endian) - Dialog Semiconductor GmbH | ||
|
||
`88 EC` -> EC 88 (little endian) - unknown | ||
|
||
## Complete Local Name | ||
`11 09 47 6F 76 65 65 5F 48 35 30 37 34 5F 41 41 41 41` | ||
|
||
`11` - 17 bytes | ||
|
||
`09` - Type = Complete Local Name | ||
|
||
`47 6F 76 65 65 5F 48 35 30 37 34 5F 41 41 41 41` = Govee_H5074_AAAA (AAAA = last 4 of mac) | ||
|
||
## Manufacturer Specific Data | ||
`0A FF 88 EC 00 65 07 75 12 64 02` | ||
|
||
`0A` - 10 bytes | ||
|
||
`FF` - Type = Manufacturer Specific Data | ||
|
||
`88 EC 00` - unknown - same across all 'p' strings | ||
|
||
`65 07` -> `07 65` (little endian) = See notes on [temperature](#temperature) below | ||
|
||
`75 12` -> `12 75` (little endian) = 4725 in decimal. Divide by 100 to get relative humidity | ||
|
||
`64` - 100 in decimal. Assuming this is battery percentage, but not sure. | ||
|
||
`02` - unknown | ||
|
||
## Temperature | ||
The GVH5074 uses [Two's Complement](https://en.wikipedia.org/wiki/Two%27s_complement#Converting_to_two's_complement_representation) for negative numbers. | ||
> In two's complement notation, a non-negative number is represented by its ordinary binary representation; in this case, the most significant bit is 0. Though, the range of numbers represented is not the same as with unsigned binary numbers. For example, an 8-bit unsigned number can represent the values 0 to 255 (11111111). However a two's complement 8-bit number can only represent positive integers from 0 to 127 (01111111), because the rest of the bit combinations with the most significant bit as '1' represent the negative integers −1 to −128. | ||
> | ||
> The two's complement operation is the additive inverse operation, so negative numbers are represented by the two's complement of the absolute value. | ||
|
||
The berry language has a `geti` [method](https://github.com/berry-lang/berry/wiki/Chapter-7#get-geti-methods) that will return a signed value. | ||
|
||
> Read a 1/2/4 bytes value from any offset in the bytes array. The standard mode is little endian, if you specify a negative size it enables big endian. `get` returns unsigned values, while `geti` returns signed values. | ||
> `b.geti(<offset>, <size>) -> bytes object` | ||
|
||
In order to get the temperature in °C, use the `geti` method and then divide by 100.0 | ||
``` | ||
# Example | ||
adv_data = bytes('88EC0052FA6E166402') | ||
temp = adv_data.geti(3,2) / 100.0 | ||
``` | ||
Output | ||
``` | ||
-14.54 | ||
``` |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can edit this section now if the
.geti
is working appropriately.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Two's complement is so close to what you figured out. It's subtracting the temp value from
0x10000
instead of from0xFFFF
!