hue 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Code Climate](https://codeclimate.com/github/soffes/hue.png)](https://codeclimate.com/github/soffes/hue) [![Dependency Status](https://gemnasium.com/soffes/hue.png)](https://gemnasium.com/soffes/hue) [![Gem Version](https://badge.fury.io/rb/hue.png)](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
|