Added more documentation.

This commit is contained in:
rodtoll
2015-10-18 21:09:59 -07:00
parent 8fcd5d39a6
commit 74e37cc488

View File

@@ -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();