@homebridge-plugins/homebridge-govee 10.17.0 → 10.18.0

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 CHANGED
@@ -8,6 +8,16 @@ This project tries to adhere to [Semantic Versioning](http://semver.org/). In pr
8
8
  - `MINOR` version when a new device type is added, or when a new feature is added that is backwards-compatible
9
9
  - `PATCH` version when backwards-compatible bug fixes are implemented
10
10
 
11
+ ## v10.18.0 (2025-04-13)
12
+
13
+ ### Added
14
+
15
+ - add support for `H5109` as a thermostat (#1082) (@nrc2358)
16
+
17
+ ### Changed
18
+
19
+ - updated dependencies
20
+
11
21
  ## v10.17.0 (2025-03-22)
12
22
 
13
23
  ### Added
package/README.md CHANGED
@@ -28,7 +28,7 @@ Homebridge plugin to integrate Govee devices into HomeKit
28
28
  ### Prerequisites
29
29
 
30
30
  - To use this plugin, you will need to already have:
31
- - [Node](https://nodejs.org): latest version of `v18` or `v20` - any other major version is not supported.
31
+ - [Node](https://nodejs.org): latest version of `v18`, `v20` or `v22` - any other major version is not supported.
32
32
  - [Homebridge](https://homebridge.io): `v1.6` - refer to link for more information and installation instructions.
33
33
  - For bluetooth connectivity, it may be necessary to install extra packages on your system, see [Bluetooth Control](https://github.com/homebridge-plugins/homebridge-govee/wiki/Bluetooth-Control). Bluetooth works best when using a Raspberry Pi, not been tested on Windows, and Mac devices are unsupported.
34
34
 
@@ -46,6 +46,7 @@ import deviceSensorLeak from './sensor-leak.js'
46
46
  import deviceSensorMonitor from './sensor-monitor.js'
47
47
  import deviceSensorPresence from './sensor-presence.js'
48
48
  import deviceSensorThermo4 from './sensor-thermo4.js'
49
+ import deviceSensorThermoH5109 from './sensor-thermo-H5109.js'
49
50
  import deviceSensorThermo from './sensor-thermo.js'
50
51
  import deviceSwitchDouble from './switch-double.js'
51
52
  import deviceSwitchSingle from './switch-single.js'
@@ -104,6 +105,7 @@ export default {
104
105
  deviceSensorMonitor,
105
106
  deviceSensorPresence,
106
107
  deviceSensorThermo,
108
+ deviceSensorThermoH5109,
107
109
  deviceSensorThermo4,
108
110
  deviceSwitchDouble,
109
111
  deviceSwitchSingle,
@@ -0,0 +1,156 @@
1
+ import platformConsts from '../utils/constants.js'
2
+ import {
3
+ cenToFar,
4
+ generateRandomString,
5
+ hasProperty,
6
+ parseError,
7
+ } from '../utils/functions.js'
8
+ import platformLang from '../utils/lang-en.js'
9
+
10
+ export default class {
11
+ constructor(platform, accessory) {
12
+ // Set up variables from the platform
13
+ this.hapChar = platform.api.hap.Characteristic
14
+ this.hapErr = platform.api.hap.HapStatusError
15
+ this.hapServ = platform.api.hap.Service
16
+ this.platform = platform
17
+ this.httpTimeout = platform.config.bleRefreshTime * 4.5 * 1000
18
+
19
+ // Set up variables from the accessory
20
+ this.accessory = accessory
21
+
22
+ // Set up custom variables for this device type
23
+ const deviceConf = platform.deviceConf[accessory.context.gvDeviceId]
24
+ this.lowBattThreshold = deviceConf && deviceConf.lowBattThreshold
25
+ ? Math.min(deviceConf.lowBattThreshold, 100)
26
+ : platformConsts.defaultValues.lowBattThreshold
27
+
28
+ // Remove temperature sensor service if it exists
29
+ if (this.accessory.getService(this.hapServ.TemperatureSensor)) {
30
+ this.accessory.removeService(this.accessory.getService(this.hapServ.TemperatureSensor))
31
+ }
32
+
33
+ // Add the thermostat service if it doesn't already exist
34
+ this.thermoService = this.accessory.getService(this.hapServ.Thermostat)
35
+ || this.accessory.addService(this.hapServ.Thermostat)
36
+
37
+ // Set up thermostat characteristics
38
+ this.cacheTemp = this.thermoService.getCharacteristic(this.hapChar.CurrentTemperature).value || 20
39
+
40
+ // Configure thermostat to be read-only (sensor only)
41
+ this.thermoService.getCharacteristic(this.hapChar.TargetTemperature)
42
+ .updateValue(this.cacheTemp)
43
+ .onGet(() => {
44
+ return this.cacheTemp
45
+ })
46
+
47
+ // Set heating/cooling state to OFF (0)
48
+ this.thermoService.getCharacteristic(this.hapChar.CurrentHeatingCoolingState)
49
+ .updateValue(0) // 0 = OFF
50
+ .setProps({
51
+ validValues: [0], // Only allow OFF state
52
+ })
53
+
54
+ this.thermoService.getCharacteristic(this.hapChar.TargetHeatingCoolingState)
55
+ .updateValue(0) // 0 = OFF
56
+ .setProps({
57
+ validValues: [0], // Only allow OFF state
58
+ })
59
+
60
+ // Set temperature display units to Celsius (0)
61
+ this.thermoService.getCharacteristic(this.hapChar.TemperatureDisplayUnits)
62
+ .updateValue(0)
63
+
64
+ this.updateCache()
65
+
66
+ // Add the battery service if it doesn't already exist
67
+ this.battService = this.accessory.getService(this.hapServ.Battery)
68
+ || this.accessory.addService(this.hapServ.Battery)
69
+ this.cacheBatt = this.battService.getCharacteristic(this.hapChar.BatteryLevel).value
70
+
71
+ // Pass the accessory to Fakegato to set up with Eve
72
+ this.accessory.eveService = new platform.eveService('custom', this.accessory, {
73
+ log: () => {},
74
+ })
75
+
76
+ // Output the customised options to the log
77
+ const opts = JSON.stringify({
78
+ lowBattThreshold: this.lowBattThreshold,
79
+ })
80
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
81
+ }
82
+
83
+ async externalUpdate(params) {
84
+ // Check to see if the provided online status is different from the cache value
85
+ if (hasProperty(params, 'online') && this.cacheOnline !== params.online) {
86
+ this.cacheOnline = params.online
87
+ this.platform.updateAccessoryStatus(this.accessory, this.cacheOnline)
88
+ }
89
+
90
+ if (params.source === 'BLE') {
91
+ // If we have a BLE update then we should ignore HTTP updates for the next 4 BLE refresh cycles
92
+ // Since BLE will be more accurate and may not have updated with the cloud yet
93
+ // Generate a random key
94
+ const bleKey = generateRandomString(5)
95
+ this.bleKey = bleKey
96
+ setTimeout(() => {
97
+ if (this.bleKey === bleKey) {
98
+ this.bleKey = false
99
+ }
100
+ }, this.httpTimeout)
101
+ }
102
+ if (params.source === 'HTTP' && this.bleKey) {
103
+ return
104
+ }
105
+
106
+ // Check to see if the provided battery is different from the cached state
107
+ if (params.battery !== this.cacheBatt && this.battService) {
108
+ // Battery is different so update Homebridge with new values
109
+ this.cacheBatt = params.battery
110
+ this.battService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBatt)
111
+ this.battService.updateCharacteristic(
112
+ this.hapChar.StatusLowBattery,
113
+ this.cacheBatt < this.lowBattThreshold ? 1 : 0,
114
+ )
115
+
116
+ // Log the change
117
+ this.accessory.log(`${platformLang.curBatt} [${this.cacheBatt}%]`)
118
+ }
119
+
120
+ // Check to see if the provided temperature is different from the cached state
121
+ if (hasProperty(params, 'temperature')) {
122
+ let newTemp = Number.parseInt(params.temperature + this.accessory.context.offTemp, 10)
123
+ newTemp /= 100
124
+ if (newTemp !== this.cacheTemp) {
125
+ // Temperature is different so update Homebridge with new values
126
+ this.cacheTemp = newTemp
127
+ this.thermoService.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
128
+ this.thermoService.updateCharacteristic(this.hapChar.TargetTemperature, this.cacheTemp)
129
+ this.accessory.eveService.addEntry({ temp: this.cacheTemp })
130
+
131
+ // Log the change
132
+ this.accessory.log(`${platformLang.curTemp} [${this.cacheTemp}°C / ${cenToFar(this.cacheTemp)}°F]`)
133
+
134
+ // Update the cache file with the new temperature
135
+ this.updateCache()
136
+ }
137
+ }
138
+ }
139
+
140
+ async updateCache() {
141
+ // Don't continue if the storage client hasn't initialised properly
142
+ if (!this.platform.storageClientData) {
143
+ return
144
+ }
145
+
146
+ // Attempt to save the new temperature to the cache
147
+ try {
148
+ await this.platform.storageData.setItem(
149
+ `${this.accessory.context.gvDeviceId}_temp`,
150
+ this.cacheTemp,
151
+ )
152
+ } catch (err) {
153
+ this.accessory.logWarn(`${platformLang.storageWriteErr} ${parseError(err)}`)
154
+ }
155
+ }
156
+ }
@@ -251,10 +251,10 @@
251
251
  try {
252
252
  const currentConfig = await homebridge.getPluginConfig()
253
253
  showIntro = () => {
254
+ homebridge.disableSaveButton?.()
254
255
  const introContinue = document.getElementById('introContinue')
255
256
  introContinue.addEventListener('click', () => {
256
257
  homebridge.showSpinner()
257
- homebridge.disableSaveButton?.()
258
258
  document.getElementById('pageIntro').style.display = 'none'
259
259
  document.getElementById('menuWrapper').style.display = 'inline-flex'
260
260
  showSettings()
package/lib/platform.js CHANGED
@@ -940,7 +940,12 @@ export default class {
940
940
  accessory = devicesInHB.get(uuid) || this.addAccessory(device)
941
941
  } else if (platformConsts.models.sensorThermo.includes(device.model)) {
942
942
  // Device is a thermo-hygrometer sensor
943
- devInstance = deviceTypes.deviceSensorThermo
943
+ if (device.model === 'H5109') {
944
+ // Special handling for Gateway H5042+ with Floating Pool Sensor H5109
945
+ devInstance = deviceTypes.deviceSensorThermoH5109
946
+ } else {
947
+ devInstance = deviceTypes.deviceSensorThermo
948
+ }
944
949
  accessory = devicesInHB.get(uuid) || this.addAccessory(device)
945
950
  } else if (platformConsts.models.sensorThermo4.includes(device.model)) {
946
951
  // Device is a thermo-hygrometer sensor with 4 prongs and AWS support
@@ -446,6 +446,7 @@ export default {
446
446
  'H5104',
447
447
  'H5105',
448
448
  'H5108',
449
+ 'H5109',
449
450
  'H5174',
450
451
  'H5177',
451
452
  'H5179',
@@ -475,7 +476,6 @@ export default {
475
476
  'H5121', // https://github.com/homebridge-plugins/homebridge-govee/issues/913
476
477
  'H5126', // https://github.com/homebridge-plugins/homebridge-govee/issues/910
477
478
  'H5107', // https://github.com/homebridge-plugins/homebridge-govee/issues/803
478
- 'H5109', // https://github.com/homebridge-plugins/homebridge-govee/issues/823
479
479
  'H5125', // https://github.com/homebridge-plugins/homebridge-govee/issues/981
480
480
  'H5185', // https://github.com/homebridge-plugins/homebridge-govee/issues/804
481
481
  ],
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@homebridge-plugins/homebridge-govee",
3
3
  "alias": "Govee",
4
4
  "type": "module",
5
- "version": "10.17.0",
5
+ "version": "10.18.0",
6
6
  "description": "Homebridge plugin to integrate Govee devices into HomeKit.",
7
7
  "author": {
8
8
  "name": "bwp91",
@@ -48,14 +48,14 @@
48
48
  "main": "lib/index.js",
49
49
  "engines": {
50
50
  "homebridge": "^1.6.0 || ^2.0.0-beta.0",
51
- "node": "^18.20.7 || ^20.19.0 || ^22.14.0"
51
+ "node": "^18.20.8 || ^20.19.0 || ^22.14.0"
52
52
  },
53
53
  "scripts": {
54
54
  "lint": "eslint . --fix",
55
55
  "rebuild": "rm -rf package-lock.json && rm -rf node_modules && npm install"
56
56
  },
57
57
  "dependencies": {
58
- "@homebridge/plugin-ui-utils": "^2.0.1",
58
+ "@homebridge/plugin-ui-utils": "^2.0.2",
59
59
  "aws-iot-device-sdk": "^2.2.15",
60
60
  "axios": "^1.8.4",
61
61
  "node-persist": "^4.0.4",
@@ -69,7 +69,7 @@
69
69
  "govee-bt-client": "^1.0.15"
70
70
  },
71
71
  "devDependencies": {
72
- "@antfu/eslint-config": "^4.10.2"
72
+ "@antfu/eslint-config": "^4.12.0"
73
73
  },
74
74
  "overrides": {
75
75
  "govee-bt-client": {