huebot 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -8
- data/bin/huebot +38 -8
- data/lib/huebot/bridge.rb +24 -0
- data/lib/huebot/cli.rb +33 -1
- data/lib/huebot/client.rb +131 -0
- data/lib/huebot/compiler.rb +5 -3
- data/lib/huebot/config.rb +41 -0
- data/lib/huebot/device_mapper.rb +2 -2
- data/lib/huebot/device_state.rb +7 -0
- data/lib/huebot/group.rb +23 -0
- data/lib/huebot/light.rb +23 -0
- data/lib/huebot/version.rb +1 -1
- data/lib/huebot.rb +6 -2
- metadata +12 -17
- data/lib/hue/LICENSE +0 -22
- data/lib/hue/bridge.rb +0 -140
- data/lib/hue/client.rb +0 -141
- data/lib/hue/editable_state.rb +0 -27
- data/lib/hue/errors.rb +0 -38
- data/lib/hue/group.rb +0 -181
- data/lib/hue/light.rb +0 -177
- data/lib/hue/scene.rb +0 -50
- data/lib/hue/translate_keys.rb +0 -21
- data/lib/hue/version.rb +0 -3
- data/lib/hue.rb +0 -13
data/lib/hue/bridge.rb
DELETED
@@ -1,140 +0,0 @@
|
|
1
|
-
module Hue
|
2
|
-
class Bridge
|
3
|
-
# ID of the bridge.
|
4
|
-
attr_reader :id
|
5
|
-
|
6
|
-
# Name of the bridge. This is also its uPnP name, so will reflect the
|
7
|
-
# actual uPnP name after any conflicts have been resolved.
|
8
|
-
attr_accessor :name
|
9
|
-
|
10
|
-
# IP address of the bridge.
|
11
|
-
attr_reader :ip
|
12
|
-
|
13
|
-
# MAC address of the bridge.
|
14
|
-
attr_reader :mac_address
|
15
|
-
|
16
|
-
# IP Address of the proxy server being used.
|
17
|
-
attr_reader :proxy_address
|
18
|
-
|
19
|
-
# Port of the proxy being used by the bridge. If set to 0 then a proxy is
|
20
|
-
# not being used.
|
21
|
-
attr_reader :proxy_port
|
22
|
-
|
23
|
-
# Software version of the bridge.
|
24
|
-
attr_reader :software_version
|
25
|
-
|
26
|
-
# Contains information related to software updates.
|
27
|
-
attr_reader :software_update
|
28
|
-
|
29
|
-
# An array of whitelisted user IDs.
|
30
|
-
attr_reader :ip_whitelist
|
31
|
-
|
32
|
-
# Network mask of the bridge.
|
33
|
-
attr_reader :network_mask
|
34
|
-
|
35
|
-
# Gateway IP address of the bridge.
|
36
|
-
attr_reader :gateway
|
37
|
-
|
38
|
-
# Whether the IP address of the bridge is obtained with DHCP.
|
39
|
-
attr_reader :dhcp
|
40
|
-
|
41
|
-
def initialize(client, hash)
|
42
|
-
@client = client
|
43
|
-
unpack(hash)
|
44
|
-
end
|
45
|
-
|
46
|
-
# Current time stored on the bridge.
|
47
|
-
def utc
|
48
|
-
json = get_configuration
|
49
|
-
DateTime.parse(json['utc'])
|
50
|
-
end
|
51
|
-
|
52
|
-
# Indicates whether the link button has been pressed within the last 30
|
53
|
-
# seconds.
|
54
|
-
def link_button_pressed?
|
55
|
-
json = get_configuration
|
56
|
-
json['linkbutton']
|
57
|
-
end
|
58
|
-
|
59
|
-
# This indicates whether the bridge is registered to synchronize data with a
|
60
|
-
# portal account.
|
61
|
-
def has_portal_services?
|
62
|
-
json = get_configuration
|
63
|
-
json['portalservices']
|
64
|
-
end
|
65
|
-
|
66
|
-
def refresh
|
67
|
-
json = get_configuration
|
68
|
-
unpack(json)
|
69
|
-
@lights = nil
|
70
|
-
@groups = nil
|
71
|
-
@scenes = nil
|
72
|
-
end
|
73
|
-
|
74
|
-
def lights
|
75
|
-
@lights ||= begin
|
76
|
-
json = JSON(Net::HTTP.get(URI.parse(base_url)))
|
77
|
-
json['lights'].map do |key, value|
|
78
|
-
Light.new(@client, self, key, value)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def add_lights
|
84
|
-
uri = URI.parse("#{base_url}/lights")
|
85
|
-
http = Net::HTTP.new(uri.host)
|
86
|
-
response = http.request_post(uri.path, nil)
|
87
|
-
(response.body).first
|
88
|
-
end
|
89
|
-
|
90
|
-
def groups
|
91
|
-
@groups ||= begin
|
92
|
-
json = JSON(Net::HTTP.get(URI.parse("#{base_url}/groups")))
|
93
|
-
json.map do |id, data|
|
94
|
-
Group.new(@client, self, id, data)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def scenes
|
100
|
-
@scenes ||= begin
|
101
|
-
json = JSON(Net::HTTP.get(URI.parse("#{base_url}/scenes")))
|
102
|
-
json.map do |id, data|
|
103
|
-
Scene.new(@client, self, id, data)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
private
|
109
|
-
|
110
|
-
KEYS_MAP = {
|
111
|
-
:id => :id,
|
112
|
-
:ip => :internalipaddress,
|
113
|
-
:name => :name,
|
114
|
-
:proxy_port => :proxyport,
|
115
|
-
:software_update => :swupdate,
|
116
|
-
:ip_whitelist => :whitelist,
|
117
|
-
:software_version => :swversion,
|
118
|
-
:proxy_address => :proxyaddress,
|
119
|
-
:mac_address => :macaddress,
|
120
|
-
:network_mask => :netmask,
|
121
|
-
:portal_services => :portalservices,
|
122
|
-
}
|
123
|
-
|
124
|
-
def unpack(hash)
|
125
|
-
KEYS_MAP.each do |local_key, remote_key|
|
126
|
-
value = hash[remote_key.to_s]
|
127
|
-
next unless value
|
128
|
-
instance_variable_set("@#{local_key}", value)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def get_configuration
|
133
|
-
JSON(Net::HTTP.get(URI.parse("#{base_url}/config")))
|
134
|
-
end
|
135
|
-
|
136
|
-
def base_url
|
137
|
-
"http://#{ip}/api/#{@client.username}"
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
data/lib/hue/client.rb
DELETED
@@ -1,141 +0,0 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
require 'json'
|
3
|
-
|
4
|
-
module Hue
|
5
|
-
class Client
|
6
|
-
attr_reader :username
|
7
|
-
|
8
|
-
def initialize(username = nil)
|
9
|
-
@bridge_id = nil
|
10
|
-
@username = username || find_username
|
11
|
-
|
12
|
-
if @username
|
13
|
-
begin
|
14
|
-
validate_user
|
15
|
-
rescue Hue::UnauthorizedUser
|
16
|
-
register_user
|
17
|
-
end
|
18
|
-
else
|
19
|
-
register_user
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def bridge
|
24
|
-
@bridge_id = find_bridge_id unless @bridge_id
|
25
|
-
if @bridge_id
|
26
|
-
bridge = bridges.select { |b| b.id == @bridge_id }.first
|
27
|
-
else
|
28
|
-
bridge = bridges.first
|
29
|
-
end
|
30
|
-
raise NoBridgeFound unless bridge
|
31
|
-
bridge
|
32
|
-
end
|
33
|
-
|
34
|
-
# Patched by Jordan Hollinger to remove use of "curb" gem
|
35
|
-
# TODO handle redirects? That's what curb was used for.
|
36
|
-
def bridges
|
37
|
-
req = Net::HTTP::Get.new(URI(ENV["HUE_DISCOVERY_API"] || "https://discovery.meethue.com/"))
|
38
|
-
resp = Net::HTTP.start req.uri.host, req.uri.port, {use_ssl: true} do |http|
|
39
|
-
http.request req
|
40
|
-
end
|
41
|
-
|
42
|
-
JSON(resp.body).lazy.map { |x|
|
43
|
-
Bridge.new(self, x)
|
44
|
-
}
|
45
|
-
|
46
|
-
rescue Net::OpenTimeout, Net::ReadTimeout, JSON::ParserError
|
47
|
-
[]
|
48
|
-
end
|
49
|
-
|
50
|
-
def lights
|
51
|
-
bridge.lights
|
52
|
-
end
|
53
|
-
|
54
|
-
def add_lights
|
55
|
-
bridge.add_lights
|
56
|
-
end
|
57
|
-
|
58
|
-
def light(id)
|
59
|
-
id = id.to_s
|
60
|
-
lights.select { |l| l.id == id }.first
|
61
|
-
end
|
62
|
-
|
63
|
-
def groups
|
64
|
-
bridge.groups
|
65
|
-
end
|
66
|
-
|
67
|
-
def group(id = nil)
|
68
|
-
return Group.new(self, bridge) if id.nil?
|
69
|
-
|
70
|
-
id = id.to_s
|
71
|
-
groups.select { |g| g.id == id }.first
|
72
|
-
end
|
73
|
-
|
74
|
-
def scenes
|
75
|
-
bridge.scenes
|
76
|
-
end
|
77
|
-
|
78
|
-
def scene(id)
|
79
|
-
id = id.to_s
|
80
|
-
scenes.select { |s| s.id == id }.first
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
def find_username
|
86
|
-
return ENV['HUE_USERNAME'] if ENV['HUE_USERNAME']
|
87
|
-
|
88
|
-
json = JSON(File.read(File.expand_path('~/.hue')))
|
89
|
-
json['username']
|
90
|
-
rescue
|
91
|
-
return nil
|
92
|
-
end
|
93
|
-
|
94
|
-
def validate_user
|
95
|
-
response = JSON(Net::HTTP.get(URI.parse("http://#{bridge.ip}/api/#{@username}")))
|
96
|
-
|
97
|
-
if response.is_a? Array
|
98
|
-
response = response.first
|
99
|
-
end
|
100
|
-
|
101
|
-
if error = response['error']
|
102
|
-
raise get_error(error)
|
103
|
-
end
|
104
|
-
|
105
|
-
response['success']
|
106
|
-
end
|
107
|
-
|
108
|
-
def register_user
|
109
|
-
body = JSON.dump({
|
110
|
-
devicetype: 'Ruby'
|
111
|
-
})
|
112
|
-
|
113
|
-
uri = URI.parse("http://#{bridge.ip}/api")
|
114
|
-
http = Net::HTTP.new(uri.host)
|
115
|
-
response = JSON(http.request_post(uri.path, body).body).first
|
116
|
-
|
117
|
-
if error = response['error']
|
118
|
-
raise get_error(error)
|
119
|
-
end
|
120
|
-
|
121
|
-
if @username = response['success']['username']
|
122
|
-
File.write(File.expand_path('~/.hue'), JSON.dump({username: @username}))
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def find_bridge_id
|
127
|
-
return ENV['HUE_BRIDGE_ID'] if ENV['HUE_BRIDGE_ID']
|
128
|
-
|
129
|
-
json = JSON(File.read(File.expand_path('~/.hue')))
|
130
|
-
json['bridge_id']
|
131
|
-
rescue
|
132
|
-
return nil
|
133
|
-
end
|
134
|
-
|
135
|
-
def get_error(error)
|
136
|
-
# Find error class and return instance
|
137
|
-
klass = Hue::ERROR_MAP[error['type']] || UnknownError unless klass
|
138
|
-
klass.new(error['description'])
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
data/lib/hue/editable_state.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
module Hue
|
2
|
-
module EditableState
|
3
|
-
def on?
|
4
|
-
@state['on']
|
5
|
-
end
|
6
|
-
|
7
|
-
def on!
|
8
|
-
self.on = true
|
9
|
-
end
|
10
|
-
|
11
|
-
def off!
|
12
|
-
self.on = false
|
13
|
-
end
|
14
|
-
|
15
|
-
%w{on hue saturation brightness color_temperature alert effect}.each do |key|
|
16
|
-
define_method "#{key}=".to_sym do |value|
|
17
|
-
set_state({key.to_sym => value})
|
18
|
-
instance_variable_set("@#{key}".to_sym, value)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def set_xy(x, y)
|
23
|
-
set_state({:xy => [x, y]})
|
24
|
-
@x, @y = x, y
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/hue/errors.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
module Hue
|
2
|
-
class Error < StandardError; end
|
3
|
-
|
4
|
-
class UnauthorizedUser < Error; end
|
5
|
-
class InvalidJSON < Error; end
|
6
|
-
class ResourceNotAvailable < Error; end
|
7
|
-
class MethodNotAvailable < Error; end
|
8
|
-
class MissingBody < Error; end
|
9
|
-
class ParameterNotAvailable < Error; end
|
10
|
-
class InvalidValueForParameter < Error; end
|
11
|
-
class ParameterNotModifiable < Error; end
|
12
|
-
class InternalError < Error; end
|
13
|
-
class LinkButtonNotPressed < Error; end
|
14
|
-
class ParameterNotModifiableWhileOff < ParameterNotModifiable; end
|
15
|
-
class TooManyGroups < Error; end
|
16
|
-
class GroupTooFull < Error; end
|
17
|
-
|
18
|
-
class InvalidUsername < Error; end
|
19
|
-
class UnknownError < Error; end
|
20
|
-
class NoBridgeFound < Error; end
|
21
|
-
|
22
|
-
# Status code to exception map
|
23
|
-
ERROR_MAP = {
|
24
|
-
1 => Hue::UnauthorizedUser,
|
25
|
-
2 => Hue::InvalidJSON,
|
26
|
-
3 => Hue::ResourceNotAvailable,
|
27
|
-
4 => Hue::MethodNotAvailable,
|
28
|
-
5 => Hue::MissingBody,
|
29
|
-
6 => Hue::ParameterNotAvailable,
|
30
|
-
7 => Hue::InvalidValueForParameter,
|
31
|
-
8 => Hue::ParameterNotModifiable,
|
32
|
-
901 => Hue::InternalError,
|
33
|
-
101 => Hue::LinkButtonNotPressed,
|
34
|
-
201 => Hue::ParameterNotModifiableWhileOff,
|
35
|
-
301 => Hue::TooManyGroups,
|
36
|
-
302 => Hue::GroupTooFull
|
37
|
-
}
|
38
|
-
end
|
data/lib/hue/group.rb
DELETED
@@ -1,181 +0,0 @@
|
|
1
|
-
module Hue
|
2
|
-
class Group
|
3
|
-
include Enumerable
|
4
|
-
include TranslateKeys
|
5
|
-
include EditableState
|
6
|
-
|
7
|
-
# Unique identification number.
|
8
|
-
attr_reader :id
|
9
|
-
|
10
|
-
# Bridge the group is associated with
|
11
|
-
attr_reader :bridge
|
12
|
-
|
13
|
-
# A unique, editable name given to the group.
|
14
|
-
attr_accessor :name
|
15
|
-
|
16
|
-
# Hue of the group. This is a wrapping value between 0 and 65535.
|
17
|
-
# Both 0 and 65535 are red, 25500 is green and 46920 is blue.
|
18
|
-
attr_accessor :hue
|
19
|
-
|
20
|
-
# Saturation of the group. 255 is the most saturated (colored)
|
21
|
-
# and 0 is the least saturated (white).
|
22
|
-
attr_accessor :saturation
|
23
|
-
|
24
|
-
# Brightness of the group. This is a scale from the minimum
|
25
|
-
# brightness the group is capable of, 0, to the maximum capable
|
26
|
-
# brightness, 255. Note a brightness of 0 is not off.
|
27
|
-
attr_accessor :brightness
|
28
|
-
|
29
|
-
# The x coordinate of a color in CIE color space. Between 0 and 1.
|
30
|
-
#
|
31
|
-
# @see http://developers.meethue.com/coreconcepts.html#color_gets_more_complicated
|
32
|
-
attr_reader :x
|
33
|
-
|
34
|
-
# The y coordinate of a color in CIE color space. Between 0 and 1.
|
35
|
-
#
|
36
|
-
# @see http://developers.meethue.com/coreconcepts.html#color_gets_more_complicated
|
37
|
-
attr_reader :y
|
38
|
-
|
39
|
-
# The Mired Color temperature of the light. 2012 connected lights
|
40
|
-
# are capable of 153 (6500K) to 500 (2000K).
|
41
|
-
#
|
42
|
-
# @see http://en.wikipedia.org/wiki/Mired
|
43
|
-
attr_accessor :color_temperature
|
44
|
-
|
45
|
-
# A fixed name describing the type of group.
|
46
|
-
attr_reader :type
|
47
|
-
|
48
|
-
def initialize(client, bridge, id = nil, data = {})
|
49
|
-
@client = client
|
50
|
-
@bridge = bridge
|
51
|
-
@id = id
|
52
|
-
|
53
|
-
unpack(data)
|
54
|
-
end
|
55
|
-
|
56
|
-
def each(&block)
|
57
|
-
lights.each(&block)
|
58
|
-
end
|
59
|
-
|
60
|
-
def lights
|
61
|
-
@lights ||= begin
|
62
|
-
@light_ids.map do |light_id|
|
63
|
-
@client.light(light_id)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def name=(name)
|
69
|
-
resp = set_group_state({:name => name})
|
70
|
-
@name = new? ? name : resp[0]['success']["/groups/#{id}/name"]
|
71
|
-
end
|
72
|
-
|
73
|
-
def lights=(light_ids)
|
74
|
-
light_ids.map! do |light_id|
|
75
|
-
light_id.is_a?(Light) ? light_id.id : light_id.to_s
|
76
|
-
end
|
77
|
-
|
78
|
-
@light_ids = light_ids.uniq
|
79
|
-
@lights = nil # resets the memoization
|
80
|
-
|
81
|
-
set_group_state({:lights => @light_ids})
|
82
|
-
end
|
83
|
-
|
84
|
-
def scene=(scene)
|
85
|
-
scene_id = scene.is_a?(Scene) ? scene.id : scene
|
86
|
-
set_group_state({:scene => scene_id})
|
87
|
-
end
|
88
|
-
|
89
|
-
def <<(light_id)
|
90
|
-
@light_ids << light_id
|
91
|
-
set_group_state({:lights => @light_ids})
|
92
|
-
end
|
93
|
-
alias_method :add_light, :<<
|
94
|
-
|
95
|
-
def set_group_state(attributes)
|
96
|
-
return if new?
|
97
|
-
body = translate_keys(attributes, GROUP_KEYS_MAP)
|
98
|
-
|
99
|
-
uri = URI.parse(base_url)
|
100
|
-
http = Net::HTTP.new(uri.host)
|
101
|
-
response = http.request_put(uri.path, JSON.dump(body))
|
102
|
-
JSON(response.body)
|
103
|
-
end
|
104
|
-
|
105
|
-
def set_state(attributes)
|
106
|
-
return if new?
|
107
|
-
body = translate_keys(attributes, STATE_KEYS_MAP)
|
108
|
-
|
109
|
-
uri = URI.parse("#{base_url}/action")
|
110
|
-
http = Net::HTTP.new(uri.host)
|
111
|
-
response = http.request_put(uri.path, JSON.dump(body))
|
112
|
-
JSON(response.body)
|
113
|
-
end
|
114
|
-
|
115
|
-
def refresh
|
116
|
-
json = JSON(Net::HTTP.get(URI.parse(base_url)))
|
117
|
-
unpack(json)
|
118
|
-
@lights = nil
|
119
|
-
end
|
120
|
-
|
121
|
-
def create!
|
122
|
-
body = {
|
123
|
-
:name => @name,
|
124
|
-
:lights => @light_ids,
|
125
|
-
}
|
126
|
-
|
127
|
-
uri = URI.parse("http://#{@bridge.ip}/api/#{@client.username}/groups")
|
128
|
-
http = Net::HTTP.new(uri.host)
|
129
|
-
response = http.request_post(uri.path, JSON.dump(body))
|
130
|
-
json = JSON(response.body)
|
131
|
-
|
132
|
-
@id = json[0]['success']['id']
|
133
|
-
end
|
134
|
-
|
135
|
-
def destroy!
|
136
|
-
uri = URI.parse(base_url)
|
137
|
-
http = Net::HTTP.new(uri.host)
|
138
|
-
response = http.delete(uri.path)
|
139
|
-
json = JSON(response.body)
|
140
|
-
@id = nil if json[0]['success']
|
141
|
-
end
|
142
|
-
|
143
|
-
def new?
|
144
|
-
@id.nil?
|
145
|
-
end
|
146
|
-
|
147
|
-
private
|
148
|
-
|
149
|
-
GROUP_KEYS_MAP = {
|
150
|
-
:name => :name,
|
151
|
-
:light_ids => :lights,
|
152
|
-
:type => :type,
|
153
|
-
:state => :action
|
154
|
-
}
|
155
|
-
|
156
|
-
STATE_KEYS_MAP = {
|
157
|
-
:on => :on,
|
158
|
-
:brightness => :bri,
|
159
|
-
:hue => :hue,
|
160
|
-
:saturation => :sat,
|
161
|
-
:xy => :xy,
|
162
|
-
:color_temperature => :ct,
|
163
|
-
:alert => :alert,
|
164
|
-
:effect => :effect,
|
165
|
-
:color_mode => :colormode,
|
166
|
-
}
|
167
|
-
|
168
|
-
def unpack(data)
|
169
|
-
unpack_hash(data, GROUP_KEYS_MAP)
|
170
|
-
|
171
|
-
unless new?
|
172
|
-
unpack_hash(@state, STATE_KEYS_MAP)
|
173
|
-
@x, @y = @state['xy']
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def base_url
|
178
|
-
"http://#{@bridge.ip}/api/#{@client.username}/groups/#{id}"
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
data/lib/hue/light.rb
DELETED
@@ -1,177 +0,0 @@
|
|
1
|
-
module Hue
|
2
|
-
class Light
|
3
|
-
include TranslateKeys
|
4
|
-
include EditableState
|
5
|
-
|
6
|
-
HUE_RANGE = 0..65535
|
7
|
-
SATURATION_RANGE = 0..255
|
8
|
-
BRIGHTNESS_RANGE = 0..255
|
9
|
-
COLOR_TEMPERATURE_RANGE = 153..500
|
10
|
-
|
11
|
-
# Unique identification number.
|
12
|
-
attr_reader :id
|
13
|
-
|
14
|
-
# Bridge the light is associated with
|
15
|
-
attr_reader :bridge
|
16
|
-
|
17
|
-
# A unique, editable name given to the light.
|
18
|
-
attr_accessor :name
|
19
|
-
|
20
|
-
# Hue of the light. This is a wrapping value between 0 and 65535.
|
21
|
-
# Both 0 and 65535 are red, 25500 is green and 46920 is blue.
|
22
|
-
attr_reader :hue
|
23
|
-
|
24
|
-
# Saturation of the light. 255 is the most saturated (colored)
|
25
|
-
# and 0 is the least saturated (white).
|
26
|
-
attr_reader :saturation
|
27
|
-
|
28
|
-
# Brightness of the light. This is a scale from the minimum
|
29
|
-
# brightness the light is capable of, 0, to the maximum capable
|
30
|
-
# brightness, 255. Note a brightness of 0 is not off.
|
31
|
-
attr_reader :brightness
|
32
|
-
|
33
|
-
# The x coordinate of a color in CIE color space. Between 0 and 1.
|
34
|
-
#
|
35
|
-
# @see http://developers.meethue.com/coreconcepts.html#color_gets_more_complicated
|
36
|
-
attr_reader :x
|
37
|
-
|
38
|
-
# The y coordinate of a color in CIE color space. Between 0 and 1.
|
39
|
-
#
|
40
|
-
# @see http://developers.meethue.com/coreconcepts.html#color_gets_more_complicated
|
41
|
-
attr_reader :y
|
42
|
-
|
43
|
-
# The Mired Color temperature of the light. 2012 connected lights
|
44
|
-
# are capable of 153 (6500K) to 500 (2000K).
|
45
|
-
#
|
46
|
-
# @see http://en.wikipedia.org/wiki/Mired
|
47
|
-
attr_reader :color_temperature
|
48
|
-
|
49
|
-
# The alert effect, which is a temporary change to the bulb’s state.
|
50
|
-
# This can take one of the following values:
|
51
|
-
# * `none` – The light is not performing an alert effect.
|
52
|
-
# * `select` – The light is performing one breathe cycle.
|
53
|
-
# * `lselect` – The light is performing breathe cycles for 30 seconds
|
54
|
-
# or until an "alert": "none" command is received.
|
55
|
-
#
|
56
|
-
# Note that in version 1.0 this contains the last alert sent to the
|
57
|
-
# light and not its current state. This will be changed to contain the
|
58
|
-
# current state in an upcoming patch.
|
59
|
-
#
|
60
|
-
# @see http://developers.meethue.com/coreconcepts.html#some_extra_fun_stuff
|
61
|
-
attr_reader :alert
|
62
|
-
|
63
|
-
# The dynamic effect of the light, can either be `none` or
|
64
|
-
# `colorloop`. If set to colorloop, the light will cycle through
|
65
|
-
# all hues using the current brightness and saturation settings.
|
66
|
-
attr_reader :effect
|
67
|
-
|
68
|
-
# Indicates the color mode in which the light is working, this is
|
69
|
-
# the last command type it received. Values are `hs` for Hue and
|
70
|
-
# Saturation, `xy` for XY and `ct` for Color Temperature. This
|
71
|
-
# parameter is only present when the light supports at least one
|
72
|
-
# of the values.
|
73
|
-
attr_reader :color_mode
|
74
|
-
|
75
|
-
# A fixed name describing the type of light.
|
76
|
-
attr_reader :type
|
77
|
-
|
78
|
-
# The hardware model of the light.
|
79
|
-
attr_reader :model
|
80
|
-
|
81
|
-
# An identifier for the software version running on the light.
|
82
|
-
attr_reader :software_version
|
83
|
-
|
84
|
-
# Reserved for future functionality.
|
85
|
-
attr_reader :point_symbol
|
86
|
-
|
87
|
-
def initialize(client, bridge, id, hash)
|
88
|
-
@client = client
|
89
|
-
@bridge = bridge
|
90
|
-
@id = id
|
91
|
-
unpack(hash)
|
92
|
-
end
|
93
|
-
|
94
|
-
def name=(new_name)
|
95
|
-
unless (1..32).include?(new_name.length)
|
96
|
-
raise InvalidValueForParameter, 'name must be between 1 and 32 characters.'
|
97
|
-
end
|
98
|
-
|
99
|
-
body = {
|
100
|
-
:name => new_name
|
101
|
-
}
|
102
|
-
|
103
|
-
uri = URI.parse(base_url)
|
104
|
-
http = Net::HTTP.new(uri.host)
|
105
|
-
response = http.request_put(uri.path, JSON.dump(body))
|
106
|
-
response = JSON(response.body).first
|
107
|
-
if response['success']
|
108
|
-
@name = new_name
|
109
|
-
# else
|
110
|
-
# TODO: Error
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Indicates if a light can be reached by the bridge. Currently
|
115
|
-
# always returns true, functionality will be added in a future
|
116
|
-
# patch.
|
117
|
-
def reachable?
|
118
|
-
@state['reachable']
|
119
|
-
end
|
120
|
-
|
121
|
-
# @param transition The duration of the transition from the light’s current
|
122
|
-
# state to the new state. This is given as a multiple of 100ms and
|
123
|
-
# defaults to 4 (400ms). For example, setting transistiontime:10 will
|
124
|
-
# make the transition last 1 second.
|
125
|
-
def set_state(attributes, transition = nil)
|
126
|
-
body = translate_keys(attributes, STATE_KEYS_MAP)
|
127
|
-
|
128
|
-
# Add transition
|
129
|
-
body.merge!({:transitiontime => transition}) if transition
|
130
|
-
|
131
|
-
uri = URI.parse("#{base_url}/state")
|
132
|
-
http = Net::HTTP.new(uri.host)
|
133
|
-
response = http.request_put(uri.path, JSON.dump(body))
|
134
|
-
JSON(response.body)
|
135
|
-
end
|
136
|
-
|
137
|
-
# Refresh the state of the lamp
|
138
|
-
def refresh
|
139
|
-
json = JSON(Net::HTTP.get(URI.parse(base_url)))
|
140
|
-
unpack(json)
|
141
|
-
end
|
142
|
-
|
143
|
-
private
|
144
|
-
|
145
|
-
KEYS_MAP = {
|
146
|
-
:state => :state,
|
147
|
-
:type => :type,
|
148
|
-
:name => :name,
|
149
|
-
:model => :modelid,
|
150
|
-
:software_version => :swversion,
|
151
|
-
:point_symbol => :pointsymbol
|
152
|
-
}
|
153
|
-
|
154
|
-
STATE_KEYS_MAP = {
|
155
|
-
:on => :on,
|
156
|
-
:brightness => :bri,
|
157
|
-
:hue => :hue,
|
158
|
-
:saturation => :sat,
|
159
|
-
:xy => :xy,
|
160
|
-
:color_temperature => :ct,
|
161
|
-
:alert => :alert,
|
162
|
-
:effect => :effect,
|
163
|
-
:color_mode => :colormode,
|
164
|
-
:reachable => :reachable,
|
165
|
-
}
|
166
|
-
|
167
|
-
def unpack(hash)
|
168
|
-
unpack_hash(hash, KEYS_MAP)
|
169
|
-
unpack_hash(@state, STATE_KEYS_MAP)
|
170
|
-
@x, @y = @state['xy']
|
171
|
-
end
|
172
|
-
|
173
|
-
def base_url
|
174
|
-
"http://#{@bridge.ip}/api/#{@client.username}/lights/#{id}"
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|