Skip to content

Commit 8573fcc

Browse files
authored
add support for H5109 as a thermostat (#1082)
1 parent c72cd61 commit 8573fcc

File tree

4 files changed

+165
-2
lines changed

4 files changed

+165
-2
lines changed

lib/device/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import deviceSensorLeak from './sensor-leak.js'
4646
import deviceSensorMonitor from './sensor-monitor.js'
4747
import deviceSensorPresence from './sensor-presence.js'
4848
import deviceSensorThermo4 from './sensor-thermo4.js'
49+
import deviceSensorThermoH5109 from './sensor-thermo-H5109.js'
4950
import deviceSensorThermo from './sensor-thermo.js'
5051
import deviceSwitchDouble from './switch-double.js'
5152
import deviceSwitchSingle from './switch-single.js'
@@ -104,6 +105,7 @@ export default {
104105
deviceSensorMonitor,
105106
deviceSensorPresence,
106107
deviceSensorThermo,
108+
deviceSensorThermoH5109,
107109
deviceSensorThermo4,
108110
deviceSwitchDouble,
109111
deviceSwitchSingle,

lib/device/sensor-thermo-H5109.js

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

lib/platform.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,12 @@ export default class {
940940
accessory = devicesInHB.get(uuid) || this.addAccessory(device)
941941
} else if (platformConsts.models.sensorThermo.includes(device.model)) {
942942
// 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+
}
944949
accessory = devicesInHB.get(uuid) || this.addAccessory(device)
945950
} else if (platformConsts.models.sensorThermo4.includes(device.model)) {
946951
// Device is a thermo-hygrometer sensor with 4 prongs and AWS support

lib/utils/constants.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ export default {
446446
'H5104',
447447
'H5105',
448448
'H5108',
449+
'H5109',
449450
'H5174',
450451
'H5177',
451452
'H5179',
@@ -475,7 +476,6 @@ export default {
475476
'H5121', // https://github.com/homebridge-plugins/homebridge-govee/issues/913
476477
'H5126', // https://github.com/homebridge-plugins/homebridge-govee/issues/910
477478
'H5107', // https://github.com/homebridge-plugins/homebridge-govee/issues/803
478-
'H5109', // https://github.com/homebridge-plugins/homebridge-govee/issues/823
479479
'H5125', // https://github.com/homebridge-plugins/homebridge-govee/issues/981
480480
'H5185', // https://github.com/homebridge-plugins/homebridge-govee/issues/804
481481
],

0 commit comments

Comments
 (0)