@homebridge-plugins/homebridge-govee 11.34.2-beta.5 → 11.34.2-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/lib/platform.js +117 -107
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -19,6 +19,7 @@ All notable changes to `@homebridge-plugins/homebridge-govee` will be documented
|
|
|
19
19
|
- fix: apply the openapi disable and refresh settings instead of asking for them to be removed
|
|
20
20
|
- fix: say once when a bluetooth reading arrives for an unknown device, not on every broadcast
|
|
21
21
|
- fix: reject a refresh time so large it would make the plugin poll every millisecond
|
|
22
|
+
- fix(H5054): don't let a slow leak warning block other sensors
|
|
22
23
|
|
|
23
24
|
## v11.34.1 (2026-08-06)
|
|
24
25
|
|
package/lib/platform.js
CHANGED
|
@@ -408,11 +408,7 @@ export default class {
|
|
|
408
408
|
|
|
409
409
|
// Set up the http client sync needed for leak and thermo sensor devices
|
|
410
410
|
if (this.httpClient && httpSyncNeeded) {
|
|
411
|
-
this.
|
|
412
|
-
this.refreshHTTPInterval = setInterval(
|
|
413
|
-
() => this.runPeriodicSync('HTTP', () => this.goveeHTTPSync()),
|
|
414
|
-
this.config.httpRefreshTime * 1000,
|
|
415
|
-
)
|
|
411
|
+
this.setupHTTPSync()
|
|
416
412
|
}
|
|
417
413
|
|
|
418
414
|
if (this.openApiClient && (openApiDevicesWereInitialised || httpDevicesWereInitialised)) {
|
|
@@ -787,6 +783,14 @@ export default class {
|
|
|
787
783
|
}
|
|
788
784
|
}
|
|
789
785
|
|
|
786
|
+
setupHTTPSync() {
|
|
787
|
+
this.runPeriodicSync('HTTP', () => this.goveeHTTPSync())
|
|
788
|
+
this.refreshHTTPInterval = setInterval(
|
|
789
|
+
() => this.runPeriodicSync('HTTP', () => this.goveeHTTPSync()),
|
|
790
|
+
this.config.httpRefreshTime * 1000,
|
|
791
|
+
)
|
|
792
|
+
}
|
|
793
|
+
|
|
790
794
|
async goveeAWSSync(allDevices = false) {
|
|
791
795
|
const pollList = allDevices ? awsDevices : awsDevicesToPoll
|
|
792
796
|
if (pollList.length === 0) {
|
|
@@ -864,123 +868,129 @@ export default class {
|
|
|
864
868
|
// Obtain a refreshed device list
|
|
865
869
|
const devices = await this.httpClient.getDevices(true)
|
|
866
870
|
|
|
867
|
-
//
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
//
|
|
876
|
-
|
|
877
|
-
|
|
871
|
+
// A stalled leak-warning request must not hold every water sensor behind
|
|
872
|
+
// it. Queue only those cloud requests so thermometer and monitor updates
|
|
873
|
+
// still arrive immediately, while a poll stays gentle on Govee's API.
|
|
874
|
+
const leakWarningQueue = new PQueue({ concurrency: 2 })
|
|
875
|
+
await Promise.all(devices
|
|
876
|
+
.filter(device => [...platformConsts.models.sensorLeak, ...platformConsts.models.sensorThermo, ...platformConsts.models.sensorMonitor].includes(device.sku))
|
|
877
|
+
.map(async (device1) => {
|
|
878
|
+
try {
|
|
879
|
+
// Reformat the device id
|
|
880
|
+
if (!device1.device.includes(':')) {
|
|
881
|
+
// Eg converts abcd1234abcd1234 to AB:CD:12:34:AB:CD:12:34
|
|
882
|
+
// For sensors with an add-on sensor like H5178
|
|
883
|
+
// Eg converts abcd1234abcd1234_1 to AB:CD:12:34:AB:CD:12:34_1
|
|
884
|
+
device1.device = device1.device.replace(DEVICE_ID_FORMAT_REGEX, '$&:').toUpperCase()
|
|
885
|
+
}
|
|
878
886
|
|
|
879
|
-
|
|
880
|
-
|
|
887
|
+
// Generate the UIID from which we can match our Homebridge accessory
|
|
888
|
+
const uiid = this.api.hap.uuid.generate(device1.device)
|
|
881
889
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
890
|
+
// Don't continue if the accessory doesn't exist
|
|
891
|
+
if (!devicesInHB.has(uiid)) {
|
|
892
|
+
return
|
|
893
|
+
}
|
|
886
894
|
|
|
887
|
-
|
|
888
|
-
|
|
895
|
+
// Retrieve the Homebridge accessory
|
|
896
|
+
const accessory = devicesInHB.get(uiid)
|
|
889
897
|
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
898
|
+
// Make sure the data we need for the device exists
|
|
899
|
+
if (!device1.deviceExt || !device1.deviceExt.deviceSettings || !device1.deviceExt.lastDeviceData) {
|
|
900
|
+
return
|
|
901
|
+
}
|
|
894
902
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
903
|
+
// Parse the data received
|
|
904
|
+
let parsedSettings
|
|
905
|
+
let parsedData
|
|
906
|
+
try {
|
|
907
|
+
parsedSettings = JSON.parse(device1.deviceExt.deviceSettings)
|
|
908
|
+
parsedData = JSON.parse(device1.deviceExt.lastDeviceData)
|
|
909
|
+
} catch {
|
|
910
|
+
return
|
|
911
|
+
}
|
|
904
912
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
913
|
+
const toReturn = { source: 'HTTP' }
|
|
914
|
+
if (platformConsts.models.sensorLeak.includes(device1.sku)) {
|
|
915
|
+
accessory.logDebug(`raw data: ${JSON.stringify({ ...parsedData, ...parsedSettings })}`)
|
|
908
916
|
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
917
|
+
// Keep the gateway details up to date for matching real-time leak
|
|
918
|
+
// events relayed by the gateway over AWS (#1276)
|
|
919
|
+
if (hasProperty(parsedSettings, 'sno') && parsedSettings.gatewayInfo?.device) {
|
|
920
|
+
accessory.context.gatewaySno = parsedSettings.sno
|
|
921
|
+
accessory.context.gatewayDevice = parsedSettings.gatewayInfo.device
|
|
922
|
+
}
|
|
915
923
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
924
|
+
// Leak Sensors - check to see of any warnings if the lastTime is above 0
|
|
925
|
+
let hasUnreadLeak = false
|
|
926
|
+
if (parsedData.lastTime > 0) {
|
|
927
|
+
// Obtain the leak warning messages for this device
|
|
928
|
+
const msgs = await leakWarningQueue.add(
|
|
929
|
+
() => this.httpClient.getLeakDeviceWarning(device1.device, device1.sku),
|
|
930
|
+
)
|
|
921
931
|
|
|
922
|
-
|
|
932
|
+
accessory.logDebug(`raw messages: ${JSON.stringify(msgs)}`)
|
|
923
933
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
934
|
+
// Check to see if unread messages exist
|
|
935
|
+
const unreadCount = msgs.filter(msg => !msg.read && msg.message.toLowerCase().replace(WHITESPACE_REGEX, '').startsWith('leakagealert'))
|
|
936
|
+
if (unreadCount.length > 0) {
|
|
937
|
+
hasUnreadLeak = true
|
|
938
|
+
}
|
|
928
939
|
}
|
|
929
|
-
}
|
|
930
940
|
|
|
931
|
-
|
|
932
|
-
toReturn.battery = parsedSettings.battery
|
|
933
|
-
toReturn.leakDetected = hasUnreadLeak
|
|
934
|
-
toReturn.online = parsedData.gwonline && parsedData.online
|
|
935
|
-
} else if (platformConsts.models.sensorThermo.includes(device1.sku)) {
|
|
936
|
-
// Some accounts report `tem` in hundredths of a degree Fahrenheit
|
|
937
|
-
// rather than Celsius, which lands in HomeKit as a reading roughly
|
|
938
|
-
// 90 degrees too high (#1269). The unit is not stated anywhere in
|
|
939
|
-
// the response, so log the raw payload to work out what
|
|
940
|
-
// distinguishes those accounts before converting anything.
|
|
941
|
-
accessory.logDebug(`[HTTP] raw sensor data: ${JSON.stringify(parsedData)}`)
|
|
942
|
-
|
|
943
|
-
if (hasProperty(parsedSettings, 'battery')) {
|
|
944
|
-
toReturn.battery = parsedSettings.battery
|
|
945
|
-
}
|
|
946
|
-
if (hasProperty(parsedData, 'tem')) {
|
|
947
|
-
toReturn.temperature = parsedData.tem
|
|
948
|
-
}
|
|
949
|
-
if (hasProperty(parsedData, 'hum')) {
|
|
950
|
-
toReturn.humidity = parsedData.hum
|
|
951
|
-
}
|
|
952
|
-
if (hasProperty(parsedData, 'online')) {
|
|
953
|
-
toReturn.online = parsedData.online
|
|
954
|
-
}
|
|
955
|
-
} else if (platformConsts.models.sensorMonitor.includes(device1.sku)) {
|
|
956
|
-
// The H5106 normally reports over AWS, but some accounts never
|
|
957
|
-
// receive those messages, leaving the readings at zero (#1322).
|
|
958
|
-
// The HTTP device list carries the same readings, so use it as a
|
|
959
|
-
// second source. Every field is guarded and the raw payload is
|
|
960
|
-
// logged, since the format for this model is not confirmed on
|
|
961
|
-
// every account
|
|
962
|
-
accessory.logDebug(`[HTTP] raw sensor data: ${JSON.stringify(parsedData)}`)
|
|
963
|
-
|
|
964
|
-
if (hasProperty(parsedSettings, 'battery')) {
|
|
941
|
+
// Generate the params to return
|
|
965
942
|
toReturn.battery = parsedSettings.battery
|
|
943
|
+
toReturn.leakDetected = hasUnreadLeak
|
|
944
|
+
toReturn.online = parsedData.gwonline && parsedData.online
|
|
945
|
+
} else if (platformConsts.models.sensorThermo.includes(device1.sku)) {
|
|
946
|
+
// Some accounts report `tem` in hundredths of a degree Fahrenheit
|
|
947
|
+
// rather than Celsius, which lands in HomeKit as a reading roughly
|
|
948
|
+
// 90 degrees too high (#1269). The unit is not stated anywhere in
|
|
949
|
+
// the response, so log the raw payload to work out what
|
|
950
|
+
// distinguishes those accounts before converting anything.
|
|
951
|
+
accessory.logDebug(`[HTTP] raw sensor data: ${JSON.stringify(parsedData)}`)
|
|
952
|
+
|
|
953
|
+
if (hasProperty(parsedSettings, 'battery')) {
|
|
954
|
+
toReturn.battery = parsedSettings.battery
|
|
955
|
+
}
|
|
956
|
+
if (hasProperty(parsedData, 'tem')) {
|
|
957
|
+
toReturn.temperature = parsedData.tem
|
|
958
|
+
}
|
|
959
|
+
if (hasProperty(parsedData, 'hum')) {
|
|
960
|
+
toReturn.humidity = parsedData.hum
|
|
961
|
+
}
|
|
962
|
+
if (hasProperty(parsedData, 'online')) {
|
|
963
|
+
toReturn.online = parsedData.online
|
|
964
|
+
}
|
|
965
|
+
} else if (platformConsts.models.sensorMonitor.includes(device1.sku)) {
|
|
966
|
+
// The H5106 normally reports over AWS, but some accounts never
|
|
967
|
+
// receive those messages, leaving the readings at zero (#1322).
|
|
968
|
+
// The HTTP device list carries the same readings, so use it as a
|
|
969
|
+
// second source. Every field is guarded and the raw payload is
|
|
970
|
+
// logged, since the format for this model is not confirmed on
|
|
971
|
+
// every account
|
|
972
|
+
accessory.logDebug(`[HTTP] raw sensor data: ${JSON.stringify(parsedData)}`)
|
|
973
|
+
|
|
974
|
+
if (hasProperty(parsedSettings, 'battery')) {
|
|
975
|
+
toReturn.battery = parsedSettings.battery
|
|
976
|
+
}
|
|
977
|
+
if (hasProperty(parsedData, 'tem')) {
|
|
978
|
+
toReturn.temperature = parsedData.tem
|
|
979
|
+
}
|
|
980
|
+
if (hasProperty(parsedData, 'hum')) {
|
|
981
|
+
toReturn.humidity = parsedData.hum
|
|
982
|
+
}
|
|
983
|
+
if (hasProperty(parsedData, 'online')) {
|
|
984
|
+
toReturn.online = parsedData.online
|
|
985
|
+
}
|
|
966
986
|
}
|
|
967
|
-
if (hasProperty(parsedData, 'tem')) {
|
|
968
|
-
toReturn.temperature = parsedData.tem
|
|
969
|
-
}
|
|
970
|
-
if (hasProperty(parsedData, 'hum')) {
|
|
971
|
-
toReturn.humidity = parsedData.hum
|
|
972
|
-
}
|
|
973
|
-
if (hasProperty(parsedData, 'online')) {
|
|
974
|
-
toReturn.online = parsedData.online
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
987
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
988
|
+
// Send the information to the update receiver function
|
|
989
|
+
this.receiveDeviceUpdate(accessory, toReturn)
|
|
990
|
+
} catch (err) {
|
|
991
|
+
this.log.warn('[%s] %s %s.', device1.deviceName, platformLang.devNotRef, parseError(err))
|
|
992
|
+
}
|
|
993
|
+
}))
|
|
984
994
|
} catch (err) {
|
|
985
995
|
this.log.warn('[HTTP] %s %s.', platformLang.syncFail, parseError(err))
|
|
986
996
|
}
|
package/package.json
CHANGED