diff --git a/platforms/Nest.js b/platforms/Nest.js new file mode 100644 index 0000000..3d5d41a --- /dev/null +++ b/platforms/Nest.js @@ -0,0 +1,321 @@ +var types = require("HAP-NodeJS/accessories/types.js"); +var nest = require('unofficial-nest-api'); + +function NestPlatform(log, config){ + // auth info + this.username = config["username"]; + this.password = config["password"]; + + this.log = log; +} + +NestPlatform.prototype = { + accessories: function(callback) { + this.log("Fetching Nest devices."); + + var that = this; + var foundAccessories = []; + + nest.login(this.username, this.password, function (err, data) { + if (err) { + that.log("There was a problem authenticating with Nest."); + } + else { + nest.fetchStatus(function (data) { + for (var deviceId in data.device) { + if (data.device.hasOwnProperty(deviceId)) { + device = data.device[deviceId]; + // it's a thermostat, adjust this to detect other accessories + if (data.shared[deviceId].hasOwnProperty('current_temperature')) + { + name = data.shared[deviceId].name + accessory = new NestThermostatAccessory(that.log, name, device, deviceId); + foundAccessories.push(accessory); + } + } + } + callback(foundAccessories) + }); + } + }); + } +} + +function NestThermostatAccessory(log, name, device, deviceId) { + // device info + this.name = name; + this.model = device.model_version; + this.serial = device.serial_number; + this.deviceId = deviceId; + this.log = log; +} + +NestThermostatAccessory.prototype = { + getCurrentHeatingCooling: function(callback){ + + var that = this; + + this.log("Checking current heating cooling for: " + this.name); + nest.fetchStatus(function (data) { + device = data.device[that.deviceId]; + that.log("Current healing cooling for " + that.name + " is: " + device.current_schedule_mode) + currentHeatingCooling = 0; + switch(device.current_schedule_mode) { + case "HEAT": + currentHeatingCooling = 1; + break; + // this is a guess, I don't have AC to test out the response + case "COOL": + currentHeatingCooling = 2; + break; + default: + currentHeatingCooling = 0; + } + callback(currentHeatingCooling); + }); + + + }, + + getCurrentTemperature: function(callback){ + + var that = this; + + nest.fetchStatus(function (data) { + device = data.shared[that.deviceId]; + that.log("Current temperature for " + this.name + " is: " + device.current_temperature); + callback(device.current_temperature); + }); + + + }, + + getTargetTemperature: function(callback){ + + var that = this; + + nest.fetchStatus(function (data) { + device = data.shared[that.deviceId]; + that.log("Target temperature for " + this.name + " is: " + device.target_temperature); + callback(device.target_temperature); + }); + + + }, + + getTemperatureUnits: function(callback){ + + var that = this; + + nest.fetchStatus(function (data) { + device = data.device[that.deviceId]; + temperatureUnits = 0; + switch(device.temperature_scale) { + case "F": + that.log("Tempature unit for " + this.name + " is: " + "Fahrenheit"); + temperatureUnits = 1; + break; + case "C": + that.log("Tempature unit for " + this.name + " is: " + "Celsius"); + temperatureUnits = 0; + break; + default: + temperatureUnits = 0; + } + + callback(temperatureUnits); + }); + + + }, + + getCurrentRelativeHumidity: function(callback){ + + var that = this; + + nest.fetchStatus(function (data) { + device = data.device[that.deviceId]; + that.log("Humidity for " + this.name + " is: " + device.current_humidity); + callback(device.current_humidity); + }) + + + }, + + setTargetTemperature: function(targetTemperature){ + + var that = this; + + this.log("Setting target temperature for " + this.name + " to: " + targetTemperature); + nest.setTemperature(this.deviceId, targetTemperature); + + + }, + + getServices: function() { + var that = this; + return [{ + sType: types.ACCESSORY_INFORMATION_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: this.name, + supportEvents: false, + supportBonjour: false, + manfDescription: "Name of the accessory", + designedMaxLength: 255 + },{ + cType: types.MANUFACTURER_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Nest", + supportEvents: false, + supportBonjour: false, + manfDescription: "Manufacturer", + designedMaxLength: 255 + },{ + cType: types.MODEL_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: this.model, + supportEvents: false, + supportBonjour: false, + manfDescription: "Model", + designedMaxLength: 255 + },{ + cType: types.SERIAL_NUMBER_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: this.serial, + supportEvents: false, + supportBonjour: false, + manfDescription: "SN", + designedMaxLength: 255 + },{ + cType: types.IDENTIFY_CTYPE, + onUpdate: null, + perms: ["pw"], + format: "bool", + initialValue: false, + supportEvents: false, + supportBonjour: false, + manfDescription: "Identify Accessory", + designedMaxLength: 1 + }] + },{ + sType: types.THERMOSTAT_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: this.name, + supportEvents: false, + supportBonjour: false, + manfDescription: "Name of thermostat", + designedMaxLength: 255 + },{ + cType: types.CURRENTHEATINGCOOLING_CTYPE, + onUpdate: null, + onRead: function(callback) { + that.getCurrentHeatingCooling(function(coolingType){ + callback(coolingType); + }); + }, + perms: ["pr","ev"], + format: "int", + initialValue: 0, + supportEvents: false, + supportBonjour: false, + manfDescription: "Current Mode", + designedMaxLength: 1, + designedMinValue: 0, + designedMaxValue: 2, + designedMinStep: 1, + },{ + cType: types.TARGETHEATINGCOOLING_CTYPE, + onUpdate: null, + perms: ["pw","pr","ev"], + format: "int", + initialValue: 0, + supportEvents: false, + supportBonjour: false, + manfDescription: "Target Mode", + designedMinValue: 0, + designedMaxValue: 3, + designedMinStep: 1, + },{ + cType: types.CURRENT_TEMPERATURE_CTYPE, + onUpdate: null, + onRead: function(callback) { + that.getCurrentTemperature(function(currentTemperature){ + callback(currentTemperature); + }); + }, + perms: ["pr","ev"], + format: "int", + initialValue: 20, + supportEvents: false, + supportBonjour: false, + manfDescription: "Current Temperature", + unit: "celsius" + },{ + cType: types.TARGET_TEMPERATURE_CTYPE, + onUpdate: function(value) { + that.setTargetTemperature(value); + }, + onRead: function(callback) { + that.getTargetTemperature(function(targetTemperature){ + callback(targetTemperature); + }); + }, + perms: ["pw","pr","ev"], + format: "int", + initialValue: 20, + supportEvents: false, + supportBonjour: false, + manfDescription: "Target Temperature", + designedMinValue: 16, + designedMaxValue: 38, + designedMinStep: 1, + unit: "celsius" + },{ + cType: types.TEMPERATURE_UNITS_CTYPE, + onUpdate: null, + onRead: function(callback) { + that.getTemperatureUnits(function(temperatureUnits){ + callback(temperatureUnits); + }); + }, + perms: ["pr","ev"], + format: "int", + initialValue: 0, + supportEvents: false, + supportBonjour: false, + manfDescription: "Unit", + },{ + cType: types.CURRENT_RELATIVE_HUMIDITY_CTYPE, + onUpdate: null, + onRead: function(callback) { + that.getCurrentRelativeHumidity(function(currentRelativeHumidity){ + callback(currentRelativeHumidity); + }); + }, + perms: ["pr","ev"], + format: "int", + initialValue: 0, + supportEvents: false, + supportBonjour: false, + manfDescription: "Humidity", + }] + }]; + } +} + +module.exports.accessory = NestThermostatAccessory; +module.exports.platform = NestPlatform; \ No newline at end of file