From e4fa276de2b29eec9a8ad640653f43781f15051e Mon Sep 17 00:00:00 2001 From: rodtoll Date: Sun, 11 Oct 2015 08:14:48 -0700 Subject: [PATCH 1/8] Adding isy-js based ISY platform support --- package.json | 1 + platforms/isy-js.js | 674 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 675 insertions(+) create mode 100644 platforms/isy-js.js diff --git a/package.json b/package.json index 3a3ca74..a55f737 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "hap-nodejs": "git+https://github.com/KhaosT/HAP-NodeJS#4650e771f356a220868d873d16564a6be6603ff7", "harmonyhubjs-client": "^1.1.4", "harmonyhubjs-discover": "git+https://github.com/swissmanu/harmonyhubjs-discover.git", + "isy-js": "", "lifx-api": "^1.0.1", "lifx": "git+https://github.com/magicmonkey/lifxjs.git", "mdns": "^2.2.4", diff --git a/platforms/isy-js.js b/platforms/isy-js.js new file mode 100644 index 0000000..37d515b --- /dev/null +++ b/platforms/isy-js.js @@ -0,0 +1,674 @@ +var types = require("HAP-NodeJS/accessories/types.js"); +var isy = require('isy-js'); +var Service = require("HAP-NodeJS").Service; +var Characteristic = require("HAP-NodeJS").Characteristic; +var inherits = require('util').inherits; + +var deviceMap = {}; + +function ISYChangeHandler(isy,device) { + var deviceToUpdate = deviceMap[device.address]; + if(deviceToUpdate != null) { + deviceToUpdate.handleExternalChange(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// PLATFORM + +function ISYPlatform(log,config) { + this.log = log; + this.config = config; + this.host = config.host; + this.username = config.username; + this.password = config.password; + this.elkEnabled = config.elkEnabled; + this.isy = new isy.ISY(this.host, this.username,this.password, config.elkEnabled, ISYChangeHandler); +} + +ISYPlatform.prototype.shouldIgnore = function(device) { + var deviceAddress = device.address; + var deviceName = device.name; + for(var index = 0; index < this.config.ignoreDevices.length; index++) { + var rule = this.config.ignoreDevices[index]; + if(rule.nameContains != "") { + if(deviceName.indexOf(rule.nameContains) == -1) { + continue; + } + } + if(rule.lastAddressDigit != "") { + if(deviceAddress.indexOf(rule.lastAddressDigit,deviceAddress.length-2) == -1) { + continue; + } + } + if(rule.address != "") { + if(deviceAddress != rule.address) { + continue; + } + } + console.log("@@@@@@ Ignoring device: "+deviceName+" ["+deviceAddress+"] because of rule ["+rule.nameContains+"] ["+rule.lastAddressDigit+"] ["+rule.address+"]"); + return true; + + } + return false; +} + +ISYPlatform.prototype.accessories = function(callback) { + var that = this; + this.isy.initialize(function() { + var results = []; + var deviceList = that.isy.getDeviceList(); + for(var index = 0; index < deviceList.length; index++) { + var device = deviceList[index]; + var homeKitDevice = null; + if(!that.shouldIgnore(device)) { + + if(device.deviceType == that.isy.DEVICE_TYPE_LIGHT || device.deviceType == that.isy.DEVICE_TYPE_DIMMABLE_LIGHT) { + homeKitDevice = new ISYLightAccessory(that.log,device); + } else if(device.deviceType == that.isy.DEVICE_TYPE_LOCK || device.deviceType == that.isy.DEVICE_TYPE_SECURE_LOCK) { + homeKitDevice = new ISYLockAccessory(that.log,device); + } else if(device.deviceType == that.isy.DEVICE_TYPE_OUTLET) { + homeKitDevice = new ISYOutletAccessory(that.log,device); + } else if(device.deviceType == that.isy.DEVICE_TYPE_FAN) { + homeKitDevice = new ISYFanAccessory(that.log,device); + } else if(device.deviceType == that.isy.DEVICE_TYPE_DOOR_WINDOW_SENSOR) { + homeKitDevice = new ISYDoorWindowSensorAccessory(that.log,device); + } else if(device.deviceType == that.isy.DEVICE_TYPE_ALARM_DOOR_WINDOW_SENSOR) { + homeKitDevice = new ISYDoorWindowSensorAccessory(that.log,device); + } else if(device.deviceType == that.isy.DEVICE_TYPE_ALARM_PANEL) { + homeKitDevice = new ISYElkAlarmPanelAccessory(that.log,device); + } + if(homeKitDevice != null) { + deviceMap[device.address] = homeKitDevice; + results.push(homeKitDevice); + } + } + } + if(that.isy.elkEnabled) { + var panelDevice = that.isy.getElkAlarmPanel(); + var panelDeviceHK = new ISYElkAlarmPanelAccessory(that.log,panelDevice); + deviceMap[panelDevice.address] = panelDeviceHK; + results.push(panelDeviceHK); + } + console.log("Filtered device has: "+results.length+" devices"); + callback(results); + }); +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// FANS + +function ISYFanAccessory(log,device) { + this.log = log; + this.device = device; + this.address = device.address; + this.name = device.name; +} + +ISYFanAccessory.prototype.identify = function(callback) { + // Do the identify action + callback(); +} + +ISYFanAccessory.prototype.translateFanSpeedToHK = function(fanSpeed) { + if(fanSpeed == "Off") { + return 0; + } else if(fanSpeed == "Low") { + return 32; + } else if(fanSpeed == "Medium") { + return 67; + } else if(fanSpeed == "High") { + return 100; + } else { + this.log("!!!! ERROR: Unknown fan speed: "+fanSpeed); + return 0; + } +} + +ISYFanAccessory.prototype.translateHKToFanSpeed = function(fanStateHK) { + if(fanStateHK == 0) { + return "Off"; + } else if(fanStateHK > 0 && fanStateHK <=32) { + return "Low"; + } else if(fanStateHK > 33 && fanStateHK <= 67) { + return "Medium"; + } else if(fanStateHK > 67) { + return "High"; + } else { + this.log("!!!!! ERROR: Unknown fan state!"); + return "Off"; + } +} + +ISYFanAccessory.prototype.getFanRotationSpeed = function(callback) { + callback(null,this.translateFanSpeedToHK(this.device.getCurrentFanState())); +} + +ISYFanAccessory.prototype.setFanRotationSpeed = function(fanStateHK,callback) { + var newFanState = this.translateHKToFanSpeed(fanStateHK); + this.log("Sending command to set fan state to: "+newFanState); + if(newFanState != this.device.getCurrentFanState()) { + this.device.sendFanCommand(newFanState, function(result) { + callback(); + }); + } else { + this.log("Fan command does not change actual speed"); + callback(); + } +} + + +ISYFanAccessory.prototype.getIsFanOn = function() { + return (this.device.getCurrentFanState() != "Off"); +} + +ISYFanAccessory.prototype.getFanOnState = function(callback) { + callback(null,this.getIsFanOn()); +} + +ISYFanAccessory.prototype.setFanOnState = function(onState,callback) { + if(onState != this.getIsFanOn()) { + if(onState) { + this.setFanRotationSpeed(this.translateFanSpeedToHK("Medium"), callback); + } else { + this.setFanRotationSpeed(this.translateFanSpeedToHK("Off"), callback); + } + } else { + this.log("Fan command does not change actual state"); + callback(); + } +} + + +ISYFanAccessory.prototype.handleExternalChange = function() { + this.fanService + .setCharacteristic(Characteristic.On, this.getIsFanOn()); + + this.fanService + .setCharacteristic(Characteristic.RotationSpeed, this.translateFanSpeedToHK(this.device.getCurrentFanState())); +} + +ISYFanAccessory.prototype.getServices = function() { + var informationService = new Service.AccessoryInformation(); + + informationService + .setCharacteristic(Characteristic.Manufacturer, "SmartHome") + .setCharacteristic(Characteristic.Model, this.device.deviceFriendlyName) + .setCharacteristic(Characteristic.SerialNumber, this.device.address); + + var fanService = new Service.Fan(); + + this.fanService = fanService; + this.informationService = informationService; + + fanService + .getCharacteristic(Characteristic.On) + .on('set', this.setFanOnState.bind(this)); + + fanService + .getCharacteristic(Characteristic.On) + .on('get', this.getFanOnState.bind(this)); + + fanService + .addCharacteristic(new Characteristic.RotationSpeed()) + .on('get', this.getFanRotationSpeed.bind(this)); + + fanService + .getCharacteristic(Characteristic.RotationSpeed) + .on('set', this.setFanRotationSpeed.bind(this)); + + return [informationService, fanService]; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// OUTLETS + +function ISYOutletAccessory(log,device) { + this.log = log; + this.device = device; + this.address = device.address; + this.name = device.name; +} + +ISYOutletAccessory.prototype.identify = function(callback) { + // Do the identify action + callback(); +} + +ISYOutletAccessory.prototype.setOutletState = function(outletState,callback) { + this.log("Sending command to set outlet state to: "+outletState); + if(outletState != this.device.getCurrentOutletState()) { + this.device.sendOutletCommand(outletState, function(result) { + callback(); + }); + } else { + callback(); + } +} + +ISYOutletAccessory.prototype.getOutletState = function(callback) { + callback(null,this.device.getCurrentOutletState()); +} + +ISYOutletAccessory.prototype.getOutletInUseState = function(callback) { + callback(null, true); +} + +ISYOutletAccessory.prototype.handleExternalChange = function() { + this.outletService + .setCharacteristic(Characteristic.On, this.device.getCurrentOutletState()); +} + +ISYOutletAccessory.prototype.getServices = function() { + var informationService = new Service.AccessoryInformation(); + + informationService + .setCharacteristic(Characteristic.Manufacturer, "SmartHome") + .setCharacteristic(Characteristic.Model, this.device.deviceFriendlyName) + .setCharacteristic(Characteristic.SerialNumber, this.device.address); + + var outletService = new Service.Outlet(); + + this.outletService = outletService; + this.informationService = informationService; + + outletService + .getCharacteristic(Characteristic.On) + .on('set', this.setOutletState.bind(this)); + + outletService + .getCharacteristic(Characteristic.On) + .on('get', this.getOutletState.bind(this)); + + outletService + .getCharacteristic(Characteristic.OutletInUse) + .on('get', this.getOutletInUseState.bind(this)); + + return [informationService, outletService]; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// LOCKS + +function ISYLockAccessory(log,device) { + this.log = log; + this.device = device; + this.address = device.address; + this.name = device.name; +} + +ISYLockAccessory.prototype.identify = function(callback) { + callback(); +} + +ISYLockAccessory.prototype.setTargetLockState = function(lockState,callback) { + this.log("Sending command to set lock state to: "+lockState); + if(lockState != this.getDeviceCurrentStateAsHK()) { + var targetLockValue = (lockState == 0) ? false : true; + this.device.sendLockCommand(targetLockValue, function(result) { + callback(); + }); + } else { + callback(); + } +} + +ISYLockAccessory.prototype.getDeviceCurrentStateAsHK = function() { + return (this.device.getCurrentLockState() ? 1 : 0); +} + +ISYLockAccessory.prototype.getLockCurrentState = function(callback) { + callback(null, this.getDeviceCurrentStateAsHK()); +} + +ISYLockAccessory.prototype.getTargetLockState = function(callback) { + this.getLockCurrentState(callback); +} + +ISYLockAccessory.prototype.handleExternalChange = function() { + this.lockService + .setCharacteristic(Characteristic.LockTargetState, this.getDeviceCurrentStateAsHK()); + this.lockService + .setCharacteristic(Characteristic.LockCurrentState, this.getDeviceCurrentStateAsHK()); +} + +ISYLockAccessory.prototype.getServices = function() { + var informationService = new Service.AccessoryInformation(); + + informationService + .setCharacteristic(Characteristic.Manufacturer, "SmartHome") + .setCharacteristic(Characteristic.Model, this.device.deviceFriendlyName) + .setCharacteristic(Characteristic.SerialNumber, this.device.address); + + var lockMechanismService = new Service.LockMechanism(); + + this.lockService = lockMechanismService; + this.informationService = informationService; + + lockMechanismService + .getCharacteristic(Characteristic.LockTargetState) + .on('set', this.setTargetLockState.bind(this)); + + lockMechanismService + .getCharacteristic(Characteristic.LockTargetState) + .on('get', this.getTargetLockState.bind(this)); + + lockMechanismService + .getCharacteristic(Characteristic.LockCurrentState) + .on('get', this.getLockCurrentState.bind(this)); + + return [informationService, lockMechanismService]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// LIGHTS + +function ISYLightAccessory(log,device) { + this.log = log; + this.device = device; + this.address = device.address; + this.name = device.name; + this.dimmable = (this.device.deviceType == "DimmableLight"); +} + +ISYLightAccessory.prototype.identify = function(callback) { + this.device.sendLightCommand(true, function(result) { + this.device.sendLightCommand(false, function(result) { + callback(); + }); + }); +} + +ISYLightAccessory.prototype.setPowerState = function(powerOn,callback) { + this.log("=== Setting powerstate to %s", powerOn); + if(powerOn != this.device.getCurrentLightState()) { + this.log("+++ Changing powerstate to "+powerOn); + this.device.sendLightCommand(powerOn, function(result) { + callback(); + }); + } else { + this.log("--- Ignoring redundant setPowerState"); + callback(); + } +} + +ISYLightAccessory.prototype.handleExternalChange = function() { + this.log("=== Handling external change for light"); + this.lightService + .setCharacteristic(Characteristic.On, this.device.getCurrentLightState()); + if(this.device.deviceType == this.device.isy.DEVICE_TYPE_DIMMABLE_LIGHT) { + this.lightService + .setCharacteristic(Characteristic.Brightness, this.device.getCurrentLightDimState() ); + } +} + +ISYLightAccessory.prototype.getPowerState = function(callback) { + callback(null,this.device.getCurrentLightState()); +} + +ISYLightAccessory.prototype.setBrightness = function(level,callback) { + this.log("Setting brightness to %s", level); + if(level != this.device.getCurrentLightDimState()) { + this.log("+++ Changing Brightness to "+level); + this.device.sendLightDimCommand(level, function(result) { + callback(); + }); + } else { + this.log("--- Ignoring redundant setBrightness"); + callback(); + } +} + +ISYLightAccessory.prototype.getBrightness = function(callback) { + callback(null,this.device.getCurrentLightDimState()); +} + +ISYLightAccessory.prototype.getServices = function() { + var informationService = new Service.AccessoryInformation(); + + informationService + .setCharacteristic(Characteristic.Manufacturer, "SmartHome") + .setCharacteristic(Characteristic.Model, this.device.deviceFriendlyName) + .setCharacteristic(Characteristic.SerialNumber, this.device.address); + + var lightBulbService = new Service.Lightbulb(); + + this.informationService = informationService; + this.lightService = lightBulbService; + + lightBulbService + .getCharacteristic(Characteristic.On) + .on('set', this.setPowerState.bind(this)); + + lightBulbService + .getCharacteristic(Characteristic.On) + .on('get', this.getPowerState.bind(this)); + + if(this.dimmable) { + lightBulbService + .addCharacteristic(new Characteristic.Brightness()) + .on('get', this.getBrightness.bind(this)); + + lightBulbService + .getCharacteristic(Characteristic.Brightness) + .on('set', this.setBrightness.bind(this)); + } + + return [informationService, lightBulbService]; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// CONTACT SENSOR + +function ISYDoorWindowSensorAccessory(log,device) { + this.log = log; + this.device = device; + this.address = device.address; + this.name = device.name; + this.doorWindowState = false; +} + +ISYDoorWindowSensorAccessory.prototype.identify = function(callback) { + // Do the identify action + callback(); +} + +ISYDoorWindowSensorAccessory.prototype.translateCurrentDoorWindowState = function() { + return (this.device.getCurrentDoorWindowState()) ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED; +} + +ISYDoorWindowSensorAccessory.prototype.getCurrentDoorWindowState = function(callback) { + callback(null,this.translateCurrentDoorWindowState()); +} + +ISYDoorWindowSensorAccessory.prototype.handleExternalChange = function() { + this.sensorService + .setCharacteristic(Characteristic.ContactSensorState, this.translateCurrentDoorWindowState()); +} + +ISYDoorWindowSensorAccessory.prototype.getServices = function() { + var informationService = new Service.AccessoryInformation(); + + informationService + .setCharacteristic(Characteristic.Manufacturer, "SmartHome") + .setCharacteristic(Characteristic.Model, this.device.deviceFriendlyName) + .setCharacteristic(Characteristic.SerialNumber, this.device.address); + + var sensorService = new Service.ContactSensor(); + + this.sensorService = sensorService; + this.informationService = informationService; + + sensorService + .getCharacteristic(Characteristic.ContactSensorState) + .on('get', this.getCurrentDoorWindowState.bind(this)); + + return [informationService, sensorService]; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// ELK SENSOR PANEL + +function ISYElkAlarmPanelAccessory(log,device) { + this.log = log; + this.device = device; + this.address = device.address; + this.name = device.name; +} + +ISYElkAlarmPanelAccessory.prototype.identify = function(callback) { + callback(); +} + +ISYElkAlarmPanelAccessory.prototype.setAlarmTargetState = function(targetStateHK,callback) { + this.log("Sending command to set alarm panel state to: "+targetStateHK); + var targetState = this.translateHKToAlarmTargetState(targetState); + if(this.alarmTargetState != targetState) { + this.device.sendSetAlarmModeCommand(targetState, function(result) { + callback(); + }); + } else { + callback(); + } +} + +////// Current State + +/* +ELKAlarmPanelDevice.prototype.ALARM_STATE_NOT_READY_TO_ARM = 0; +ELKAlarmPanelDevice.prototype.ALARM_STATE_READY_TO_ARM = 1; +ELKAlarmPanelDevice.prototype.ALARM_STATE_READY_TO_ARM_VIOLATION = 2; +ELKAlarmPanelDevice.prototype.ALARM_STATE_ARMED_WITH_TIMER = 3; +ELKAlarmPanelDevice.prototype.ALARM_STATE_ARMED_FULLY = 4; +ELKAlarmPanelDevice.prototype.ALARM_STATE_FORCE_ARMED_VIOLATION = 5; +ELKAlarmPanelDevice.prototype.ALARM_STATE_ARMED_WITH_BYPASS = 6; +*/ + +/* +ELKAlarmPanelDevice.prototype.ALARM_TRIP_STATE_DISARMED = 0; +ELKAlarmPanelDevice.prototype.ALARM_TRIP_STATE_EXIT_DELAY = 1; +ELKAlarmPanelDevice.prototype.ALARM_TRIP_STATE_TRIPPED = 2; +*/ + +/* +Characteristic.SecuritySystemCurrentState.STAY_ARM = 0; +Characteristic.SecuritySystemCurrentState.AWAY_ARM = 1; +Characteristic.SecuritySystemCurrentState.NIGHT_ARM = 2; +Characteristic.SecuritySystemCurrentState.DISARMED = 3; +Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED = 4; +*/ + +ISYElkAlarmPanelAccessory.prototype.translateAlarmCurrentStateToHK = function() { + var tripState = this.device.getAlarmTripState(); + if(tripState == this.device.ALARM_TRIP_STATE_DISARMED || tripState == this.device.ALARM_TRIP_STATE_EXIT_DELAY) { + return Characteristic.SecuritySystemCurrentState.DISARMED; + } else if(tripState ==this.device.ALARM_TRIP_STATE_TRIPPED) { + return Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED; + } else { + var sourceAlarmState = this.device.getAlarmMode(); + if(sourceAlarmState == this.device.ALARM_MODE_STAY || sourceAlarmState == this.device.ALARM_MODE_STAY_INSTANT ) { + return Characteristic.SecuritySystemCurrentState.STAY_ARM; + } else if(sourceAlarmState == this.device.ALARM_MODE_AWAY || sourceAlarmState == this.device.ALARM_MODE_VACATION) { + return Characteristic.SecuritySystemCurrentState.AWAY_ARM; + } else if(sourceAlarmState == this.device.ALARM_MODE_NIGHT || sourceAlarmState == this.device.ALARM_MODE_NIGHT_INSTANT) { + return Characteristic.SecuritySystemCurrentState.NIGHT_ARM; + } else { + return Characteristic.SecuritySystemCurrentState.DISARM; + } + } +} + +////// Target Mode + +/* +ELKAlarmPanelDevice.prototype.ALARM_MODE_DISARMED = 0; +ELKAlarmPanelDevice.prototype.ALARM_MODE_AWAY = 1; +ELKAlarmPanelDevice.prototype.ALARM_MODE_STAY = 2; +ELKAlarmPanelDevice.prototype.ALARM_MODE_STAY_INSTANT = 3; +ELKAlarmPanelDevice.prototype.ALARM_MODE_NIGHT = 4; +ELKAlarmPanelDevice.prototype.ALARM_MODE_NIGHT_INSTANT = 5; +ELKAlarmPanelDevice.prototype.ALARM_MODE_VACATION = 6; +*/ + +/* +Characteristic.SecuritySystemTargetState.STAY_ARM = 0; +Characteristic.SecuritySystemTargetState.AWAY_ARM = 1; +Characteristic.SecuritySystemTargetState.NIGHT_ARM = 2; +Characteristic.SecuritySystemTargetState.DISARM = 3; +*/ + + +ISYElkAlarmPanelAccessory.prototype.translateAlarmTargetStateToHK = function() { + var sourceAlarmState = this.device.getAlarmMode(); + if(sourceAlarmState == this.device.ALARM_MODE_STAY || sourceAlarmState == this.device.ALARM_MODE_STAY_INSTANT ) { + return Characteristic.SecuritySystemTargetState.STAY_ARM; + } else if(sourceAlarmState == this.device.ALARM_MODE_AWAY || sourceAlarmState == this.device.ALARM_MODE_VACATION) { + return Characteristic.SecuritySystemTargetState.AWAY_ARM; + } else if(sourceAlarmState == this.device.ALARM_MODE_NIGHT || sourceAlarmState == this.device.ALARM_MODE_NIGHT_INSTANT) { + return Characteristic.SecuritySystemTargetState.NIGHT_ARM; + } else { + return Characteristic.SecuritySystemTargetState.DISARM; + } +} + +ISYElkAlarmPanelAccessory.prototype.translateHKToAlarmTargetState = function(state) { + if(state == Characteristic.SecuritySystemTargetState.STAY_ARM) { + return this.device.ALARM_MODE_STAY; + } else if(state == Characteristic.SecuritySystemTargetState.AWAY_ARM) { + return this.device.ALARM_MODE_AWAY; + } else if(state == Characteristic.SecuritySystemTargetState.NIGHT_ARM) { + return this.device.NIGHT_ARM; + } else { + return this.device.DISARM; + } +} + +ISYElkAlarmPanelAccessory.prototype.getAlarmTargetState = function(callback) { + callback(null,this.translateAlarmTargetStateToHK()); +} + +ISYElkAlarmPanelAccessory.prototype.getAlarmCurrentState = function(callback) { + callback(null,this.translateAlarmCurrentStateToHK()); +} + +ISYElkAlarmPanelAccessory.prototype.handleExternalChange = function() { + this.alarmPanelService + .setCharacteristic(Characteristic.SecuritySystemTargetState, this.translateAlarmTargetStateToHK()); + this.alarmPanelService + .setCharacteristic(Characteristic.SecuritySystemCurrentState, this.translateAlarmCurrentStateToHK()); +} + +ISYElkAlarmPanelAccessory.prototype.getServices = function() { + var informationService = new Service.AccessoryInformation(); + + informationService + .setCharacteristic(Characteristic.Manufacturer, "SmartHome") + .setCharacteristic(Characteristic.Model, this.device.deviceFriendlyName) + .setCharacteristic(Characteristic.SerialNumber, this.device.address); + + var alarmPanelService = new Service.SecuritySystem(); + + this.alarmPanelService = alarmPanelService; + this.informationService = informationService; + + alarmPanelService + .getCharacteristic(Characteristic.SecuritySystemTargetState) + .on('set', this.setAlarmTargetState.bind(this)); + + alarmPanelService + .getCharacteristic(Characteristic.SecuritySystemTargetState) + .on('get', this.getAlarmTargetState.bind(this)); + + alarmPanelService + .getCharacteristic(Characteristic.SecuritySystemCurrentState) + .on('get', this.getAlarmCurrentState.bind(this)); + + return [informationService, alarmPanelService]; +} + +module.exports.platform = ISYPlatform; +module.exports.accessory = ISYFanAccessory; +module.exports.accessory = ISYLightAccessory; +module.exports.accessory = ISYLockAccessory; +module.exports.accessory = ISYOutletAccessory; +module.exports.accessory = ISYDoorWindowSensorAccessory; From 40a96808b2e69137e6f2d690f213fbb7751b8fd5 Mon Sep 17 00:00:00 2001 From: rodtoll Date: Sun, 11 Oct 2015 08:45:18 -0700 Subject: [PATCH 2/8] Added docs to the isy-js file. --- platforms/isy-js.js | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/platforms/isy-js.js b/platforms/isy-js.js index 37d515b..f28c0c0 100644 --- a/platforms/isy-js.js +++ b/platforms/isy-js.js @@ -1,9 +1,61 @@ +/* + ISY-JS + + ISY-99 REST / WebSockets based HomeBridge shim. + + Supports the following Insteon devices: Lights (dimmable and non-dimmable), Fans, Outlets, Door/Window Sensors, MorningLinc locks, Inline Lincs and I/O Lincs. + Also supports ZWave based locks. If elkEnabled is set to true then this will also expose your Elk Alarm Panel and all of your Elk Sensors. + + Turns out that HomeBridge platforms can only return a maximum of 100 devices. So if you end up exposing more then 100 devices through HomeBridge the HomeKit + software will fail adding the HomeBridge to your HomeKit network. To address this issue this platform provides an option to screen out devices based on + criteria specified in the config. + + Configuration sample: + + "platforms": [ + { + "platform": "isy-js", + "name": "isy-js", + "host": "10.0.1.12", + "username": "admin", + "password": "password", + "elkEnabled": true, + "ignoreDevices": [ + { "nameContains": "ApplianceLinc", "lastAddressDigit": "", "address": ""}, + { "nameContains": "Bedroom.Side Gate", "lastAddressDigit": "", "address": ""}, + { "nameContains": "Remote", "lastAddressDigit": "", "address": "" }, + { "nameContains": "Keypad", "lastAddressDigit": "2", "address": "" }, + ] + } + ] + + Fields: + "platform" - Must be set to isy-js + "name" - Can be set to whatever you want + "host" - IP address of the ISY + "username" - Your ISY username + "password" - Your ISY password + "elkEnabled" - true if there is an elk alarm panel connected to your ISY + "ignoreDevices" - Array of objects specifying criteria for screening out devices from the network. nameContains is the only required criteria. If the other criteria + are blank all devices will match those criteria (providing they match the name criteria). + "nameContains" - Specifies a substring to check against the names of the ISY devices. Required field for the criteria. + "lastAddressDigit" - Specifies a single digit in the ISY address of a device which should be used to match the device. Example use of this is for composite + devices like keypads so you can screen out the non-main buttons. + "address" - ISY address to match. + + Examples: + + { "nameContains": "Keypad", "lastAddressDigit": "2", "address": "" } - Ignore all devices which have the word Keypad in their name and whose last address digit is 2. + { "nameContains": "Remote", "lastAddressDigit": "", "address": "" } - Ignore all devices which have the word Remote in their name + { "nameContains": "", "lastAddressDigit": "", "address": "15 5 3 2"} - Ignore the device with an ISY address of 15 5 3 2. +*/ var types = require("HAP-NodeJS/accessories/types.js"); var isy = require('isy-js'); var Service = require("HAP-NodeJS").Service; var Characteristic = require("HAP-NodeJS").Characteristic; var inherits = require('util').inherits; +// Global device map. Needed to map incoming notifications to the corresponding HomeKit device for update. var deviceMap = {}; function ISYChangeHandler(isy,device) { From 6030928c1271f4f704502e9f7b7981014fa13e1e Mon Sep 17 00:00:00 2001 From: rodtoll Date: Sun, 11 Oct 2015 13:34:58 -0700 Subject: [PATCH 3/8] Fixed elk panel state transitions. --- platforms/isy-js.js | 77 ++++++++++++--------------------------------- 1 file changed, 20 insertions(+), 57 deletions(-) diff --git a/platforms/isy-js.js b/platforms/isy-js.js index f28c0c0..5f01a11 100644 --- a/platforms/isy-js.js +++ b/platforms/isy-js.js @@ -573,51 +573,30 @@ ISYElkAlarmPanelAccessory.prototype.identify = function(callback) { } ISYElkAlarmPanelAccessory.prototype.setAlarmTargetState = function(targetStateHK,callback) { - this.log("Sending command to set alarm panel state to: "+targetStateHK); - var targetState = this.translateHKToAlarmTargetState(targetState); - if(this.alarmTargetState != targetState) { + this.log("***** Sending command to set alarm panel state to: "+targetStateHK); + var targetState = this.translateHKToAlarmTargetState(targetStateHK); + this.log("***** Would send the target state of: "+targetState); + if(this.device.getAlarmMode() != targetState) { this.device.sendSetAlarmModeCommand(targetState, function(result) { callback(); }); } else { + this.log("***** Redundant command, already in that state."); callback(); } } -////// Current State - -/* -ELKAlarmPanelDevice.prototype.ALARM_STATE_NOT_READY_TO_ARM = 0; -ELKAlarmPanelDevice.prototype.ALARM_STATE_READY_TO_ARM = 1; -ELKAlarmPanelDevice.prototype.ALARM_STATE_READY_TO_ARM_VIOLATION = 2; -ELKAlarmPanelDevice.prototype.ALARM_STATE_ARMED_WITH_TIMER = 3; -ELKAlarmPanelDevice.prototype.ALARM_STATE_ARMED_FULLY = 4; -ELKAlarmPanelDevice.prototype.ALARM_STATE_FORCE_ARMED_VIOLATION = 5; -ELKAlarmPanelDevice.prototype.ALARM_STATE_ARMED_WITH_BYPASS = 6; -*/ - -/* -ELKAlarmPanelDevice.prototype.ALARM_TRIP_STATE_DISARMED = 0; -ELKAlarmPanelDevice.prototype.ALARM_TRIP_STATE_EXIT_DELAY = 1; -ELKAlarmPanelDevice.prototype.ALARM_TRIP_STATE_TRIPPED = 2; -*/ - -/* -Characteristic.SecuritySystemCurrentState.STAY_ARM = 0; -Characteristic.SecuritySystemCurrentState.AWAY_ARM = 1; -Characteristic.SecuritySystemCurrentState.NIGHT_ARM = 2; -Characteristic.SecuritySystemCurrentState.DISARMED = 3; -Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED = 4; -*/ - ISYElkAlarmPanelAccessory.prototype.translateAlarmCurrentStateToHK = function() { var tripState = this.device.getAlarmTripState(); - if(tripState == this.device.ALARM_TRIP_STATE_DISARMED || tripState == this.device.ALARM_TRIP_STATE_EXIT_DELAY) { - return Characteristic.SecuritySystemCurrentState.DISARMED; - } else if(tripState ==this.device.ALARM_TRIP_STATE_TRIPPED) { - return Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED; + var sourceAlarmState = this.device.getAlarmState(); + + if(tripState >= this.device.ALARM_TRIP_STATE_TRIPPED) { + return Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED; + } else if(sourceAlarmState == this.device.ALARM_STATE_NOT_READY_TO_ARM || + sourceAlarmState == this.device.ALARM_STATE_READY_TO_ARM || + sourceAlarmState == this.device.ALARM_STATE_READY_TO_ARM_VIOLATION) { + return Characteristic.SecuritySystemCurrentState.DISARMED; } else { - var sourceAlarmState = this.device.getAlarmMode(); if(sourceAlarmState == this.device.ALARM_MODE_STAY || sourceAlarmState == this.device.ALARM_MODE_STAY_INSTANT ) { return Characteristic.SecuritySystemCurrentState.STAY_ARM; } else if(sourceAlarmState == this.device.ALARM_MODE_AWAY || sourceAlarmState == this.device.ALARM_MODE_VACATION) { @@ -625,31 +604,12 @@ ISYElkAlarmPanelAccessory.prototype.translateAlarmCurrentStateToHK = function() } else if(sourceAlarmState == this.device.ALARM_MODE_NIGHT || sourceAlarmState == this.device.ALARM_MODE_NIGHT_INSTANT) { return Characteristic.SecuritySystemCurrentState.NIGHT_ARM; } else { - return Characteristic.SecuritySystemCurrentState.DISARM; + this.log("***** Setting to disarmed because sourceAlarmState is "+sourceAlarmState); + return Characteristic.SecuritySystemCurrentState.DISARMED; } } } -////// Target Mode - -/* -ELKAlarmPanelDevice.prototype.ALARM_MODE_DISARMED = 0; -ELKAlarmPanelDevice.prototype.ALARM_MODE_AWAY = 1; -ELKAlarmPanelDevice.prototype.ALARM_MODE_STAY = 2; -ELKAlarmPanelDevice.prototype.ALARM_MODE_STAY_INSTANT = 3; -ELKAlarmPanelDevice.prototype.ALARM_MODE_NIGHT = 4; -ELKAlarmPanelDevice.prototype.ALARM_MODE_NIGHT_INSTANT = 5; -ELKAlarmPanelDevice.prototype.ALARM_MODE_VACATION = 6; -*/ - -/* -Characteristic.SecuritySystemTargetState.STAY_ARM = 0; -Characteristic.SecuritySystemTargetState.AWAY_ARM = 1; -Characteristic.SecuritySystemTargetState.NIGHT_ARM = 2; -Characteristic.SecuritySystemTargetState.DISARM = 3; -*/ - - ISYElkAlarmPanelAccessory.prototype.translateAlarmTargetStateToHK = function() { var sourceAlarmState = this.device.getAlarmMode(); if(sourceAlarmState == this.device.ALARM_MODE_STAY || sourceAlarmState == this.device.ALARM_MODE_STAY_INSTANT ) { @@ -669,9 +629,9 @@ ISYElkAlarmPanelAccessory.prototype.translateHKToAlarmTargetState = function(sta } else if(state == Characteristic.SecuritySystemTargetState.AWAY_ARM) { return this.device.ALARM_MODE_AWAY; } else if(state == Characteristic.SecuritySystemTargetState.NIGHT_ARM) { - return this.device.NIGHT_ARM; + return this.device.ALARM_MODE_NIGHT; } else { - return this.device.DISARM; + return this.device.ALARM_MODE_DISARMED; } } @@ -684,6 +644,8 @@ ISYElkAlarmPanelAccessory.prototype.getAlarmCurrentState = function(callback) { } ISYElkAlarmPanelAccessory.prototype.handleExternalChange = function() { + this.log("***** Source device. Currenty state locally -"+this.device.getAlarmStatusAsText()); + this.log("***** Got alarm change notification. Setting HK target state to: "+this.translateAlarmTargetStateToHK()+" Setting HK Current state to: "+this.translateAlarmCurrentStateToHK()); this.alarmPanelService .setCharacteristic(Characteristic.SecuritySystemTargetState, this.translateAlarmTargetStateToHK()); this.alarmPanelService @@ -724,3 +686,4 @@ module.exports.accessory = ISYLightAccessory; module.exports.accessory = ISYLockAccessory; module.exports.accessory = ISYOutletAccessory; module.exports.accessory = ISYDoorWindowSensorAccessory; +module.exports.accessory = ISYElkAlarmPanelAccessory; From 2d80e5f838c94d2f481be79c6832c286032fd06f Mon Sep 17 00:00:00 2001 From: rodtoll Date: Sun, 18 Oct 2015 11:19:08 -0700 Subject: [PATCH 4/8] Updated to latest version of hap base library. Root project migrated to lower case version. Also added new uuid_base required field which is now needed. Refactored device constructors to use common code. --- platforms/isy-js.js | 49 ++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/platforms/isy-js.js b/platforms/isy-js.js index 5f01a11..03ca340 100644 --- a/platforms/isy-js.js +++ b/platforms/isy-js.js @@ -49,10 +49,12 @@ { "nameContains": "Remote", "lastAddressDigit": "", "address": "" } - Ignore all devices which have the word Remote in their name { "nameContains": "", "lastAddressDigit": "", "address": "15 5 3 2"} - Ignore the device with an ISY address of 15 5 3 2. */ -var types = require("HAP-NodeJS/accessories/types.js"); + + +var types = require("hap-nodejs/accessories/types.js"); var isy = require('isy-js'); -var Service = require("HAP-NodeJS").Service; -var Characteristic = require("HAP-NodeJS").Characteristic; +var Service = require("hap-nodejs").Service; +var Characteristic = require("hap-nodejs").Characteristic; var inherits = require('util').inherits; // Global device map. Needed to map incoming notifications to the corresponding HomeKit device for update. @@ -147,14 +149,22 @@ ISYPlatform.prototype.accessories = function(callback) { }); } +///////////////////////////////////////////////////////////////////////////////////////////////// +// BASE FOR ALL DEVICES + +function ISYAccessoryBaseSetup(accessory,log,device) { + accessory.log = log; + accessory.device = device; + accessory.address = device.address; + accessory.name = device.name; + accessory.uuid_base = device.isy.address+":"+device.address; +} + ///////////////////////////////////////////////////////////////////////////////////////////////// // FANS function ISYFanAccessory(log,device) { - this.log = log; - this.device = device; - this.address = device.address; - this.name = device.name; + ISYAccessoryBaseSetup(this,log,device); } ISYFanAccessory.prototype.identify = function(callback) { @@ -276,10 +286,7 @@ ISYFanAccessory.prototype.getServices = function() { // OUTLETS function ISYOutletAccessory(log,device) { - this.log = log; - this.device = device; - this.address = device.address; - this.name = device.name; + ISYAccessoryBaseSetup(this,log,device); } ISYOutletAccessory.prototype.identify = function(callback) { @@ -343,10 +350,7 @@ ISYOutletAccessory.prototype.getServices = function() { // LOCKS function ISYLockAccessory(log,device) { - this.log = log; - this.device = device; - this.address = device.address; - this.name = device.name; + ISYAccessoryBaseSetup(this,log,device); } ISYLockAccessory.prototype.identify = function(callback) { @@ -416,10 +420,7 @@ ISYLockAccessory.prototype.getServices = function() { // LIGHTS function ISYLightAccessory(log,device) { - this.log = log; - this.device = device; - this.address = device.address; - this.name = device.name; + ISYAccessoryBaseSetup(this,log,device); this.dimmable = (this.device.deviceType == "DimmableLight"); } @@ -513,10 +514,7 @@ ISYLightAccessory.prototype.getServices = function() { // CONTACT SENSOR function ISYDoorWindowSensorAccessory(log,device) { - this.log = log; - this.device = device; - this.address = device.address; - this.name = device.name; + ISYAccessoryBaseSetup(this,log,device); this.doorWindowState = false; } @@ -562,10 +560,7 @@ ISYDoorWindowSensorAccessory.prototype.getServices = function() { // ELK SENSOR PANEL function ISYElkAlarmPanelAccessory(log,device) { - this.log = log; - this.device = device; - this.address = device.address; - this.name = device.name; + ISYAccessoryBaseSetup(this,log,device); } ISYElkAlarmPanelAccessory.prototype.identify = function(callback) { From 8fcd5d39a6b3756d5f9860bd9619cd21258cdeba Mon Sep 17 00:00:00 2001 From: rodtoll Date: Sun, 18 Oct 2015 19:47:30 -0700 Subject: [PATCH 5/8] Moved all debug logging to be controlled by the ISYJSDEBUG environment variable AND moved all log messages to go through the global logger offered by homebridge. --- platforms/isy-js.js | 50 +++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/platforms/isy-js.js b/platforms/isy-js.js index 03ca340..3e24ab8 100644 --- a/platforms/isy-js.js +++ b/platforms/isy-js.js @@ -67,6 +67,12 @@ function ISYChangeHandler(isy,device) { } } +function ISYJSDebugMessage(isy,message) { + if(process.env.ISYJSDEBUG != undefined) { + isy.log(message); + } +} + //////////////////////////////////////////////////////////////////////////////////////////////// // PLATFORM @@ -100,7 +106,7 @@ ISYPlatform.prototype.shouldIgnore = function(device) { continue; } } - console.log("@@@@@@ Ignoring device: "+deviceName+" ["+deviceAddress+"] because of rule ["+rule.nameContains+"] ["+rule.lastAddressDigit+"] ["+rule.address+"]"); + ISYJSDebugMessage(this,"Ignoring device: "+deviceName+" ["+deviceAddress+"] because of rule ["+rule.nameContains+"] ["+rule.lastAddressDigit+"] ["+rule.address+"]"); return true; } @@ -144,7 +150,7 @@ ISYPlatform.prototype.accessories = function(callback) { deviceMap[panelDevice.address] = panelDeviceHK; results.push(panelDeviceHK); } - console.log("Filtered device has: "+results.length+" devices"); + ISYJSDebugMessage(that,"Filtered device has: "+results.length+" devices"); callback(results); }); } @@ -182,7 +188,7 @@ ISYFanAccessory.prototype.translateFanSpeedToHK = function(fanSpeed) { } else if(fanSpeed == "High") { return 100; } else { - this.log("!!!! ERROR: Unknown fan speed: "+fanSpeed); + ISYJSDebugMessage(this,"!!!! ERROR: Unknown fan speed: "+fanSpeed); return 0; } } @@ -197,7 +203,7 @@ ISYFanAccessory.prototype.translateHKToFanSpeed = function(fanStateHK) { } else if(fanStateHK > 67) { return "High"; } else { - this.log("!!!!! ERROR: Unknown fan state!"); + ISYJSDebugMessage(this,"ERROR: Unknown fan state!"); return "Off"; } } @@ -208,13 +214,13 @@ ISYFanAccessory.prototype.getFanRotationSpeed = function(callback) { ISYFanAccessory.prototype.setFanRotationSpeed = function(fanStateHK,callback) { var newFanState = this.translateHKToFanSpeed(fanStateHK); - this.log("Sending command to set fan state to: "+newFanState); + ISYJSDebugMessage(this,"Sending command to set fan state to: "+newFanState); if(newFanState != this.device.getCurrentFanState()) { this.device.sendFanCommand(newFanState, function(result) { callback(); }); } else { - this.log("Fan command does not change actual speed"); + ISYJSDebugMessage(this,"Fan command does not change actual speed"); callback(); } } @@ -236,7 +242,7 @@ ISYFanAccessory.prototype.setFanOnState = function(onState,callback) { this.setFanRotationSpeed(this.translateFanSpeedToHK("Off"), callback); } } else { - this.log("Fan command does not change actual state"); + ISYJSDebugMessage(this,"Fan command does not change actual state"); callback(); } } @@ -295,7 +301,7 @@ ISYOutletAccessory.prototype.identify = function(callback) { } ISYOutletAccessory.prototype.setOutletState = function(outletState,callback) { - this.log("Sending command to set outlet state to: "+outletState); + ISYJSDebugMessage(this,"Sending command to set outlet state to: "+outletState); if(outletState != this.device.getCurrentOutletState()) { this.device.sendOutletCommand(outletState, function(result) { callback(); @@ -358,7 +364,7 @@ ISYLockAccessory.prototype.identify = function(callback) { } ISYLockAccessory.prototype.setTargetLockState = function(lockState,callback) { - this.log("Sending command to set lock state to: "+lockState); + ISYJSDebugMessage(this,"Sending command to set lock state to: "+lockState); if(lockState != this.getDeviceCurrentStateAsHK()) { var targetLockValue = (lockState == 0) ? false : true; this.device.sendLockCommand(targetLockValue, function(result) { @@ -433,20 +439,20 @@ ISYLightAccessory.prototype.identify = function(callback) { } ISYLightAccessory.prototype.setPowerState = function(powerOn,callback) { - this.log("=== Setting powerstate to %s", powerOn); + ISYJSDebugMessage(this,"Setting powerstate to %s", powerOn); if(powerOn != this.device.getCurrentLightState()) { - this.log("+++ Changing powerstate to "+powerOn); + ISYJSDebugMessage(this,"Changing powerstate to "+powerOn); this.device.sendLightCommand(powerOn, function(result) { callback(); }); } else { - this.log("--- Ignoring redundant setPowerState"); + ISYJSDebugMessage(this,"Ignoring redundant setPowerState"); callback(); } } ISYLightAccessory.prototype.handleExternalChange = function() { - this.log("=== Handling external change for light"); + ISYJSDebugMessage(this,"Handling external change for light"); this.lightService .setCharacteristic(Characteristic.On, this.device.getCurrentLightState()); if(this.device.deviceType == this.device.isy.DEVICE_TYPE_DIMMABLE_LIGHT) { @@ -460,14 +466,14 @@ ISYLightAccessory.prototype.getPowerState = function(callback) { } ISYLightAccessory.prototype.setBrightness = function(level,callback) { - this.log("Setting brightness to %s", level); + ISYJSDebugMessage(this,"Setting brightness to %s", level); if(level != this.device.getCurrentLightDimState()) { - this.log("+++ Changing Brightness to "+level); + ISYJSDebugMessage(this,"Changing Brightness to "+level); this.device.sendLightDimCommand(level, function(result) { callback(); }); } else { - this.log("--- Ignoring redundant setBrightness"); + ISYJSDebugMessage(this,"Ignoring redundant setBrightness"); callback(); } } @@ -568,15 +574,15 @@ ISYElkAlarmPanelAccessory.prototype.identify = function(callback) { } ISYElkAlarmPanelAccessory.prototype.setAlarmTargetState = function(targetStateHK,callback) { - this.log("***** Sending command to set alarm panel state to: "+targetStateHK); + ISYJSDebugMessage(this,"Sending command to set alarm panel state to: "+targetStateHK); var targetState = this.translateHKToAlarmTargetState(targetStateHK); - this.log("***** Would send the target state of: "+targetState); + ISYJSDebugMessage(this,"Would send the target state of: "+targetState); if(this.device.getAlarmMode() != targetState) { this.device.sendSetAlarmModeCommand(targetState, function(result) { callback(); }); } else { - this.log("***** Redundant command, already in that state."); + ISYJSDebugMessage(this,"Redundant command, already in that state."); callback(); } } @@ -599,7 +605,7 @@ ISYElkAlarmPanelAccessory.prototype.translateAlarmCurrentStateToHK = function() } else if(sourceAlarmState == this.device.ALARM_MODE_NIGHT || sourceAlarmState == this.device.ALARM_MODE_NIGHT_INSTANT) { return Characteristic.SecuritySystemCurrentState.NIGHT_ARM; } else { - this.log("***** Setting to disarmed because sourceAlarmState is "+sourceAlarmState); + ISYJSDebugMessage(this,"Setting to disarmed because sourceAlarmState is "+sourceAlarmState); return Characteristic.SecuritySystemCurrentState.DISARMED; } } @@ -639,8 +645,8 @@ ISYElkAlarmPanelAccessory.prototype.getAlarmCurrentState = function(callback) { } ISYElkAlarmPanelAccessory.prototype.handleExternalChange = function() { - this.log("***** Source device. Currenty state locally -"+this.device.getAlarmStatusAsText()); - this.log("***** Got alarm change notification. Setting HK target state to: "+this.translateAlarmTargetStateToHK()+" Setting HK Current state to: "+this.translateAlarmCurrentStateToHK()); + ISYJSDebugMessage(this,"Source device. Currenty state locally -"+this.device.getAlarmStatusAsText()); + ISYJSDebugMessage(this,"Got alarm change notification. Setting HK target state to: "+this.translateAlarmTargetStateToHK()+" Setting HK Current state to: "+this.translateAlarmCurrentStateToHK()); this.alarmPanelService .setCharacteristic(Characteristic.SecuritySystemTargetState, this.translateAlarmTargetStateToHK()); this.alarmPanelService From 74e37cc488288f11b201fb218f81b088844a5e6c Mon Sep 17 00:00:00 2001 From: rodtoll Date: Sun, 18 Oct 2015 21:09:59 -0700 Subject: [PATCH 6/8] Added more documentation. --- platforms/isy-js.js | 108 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 18 deletions(-) diff --git a/platforms/isy-js.js b/platforms/isy-js.js index 3e24ab8..b2c3728 100644 --- a/platforms/isy-js.js +++ b/platforms/isy-js.js @@ -48,6 +48,8 @@ { "nameContains": "Keypad", "lastAddressDigit": "2", "address": "" } - Ignore all devices which have the word Keypad in their name and whose last address digit is 2. { "nameContains": "Remote", "lastAddressDigit": "", "address": "" } - Ignore all devices which have the word Remote in their name { "nameContains": "", "lastAddressDigit": "", "address": "15 5 3 2"} - Ignore the device with an ISY address of 15 5 3 2. + + TODOS: Implement identify functions (beep perhaps?) and more device types. */ @@ -60,6 +62,9 @@ var inherits = require('util').inherits; // Global device map. Needed to map incoming notifications to the corresponding HomeKit device for update. var deviceMap = {}; +// This function responds to changes in devices from the isy-js library. Uses the global device map to update +// the state. +// TODO: Move this to a member function of the ISYPlatform object so we don't need a global map. function ISYChangeHandler(isy,device) { var deviceToUpdate = deviceMap[device.address]; if(deviceToUpdate != null) { @@ -67,6 +72,7 @@ function ISYChangeHandler(isy,device) { } } +// Helper function to have ISYJSDEBUG control if debug output appears function ISYJSDebugMessage(isy,message) { if(process.env.ISYJSDEBUG != undefined) { isy.log(message); @@ -76,6 +82,7 @@ function ISYJSDebugMessage(isy,message) { //////////////////////////////////////////////////////////////////////////////////////////////// // PLATFORM +// Construct the ISY platform. log = Logger, config = homebridge cofnig function ISYPlatform(log,config) { this.log = log; this.config = config; @@ -86,6 +93,7 @@ function ISYPlatform(log,config) { this.isy = new isy.ISY(this.host, this.username,this.password, config.elkEnabled, ISYChangeHandler); } +// Checks the device against the configuration to see if it should be ignored. ISYPlatform.prototype.shouldIgnore = function(device) { var deviceAddress = device.address; var deviceName = device.name; @@ -113,6 +121,7 @@ ISYPlatform.prototype.shouldIgnore = function(device) { return false; } +// Calls the isy-js library, retrieves the list of devices, and maps them to appropriate ISYXXXXAccessory devices. ISYPlatform.prototype.accessories = function(callback) { var that = this; this.isy.initialize(function() { @@ -139,6 +148,7 @@ ISYPlatform.prototype.accessories = function(callback) { homeKitDevice = new ISYElkAlarmPanelAccessory(that.log,device); } if(homeKitDevice != null) { + // Make sure the device is address to the global map deviceMap[device.address] = homeKitDevice; results.push(homeKitDevice); } @@ -158,6 +168,7 @@ ISYPlatform.prototype.accessories = function(callback) { ///////////////////////////////////////////////////////////////////////////////////////////////// // BASE FOR ALL DEVICES +// Provides common constructor tasks function ISYAccessoryBaseSetup(accessory,log,device) { accessory.log = log; accessory.device = device; @@ -167,8 +178,10 @@ function ISYAccessoryBaseSetup(accessory,log,device) { } ///////////////////////////////////////////////////////////////////////////////////////////////// -// FANS +// FANS - ISYFanAccessory +// Implemetnts the fan service for an isy fan device. +// Constructs a fan accessory object. device is the isy-js device object and log is the logger. function ISYFanAccessory(log,device) { ISYAccessoryBaseSetup(this,log,device); } @@ -178,14 +191,17 @@ ISYFanAccessory.prototype.identify = function(callback) { callback(); } +// Translates the fan speed as an isy-js string into the corresponding homekit constant level. +// Homekit doesn't have steps for the fan speed and needs to have a value from 0 to 100. We +// split the range into 4 steps and map them to the 4 isy-js levels. ISYFanAccessory.prototype.translateFanSpeedToHK = function(fanSpeed) { - if(fanSpeed == "Off") { + if(fanSpeed == this.device.isy.ISYFanDevice.FAN_OFF) { return 0; - } else if(fanSpeed == "Low") { + } else if(fanSpeed == this.device.isy.ISYFanDevice.FAN_LOW) { return 32; - } else if(fanSpeed == "Medium") { + } else if(fanSpeed == this.device.isy.ISYFanDevice.FAN_MEDIUM) { return 67; - } else if(fanSpeed == "High") { + } else if(fanSpeed == this.device.isy.ISYFanDevice.FAN_HIGH) { return 100; } else { ISYJSDebugMessage(this,"!!!! ERROR: Unknown fan speed: "+fanSpeed); @@ -193,25 +209,29 @@ ISYFanAccessory.prototype.translateFanSpeedToHK = function(fanSpeed) { } } +// Translates the fan level from homebridge into the isy-js level. Maps from the 0-100 +// to the four isy-js fan speed levels. ISYFanAccessory.prototype.translateHKToFanSpeed = function(fanStateHK) { if(fanStateHK == 0) { - return "Off"; + return this.device.isy.ISYFanDevice.FAN_OFF; } else if(fanStateHK > 0 && fanStateHK <=32) { - return "Low"; + return this.device.isy.ISYFanDevice.FAN_LOW; } else if(fanStateHK > 33 && fanStateHK <= 67) { - return "Medium"; + return this.device.isy.ISYFanDevice.FAN_MEDIUM; } else if(fanStateHK > 67) { - return "High"; + return this.device.isy.ISYFanDevice.FAN_HIGH; } else { ISYJSDebugMessage(this,"ERROR: Unknown fan state!"); - return "Off"; + return this.device.isy.ISYFanDevice.FAN_OFF; } } +// Returns the current state of the fan from the isy-js level to the 0-100 level of HK. ISYFanAccessory.prototype.getFanRotationSpeed = function(callback) { callback(null,this.translateFanSpeedToHK(this.device.getCurrentFanState())); } +// Sets the current state of the fan from the 0-100 level of HK to the isy-js level. ISYFanAccessory.prototype.setFanRotationSpeed = function(fanStateHK,callback) { var newFanState = this.translateHKToFanSpeed(fanStateHK); ISYJSDebugMessage(this,"Sending command to set fan state to: "+newFanState); @@ -225,21 +245,23 @@ ISYFanAccessory.prototype.setFanRotationSpeed = function(fanStateHK,callback) { } } - +// Returns true if the fan is on ISYFanAccessory.prototype.getIsFanOn = function() { return (this.device.getCurrentFanState() != "Off"); } +// Returns the state of the fan to the homebridge system for the On characteristic ISYFanAccessory.prototype.getFanOnState = function(callback) { callback(null,this.getIsFanOn()); } +// Sets the fan state based on the value of the On characteristic. Default to Medium for on. ISYFanAccessory.prototype.setFanOnState = function(onState,callback) { if(onState != this.getIsFanOn()) { if(onState) { - this.setFanRotationSpeed(this.translateFanSpeedToHK("Medium"), callback); + this.setFanRotationSpeed(this.translateFanSpeedToHK(this.device.isy.ISYFanDevice.FAN_MEDIUM), callback); } else { - this.setFanRotationSpeed(this.translateFanSpeedToHK("Off"), callback); + this.setFanRotationSpeed(this.translateFanSpeedToHK(this.device.isy.ISYFanDevice.FAN_OFF), callback); } } else { ISYJSDebugMessage(this,"Fan command does not change actual state"); @@ -247,7 +269,7 @@ ISYFanAccessory.prototype.setFanOnState = function(onState,callback) { } } - +// Mirrors change in the state of the underlying isj-js device object. ISYFanAccessory.prototype.handleExternalChange = function() { this.fanService .setCharacteristic(Characteristic.On, this.getIsFanOn()); @@ -256,6 +278,7 @@ ISYFanAccessory.prototype.handleExternalChange = function() { .setCharacteristic(Characteristic.RotationSpeed, this.translateFanSpeedToHK(this.device.getCurrentFanState())); } +// Returns the services supported by the fan device. ISYFanAccessory.prototype.getServices = function() { var informationService = new Service.AccessoryInformation(); @@ -289,17 +312,21 @@ ISYFanAccessory.prototype.getServices = function() { } ///////////////////////////////////////////////////////////////////////////////////////////////// -// OUTLETS +// OUTLETS - ISYOutletAccessory +// Implements the Outlet service for ISY devices. +// Constructs an outlet. log = HomeBridge logger, device = isy-js device to wrap function ISYOutletAccessory(log,device) { ISYAccessoryBaseSetup(this,log,device); } +// Handles the identify command ISYOutletAccessory.prototype.identify = function(callback) { // Do the identify action callback(); } +// Handles a request to set the outlet state. Ignores redundant sets based on current states. ISYOutletAccessory.prototype.setOutletState = function(outletState,callback) { ISYJSDebugMessage(this,"Sending command to set outlet state to: "+outletState); if(outletState != this.device.getCurrentOutletState()) { @@ -311,19 +338,24 @@ ISYOutletAccessory.prototype.setOutletState = function(outletState,callback) { } } +// Handles a request to get the current outlet state based on underlying isy-js device object. ISYOutletAccessory.prototype.getOutletState = function(callback) { callback(null,this.device.getCurrentOutletState()); } +// Handles a request to get the current in use state of the outlet. We set this to true always as +// there is no way to deterine this through the isy. ISYOutletAccessory.prototype.getOutletInUseState = function(callback) { callback(null, true); } +// Mirrors change in the state of the underlying isj-js device object. ISYOutletAccessory.prototype.handleExternalChange = function() { this.outletService .setCharacteristic(Characteristic.On, this.device.getCurrentOutletState()); } +// Returns the set of services supported by this object. ISYOutletAccessory.prototype.getServices = function() { var informationService = new Service.AccessoryInformation(); @@ -353,16 +385,20 @@ ISYOutletAccessory.prototype.getServices = function() { } ///////////////////////////////////////////////////////////////////////////////////////////////// -// LOCKS +// LOCKS - ISYLockAccessory +// Implements the lock service for isy-js devices. +// Constructs a lock accessory. log = homebridge logger, device = isy-js device object being wrapped function ISYLockAccessory(log,device) { ISYAccessoryBaseSetup(this,log,device); } +// Handles an identify request ISYLockAccessory.prototype.identify = function(callback) { callback(); } +// Handles a set to the target lock state. Will ignore redundant commands. ISYLockAccessory.prototype.setTargetLockState = function(lockState,callback) { ISYJSDebugMessage(this,"Sending command to set lock state to: "+lockState); if(lockState != this.getDeviceCurrentStateAsHK()) { @@ -375,18 +411,22 @@ ISYLockAccessory.prototype.setTargetLockState = function(lockState,callback) { } } +// Translates underlying lock state into the corresponding homekit state ISYLockAccessory.prototype.getDeviceCurrentStateAsHK = function() { return (this.device.getCurrentLockState() ? 1 : 0); } +// Handles request to get the current lock state for homekit ISYLockAccessory.prototype.getLockCurrentState = function(callback) { callback(null, this.getDeviceCurrentStateAsHK()); } +// Handles request to get the target lock state for homekit ISYLockAccessory.prototype.getTargetLockState = function(callback) { this.getLockCurrentState(callback); } +// Mirrors change in the state of the underlying isj-js device object. ISYLockAccessory.prototype.handleExternalChange = function() { this.lockService .setCharacteristic(Characteristic.LockTargetState, this.getDeviceCurrentStateAsHK()); @@ -394,6 +434,7 @@ ISYLockAccessory.prototype.handleExternalChange = function() { .setCharacteristic(Characteristic.LockCurrentState, this.getDeviceCurrentStateAsHK()); } +// Returns the set of services supported by this object. ISYLockAccessory.prototype.getServices = function() { var informationService = new Service.AccessoryInformation(); @@ -424,12 +465,16 @@ ISYLockAccessory.prototype.getServices = function() { //////////////////////////////////////////////////////////////////////////////////////////////////////// // LIGHTS +// Implements the Light service for homekit based on an underlying isy-js device. Is dimmable or not depending +// on if the underlying device is dimmable. +// Constructs the light accessory. log = homebridge logger, device = isy-js device object being wrapped function ISYLightAccessory(log,device) { ISYAccessoryBaseSetup(this,log,device); this.dimmable = (this.device.deviceType == "DimmableLight"); } +// Handles the identify command ISYLightAccessory.prototype.identify = function(callback) { this.device.sendLightCommand(true, function(result) { this.device.sendLightCommand(false, function(result) { @@ -438,6 +483,7 @@ ISYLightAccessory.prototype.identify = function(callback) { }); } +// Handles request to set the current powerstate from homekit. Will ignore redundant commands. ISYLightAccessory.prototype.setPowerState = function(powerOn,callback) { ISYJSDebugMessage(this,"Setting powerstate to %s", powerOn); if(powerOn != this.device.getCurrentLightState()) { @@ -451,6 +497,7 @@ ISYLightAccessory.prototype.setPowerState = function(powerOn,callback) { } } +// Mirrors change in the state of the underlying isj-js device object. ISYLightAccessory.prototype.handleExternalChange = function() { ISYJSDebugMessage(this,"Handling external change for light"); this.lightService @@ -461,10 +508,12 @@ ISYLightAccessory.prototype.handleExternalChange = function() { } } +// Handles request to get the current on state ISYLightAccessory.prototype.getPowerState = function(callback) { callback(null,this.device.getCurrentLightState()); } +// Handles request to set the brightness level of dimmable lights. Ignore redundant commands. ISYLightAccessory.prototype.setBrightness = function(level,callback) { ISYJSDebugMessage(this,"Setting brightness to %s", level); if(level != this.device.getCurrentLightDimState()) { @@ -478,10 +527,12 @@ ISYLightAccessory.prototype.setBrightness = function(level,callback) { } } +// Handles a request to get the current brightness level for dimmable lights. ISYLightAccessory.prototype.getBrightness = function(callback) { callback(null,this.device.getCurrentLightDimState()); } +// Returns the set of services supported by this object. ISYLightAccessory.prototype.getServices = function() { var informationService = new Service.AccessoryInformation(); @@ -517,31 +568,38 @@ ISYLightAccessory.prototype.getServices = function() { } ///////////////////////////////////////////////////////////////////////////////////////////////// -// CONTACT SENSOR +// CONTACT SENSOR - ISYDoorWindowSensorAccessory +// Implements the ContactSensor service. +// Constructs a Door Window Sensor (contact sensor) accessory. log = HomeBridge logger, device = wrapped isy-js device. function ISYDoorWindowSensorAccessory(log,device) { ISYAccessoryBaseSetup(this,log,device); this.doorWindowState = false; } +// Handles the identify command. ISYDoorWindowSensorAccessory.prototype.identify = function(callback) { // Do the identify action callback(); } +// Translates the state of the underlying device object into the corresponding homekit compatible state ISYDoorWindowSensorAccessory.prototype.translateCurrentDoorWindowState = function() { return (this.device.getCurrentDoorWindowState()) ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED; } +// Handles the request to get he current door window state. ISYDoorWindowSensorAccessory.prototype.getCurrentDoorWindowState = function(callback) { callback(null,this.translateCurrentDoorWindowState()); } +// Mirrors change in the state of the underlying isj-js device object. ISYDoorWindowSensorAccessory.prototype.handleExternalChange = function() { this.sensorService .setCharacteristic(Characteristic.ContactSensorState, this.translateCurrentDoorWindowState()); } +// Returns the set of services supported by this object. ISYDoorWindowSensorAccessory.prototype.getServices = function() { var informationService = new Service.AccessoryInformation(); @@ -563,16 +621,20 @@ ISYDoorWindowSensorAccessory.prototype.getServices = function() { } ///////////////////////////////////////////////////////////////////////////////////////////////// -// ELK SENSOR PANEL +// ELK SENSOR PANEL - ISYElkAlarmPanelAccessory +// Implements the SecuritySystem service for an elk security panel connected to the isy system +// Constructs the alarm panel accessory. log = HomeBridge logger, device = underlying isy-js device being wrapped function ISYElkAlarmPanelAccessory(log,device) { ISYAccessoryBaseSetup(this,log,device); } +// Handles the identify command ISYElkAlarmPanelAccessory.prototype.identify = function(callback) { callback(); } +// Handles the request to set the alarm target state ISYElkAlarmPanelAccessory.prototype.setAlarmTargetState = function(targetStateHK,callback) { ISYJSDebugMessage(this,"Sending command to set alarm panel state to: "+targetStateHK); var targetState = this.translateHKToAlarmTargetState(targetStateHK); @@ -587,6 +649,10 @@ ISYElkAlarmPanelAccessory.prototype.setAlarmTargetState = function(targetStateHK } } +// Translates from the current state of the elk alarm system into a homekit compatible state. The elk panel has a lot more +// possible states then can be directly represented by homekit so we map them. If the alarm is going off then it is tripped. +// If it is arming or armed it is considered armed. Stay maps to the state state, away to the away state, night to the night +// state. ISYElkAlarmPanelAccessory.prototype.translateAlarmCurrentStateToHK = function() { var tripState = this.device.getAlarmTripState(); var sourceAlarmState = this.device.getAlarmState(); @@ -611,6 +677,7 @@ ISYElkAlarmPanelAccessory.prototype.translateAlarmCurrentStateToHK = function() } } +// Translates the current target state of hthe underlying alarm into the appropriate homekit value ISYElkAlarmPanelAccessory.prototype.translateAlarmTargetStateToHK = function() { var sourceAlarmState = this.device.getAlarmMode(); if(sourceAlarmState == this.device.ALARM_MODE_STAY || sourceAlarmState == this.device.ALARM_MODE_STAY_INSTANT ) { @@ -624,6 +691,7 @@ ISYElkAlarmPanelAccessory.prototype.translateAlarmTargetStateToHK = function() { } } +// Translates the homekit version of the alarm target state into the appropriate elk alarm panel state ISYElkAlarmPanelAccessory.prototype.translateHKToAlarmTargetState = function(state) { if(state == Characteristic.SecuritySystemTargetState.STAY_ARM) { return this.device.ALARM_MODE_STAY; @@ -636,14 +704,17 @@ ISYElkAlarmPanelAccessory.prototype.translateHKToAlarmTargetState = function(sta } } +// Handles request to get the target alarm state ISYElkAlarmPanelAccessory.prototype.getAlarmTargetState = function(callback) { callback(null,this.translateAlarmTargetStateToHK()); } +// Handles request to get the current alarm state ISYElkAlarmPanelAccessory.prototype.getAlarmCurrentState = function(callback) { callback(null,this.translateAlarmCurrentStateToHK()); } +// Mirrors change in the state of the underlying isj-js device object. ISYElkAlarmPanelAccessory.prototype.handleExternalChange = function() { ISYJSDebugMessage(this,"Source device. Currenty state locally -"+this.device.getAlarmStatusAsText()); ISYJSDebugMessage(this,"Got alarm change notification. Setting HK target state to: "+this.translateAlarmTargetStateToHK()+" Setting HK Current state to: "+this.translateAlarmCurrentStateToHK()); @@ -653,6 +724,7 @@ ISYElkAlarmPanelAccessory.prototype.handleExternalChange = function() { .setCharacteristic(Characteristic.SecuritySystemCurrentState, this.translateAlarmCurrentStateToHK()); } +// Returns the set of services supported by this object. ISYElkAlarmPanelAccessory.prototype.getServices = function() { var informationService = new Service.AccessoryInformation(); From 0cb57d2a44e8b8708a66cc20d335902228d49b2c Mon Sep 17 00:00:00 2001 From: rodtoll Date: Mon, 19 Oct 2015 08:03:42 -0700 Subject: [PATCH 7/8] Improper constants for the fan speed. Fixing. --- platforms/isy-js.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/platforms/isy-js.js b/platforms/isy-js.js index b2c3728..1db30b4 100644 --- a/platforms/isy-js.js +++ b/platforms/isy-js.js @@ -195,13 +195,13 @@ ISYFanAccessory.prototype.identify = function(callback) { // Homekit doesn't have steps for the fan speed and needs to have a value from 0 to 100. We // split the range into 4 steps and map them to the 4 isy-js levels. ISYFanAccessory.prototype.translateFanSpeedToHK = function(fanSpeed) { - if(fanSpeed == this.device.isy.ISYFanDevice.FAN_OFF) { + if(fanSpeed == this.device.FAN_LEVEL_OFF) { return 0; - } else if(fanSpeed == this.device.isy.ISYFanDevice.FAN_LOW) { + } else if(fanSpeed == this.device.FAN_LEVEL_LOW) { return 32; - } else if(fanSpeed == this.device.isy.ISYFanDevice.FAN_MEDIUM) { + } else if(fanSpeed == this.device.FAN_LEVEL_MEDIUM) { return 67; - } else if(fanSpeed == this.device.isy.ISYFanDevice.FAN_HIGH) { + } else if(fanSpeed == this.device.FAN_LEVEL_HIGH) { return 100; } else { ISYJSDebugMessage(this,"!!!! ERROR: Unknown fan speed: "+fanSpeed); @@ -213,16 +213,16 @@ ISYFanAccessory.prototype.translateFanSpeedToHK = function(fanSpeed) { // to the four isy-js fan speed levels. ISYFanAccessory.prototype.translateHKToFanSpeed = function(fanStateHK) { if(fanStateHK == 0) { - return this.device.isy.ISYFanDevice.FAN_OFF; + return this.device.FAN_LEVEL_OFF; } else if(fanStateHK > 0 && fanStateHK <=32) { - return this.device.isy.ISYFanDevice.FAN_LOW; - } else if(fanStateHK > 33 && fanStateHK <= 67) { - return this.device.isy.ISYFanDevice.FAN_MEDIUM; + return this.device.FAN_LEVEL_LOW; + } else if(fanStateHK >= 33 && fanStateHK <= 67) { + return this.device.FAN_LEVEL_MEDIUM; } else if(fanStateHK > 67) { - return this.device.isy.ISYFanDevice.FAN_HIGH; + return this.device.FAN_LEVEL_HIGH; } else { ISYJSDebugMessage(this,"ERROR: Unknown fan state!"); - return this.device.isy.ISYFanDevice.FAN_OFF; + return this.device.FAN_LEVEL_OFF; } } @@ -259,9 +259,9 @@ ISYFanAccessory.prototype.getFanOnState = function(callback) { ISYFanAccessory.prototype.setFanOnState = function(onState,callback) { if(onState != this.getIsFanOn()) { if(onState) { - this.setFanRotationSpeed(this.translateFanSpeedToHK(this.device.isy.ISYFanDevice.FAN_MEDIUM), callback); + this.setFanRotationSpeed(this.translateFanSpeedToHK(this.device.FAN_LEVEL_MEDIUM), callback); } else { - this.setFanRotationSpeed(this.translateFanSpeedToHK(this.device.isy.ISYFanDevice.FAN_OFF), callback); + this.setFanRotationSpeed(this.translateFanSpeedToHK(this.device.FAN_LEVEL_OFF), callback); } } else { ISYJSDebugMessage(this,"Fan command does not change actual state"); From 70ec9a889129d069eb34c632c8ee8093e582b482 Mon Sep 17 00:00:00 2001 From: rodtoll Date: Mon, 19 Oct 2015 19:38:14 -0700 Subject: [PATCH 8/8] Fixed bug in alarm state. Was using alarm state instead of mode to translate current state. --- platforms/isy-js.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/platforms/isy-js.js b/platforms/isy-js.js index 1db30b4..172bd32 100644 --- a/platforms/isy-js.js +++ b/platforms/isy-js.js @@ -656,6 +656,7 @@ ISYElkAlarmPanelAccessory.prototype.setAlarmTargetState = function(targetStateHK ISYElkAlarmPanelAccessory.prototype.translateAlarmCurrentStateToHK = function() { var tripState = this.device.getAlarmTripState(); var sourceAlarmState = this.device.getAlarmState(); + var sourceAlarmMode = this.device.getAlarmMode(); if(tripState >= this.device.ALARM_TRIP_STATE_TRIPPED) { return Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED; @@ -664,14 +665,14 @@ ISYElkAlarmPanelAccessory.prototype.translateAlarmCurrentStateToHK = function() sourceAlarmState == this.device.ALARM_STATE_READY_TO_ARM_VIOLATION) { return Characteristic.SecuritySystemCurrentState.DISARMED; } else { - if(sourceAlarmState == this.device.ALARM_MODE_STAY || sourceAlarmState == this.device.ALARM_MODE_STAY_INSTANT ) { + if(sourceAlarmMode == this.device.ALARM_MODE_STAY || sourceAlarmMode == this.device.ALARM_MODE_STAY_INSTANT ) { return Characteristic.SecuritySystemCurrentState.STAY_ARM; - } else if(sourceAlarmState == this.device.ALARM_MODE_AWAY || sourceAlarmState == this.device.ALARM_MODE_VACATION) { + } else if(sourceAlarmMode == this.device.ALARM_MODE_AWAY || sourceAlarmMode == this.device.ALARM_MODE_VACATION) { return Characteristic.SecuritySystemCurrentState.AWAY_ARM; - } else if(sourceAlarmState == this.device.ALARM_MODE_NIGHT || sourceAlarmState == this.device.ALARM_MODE_NIGHT_INSTANT) { + } else if(sourceAlarmMode == this.device.ALARM_MODE_NIGHT || sourceAlarmMode == this.device.ALARM_MODE_NIGHT_INSTANT) { return Characteristic.SecuritySystemCurrentState.NIGHT_ARM; } else { - ISYJSDebugMessage(this,"Setting to disarmed because sourceAlarmState is "+sourceAlarmState); + ISYJSDebugMessage(this,"Setting to disarmed because sourceAlarmMode is "+sourceAlarmMode); return Characteristic.SecuritySystemCurrentState.DISARMED; } }