From abe88b75020c73551747228355ccdcf03701f6d0 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 8 Sep 2015 10:41:03 -0700 Subject: [PATCH 1/5] [MiLight] Converted accessory to platform. Not fully tested yet --- {accessories => platforms}/MiLight.js | 81 ++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 14 deletions(-) rename {accessories => platforms}/MiLight.js (73%) diff --git a/accessories/MiLight.js b/platforms/MiLight.js similarity index 73% rename from accessories/MiLight.js rename to platforms/MiLight.js index c5ce67c..d38cb3f 100644 --- a/accessories/MiLight.js +++ b/platforms/MiLight.js @@ -1,6 +1,6 @@ /* -MiLight accessory shim for Homebridge +MiLight platform shim for Homebridge Written by Sam Edwards (https://samedwards.ca/) Uses the node-milight-promise library (https://github.com/mwittig/node-milight-promise) which features some code from @@ -8,28 +8,28 @@ applamp.nl (http://www.applamp.nl/service/applamp-api/) and uses other details f Configure in config.json as follows: -"accessories": [ +"platforms": [ { - "accessory":"MiLight", - "name": "Lamp", + "platform":"MiLight", + "name":"MiLight", "ip_address": "255.255.255.255", "port": 8899, - "zone": 1, "type": "rgbw", "delay": 30, - "repeat": 3 + "repeat": 3, + "zones":["Kitchen Lamp","Bedroom Lamp","Living Room Lamp","Hallway Lamp"] } ] Where the parameters are: - *accessory (required): This must be "MiLight", and refers to the name of the accessory as exported from this file - *name (required): The name for this light/zone, as passed on to Homebridge and HomeKit + *platform (required): This must be "MiLight", and refers to the name of the accessory as exported from this file + *name (optional): The display name used for logging output by Homebridge. Best to set to "MiLight" *ip_address (optional): The IP address of the WiFi Bridge. Default to the broadcast address of 255.255.255.255 if not specified *port (optional): Port of the WiFi bridge. Defaults to 8899 if not specified - *zone (required): The zone to target with this accessory. "0" for all zones on the bridge, otherwise 1-4 for a specific zone - *type (required): One of either "rgbw", "rgb", or "white", depending on the type of bulb being controlled + *type (optional): One of either "rgbw", "rgb", or "white", depending on the type of bulb being controlled. This applies to all zones. Defaults to rgbw. *delay (optional): Delay between commands sent over UDP. Default 30ms *repeat (optional): Number of times to repeat the UDP command for better reliability. Default 3 + *zones (required): An array of the names of the zones, in order, 1-4. Use null if a zone is skipped. RGB lamps can only have a single zone. Tips and Tricks: *Setting the brightness of an rgbw or a white bulb will set it to "night mode", which is dimmer than the lowest brightness setting @@ -43,7 +43,6 @@ Troubleshooting: The node-milight-promise library provides additional debugging output when the MILIGHT_DEBUG environmental variable is set TODO: - *Probably convert this module to a platform that can configure an entire bridge at once, just passing a name for each zone *Possibly build in some sort of state logging and persistance so that we can answswer HomeKit status queries to the best of our ability */ @@ -54,10 +53,64 @@ var Milight = require('node-milight-promise').MilightController; var commands = require('node-milight-promise').commands; module.exports = { - accessory: MiLight + accessory: MiLightAccessory, + platform: MiLightPlatform } -function MiLight(log, config) { +function MiLightPlatform(log, config) { + this.log = log; + + this.config = config; +} + +MiLightPlatform.prototype = { + accessories: function(callback) { + var that = this; + var zones = []; + + // Various error checking + if (this.config.zones) { + var zoneLength = this.config.zones.length; + } else { + this.log("ERROR: Could not read zones from configuration."); + return; + } + + if (!this.config["type"]) { + this.log("INFO: Type not specified, defaulting to rgbw"); + this.config["type"] = "rgbw"; + } + + if (zoneLength == 0) { + this.log("ERROR: No zones found in configuration."); + return; + } else if (this.config["type"] == "rgb" && zoneLength > 1) { + this.log("WARNING: RGB lamps only have a single zone. Only the first defined zone will be used."); + zoneLength = 1; + } else if (zoneLength > 4) { + this.log("WARNING: Only a maximum of 4 zones are supported per bridge. Only recognizing the first 4 zones."); + zoneLength = 4; + } + + // Create lamp accessories for all of the defined zones + for (var i=0; i < zoneLength; i++) { + if (!!this.config.zones[i]) { + this.config["name"] = this.config.zones[i]; + this.config["zone"] = i+1; + lamp = new MiLightAccessory(this.log, this.config); + zones.push(lamp); + } + } + if (zones.length > 0) { + callback(zones); + } else { + this.log("ERROR: Unable to find any valid zones"); + return; + } + } +} + +function MiLightAccessory(log, config) { this.log = log; // config info @@ -77,7 +130,7 @@ function MiLight(log, config) { }); } -MiLight.prototype = { +MiLightAccessory.prototype = { setPowerState: function(powerOn, callback) { if (powerOn) { From 5cccd3f916d93b0dd576a3b31d6f72d4bfb63b89 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 8 Sep 2015 11:01:30 -0700 Subject: [PATCH 2/5] [MiLight] Modify logging to show the zone name when used as a platform accessory --- platforms/MiLight.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/platforms/MiLight.js b/platforms/MiLight.js index d38cb3f..7cbf1c9 100644 --- a/platforms/MiLight.js +++ b/platforms/MiLight.js @@ -134,10 +134,10 @@ MiLightAccessory.prototype = { setPowerState: function(powerOn, callback) { if (powerOn) { - this.log("Setting power state to on"); + this.log("["+this.name+"] Setting power state to on"); this.light.sendCommands(commands[this.type].on(this.zone)); } else { - this.log("Setting power state to off"); + this.log("["+this.name+"] Setting power state to off"); this.light.sendCommands(commands[this.type].off(this.zone)); } callback(); @@ -146,11 +146,11 @@ MiLightAccessory.prototype = { setBrightness: function(level, callback) { if (level == 0) { // If brightness is set to 0, turn off the lamp - this.log("Setting brightness to 0 (off)"); + this.log("["+this.name+"] Setting brightness to 0 (off)"); this.light.sendCommands(commands[this.type].off(this.zone)); } else if (level <= 2 && (this.type == "rgbw" || this.type == "white")) { // If setting brightness to 2 or lower, instead set night mode for lamps that support it - this.log("Setting night mode", level); + this.log("["+this.name+"] Setting night mode", level); this.light.sendCommands(commands[this.type].off(this.zone)); // Ensure we're pausing for 100ms between these commands as per the spec @@ -158,7 +158,7 @@ MiLightAccessory.prototype = { this.light.sendCommands(commands[this.type].nightMode(this.zone)); } else { - this.log("Setting brightness to %s", level); + this.log("["+this.name+"] Setting brightness to %s", level); // Send on command to ensure we're addressing the right bulb this.light.sendCommands(commands[this.type].on(this.zone)); @@ -185,7 +185,7 @@ MiLightAccessory.prototype = { }, setHue: function(value, callback) { - this.log("Setting hue to %s", value); + this.log("["+this.name+"] Setting hue to %s", value); var hue = Array(value, 0, 0); @@ -212,7 +212,7 @@ MiLightAccessory.prototype = { }, identify: function(callback) { - this.log("Identify requested!"); + this.log("["+this.name+"] Identify requested!"); callback(); // success }, From 18333242ff3866fb66750123caf001bfe9f74760 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 8 Sep 2015 11:20:36 -0700 Subject: [PATCH 3/5] [MiLight] Add missing callback from hue function --- platforms/MiLight.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platforms/MiLight.js b/platforms/MiLight.js index 7cbf1c9..4382dea 100644 --- a/platforms/MiLight.js +++ b/platforms/MiLight.js @@ -65,7 +65,6 @@ function MiLightPlatform(log, config) { MiLightPlatform.prototype = { accessories: function(callback) { - var that = this; var zones = []; // Various error checking @@ -208,7 +207,7 @@ MiLightAccessory.prototype = { this.light.sendCommands(commands.white.cooler()); } } - + callback(); }, identify: function(callback) { From 7dc168e9dc51178df4e84793488c3ad06192d76f Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 8 Sep 2015 11:33:17 -0700 Subject: [PATCH 4/5] [MiLight] Update config-sample.json to replace MiLight accessory with MiLight platform --- config-sample.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/config-sample.json b/config-sample.json index 4245bd5..d684c9d 100644 --- a/config-sample.json +++ b/config-sample.json @@ -71,7 +71,17 @@ "platform": "YamahaAVR", "play_volume": -35, "setMainInputTo": "AirPlay" - } + }, + { + "platform": "MiLight", + "name": "MiLight", + "ip_address": "255.255.255.255", + "port": 8899, + "type": "rgbw", + "delay": 30, + "repeat": 3, + "zones":["Kitchen Lamp","Bedroom Lamp","Living Room Lamp","Hallway Lamp"] + } ], "accessories": [ @@ -152,16 +162,6 @@ "port" : 4999, // Port the SER2SOCK process is running on "pin": "1234" // PIN used for arming / disarming }, - { - "accessory":"MiLight", - "name": "Lamp", - "ip_address": "255.255.255.255", - "port": 8899, - "zone": 1, - "type": "rgbw", - "delay": 35, - "repeat": 3 - }, { "accessory": "Tesla", "name": "Tesla", From d6e31b4aa71d388e6f2905893acfa4273c423b4a Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Wed, 9 Sep 2015 08:13:22 -0700 Subject: [PATCH 5/5] [MiLight] Swap cooler/warmer direction for white bulbs, and add note about delay --- platforms/MiLight.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platforms/MiLight.js b/platforms/MiLight.js index 4382dea..3869e74 100644 --- a/platforms/MiLight.js +++ b/platforms/MiLight.js @@ -27,7 +27,7 @@ Where the parameters are: *ip_address (optional): The IP address of the WiFi Bridge. Default to the broadcast address of 255.255.255.255 if not specified *port (optional): Port of the WiFi bridge. Defaults to 8899 if not specified *type (optional): One of either "rgbw", "rgb", or "white", depending on the type of bulb being controlled. This applies to all zones. Defaults to rgbw. - *delay (optional): Delay between commands sent over UDP. Default 30ms + *delay (optional): Delay between commands sent over UDP. Default 30ms. May cause delays when sending a lot of commands. Try decreasing to improve. *repeat (optional): Number of times to repeat the UDP command for better reliability. Default 3 *zones (required): An array of the names of the zones, in order, 1-4. Use null if a zone is skipped. RGB lamps can only have a single zone. @@ -202,9 +202,9 @@ MiLightAccessory.prototype = { } 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) { - this.light.sendCommands(commands.white.warmer()); - } else { this.light.sendCommands(commands.white.cooler()); + } else { + this.light.sendCommands(commands.white.warmer()); } } callback();