homebridge-wemo
Version:
Homebridge plugin to integrate Wemo devices into HomeKit.
149 lines (124 loc) • 5.49 kB
JavaScript
import platformConsts from '../utils/constants.js'
import { 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.eveChar = platform.eveChar
this.hapChar = platform.api.hap.Characteristic
this.hapServ = platform.api.hap.Service
this.platform = platform
// Set up variables from the accessory
this.accessory = accessory
// Set up custom variables for this device type
const deviceConf = platform.deviceConf[accessory.context.serialNumber] || {}
this.noMotionTimer = deviceConf.noMotionTimer || platformConsts.defaultValues.noMotionTimer
// Add the motion sensor service if it doesn't already exist
this.service = this.accessory.getService(this.hapServ.MotionSensor)
|| this.accessory.addService(this.hapServ.MotionSensor)
// Pass the accessory to fakegato to set up the Eve info service
this.accessory.historyService = new platform.eveService('motion', this.accessory, {
log: () => {},
})
// Output the customised options to the log
const opts = JSON.stringify({
noMotionTimer: this.noMotionTimer,
})
platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
// Request a device update immediately
this.requestDeviceUpdate()
// Start a polling interval if the user has disabled upnp
if (this.accessory.context.connection === 'http') {
this.pollingInterval = setInterval(
() => this.requestDeviceUpdate(),
platform.config.pollingInterval * 1000,
)
}
}
receiveDeviceUpdate(attribute) {
// Log the receiving update if debug is enabled
this.accessory.logDebug(`${platformLang.recUpd} [${attribute.name}: ${JSON.stringify(attribute.value)}]`)
// Send a HomeKit needed true/false argument
// attribute.value is 1 if and only if motion is detected
this.externalUpdate(attribute.value === 1)
}
async requestDeviceUpdate() {
try {
// Request the update
const data = await this.platform.httpClient.sendDeviceUpdate(
this.accessory,
'urn:Belkin:service:basicevent:1',
'GetBinaryState',
)
// Check for existence since BinaryState can be int 0
if (hasProperty(data, 'BinaryState')) {
// Send the data to the receiver function
this.receiveDeviceUpdate({
name: 'BinaryState',
value: Number.parseInt(data.BinaryState, 10),
})
}
} catch (err) {
const eText = parseError(err, [
platformLang.timeout,
platformLang.timeoutUnreach,
platformLang.noService,
])
this.accessory.logDebugWarn(`${platformLang.rduErr} ${eText}`)
}
}
externalUpdate(value) {
try {
// Obtain the previous state of the motion sensor
const prevState = this.service.getCharacteristic(this.hapChar.MotionDetected).value
// Don't continue in the following cases:
// (1) the previous state is the same as before and the motion timer isn't running
// (2) the new value is 'no motion detected' but the motion timer is still running
if ((value === prevState && !this.motionTimer) || (!value && this.motionTimer)) {
return
}
// Next logic depends on two cases
if (value || this.noMotionTimer === 0) {
// CASE: new motion detected or the user motion timer is set to 0 seconds
// If a motion timer is already present then stop it
if (this.motionTimer) {
this.accessory.log(platformLang.timerStopped)
clearTimeout(this.motionTimer)
this.motionTimer = false
}
// Update the HomeKit characteristics
this.service.updateCharacteristic(this.hapChar.MotionDetected, value)
// Add the entry to Eve
this.accessory.historyService.addEntry({ status: value ? 1 : 0 })
// If motion detected then update the LastActivation Eve characteristic
if (value) {
this.service.updateCharacteristic(
this.eveChar.LastActivation,
Math.round(new Date().valueOf() / 1000) - this.accessory.historyService.getInitialTime(),
)
}
// Log the change if appropriate
this.accessory.log(`${platformLang.motionSensor} [${value ? platformLang.motionYes : platformLang.motionNo}]`)
} else {
// CASE: motion not detected and the user motion timer is more than 0 seconds
this.accessory.log(`${platformLang.timerStarted} [${this.noMotionTimer}s]`)
// Clear any existing timers
clearTimeout(this.motionTimer)
// Create a new 'no motion timer'
this.motionTimer = setTimeout(() => {
// Update the HomeKit characteristic to false
this.service.updateCharacteristic(this.hapChar.MotionDetected, false)
// Add a no motion detected value to Eve
this.accessory.historyService.addEntry({ status: 0 })
// Log the change if appropriate
this.accessory.log(`${platformLang.motionSensor} [${platformLang.motionNo}] [${platformLang.timerComplete}]`)
// Set the motion timer in use to false
this.motionTimer = false
}, this.noMotionTimer * 1000)
}
} catch (err) {
// Catch any errors
this.accessory.logWarn(`${platformLang.cantUpd} ${parseError(err)}`)
}
}
}