diff --git a/README.md b/README.md index d75b54e..4fae78b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Since Siri supports devices added through HomeKit, this means that with Homebrid * _Siri, turn off the Speakers._ ([Sonos](http://www.sonos.com)) * _Siri, turn on the Dehumidifier._ ([WeMo](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/)) * _Siri, turn on Away Mode._ ([Xfinity Home](http://www.comcast.com/home-security.html)) - * _Siri, turn on the living room lights._ ([Wink](http://www.wink.com), [SmartThings](http://www.smartthings.com), [X10](http://github.com/edc1591/rest-mochad), [Philips Hue](http://meethue.com)) + * _Siri, turn on the living room lights._ ([Wink](http://www.wink.com), [SmartThings](http://www.smartthings.com), [X10](http://github.com/edc1591/rest-mochad), [Philips Hue](http://meethue.com), [LimitlessLED/MiLight/Easybulb](http://www.limitlessled.com/)) * _Siri, set the movie scene._ ([Logitech Harmony](http://myharmony.com/)) If you would like to support any other devices, please write a shim and create a pull request and I'd be happy to add it to this official list. diff --git a/accessories/HomeMatic.js b/accessories/HomeMatic.js old mode 100755 new mode 100644 diff --git a/accessories/MiLight.js b/accessories/MiLight.js index 409fcb5..9ab18f6 100644 --- a/accessories/MiLight.js +++ b/accessories/MiLight.js @@ -1,181 +1,113 @@ -var types = require("HAP-NodeJS/accessories/types.js"); +var Service = require("HAP-NodeJS").Service; +var Characteristic = require("HAP-NodeJS").Characteristic; var Milight = require('node-milight-promise').MilightController; var commands = require('node-milight-promise').commands; +module.exports = { + accessory: MiLight +} + function MiLight(log, config) { - this.log = log; - this.ip_address = config["ip_address"]; - this.port = config["port"]; - this.name = config["name"]; - this.zone = config["zone"]; - this.type = config["type"]; - this.delay = config["delay"]; - this.repeat = config["repeat"]; + this.log = log; + + // config info + this.ip_address = config["ip_address"]; + this.port = config["port"]; + this.name = config["name"]; + this.zone = config["zone"]; + this.type = config["type"]; + this.delay = config["delay"]; + this.repeat = config["repeat"]; } var light = new Milight({ - ip: this.ip_address, - port: this.port, - delayBetweenCommands: this.delay, - commandRepeat: this.repeat + ip: this.ip_address, + port: this.port, + delayBetweenCommands: this.delay, + commandRepeat: this.repeat }); MiLight.prototype = { - setPowerState: function(powerOn) { + setPowerState: function(powerOn, callback) { + if (powerOn) { + light.sendCommands(commands[this.type].on(this.zone)); + this.log("Setting power state to on"); + } + else { + light.sendCommands(commands[this.type].off(this.zone)); + this.log("Setting power state to off"); + } + callback(); + }, - var binaryState = powerOn ? "on" : "off"; - var that = this; + setBrightness: function(level, callback) { + this.log("Setting brightness to %s", level); - if (binaryState === "on") { - this.log("Setting power state of zone " + this.zone + " to " + powerOn); - light.sendCommands(commands[this.type].on(this.zone)); - } else { - this.log("Setting power state of zone " + this.zone + " to " + powerOn); - light.sendCommands(commands[this.type].off(this.zone)); - } + // If this is an rgbw lamp, set the absolute brightness specified + if (this.type == "rgbw") { + light.sendCommands(commands.rgbw.brightness(level)); + } else { + // If this is an rgb or a white lamp, they only support brightness up and down. + // Set brightness up when value is >50 and down otherwise. Not sure how well this works real-world. + if (level >= 50) { + light.sendCommands(commands[this.type].brightUp()); + } else { + light.sendCommands(commands[this.type].brightDown()); + } + } + callback(); + }, - }, + setHue: function(value, callback) { + this.log("Setting hue to %s", value); - setBrightnessLevel: function(value) { + if (this.type == "rgbw") { + if (value == 0) { + light.sendCommands(commands.rgbw.whiteMode(this.zone)); + } else { + light.sendCommands(commands.rgbw.hue(commands.rgbw.hsvToMilightColor(Array(value, 0, 0)))); + } + } else if (this.type == "rgb") { + light.sendCommands(commands.rgb.hue(commands.rgbw.hsvToMilightColor(Array(value, 0, 0)))); + } else if (this.type == "white") { + // Again, white lamps don't support setting an absolue colour temp, so trying to do warmer/cooler step at a time based on colour + if (value >= 180) { + light.sendCommands(commands.white.warmer()); + } else { + light.sendCommands(commands.white.cooler()); + } + } - var that = this; + }, + + identify: function(callback) { + this.log("Identify requested!"); + callback(); // success + }, + + getServices: function() { + var informationService = new Service.AccessoryInformation(); + + informationService + .setCharacteristic(Characteristic.Manufacturer, "MiLight") + .setCharacteristic(Characteristic.Model, this.type) + .setCharacteristic(Characteristic.SerialNumber, "MILIGHT12345"); + + var lightbulbService = new Service.Lightbulb(); + + lightbulbService + .getCharacteristic(Characteristic.On) + .on('set', this.setPowerState.bind(this)); + + lightbulbService + .addCharacteristic(new Characteristic.Brightness()) + .on('set', this.setBrightness.bind(this)); - this.log("Setting brightness level of zone " + this.zone + " to " + value); - - light.sendCommands(commands[this.type].brightness(value)); - }, - - setHue: function(value) { - - var that = this; - - this.log("Setting hue of zone " + this.zone + " to " + value); - - if (value == "0") { - light.sendCommands(commands.rgbw.whiteMode(this.zone)); - } else { - light.sendCommands(commands.rgbw.hue(commands.rgbw.hsvToMilightColor(Array(value, 0, 0)))); - } - }, - - - getServices: function() { - var that = this; - var services = [{ - 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: "MiLight", - supportEvents: false, - supportBonjour: false, - manfDescription: "Manufacturer", - designedMaxLength: 255 - }, { - cType: types.MODEL_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: this.type, - supportEvents: false, - supportBonjour: false, - manfDescription: "Model", - designedMaxLength: 255 - }, { - cType: types.SERIAL_NUMBER_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: "MILIGHT1234", - 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.LIGHTBULB_STYPE, - characteristics: [{ - cType: types.NAME_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: this.name, - supportEvents: false, - supportBonjour: false, - manfDescription: "Name of service", - designedMaxLength: 255 - }, { - cType: types.POWER_STATE_CTYPE, - onUpdate: function(value) { - that.setPowerState(value); - }, - perms: ["pw", "pr", "ev"], - format: "bool", - initialValue: false, - supportEvents: false, - supportBonjour: false, - manfDescription: "Turn on the light", - designedMaxLength: 1 - }, { - cType: types.BRIGHTNESS_CTYPE, - onUpdate: function(value) { - that.setBrightnessLevel(value); - }, - perms: ["pw", "pr", "ev"], - format: "bool", - initialValue: 100, - supportEvents: false, - supportBonjour: false, - manfDescription: "Adjust brightness of light", - designedMinValue: 0, - designedMaxValue: 100, - designedMinStep: 1, - unit: "%" - }] - }]; - if (that.type == "rgbw" || that.type == "rgb") { - services[1].characteristics.push({ - cType: types.HUE_CTYPE, - onUpdate: function(value) { - that.setHue(value); - }, - perms: ["pw", "pr", "ev"], - format: "int", - initialValue: 0, - supportEvents: false, - supportBonjour: false, - manfDescription: "Adjust Hue of Light", - designedMinValue: 0, - designedMaxValue: 360, - designedMinStep: 1, - unit: "arcdegrees" - }); - } - return services; - } + lightbulbService + .addCharacteristic(new Characteristic.Hue()) + .on('set', this.setHue.bind(this)); + + return [informationService, lightbulbService]; + } }; - -module.exports.accessory = MiLight; diff --git a/config-sample.json b/config-sample.json index adfe40c..ccad7dc 100644 --- a/config-sample.json +++ b/config-sample.json @@ -153,12 +153,12 @@ { "accessory":"MiLight", "name": "Lamp", - "ip_address": "255.255.255.255", // IP Address of the WiFi Bridge, or 255.255.255.255 to broadcast to all - "port": 8899, // Default port 8899 (50000 for v1 or v2 bridge) - "zone": 1, // Zone to address commands to (not used for rgb only bulbs) - "type": "rgbw", // Bulb type (rgbw, rgb, white) - "delay": 35, // Delay between commands sent to the WiFi bridge (default 35) - "repeat": 3 // Number of times each command is repeated for reliability (default 3) + "ip_address": "255.255.255.255", + "port": 8899, + "zone": 1, + "type": "rgbw", + "delay": 35, + "repeat": 3 }, { "accessory": "Tesla", diff --git a/package.json b/package.json index 5604b0f..ac28c5f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "harmonyhubjs-discover": "git+https://github.com/swissmanu/harmonyhubjs-discover.git", "mdns": "^2.2.4", "node-hue-api": "^1.0.5", - "node-milight-promise": "0.0.2", + "node-milight-promise": "0.0.x", "node-persist": "0.0.x", "request": "2.49.x", "sonos": "0.8.x",