homebridge-broadlink-rm-pro
Version:
Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features
196 lines (150 loc) • 5.99 kB
JavaScript
const ServiceManagerTypes = require('../helpers/serviceManagerTypes');
const delayForDuration = require('../helpers/delayForDuration');
const catchDelayCancelError = require('../helpers/catchDelayCancelError');
const ping = require('../helpers/ping')
const arp = require('../helpers/arp')
const BroadlinkRMAccessory = require('./accessory');
class SwitchAccessory extends BroadlinkRMAccessory {
constructor (log, config = {}, serviceManagerType) {
super(log, config, serviceManagerType);
if (!config.isUnitTest) {this.checkPing(ping)}
}
setDefaults () {
const { config } = this;
config.pingFrequency = config.pingFrequency || 1;
config.pingGrace = config.pingGrace || 10;
config.offDuration = config.offDuration || 60;
config.onDuration = config.onDuration || 60;
if (config.enableAutoOn === undefined && config.disableAutomaticOn === undefined) {
config.enableAutoOn = false;
} else if (config.disableAutomaticOn !== undefined) {
config.enableAutoOn = !config.disableAutomaticOn;
}
if (config.enableAutoOff === undefined && config.disableAutomaticOff === undefined) {
config.enableAutoOff = false;
} else if (config.disableAutomaticOff !== undefined) {
config.enableAutoOff = !config.disableAutomaticOff;
}
}
reset () {
super.reset();
this.stateChangeInProgress = true;
// Clear Timeouts
if (this.delayTimeoutPromise) {
this.delayTimeoutPromise.cancel();
this.delayTimeoutPromise = null;
}
if (this.autoOffTimeoutPromise) {
this.autoOffTimeoutPromise.cancel();
this.autoOffTimeoutPromise = null;
}
if (this.autoOnTimeoutPromise) {
this.autoOnTimeoutPromise.cancel();
this.autoOnTimeoutPromise = null
}
if (this.pingGraceTimeout) {
this.pingGraceTimeout.cancel();
this.pingGraceTimeout = null;
}
if (this.serviceManager.getCharacteristic(Characteristic.On) === undefined) {
this.state.switchState = false;
this.serviceManager.updateCharacteristic(Characteristic.On, this.state.switchState);
}
}
checkAutoOnOff () {
this.reset();
this.checkPingGrace();
this.checkAutoOn();
this.checkAutoOff();
}
checkPing (ping) {
const { config } = this
let { pingIPAddress, pingFrequency, pingUseArp } = config;
if (!pingIPAddress) {return}
// Setup Ping/Arp-based State
if(!pingUseArp) {
ping(pingIPAddress, pingFrequency, this.pingCallback.bind(this));
} else {
arp(pingIPAddress, pingFrequency, this.pingCallback.bind(this));
}
}
pingCallback (active) {
const { config, state, serviceManager, name, log, logLevel } = this;
if (this.stateChangeInProgress){
return;
}
if (state.switchState !== active && logLevel <=2){log(`\x1b[35m[INFO]\x1b[0m ${name} ping detected state change, now ${active}`);}
if (config.pingIPAddressStateOnly) {
state.switchState = active ? true : false;
serviceManager.updateCharacteristic(Characteristic.On,state.switchState);
return;
}
const value = active ? true : false;
serviceManager.setCharacteristic(Characteristic.On, value);
}
async setSwitchState (hexData) {
const { data, host, log, name, logLevel, config, state, serviceManager } = this;
this.stateChangeInProgress = true;
this.reset();
if (hexData) {await this.performSend(hexData);}
if (config.stateless === true) {
state.switchState = false;
serviceManager.updateCharacteristic(Characteristic.On,state.switchState);
} else {
this.checkAutoOnOff();
}
}
async checkPingGrace () {
await catchDelayCancelError(async () => {
const { config, log, name, state, serviceManager } = this;
let { pingGrace } = config;
if (pingGrace) {
this.pingGraceTimeoutPromise = delayForDuration(pingGrace);
await this.pingGraceTimeoutPromise;
this.stateChangeInProgress = false;
}
});
}
async checkAutoOff () {
await catchDelayCancelError(async () => {
const { config, log, name, state, serviceManager } = this;
let { disableAutomaticOff, enableAutoOff, onDuration } = config;
if (state.switchState && enableAutoOff) {
log(`${name} setSwitchState: (automatically turn off in ${onDuration} seconds)`);
this.autoOffTimeoutPromise = delayForDuration(onDuration);
await this.autoOffTimeoutPromise;
serviceManager.setCharacteristic(Characteristic.On, false);
}
});
}
async checkAutoOn () {
await catchDelayCancelError(async () => {
const { config, log, name, state, serviceManager } = this;
let { disableAutomaticOn, enableAutoOn, offDuration } = config;
if (!state.switchState && enableAutoOn) {
log(`${name} setSwitchState: (automatically turn on in ${offDuration} seconds)`);
this.autoOnTimeoutPromise = delayForDuration(offDuration);
await this.autoOnTimeoutPromise;
serviceManager.setCharacteristic(Characteristic.On, true);
}
});
}
setupServiceManager () {
const { data, name, config, serviceManagerType } = this;
const { on, off } = data || { };
this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log);
this.serviceManager.addToggleCharacteristic({
name: 'switchState',
type: Characteristic.On,
getMethod: this.getCharacteristicValue,
setMethod: this.setCharacteristicValue,
bind: this,
props: {
onData: on || data,
offData: off || undefined,
setValuePromise: this.setSwitchState.bind(this)
}
});
}
}
module.exports = SwitchAccessory;