Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/device/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import deviceSensorLeak from './sensor-leak.js'
import deviceSensorMonitor from './sensor-monitor.js'
import deviceSensorPresence from './sensor-presence.js'
import deviceSensorThermo4 from './sensor-thermo4.js'
import deviceSensorThermoH5109 from './sensor-thermo-H5109.js'
import deviceSensorThermo from './sensor-thermo.js'
import deviceSwitchDouble from './switch-double.js'
import deviceSwitchSingle from './switch-single.js'
Expand Down Expand Up @@ -104,6 +105,7 @@ export default {
deviceSensorMonitor,
deviceSensorPresence,
deviceSensorThermo,
deviceSensorThermoH5109,
deviceSensorThermo4,
deviceSwitchDouble,
deviceSwitchSingle,
Expand Down
156 changes: 156 additions & 0 deletions lib/device/sensor-thermo-H5109.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import platformConsts from '../utils/constants.js'
import {
cenToFar,
generateRandomString,
hasProperty,
parseError,
} from '../utils/functions.js'
import platformLang from '../utils/lang-en.js'

export default class {
constructor(platform, accessory) {
// Set up variables from the platform
this.hapChar = platform.api.hap.Characteristic
this.hapErr = platform.api.hap.HapStatusError
this.hapServ = platform.api.hap.Service
this.platform = platform
this.httpTimeout = platform.config.bleRefreshTime * 4.5 * 1000

// Set up variables from the accessory
this.accessory = accessory

// Set up custom variables for this device type
const deviceConf = platform.deviceConf[accessory.context.gvDeviceId]
this.lowBattThreshold = deviceConf && deviceConf.lowBattThreshold
? Math.min(deviceConf.lowBattThreshold, 100)
: platformConsts.defaultValues.lowBattThreshold

// Remove temperature sensor service if it exists
if (this.accessory.getService(this.hapServ.TemperatureSensor)) {
this.accessory.removeService(this.accessory.getService(this.hapServ.TemperatureSensor))
}

// Add the thermostat service if it doesn't already exist
this.thermoService = this.accessory.getService(this.hapServ.Thermostat)
|| this.accessory.addService(this.hapServ.Thermostat)

// Set up thermostat characteristics
this.cacheTemp = this.thermoService.getCharacteristic(this.hapChar.CurrentTemperature).value || 20

// Configure thermostat to be read-only (sensor only)
this.thermoService.getCharacteristic(this.hapChar.TargetTemperature)
.updateValue(this.cacheTemp)
.onGet(() => {
return this.cacheTemp;
});

// Set heating/cooling state to OFF (0)
this.thermoService.getCharacteristic(this.hapChar.CurrentHeatingCoolingState)
.updateValue(0) // 0 = OFF
.setProps({
validValues: [0] // Only allow OFF state
});

this.thermoService.getCharacteristic(this.hapChar.TargetHeatingCoolingState)
.updateValue(0) // 0 = OFF
.setProps({
validValues: [0] // Only allow OFF state
});

// Set temperature display units to Celsius (0)
this.thermoService.getCharacteristic(this.hapChar.TemperatureDisplayUnits)
.updateValue(0);

this.updateCache()

// Add the battery service if it doesn't already exist
this.battService = this.accessory.getService(this.hapServ.Battery)
|| this.accessory.addService(this.hapServ.Battery)
this.cacheBatt = this.battService.getCharacteristic(this.hapChar.BatteryLevel).value

// Pass the accessory to Fakegato to set up with Eve
this.accessory.eveService = new platform.eveService('custom', this.accessory, {
log: () => {},
})

// Output the customised options to the log
const opts = JSON.stringify({
lowBattThreshold: this.lowBattThreshold,
})
platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
}

async externalUpdate(params) {
// Check to see if the provided online status is different from the cache value
if (hasProperty(params, 'online') && this.cacheOnline !== params.online) {
this.cacheOnline = params.online
this.platform.updateAccessoryStatus(this.accessory, this.cacheOnline)
}

if (params.source === 'BLE') {
// If we have a BLE update then we should ignore HTTP updates for the next 4 BLE refresh cycles
// Since BLE will be more accurate and may not have updated with the cloud yet
// Generate a random key
const bleKey = generateRandomString(5)
this.bleKey = bleKey
setTimeout(() => {
if (this.bleKey === bleKey) {
this.bleKey = false
}
}, this.httpTimeout)
}
if (params.source === 'HTTP' && this.bleKey) {
return
}

// Check to see if the provided battery is different from the cached state
if (params.battery !== this.cacheBatt && this.battService) {
// Battery is different so update Homebridge with new values
this.cacheBatt = params.battery
this.battService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBatt)
this.battService.updateCharacteristic(
this.hapChar.StatusLowBattery,
this.cacheBatt < this.lowBattThreshold ? 1 : 0,
)

// Log the change
this.accessory.log(`${platformLang.curBatt} [${this.cacheBatt}%]`)
}

// Check to see if the provided temperature is different from the cached state
if (hasProperty(params, 'temperature')) {
let newTemp = Number.parseInt(params.temperature + this.accessory.context.offTemp, 10)
newTemp /= 100
if (newTemp !== this.cacheTemp) {
// Temperature is different so update Homebridge with new values
this.cacheTemp = newTemp
this.thermoService.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
this.thermoService.updateCharacteristic(this.hapChar.TargetTemperature, this.cacheTemp)
this.accessory.eveService.addEntry({ temp: this.cacheTemp })

// Log the change
this.accessory.log(`${platformLang.curTemp} [${this.cacheTemp}°C / ${cenToFar(this.cacheTemp)}°F]`)

// Update the cache file with the new temperature
this.updateCache()
}
}
}

async updateCache() {
// Don't continue if the storage client hasn't initialised properly
if (!this.platform.storageClientData) {
return
}

// Attempt to save the new temperature to the cache
try {
await this.platform.storageData.setItem(
`${this.accessory.context.gvDeviceId}_temp`,
this.cacheTemp,
)
} catch (err) {
this.accessory.logWarn(`${platformLang.storageWriteErr} ${parseError(err)}`)
}
}
}
7 changes: 6 additions & 1 deletion lib/platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,12 @@ export default class {
accessory = devicesInHB.get(uuid) || this.addAccessory(device)
} else if (platformConsts.models.sensorThermo.includes(device.model)) {
// Device is a thermo-hygrometer sensor
devInstance = deviceTypes.deviceSensorThermo
if (device.model === 'H5109') {
// Special handling for Gateway H5042+ with Floating Pool Sensor H5109
devInstance = deviceTypes.deviceSensorThermoH5109
} else {
devInstance = deviceTypes.deviceSensorThermo
}
accessory = devicesInHB.get(uuid) || this.addAccessory(device)
} else if (platformConsts.models.sensorThermo4.includes(device.model)) {
// Device is a thermo-hygrometer sensor with 4 prongs and AWS support
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ export default {
'H5104',
'H5105',
'H5108',
'H5109',
'H5174',
'H5177',
'H5179',
Expand Down Expand Up @@ -475,7 +476,6 @@ export default {
'H5121', // https://github.com/homebridge-plugins/homebridge-govee/issues/913
'H5126', // https://github.com/homebridge-plugins/homebridge-govee/issues/910
'H5107', // https://github.com/homebridge-plugins/homebridge-govee/issues/803
'H5109', // https://github.com/homebridge-plugins/homebridge-govee/issues/823
'H5125', // https://github.com/homebridge-plugins/homebridge-govee/issues/981
'H5185', // https://github.com/homebridge-plugins/homebridge-govee/issues/804
],
Expand Down
Loading