hue 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/main.yml +29 -0
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +5 -2
- data/LICENSE +1 -1
- data/{Readme.markdown → README.md} +0 -5
- data/Rakefile +10 -8
- data/bin/console +7 -0
- data/bin/hue +5 -1
- data/hue.gemspec +17 -22
- data/lib/hue/bridge.rb +21 -18
- data/lib/hue/cli.rb +30 -30
- data/lib/hue/client.rb +64 -32
- data/lib/hue/editable_state.rb +42 -5
- data/lib/hue/errors.rb +22 -8
- data/lib/hue/group.rb +28 -30
- data/lib/hue/light.rb +40 -31
- data/lib/hue/scene.rb +5 -7
- data/lib/hue/translate_keys.rb +1 -1
- data/lib/hue/version.rb +1 -1
- data/lib/hue.rb +9 -9
- data/test/hue/client_test.rb +26 -0
- data/test/hue/light_test.rb +44 -0
- data/test/test_helper.rb +6 -0
- metadata +17 -60
- data/.rspec +0 -2
- data/Contributing.markdown +0 -19
- data/Todo.markdown +0 -8
- data/spec/hue/light_spec.rb +0 -24
- data/spec/spec_helper.rb +0 -94
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 17b9710dcfb0defef023c1adb4c4da4ca86fddc6f2e6c0d971bcb562c57ec61a
|
4
|
+
data.tar.gz: 8d8afd006ca7892d74f33af84f4040aedd0718b13583e1708a6994bb7803c3d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d3a2e81c450c2d1dd5c94ade3cf146ea4f56f4102f710051c54185902c388f9c9494a6f597f3f0ee05b59d0b0ade9ba837c2a7983df9679ce14ea34dd07e9eb
|
7
|
+
data.tar.gz: eea449790732dbcfcd0795f1e01af3d6d1a19b800c3b41404fe0bd1a12a76fa706f59269f90320365dde650c6425811fca9bd0ea38558945e8d8c0800badcdc4
|
@@ -0,0 +1,29 @@
|
|
1
|
+
name: Tests
|
2
|
+
on: [push]
|
3
|
+
jobs:
|
4
|
+
test:
|
5
|
+
name: Test
|
6
|
+
runs-on: ubuntu-latest
|
7
|
+
timeout-minutes: 5
|
8
|
+
steps:
|
9
|
+
- name: Checkout
|
10
|
+
uses: actions/checkout@v4
|
11
|
+
- name: Setup Ruby
|
12
|
+
uses: ruby/setup-ruby@v1
|
13
|
+
with:
|
14
|
+
bundler-cache: true
|
15
|
+
- name: Test
|
16
|
+
run: bundle exec rake test
|
17
|
+
lint:
|
18
|
+
name: Lint
|
19
|
+
runs-on: ubuntu-latest
|
20
|
+
timeout-minutes: 5
|
21
|
+
steps:
|
22
|
+
- name: Checkout
|
23
|
+
uses: actions/checkout@v4
|
24
|
+
- name: Setup Ruby
|
25
|
+
uses: ruby/setup-ruby@v1
|
26
|
+
with:
|
27
|
+
bundler-cache: true
|
28
|
+
- name: Test
|
29
|
+
run: bundle exec rake standard
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.2.2
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
Work with Philips Hue light bulbs from Ruby.
|
4
4
|
|
5
|
-
[](https://codeclimate.com/github/soffes/hue) [](https://gemnasium.com/soffes/hue) [](http://badge.fury.io/rb/hue)
|
6
5
|
|
7
6
|
## Installation
|
8
7
|
|
@@ -78,7 +77,3 @@ group.new? # => false
|
|
78
77
|
# Destroying groups
|
79
78
|
client.groups.last.destroy!
|
80
79
|
```
|
81
|
-
|
82
|
-
## Contributing
|
83
|
-
|
84
|
-
See the [contributing guide](Contributing.markdown).
|
data/Rakefile
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
require
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
task :default => :spec
|
8
|
-
rescue LoadError
|
9
|
-
# no rspec available
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << "test"
|
6
|
+
t.libs << "lib"
|
7
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
10
8
|
end
|
9
|
+
|
10
|
+
require "standard/rake"
|
11
|
+
|
12
|
+
task default: :test
|
data/bin/console
ADDED
data/bin/hue
CHANGED
@@ -5,4 +5,8 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
5
|
require 'hue'
|
6
6
|
require 'hue/cli'
|
7
7
|
|
8
|
-
|
8
|
+
begin
|
9
|
+
Hue::Cli.start
|
10
|
+
rescue Hue::LinkButtonNotPressed
|
11
|
+
abort("Error: Press the link button on your bridge and then run this command again within 30 seconds of pressing it.")
|
12
|
+
end
|
data/hue.gemspec
CHANGED
@@ -1,28 +1,23 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
3
|
+
require "hue/version"
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name
|
8
|
-
spec.version
|
9
|
-
spec.authors
|
10
|
-
spec.email
|
11
|
-
spec.description
|
12
|
-
spec.summary
|
13
|
-
spec.homepage
|
14
|
-
spec.license
|
6
|
+
spec.name = "hue"
|
7
|
+
spec.version = Hue::VERSION
|
8
|
+
spec.authors = ["Sam Soffes"]
|
9
|
+
spec.email = ["sam@soff.es"]
|
10
|
+
spec.description = "Work with Philips Hue light bulbs."
|
11
|
+
spec.summary = "Work with Philips Hue light bulbs from Ruby."
|
12
|
+
spec.homepage = "https://github.com/soffes/hue"
|
13
|
+
spec.license = "MIT"
|
15
14
|
|
16
|
-
spec.files
|
17
|
-
spec.executables
|
18
|
-
spec.
|
19
|
-
spec.require_paths = ['lib']
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.require_paths = ["lib"]
|
20
18
|
|
21
|
-
spec.required_ruby_version =
|
22
|
-
spec.add_dependency
|
23
|
-
spec.add_dependency
|
24
|
-
spec.add_dependency
|
25
|
-
spec.add_dependency 'curb'
|
26
|
-
spec.add_development_dependency 'rspec', '~> 3.2.0'
|
27
|
-
spec.add_development_dependency 'webmock'
|
19
|
+
spec.required_ruby_version = ">= 2.1.0"
|
20
|
+
spec.add_dependency "thor"
|
21
|
+
spec.add_dependency "json"
|
22
|
+
spec.add_dependency "color_conversion"
|
28
23
|
end
|
data/lib/hue/bridge.rb
CHANGED
@@ -46,32 +46,35 @@ module Hue
|
|
46
46
|
# Current time stored on the bridge.
|
47
47
|
def utc
|
48
48
|
json = get_configuration
|
49
|
-
DateTime.parse(json[
|
49
|
+
DateTime.parse(json["utc"])
|
50
50
|
end
|
51
51
|
|
52
52
|
# Indicates whether the link button has been pressed within the last 30
|
53
53
|
# seconds.
|
54
54
|
def link_button_pressed?
|
55
55
|
json = get_configuration
|
56
|
-
json[
|
56
|
+
json["linkbutton"]
|
57
57
|
end
|
58
58
|
|
59
59
|
# This indicates whether the bridge is registered to synchronize data with a
|
60
60
|
# portal account.
|
61
61
|
def has_portal_services?
|
62
62
|
json = get_configuration
|
63
|
-
json[
|
63
|
+
json["portalservices"]
|
64
64
|
end
|
65
65
|
|
66
66
|
def refresh
|
67
67
|
json = get_configuration
|
68
68
|
unpack(json)
|
69
|
+
@lights = nil
|
70
|
+
@groups = nil
|
71
|
+
@scenes = nil
|
69
72
|
end
|
70
73
|
|
71
74
|
def lights
|
72
75
|
@lights ||= begin
|
73
76
|
json = JSON(Net::HTTP.get(URI.parse(base_url)))
|
74
|
-
json[
|
77
|
+
json["lights"].map do |key, value|
|
75
78
|
Light.new(@client, self, key, value)
|
76
79
|
end
|
77
80
|
end
|
@@ -81,7 +84,7 @@ module Hue
|
|
81
84
|
uri = URI.parse("#{base_url}/lights")
|
82
85
|
http = Net::HTTP.new(uri.host)
|
83
86
|
response = http.request_post(uri.path, nil)
|
84
|
-
|
87
|
+
response.body.first
|
85
88
|
end
|
86
89
|
|
87
90
|
def groups
|
@@ -102,27 +105,27 @@ module Hue
|
|
102
105
|
end
|
103
106
|
end
|
104
107
|
|
105
|
-
|
108
|
+
private
|
106
109
|
|
107
110
|
KEYS_MAP = {
|
108
|
-
:
|
109
|
-
:
|
110
|
-
:
|
111
|
-
:
|
112
|
-
:
|
113
|
-
:
|
114
|
-
:
|
115
|
-
:
|
116
|
-
:
|
117
|
-
:
|
118
|
-
:
|
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
|
119
122
|
}
|
120
123
|
|
121
124
|
def unpack(hash)
|
122
125
|
KEYS_MAP.each do |local_key, remote_key|
|
123
126
|
value = hash[remote_key.to_s]
|
124
127
|
next unless value
|
125
|
-
instance_variable_set("@#{local_key}", value)
|
128
|
+
instance_variable_set(:"@#{local_key}", value)
|
126
129
|
end
|
127
130
|
end
|
128
131
|
|
data/lib/hue/cli.rb
CHANGED
@@ -1,67 +1,67 @@
|
|
1
|
-
require
|
1
|
+
require "thor"
|
2
2
|
|
3
3
|
module Hue
|
4
4
|
class Cli < Thor
|
5
|
-
desc
|
5
|
+
desc "lights", "Find all of the lights on your network"
|
6
6
|
def lights
|
7
7
|
client.lights.each do |light|
|
8
8
|
puts light.id.to_s.ljust(6) + light.name
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
desc
|
12
|
+
desc "add LIGHTS", "Search for new lights"
|
13
13
|
def add(thing)
|
14
14
|
case thing
|
15
|
-
when
|
15
|
+
when "lights"
|
16
16
|
client.add_lights
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
desc
|
20
|
+
desc "light ID STATE [COLOR]", "Access a light"
|
21
21
|
long_desc <<-LONGDESC
|
22
22
|
Examples: \n
|
23
23
|
hue all on \n
|
24
24
|
hue all off \n
|
25
25
|
hue all --hue 12345 \n
|
26
|
-
hue all --
|
27
|
-
hue all --hue 50000 --
|
26
|
+
hue all --brightness 25 \n
|
27
|
+
hue all --hue 50000 --brightness 200 --saturation 240 \n
|
28
28
|
hue all --alert lselect \n
|
29
29
|
LONGDESC
|
30
|
-
option :hue, :
|
31
|
-
option :sat, :
|
32
|
-
option :bri, :
|
33
|
-
option :alert, :
|
34
|
-
desc
|
35
|
-
def all(state =
|
30
|
+
option :hue, type: :numeric
|
31
|
+
option :sat, type: :numeric, aliases: "--saturation"
|
32
|
+
option :bri, type: :numeric, aliases: "--brightness"
|
33
|
+
option :alert, type: :string
|
34
|
+
desc "all STATE", "Send commands to all lights"
|
35
|
+
def all(state = "on")
|
36
36
|
body = options.dup
|
37
|
-
body[:on] = state ==
|
37
|
+
body[:on] = state == "on"
|
38
38
|
client.lights.each do |light|
|
39
39
|
puts light.set_state body
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
desc
|
43
|
+
desc "light ID STATE [COLOR]", "Access a light"
|
44
44
|
long_desc <<-LONGDESC
|
45
45
|
Examples: \n
|
46
46
|
hue light 1 on --hue 12345 \n
|
47
|
-
hue light 1 --
|
47
|
+
hue light 1 --brightness 25 \n
|
48
48
|
hue light 1 --alert lselect \n
|
49
49
|
hue light 1 off
|
50
50
|
LONGDESC
|
51
|
-
option :hue, :
|
52
|
-
option :sat, :
|
53
|
-
option :
|
54
|
-
option :alert, :
|
51
|
+
option :hue, type: :numeric
|
52
|
+
option :sat, type: :numeric, aliases: "--saturation"
|
53
|
+
option :bri, type: :numeric, aliases: "--brightness"
|
54
|
+
option :alert, type: :string
|
55
55
|
def light(id, state = nil)
|
56
56
|
light = client.light(id)
|
57
57
|
puts light.name
|
58
58
|
|
59
59
|
body = options.dup
|
60
|
-
body[:on] = (state ==
|
60
|
+
body[:on] = (state == "on" || !(state == "off"))
|
61
61
|
puts light.set_state(body) if body.length > 0
|
62
62
|
end
|
63
63
|
|
64
|
-
desc
|
64
|
+
desc "groups", "Find all light groups on your network"
|
65
65
|
def groups
|
66
66
|
client.groups.each do |group|
|
67
67
|
puts group.id.to_s.ljust(6) + group.name
|
@@ -71,28 +71,28 @@ module Hue
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
desc
|
74
|
+
desc "group ID STATE [COLOR]", "Update a group of lights"
|
75
75
|
long_desc <<-LONGDESC
|
76
76
|
Examples: \n
|
77
77
|
hue groups 1 on --hue 12345
|
78
|
-
hue groups 1 --
|
78
|
+
hue groups 1 --brightness 25
|
79
79
|
hue groups 1 --alert lselect
|
80
80
|
hue groups 1 off
|
81
81
|
LONGDESC
|
82
|
-
option :hue, :
|
83
|
-
option :sat, :
|
84
|
-
option :
|
85
|
-
option :alert, :
|
82
|
+
option :hue, type: :numeric
|
83
|
+
option :sat, type: :numeric, aliases: "--saturation"
|
84
|
+
option :bri, type: :numeric, aliases: "--brightness"
|
85
|
+
option :alert, type: :string
|
86
86
|
def group(id, state = nil)
|
87
87
|
group = client.group(id)
|
88
88
|
puts group.name
|
89
89
|
|
90
90
|
body = options.dup
|
91
|
-
body[:on] = (state ==
|
91
|
+
body[:on] = (state == "on" || !(state == "off"))
|
92
92
|
puts group.set_state(body) if body.length > 0
|
93
93
|
end
|
94
94
|
|
95
|
-
|
95
|
+
private
|
96
96
|
|
97
97
|
def client
|
98
98
|
@client ||= Hue::Client.new
|
data/lib/hue/client.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "net/http"
|
2
|
+
require "json"
|
3
|
+
require "resolv"
|
4
4
|
|
5
5
|
module Hue
|
6
6
|
class Client
|
7
7
|
attr_reader :username
|
8
8
|
|
9
|
-
def initialize(username = nil)
|
10
|
-
|
11
|
-
|
12
|
-
@
|
9
|
+
def initialize(username = nil, use_mdns: true)
|
10
|
+
@bridge_id = nil
|
11
|
+
@username = username || find_username
|
12
|
+
@use_mdns = use_mdns
|
13
13
|
|
14
14
|
if @username
|
15
15
|
begin
|
@@ -23,8 +23,12 @@ module Hue
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def bridge
|
26
|
-
|
27
|
-
bridge =
|
26
|
+
@bridge_id ||= find_bridge_id
|
27
|
+
bridge = if @bridge_id
|
28
|
+
bridges.find { |b| b.id == @bridge_id }
|
29
|
+
else
|
30
|
+
bridges.first
|
31
|
+
end
|
28
32
|
raise NoBridgeFound unless bridge
|
29
33
|
bridge
|
30
34
|
end
|
@@ -32,14 +36,8 @@ module Hue
|
|
32
36
|
def bridges
|
33
37
|
@bridges ||= begin
|
34
38
|
bs = []
|
35
|
-
|
36
|
-
|
37
|
-
easy.max_redirects = 10
|
38
|
-
easy.url = 'https://www.meethue.com/api/nupnp'
|
39
|
-
easy.perform
|
40
|
-
JSON(easy.body).each do |hash|
|
41
|
-
bs << Bridge.new(self, hash)
|
42
|
-
end
|
39
|
+
discovery_mdns(bs) if @use_mdns
|
40
|
+
discovery_meethue(bs) if bs.empty?
|
43
41
|
bs
|
44
42
|
end
|
45
43
|
end
|
@@ -54,7 +52,7 @@ module Hue
|
|
54
52
|
|
55
53
|
def light(id)
|
56
54
|
id = id.to_s
|
57
|
-
lights.
|
55
|
+
lights.find { |l| l.id == id }
|
58
56
|
end
|
59
57
|
|
60
58
|
def groups
|
@@ -65,7 +63,7 @@ module Hue
|
|
65
63
|
return Group.new(self, bridge) if id.nil?
|
66
64
|
|
67
65
|
id = id.to_s
|
68
|
-
groups.
|
66
|
+
groups.find { |g| g.id == id }
|
69
67
|
end
|
70
68
|
|
71
69
|
def scenes
|
@@ -74,18 +72,18 @@ module Hue
|
|
74
72
|
|
75
73
|
def scene(id)
|
76
74
|
id = id.to_s
|
77
|
-
scenes.
|
75
|
+
scenes.find { |s| s.id == id }
|
78
76
|
end
|
79
77
|
|
80
78
|
private
|
81
79
|
|
82
80
|
def find_username
|
83
|
-
return ENV[
|
81
|
+
return ENV["HUE_USERNAME"] if ENV["HUE_USERNAME"]
|
84
82
|
|
85
|
-
json = JSON(File.read(File.expand_path(
|
86
|
-
json[
|
83
|
+
json = JSON(File.read(File.expand_path("~/.hue")))
|
84
|
+
json["username"]
|
87
85
|
rescue
|
88
|
-
|
86
|
+
nil
|
89
87
|
end
|
90
88
|
|
91
89
|
def validate_user
|
@@ -95,35 +93,69 @@ module Hue
|
|
95
93
|
response = response.first
|
96
94
|
end
|
97
95
|
|
98
|
-
if error = response[
|
96
|
+
if (error = response["error"])
|
99
97
|
raise get_error(error)
|
100
98
|
end
|
101
99
|
|
102
|
-
response[
|
100
|
+
response["success"]
|
103
101
|
end
|
104
102
|
|
105
103
|
def register_user
|
106
104
|
body = JSON.dump({
|
107
|
-
devicetype:
|
105
|
+
devicetype: "Ruby"
|
108
106
|
})
|
109
107
|
|
110
108
|
uri = URI.parse("http://#{bridge.ip}/api")
|
111
109
|
http = Net::HTTP.new(uri.host)
|
112
110
|
response = JSON(http.request_post(uri.path, body).body).first
|
113
111
|
|
114
|
-
if error = response[
|
112
|
+
if (error = response["error"])
|
115
113
|
raise get_error(error)
|
116
114
|
end
|
117
115
|
|
118
|
-
if @username = response[
|
119
|
-
File.write(File.expand_path(
|
116
|
+
if (@username = response["success"]["username"])
|
117
|
+
File.write(File.expand_path("~/.hue"), JSON.dump({username: @username}))
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def find_bridge_id
|
122
|
+
return ENV["HUE_BRIDGE_ID"] if ENV["HUE_BRIDGE_ID"]
|
123
|
+
|
124
|
+
json = JSON(File.read(File.expand_path("~/.hue")))
|
125
|
+
json["bridge_id"]
|
126
|
+
rescue
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def discovery_mdns(bs)
|
131
|
+
resolver = Resolv::MDNS.new
|
132
|
+
resolver.timeouts = 10
|
133
|
+
|
134
|
+
resolver.each_resource("_hue._tcp.local", Resolv::DNS::Resource::IN::PTR) do |bridge_ptr|
|
135
|
+
bridge_target = resolver.getresource(bridge_ptr.name, Resolv::DNS::Resource::IN::SRV).target
|
136
|
+
|
137
|
+
bridge_hash = {
|
138
|
+
"id" => resolver.getresource(bridge_ptr.name, Resolv::DNS::Resource::IN::TXT).strings[0].split("=")[1],
|
139
|
+
"internalipaddress" => resolver.getresource(bridge_target, Resolv::DNS::Resource::IN::A).address
|
140
|
+
}
|
141
|
+
|
142
|
+
bs << Bridge.new(self, bridge_hash)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def discovery_meethue(bs)
|
147
|
+
uri = URI("https://discovery.meethue.com/")
|
148
|
+
response = Net::HTTP.get(uri)
|
149
|
+
|
150
|
+
JSON(response).each do |hash|
|
151
|
+
bs << Bridge.new(self, hash)
|
120
152
|
end
|
121
153
|
end
|
122
154
|
|
123
155
|
def get_error(error)
|
124
156
|
# Find error class and return instance
|
125
|
-
klass
|
126
|
-
klass.new(error[
|
157
|
+
klass ||= Hue::ERROR_MAP[error["type"]] || UnknownError
|
158
|
+
klass.new(error["description"])
|
127
159
|
end
|
128
160
|
end
|
129
161
|
end
|
data/lib/hue/editable_state.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
+
require "color_conversion"
|
2
|
+
|
1
3
|
module Hue
|
2
4
|
module EditableState
|
5
|
+
HUE_RANGE = 0..65535
|
6
|
+
SATURATION_RANGE = 0..254
|
7
|
+
BRIGHTNESS_RANGE = 0..254
|
8
|
+
|
3
9
|
def on?
|
4
|
-
@
|
10
|
+
@on || false
|
5
11
|
end
|
6
12
|
|
7
13
|
def on!
|
@@ -12,16 +18,47 @@ module Hue
|
|
12
18
|
self.on = false
|
13
19
|
end
|
14
20
|
|
15
|
-
|
16
|
-
|
21
|
+
# Turn the light on if it's off and vice versa
|
22
|
+
def toggle!
|
23
|
+
if @on
|
24
|
+
off!
|
25
|
+
else
|
26
|
+
on!
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
%w[on hue saturation brightness color_temperature alert effect].each do |key|
|
31
|
+
define_method :"#{key}=" do |value|
|
17
32
|
set_state({key.to_sym => value})
|
18
|
-
instance_variable_set("@#{key}"
|
33
|
+
instance_variable_set(:"@#{key}", value)
|
19
34
|
end
|
20
35
|
end
|
21
36
|
|
22
37
|
def set_xy(x, y)
|
23
|
-
set_state({:
|
38
|
+
set_state({xy: [x, y]})
|
24
39
|
@x, @y = x, y
|
25
40
|
end
|
41
|
+
|
42
|
+
def hex
|
43
|
+
ColorConversion::Color.new(h: hue, s: saturation, b: brightness).hex
|
44
|
+
end
|
45
|
+
|
46
|
+
def hex=(hex)
|
47
|
+
hex = "##{hex}" unless hex.start_with?("#")
|
48
|
+
hsb = ColorConversion::Color.new(hex).hsb
|
49
|
+
|
50
|
+
# Map values from standard HSB to what Hue wants and update state
|
51
|
+
state = {
|
52
|
+
hue: ((hsb[:h].to_f / 360.0) * HUE_RANGE.last.to_f).to_i,
|
53
|
+
saturation: ((hsb[:s].to_f / 100.0) * SATURATION_RANGE.last.to_f).to_i,
|
54
|
+
brightness: ((hsb[:b].to_f / 100.0) * BRIGHTNESS_RANGE.last.to_f).to_i
|
55
|
+
}
|
56
|
+
|
57
|
+
set_state(state)
|
58
|
+
|
59
|
+
@hue = state[:hue]
|
60
|
+
@saturation = state[:saturation]
|
61
|
+
@brightness = state[:brightness]
|
62
|
+
end
|
26
63
|
end
|
27
64
|
end
|