UNPKG

9.77 kBtext/coffeescriptView Raw
1# Description:
2# Control your Philips Hue Lights from HUBOT! BAM, easy candy for the kids
3#
4# Configuration:
5# PHILIPS_HUE_HASH : export PHILIPS_HUE_HASH="secrets"
6# PHILIPS_HUE_IP : export PHILIPS_HUE_IP="xxx.xxx.xxx.xxx"
7#
8# Setting your Hue Hash
9#
10# This needs to be done once, it seems older versions of the Hue bridge used an md5 hash as a 'username' but now you can use anything.
11#
12# Make an HTTP POST request of the following to http://YourHueHub/api
13#
14# {"username": "YourHash", "devicetype": "YourAppName"}
15# If you have not pressed the button on the Hue Hub you will receive an error like this;
16#
17# {"error":{"type":101,"address":"/","description":"link button not pressed"}}
18# Press the link button on the hub and try again and you should receive;
19#
20# {"success":{"username":"YourHash"}}
21# The key above will be the username you sent, remember this, you'll need it in all future requests
22#
23# ie: curl -v -H "Content-Type: application/json" -X POST 'http://YourHueHub/api' -d '{"username": "YourHash", "devicetype": "YourAppName"}'
24#
25# Dependencies:
26# "node-hue-api": "^2.4"
27#
28# Commands:
29# hubot hue lights - list all lights
30# hubot hue light <light number> - shows light status
31# hubot hue turn light <light number> <on|off> - flips the switch
32# hubot hue groups - lists the groups of lights
33# hubot hue config - reads bridge config
34# hubot hue (alert|alerts) light <light number> - blink once or blink for 10 seconds specific light
35# hubot hue (colors|colorloop|colorloop) (on|off) light <light number> - enable or disable the colorloop effect
36# hubot hue hsb light <light number> <hue 0-65535> <saturation 0-254> <brightness 0-254>
37# hubot hue xy light <light number> <x 0.0-1.0> <y 0.0-1.0>
38# hubot hue ct light <light number> <color temp 153-500>
39# hubot hue group <group name>=[<comma separated list of light indexes>]
40# hubot hue rm group <group number> - remove grouping of lights with ID <group number>
41# hubot hue @<group name> <on|off> - turn all lights in <group name> on or off
42# hubot hue @<group name> hsb=(<hue>,<sat>,<bri>) - set hsb value for all lights in group
43# hubot hue @<group name> xy=(<x>,<y>) - set x, y value for all lights in group
44# hubot hue @<group name> ct=<color temp> - set color temp for all lights in group
45#
46# Author:
47# kingbin - chris.blazek@gmail.com
48
49hue = require("node-hue-api")
50HueApi = hue.HueApi
51lightState = hue.lightState
52
53module.exports = (robot) ->
54 base_url = process.env.PHILIPS_HUE_IP
55 hash = process.env.PHILIPS_HUE_HASH
56 api = new HueApi(base_url, hash)
57 state = lightState.create();
58
59 # GROUP COMMANDS
60 robot.respond /hue (?:ls )?groups/i, (msg) ->
61 api.groups (err, groups) ->
62 return handleError msg, err if err
63 robot.logger.debug groups
64 msg.send "Light groups:"
65 for group in groups
66 if group.id == '0'
67 msg.send "- #{group.id}: '#{group.name}' (All)"
68 else
69 msg.send "- #{group.id}: '#{group.name}' (#{group.lights.join(', ')})"
70
71 robot.respond /hue group (\w+)=(\[((\d)+,)*((\d)+)\])/i, (msg) ->
72 group_name = msg.match[1]
73 group_lights = JSON.parse(msg.match[2])
74 msg.send "Setting #{group_name} to #{group_lights.join(', ')}"
75 api.createGroup group_name, group_lights, (err, response) ->
76 return handleError msg, err if err
77 robot.logger.debug response
78 msg.send "Group created!"
79
80 robot.respond /hue rm group (\d)/i, (msg) ->
81 group_id = msg.match[1]
82 msg.send "Deleting #{group_id}"
83 api.deleteGroup group_id, (err, response) ->
84 return handleError msg, err if err
85 robot.logger.debug response
86 msg.send "Group deleted!"
87
88 # LIGHT COMMANDS
89 robot.respond /hue lights/i, (msg) ->
90 api.lights (err, lights) ->
91 return handleError msg, err if err
92 robot.logger.debug lights
93 msg.send "Connected hue lights:"
94 for light in lights.lights
95 msg.send "- #{light.id}: '#{light.name}'"
96
97 robot.respond /hue light (.*)/i, (msg) ->
98 light = msg.match[1]
99 api.lightStatus light, (err, light) ->
100 return handleError msg, err if err
101 robot.logger.debug light
102 msg.send "Light Status:"
103 msg.send "- On: #{light.state.on}"
104 msg.send "- Reachable: #{light.state.reachable}"
105 msg.send "- Name: '#{light.name}'"
106 msg.send "- Model: #{light.modelid} - #{light.type}"
107 msg.send "- Unique ID: #{light.uniqueid}"
108 msg.send "- Software Version: #{light.swversion}"
109
110 robot.respond /hue @(\w+) hsb=\((\d+),(\d+),(\d+)\)/i, (msg) ->
111 [group_name, vHue, vSat, vBri] = msg.match[1..4]
112 groupMap group_name, (group) ->
113 return msg.send "Could not find '#{group_name}' in list of groups" unless group
114 msg.send "Setting light group #{group} to: Hue=#{vHue}, Saturation=#{vSat}, Brightness=#{vBri}"
115 state = lightState.create().on(true).bri(vBri).hue(vHue).sat(vSat)
116 api.setGroupLightState group, state, (err, status) ->
117 return handleError msg, err if err
118 robot.logger.debug status
119
120 robot.respond /hue hsb light (\d+) (\d+) (\d+) (\d+)/i, (msg) ->
121 [light, vHue, vSat, vBri] = msg.match[1..4]
122 msg.send "Setting light #{light} to: Hue=#{vHue}, Saturation=#{vSat}, Brightness=#{vBri}"
123 state = lightState.create().on(true).bri(vBri).hue(vHue).sat(vSat)
124 api.setLightState light, state, (err, status) ->
125 return handleError msg, err if err
126 robot.logger.debug status
127
128 robot.respond /hue @(\w+) xy=\(([0-9]*[.][0-9]+),([0-9]*[.][0-9]+)\)/i, (msg) ->
129 [group_name,x,y] = msg.match[1..3]
130 groupMap group_name, (group) ->
131 return msg.send "Could not find '#{group_name}' in list of groups" unless group
132 msg.send "Setting light group #{group} to: X=#{x}, Y=#{y}"
133 state = lightState.create().on(true).xy(x, y)
134 api.setGroupLightState group, state, (err, status) ->
135 return handleError msg, err if err
136 robot.logger.debug status
137
138 robot.respond /hue xy light (.*) ([0-9]*[.][0-9]+) ([0-9]*[.][0-9]+)/i, (msg) ->
139 [light,x,y] = msg.match[1..3]
140 msg.send "Setting light #{light} to: X=#{x}, Y=#{y}"
141 state = lightState.create().on(true).xy(x, y)
142 api.setLightState light, state, (err, status) ->
143 return handleError msg, err if err
144 robot.logger.debug status
145
146 robot.respond /hue @(\w+) ct=(\d{3})/i, (msg) ->
147 [group_name,ct] = msg.match[1..2]
148 groupMap group_name, (group) ->
149 return msg.send "Could not find '#{group_name}' in list of groups" unless group
150 msg.send "Setting light group #{group} to: CT=#{ct}"
151 state = lightState.create().on(true).ct(ct)
152 api.setGroupLightState group, state, (err, status) ->
153 return handleError msg, err if err
154 robot.logger.debug status
155
156 robot.respond /hue ct light (.*) (\d{3})/i, (msg) ->
157 [light,ct] = msg.match[1..2]
158 msg.send "Setting light #{light} to: CT=#{ct}"
159 state = lightState.create().on(true).ct(ct)
160 api.setLightState light, state, (err, status) ->
161 return handleError msg, err if err
162 robot.logger.debug status
163
164 robot.respond /hue @(\w+) (on|off)/i, (msg) ->
165 [group_name, state] = msg.match[1..2]
166 groupMap group_name, (group) ->
167 return msg.send "Could not find '#{group_name}' in list of groups" unless group
168 msg.send "Setting light group #{group} to #{state}"
169 state = lightState.create().on(state=='on')
170 api.setGroupLightState group, state, (err, status) ->
171 return handleError msg, err if err
172 robot.logger.debug status
173
174 robot.respond /hue turn light (\d+) (on|off)/i, (msg) ->
175 [light, state] = msg.match[1..2]
176 msg.send "Setting light #{light} to #{state}"
177 state = lightState.create().on(state=='on')
178 api.setLightState light, state, (err, status) ->
179 return handleError msg, err if err
180 robot.logger.debug status
181
182 robot.respond /hue (alert|alerts) light (.+)/i, (msg) ->
183 [alert_length,light] = msg.match[1..2]
184 if alert_length == 'alert'
185 alert_text = 'short alert'
186 state = lightState.create().alertShort()
187 else
188 alert_text = 'long alert'
189 state = lightState.create().alertLong()
190 msg.send "Setting light #{light} to #{alert_text}"
191 api.setLightState light, state, (err, status) ->
192 return handleError msg, err if err
193 robot.logger.debug status
194
195 robot.respond /hue (?:colors|colorloop|loop) (on|off) light (.+)/i, (msg) ->
196 [loop_status,light] = msg.match[1..2]
197 if loop_status == 'on'
198 colorloop_text = 'on'
199 state = lightState.create().effect('colorloop')
200 else
201 colorloop_text = 'off'
202 state = lightState.create().effect('none')
203 msg.send "Setting light #{light} colorloop to #{colorloop_text}"
204 api.setLightState light, state, (err, status) ->
205 return handleError msg, err if err
206 robot.logger.debug status
207
208 # BRIDGE COMMANDS
209 robot.respond /hue config/i, (msg) ->
210 api.config (err, config) ->
211 return handleError msg, err if err
212 robot.logger.debug config
213 msg.send "Base Station: '#{config.name}'"
214 msg.send "IP: #{config.ipaddress} / MAC: #{config.mac} / ZigBee Channel: #{config.zigbeechannel}"
215 msg.send "Software: #{config.swversion} / API: #{config.apiversion} / Update Available: #{config.swupdate.updatestate}"
216
217 # HELPERS
218 groupMap = (group_name, callback) ->
219 robot.logger.debug "mapping group names to group ids"
220 api.groups (err, groups) ->
221 return handleError msg, err if err
222 group_map = {}
223 for group in groups
224 robot.logger.debug group
225 if group.id == '0'
226 group_map['all'] = '0'
227 else
228 group_map[group.name.toLowerCase()] = group.id
229 match = group_map[group_name.toLowerCase()]
230 callback match
231
232 handleError = (msg, err) ->
233 msg.send err