hue 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af74df93c5514679bab0613c9c6c87b0a0dfae19b919fc903ad42a8fafe9b681
4
- data.tar.gz: 0afb9bd5b7ee11be0a1dce6b56846c6d13fa7cd9a9b67e2f9c8014c8d03f0fb7
3
+ metadata.gz: 17b9710dcfb0defef023c1adb4c4da4ca86fddc6f2e6c0d971bcb562c57ec61a
4
+ data.tar.gz: 8d8afd006ca7892d74f33af84f4040aedd0718b13583e1708a6994bb7803c3d9
5
5
  SHA512:
6
- metadata.gz: 00f64a5fdad18722af090747e6a2dfe2a5fefb556bcd634ee7b498f54df80e23e94975c295a2925a46cf2166e88df0af07dee1999e26446f7e42e66ebbc8778b
7
- data.tar.gz: f54f5552bceb7456b0a1d6ccdc29f7ca3cb01636231d83a5f0d7d93b907defce6bfbfcb0e2f96444e49543fbb85f7cda66586f72eedaea912c7a18f5ededb570
6
+ metadata.gz: 8d3a2e81c450c2d1dd5c94ade3cf146ea4f56f4102f710051c54185902c388f9c9494a6f597f3f0ee05b59d0b0ade9ba837c2a7983df9679ce14ea34dd07e9eb
7
+ data.tar.gz: eea449790732dbcfcd0795f1e01af3d6d1a19b800c3b41404fe0bd1a12a76fa706f59269f90320365dde650c6425811fca9bd0ea38558945e8d8c0800badcdc4
@@ -2,13 +2,28 @@ name: Tests
2
2
  on: [push]
3
3
  jobs:
4
4
  test:
5
- name: Test Swift Package
5
+ name: Test
6
6
  runs-on: ubuntu-latest
7
7
  timeout-minutes: 5
8
8
  steps:
9
- - uses: actions/checkout@v1
10
- - uses: actions/setup-ruby@v1
11
- - name: 'Install Dependencies'
12
- run: sudo apt-get install libcurl4-openssl-dev && gem install bundler && bundle install
13
- - name: 'Test'
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
14
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
@@ -1,3 +1,4 @@
1
+ .DS_Store
1
2
  *.gem
2
3
  *.rbc
3
4
  .bundle
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.2
data/Gemfile CHANGED
@@ -1,5 +1,8 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rake'
5
+ gem "rake", "~> 13.0"
6
+ gem "minitest", "~> 5.0"
7
+ gem "standard", "~> 1.3"
8
+ gem "webmock", "~> 3.19"
data/Rakefile CHANGED
@@ -1,10 +1,12 @@
1
- require 'bundler/gem_tasks'
2
- require 'rake/testtask'
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
3
 
4
4
  Rake::TestTask.new(:test) do |t|
5
- t.libs << 'test'
6
- t.libs << 'lib'
7
- t.test_files = FileList['test/**/*_test.rb']
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
8
  end
9
9
 
10
- task :default => :test
10
+ require "standard/rake"
11
+
12
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'hue'
5
+
6
+ require 'irb'
7
+ IRB.start(__FILE__)
data/hue.gemspec CHANGED
@@ -1,28 +1,23 @@
1
- # coding: utf-8
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 'hue/version'
3
+ require "hue/version"
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = 'hue'
8
- spec.version = Hue::VERSION
9
- spec.authors = ['Sam Soffes']
10
- spec.email = ['sam@soff.es']
11
- spec.description = 'Work with Philips Hue light bulbs.'
12
- spec.summary = 'Work with Philips Hue light bulbs from Ruby.'
13
- spec.homepage = 'https://github.com/soffes/hue'
14
- spec.license = 'MIT'
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 = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
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 = '>= 2.1.0'
22
- spec.add_dependency 'thor'
23
- spec.add_dependency 'json'
24
- spec.add_dependency 'log_switch', '0.4.0'
25
- spec.add_dependency 'curb'
26
- spec.add_development_dependency 'minitest', '~> 5.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,21 +46,21 @@ module Hue
46
46
  # Current time stored on the bridge.
47
47
  def utc
48
48
  json = get_configuration
49
- DateTime.parse(json['utc'])
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['linkbutton']
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['portalservices']
63
+ json["portalservices"]
64
64
  end
65
65
 
66
66
  def refresh
@@ -74,7 +74,7 @@ module Hue
74
74
  def lights
75
75
  @lights ||= begin
76
76
  json = JSON(Net::HTTP.get(URI.parse(base_url)))
77
- json['lights'].map do |key, value|
77
+ json["lights"].map do |key, value|
78
78
  Light.new(@client, self, key, value)
79
79
  end
80
80
  end
@@ -84,7 +84,7 @@ module Hue
84
84
  uri = URI.parse("#{base_url}/lights")
85
85
  http = Net::HTTP.new(uri.host)
86
86
  response = http.request_post(uri.path, nil)
87
- (response.body).first
87
+ response.body.first
88
88
  end
89
89
 
90
90
  def groups
@@ -105,27 +105,27 @@ module Hue
105
105
  end
106
106
  end
107
107
 
108
- private
108
+ private
109
109
 
110
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,
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
122
  }
123
123
 
124
124
  def unpack(hash)
125
125
  KEYS_MAP.each do |local_key, remote_key|
126
126
  value = hash[remote_key.to_s]
127
127
  next unless value
128
- instance_variable_set("@#{local_key}", value)
128
+ instance_variable_set(:"@#{local_key}", value)
129
129
  end
130
130
  end
131
131
 
data/lib/hue/cli.rb CHANGED
@@ -1,67 +1,67 @@
1
- require 'thor'
1
+ require "thor"
2
2
 
3
3
  module Hue
4
4
  class Cli < Thor
5
- desc 'lights', 'Find all of the lights on your network'
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 'add LIGHTS', 'Search for new lights'
12
+ desc "add LIGHTS", "Search for new lights"
13
13
  def add(thing)
14
14
  case thing
15
- when 'lights'
15
+ when "lights"
16
16
  client.add_lights
17
17
  end
18
18
  end
19
19
 
20
- desc 'light ID STATE [COLOR]', 'Access a light'
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 --bri 25 \n
27
- hue all --hue 50000 --bri 200 --sat 240 \n
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, :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')
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 == 'on'
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 'light ID STATE [COLOR]', 'Access a light'
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 --bri 25 \n
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, :type => :numeric
52
- option :sat, :type => :numeric, :aliases => '--saturation'
53
- option :brightness, :type => :numeric, :aliases => '--brightness'
54
- option :alert, :type => :string
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 == 'on' || !(state == 'off'))
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 'groups', 'Find all light groups on your network'
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 'group ID STATE [COLOR]', 'Update a group of lights'
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 --bri 25
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, :type => :numeric
83
- option :sat, :type => :numeric, :aliases => '--saturation'
84
- option :brightness, :type => :numeric, :aliases => '--brightness'
85
- option :alert, :type => :string
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 == 'on' || !(state == 'off'))
91
+ body[:on] = (state == "on" || !(state == "off"))
92
92
  puts group.set_state(body) if body.length > 0
93
93
  end
94
94
 
95
- private
95
+ private
96
96
 
97
97
  def client
98
98
  @client ||= Hue::Client.new
data/lib/hue/client.rb CHANGED
@@ -1,7 +1,6 @@
1
- require 'net/http'
2
- require 'json'
3
- require 'resolv'
4
- require 'curb'
1
+ require "net/http"
2
+ require "json"
3
+ require "resolv"
5
4
 
6
5
  module Hue
7
6
  class Client
@@ -24,11 +23,11 @@ module Hue
24
23
  end
25
24
 
26
25
  def bridge
27
- @bridge_id = find_bridge_id unless @bridge_id
28
- if @bridge_id
29
- bridge = bridges.select { |b| b.id == @bridge_id }.first
26
+ @bridge_id ||= find_bridge_id
27
+ bridge = if @bridge_id
28
+ bridges.find { |b| b.id == @bridge_id }
30
29
  else
31
- bridge = bridges.first
30
+ bridges.first
32
31
  end
33
32
  raise NoBridgeFound unless bridge
34
33
  bridge
@@ -53,7 +52,7 @@ module Hue
53
52
 
54
53
  def light(id)
55
54
  id = id.to_s
56
- lights.select { |l| l.id == id }.first
55
+ lights.find { |l| l.id == id }
57
56
  end
58
57
 
59
58
  def groups
@@ -64,7 +63,7 @@ module Hue
64
63
  return Group.new(self, bridge) if id.nil?
65
64
 
66
65
  id = id.to_s
67
- groups.select { |g| g.id == id }.first
66
+ groups.find { |g| g.id == id }
68
67
  end
69
68
 
70
69
  def scenes
@@ -73,18 +72,18 @@ module Hue
73
72
 
74
73
  def scene(id)
75
74
  id = id.to_s
76
- scenes.select { |s| s.id == id }.first
75
+ scenes.find { |s| s.id == id }
77
76
  end
78
77
 
79
78
  private
80
79
 
81
80
  def find_username
82
- return ENV['HUE_USERNAME'] if ENV['HUE_USERNAME']
81
+ return ENV["HUE_USERNAME"] if ENV["HUE_USERNAME"]
83
82
 
84
- json = JSON(File.read(File.expand_path('~/.hue')))
85
- json['username']
83
+ json = JSON(File.read(File.expand_path("~/.hue")))
84
+ json["username"]
86
85
  rescue
87
- return nil
86
+ nil
88
87
  end
89
88
 
90
89
  def validate_user
@@ -94,38 +93,38 @@ module Hue
94
93
  response = response.first
95
94
  end
96
95
 
97
- if error = response['error']
96
+ if (error = response["error"])
98
97
  raise get_error(error)
99
98
  end
100
99
 
101
- response['success']
100
+ response["success"]
102
101
  end
103
102
 
104
103
  def register_user
105
104
  body = JSON.dump({
106
- devicetype: 'Ruby'
105
+ devicetype: "Ruby"
107
106
  })
108
107
 
109
108
  uri = URI.parse("http://#{bridge.ip}/api")
110
109
  http = Net::HTTP.new(uri.host)
111
110
  response = JSON(http.request_post(uri.path, body).body).first
112
111
 
113
- if error = response['error']
112
+ if (error = response["error"])
114
113
  raise get_error(error)
115
114
  end
116
115
 
117
- if @username = response['success']['username']
118
- File.write(File.expand_path('~/.hue'), JSON.dump({username: @username}))
116
+ if (@username = response["success"]["username"])
117
+ File.write(File.expand_path("~/.hue"), JSON.dump({username: @username}))
119
118
  end
120
119
  end
121
120
 
122
121
  def find_bridge_id
123
- return ENV['HUE_BRIDGE_ID'] if ENV['HUE_BRIDGE_ID']
122
+ return ENV["HUE_BRIDGE_ID"] if ENV["HUE_BRIDGE_ID"]
124
123
 
125
- json = JSON(File.read(File.expand_path('~/.hue')))
126
- json['bridge_id']
124
+ json = JSON(File.read(File.expand_path("~/.hue")))
125
+ json["bridge_id"]
127
126
  rescue
128
- return nil
127
+ nil
129
128
  end
130
129
 
131
130
  def discovery_mdns(bs)
@@ -136,8 +135,8 @@ module Hue
136
135
  bridge_target = resolver.getresource(bridge_ptr.name, Resolv::DNS::Resource::IN::SRV).target
137
136
 
138
137
  bridge_hash = {
139
- 'id' => resolver.getresource(bridge_ptr.name, Resolv::DNS::Resource::IN::TXT).strings[0].split('=')[1],
140
- 'internalipaddress' => resolver.getresource(bridge_target, Resolv::DNS::Resource::IN::A).address
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
141
140
  }
142
141
 
143
142
  bs << Bridge.new(self, bridge_hash)
@@ -145,20 +144,18 @@ module Hue
145
144
  end
146
145
 
147
146
  def discovery_meethue(bs)
148
- easy = Curl::Easy.new
149
- easy.follow_location = true
150
- easy.max_redirects = 10
151
- easy.url = 'https://discovery.meethue.com/'
152
- easy.perform
153
- JSON(easy.body).each do |hash|
147
+ uri = URI("https://discovery.meethue.com/")
148
+ response = Net::HTTP.get(uri)
149
+
150
+ JSON(response).each do |hash|
154
151
  bs << Bridge.new(self, hash)
155
152
  end
156
153
  end
157
154
 
158
155
  def get_error(error)
159
156
  # Find error class and return instance
160
- klass = Hue::ERROR_MAP[error['type']] || UnknownError unless klass
161
- klass.new(error['description'])
157
+ klass ||= Hue::ERROR_MAP[error["type"]] || UnknownError
158
+ klass.new(error["description"])
162
159
  end
163
160
  end
164
161
  end
@@ -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
- @state['on']
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
- %w{on hue saturation brightness color_temperature alert effect}.each do |key|
16
- define_method "#{key}=".to_sym do |value|
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}".to_sym, value)
33
+ instance_variable_set(:"@#{key}", value)
19
34
  end
20
35
  end
21
36
 
22
37
  def set_xy(x, y)
23
- set_state({:xy => [x, y]})
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
data/lib/hue/errors.rb CHANGED
@@ -2,33 +2,47 @@ module Hue
2
2
  class Error < StandardError; end
3
3
 
4
4
  class UnauthorizedUser < Error; end
5
+
5
6
  class InvalidJSON < Error; end
7
+
6
8
  class ResourceNotAvailable < Error; end
9
+
7
10
  class MethodNotAvailable < Error; end
11
+
8
12
  class MissingBody < Error; end
13
+
9
14
  class ParameterNotAvailable < Error; end
15
+
10
16
  class InvalidValueForParameter < Error; end
17
+
11
18
  class ParameterNotModifiable < Error; end
19
+
12
20
  class InternalError < Error; end
21
+
13
22
  class LinkButtonNotPressed < Error; end
23
+
14
24
  class ParameterNotModifiableWhileOff < ParameterNotModifiable; end
25
+
15
26
  class TooManyGroups < Error; end
27
+
16
28
  class GroupTooFull < Error; end
17
29
 
18
30
  class InvalidUsername < Error; end
31
+
19
32
  class UnknownError < Error; end
33
+
20
34
  class NoBridgeFound < Error; end
21
35
 
22
36
  # Status code to exception map
23
37
  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,
38
+ 1 => Hue::UnauthorizedUser,
39
+ 2 => Hue::InvalidJSON,
40
+ 3 => Hue::ResourceNotAvailable,
41
+ 4 => Hue::MethodNotAvailable,
42
+ 5 => Hue::MissingBody,
43
+ 6 => Hue::ParameterNotAvailable,
44
+ 7 => Hue::InvalidValueForParameter,
45
+ 8 => Hue::ParameterNotModifiable,
32
46
  901 => Hue::InternalError,
33
47
  101 => Hue::LinkButtonNotPressed,
34
48
  201 => Hue::ParameterNotModifiableWhileOff,
data/lib/hue/group.rb CHANGED
@@ -11,19 +11,19 @@ module Hue
11
11
  attr_reader :bridge
12
12
 
13
13
  # A unique, editable name given to the group.
14
- attr_accessor :name
14
+ attr_reader :name
15
15
 
16
16
  # Hue of the group. This is a wrapping value between 0 and 65535.
17
17
  # Both 0 and 65535 are red, 25500 is green and 46920 is blue.
18
18
  attr_accessor :hue
19
19
 
20
- # Saturation of the group. 255 is the most saturated (colored)
20
+ # Saturation of the group. 254 is the most saturated (colored)
21
21
  # and 0 is the least saturated (white).
22
22
  attr_accessor :saturation
23
23
 
24
24
  # Brightness of the group. This is a scale from the minimum
25
25
  # brightness the group is capable of, 0, to the maximum capable
26
- # brightness, 255. Note a brightness of 0 is not off.
26
+ # brightness, 254. Note a brightness of 0 is not off.
27
27
  attr_accessor :brightness
28
28
 
29
29
  # The x coordinate of a color in CIE color space. Between 0 and 1.
@@ -58,16 +58,14 @@ module Hue
58
58
  end
59
59
 
60
60
  def lights
61
- @lights ||= begin
62
- @light_ids.map do |light_id|
63
- @client.light(light_id)
64
- end
61
+ @lights ||= @light_ids.map do |light_id|
62
+ @client.light(light_id)
65
63
  end
66
64
  end
67
65
 
68
66
  def name=(name)
69
- resp = set_group_state({:name => name})
70
- @name = new? ? name : resp[0]['success']["/groups/#{id}/name"]
67
+ resp = set_group_state({name: name})
68
+ @name = new? ? name : resp[0]["success"]["/groups/#{id}/name"]
71
69
  end
72
70
 
73
71
  def lights=(light_ids)
@@ -78,17 +76,17 @@ module Hue
78
76
  @light_ids = light_ids.uniq
79
77
  @lights = nil # resets the memoization
80
78
 
81
- set_group_state({:lights => @light_ids})
79
+ set_group_state({lights: @light_ids})
82
80
  end
83
81
 
84
82
  def scene=(scene)
85
83
  scene_id = scene.is_a?(Scene) ? scene.id : scene
86
- set_group_state({:scene => scene_id})
84
+ set_group_state({scene: scene_id})
87
85
  end
88
86
 
89
87
  def <<(light_id)
90
88
  @light_ids << light_id
91
- set_group_state({:lights => @light_ids})
89
+ set_group_state({lights: @light_ids})
92
90
  end
93
91
  alias_method :add_light, :<<
94
92
 
@@ -120,8 +118,8 @@ module Hue
120
118
 
121
119
  def create!
122
120
  body = {
123
- :name => @name,
124
- :lights => @light_ids,
121
+ name: @name,
122
+ lights: @light_ids
125
123
  }
126
124
 
127
125
  uri = URI.parse("http://#{@bridge.ip}/api/#{@client.username}/groups")
@@ -129,7 +127,7 @@ module Hue
129
127
  response = http.request_post(uri.path, JSON.dump(body))
130
128
  json = JSON(response.body)
131
129
 
132
- @id = json[0]['success']['id']
130
+ @id = json[0]["success"]["id"]
133
131
  end
134
132
 
135
133
  def destroy!
@@ -137,7 +135,7 @@ module Hue
137
135
  http = Net::HTTP.new(uri.host)
138
136
  response = http.delete(uri.path)
139
137
  json = JSON(response.body)
140
- @id = nil if json[0]['success']
138
+ @id = nil if json[0]["success"]
141
139
  end
142
140
 
143
141
  def new?
@@ -147,22 +145,22 @@ module Hue
147
145
  private
148
146
 
149
147
  GROUP_KEYS_MAP = {
150
- :name => :name,
151
- :light_ids => :lights,
152
- :type => :type,
153
- :state => :action
148
+ name: :name,
149
+ light_ids: :lights,
150
+ type: :type,
151
+ state: :action
154
152
  }
155
153
 
156
154
  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,
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
166
164
  }
167
165
 
168
166
  def unpack(data)
@@ -170,7 +168,7 @@ module Hue
170
168
 
171
169
  unless new?
172
170
  unpack_hash(@state, STATE_KEYS_MAP)
173
- @x, @y = @state['xy']
171
+ @x, @y = @state["xy"]
174
172
  end
175
173
  end
176
174
 
data/lib/hue/light.rb CHANGED
@@ -3,9 +3,6 @@ module Hue
3
3
  include TranslateKeys
4
4
  include EditableState
5
5
 
6
- HUE_RANGE = 0..65535
7
- SATURATION_RANGE = 0..255
8
- BRIGHTNESS_RANGE = 0..255
9
6
  COLOR_TEMPERATURE_RANGE = 153..500
10
7
 
11
8
  # Unique identification number.
@@ -15,19 +12,19 @@ module Hue
15
12
  attr_reader :bridge
16
13
 
17
14
  # A unique, editable name given to the light.
18
- attr_accessor :name
15
+ attr_reader :name
19
16
 
20
17
  # Hue of the light. This is a wrapping value between 0 and 65535.
21
18
  # Both 0 and 65535 are red, 25500 is green and 46920 is blue.
22
19
  attr_reader :hue
23
20
 
24
- # Saturation of the light. 255 is the most saturated (colored)
21
+ # Saturation of the light. 254 is the most saturated (colored)
25
22
  # and 0 is the least saturated (white).
26
23
  attr_reader :saturation
27
24
 
28
25
  # Brightness of the light. This is a scale from the minimum
29
26
  # brightness the light is capable of, 0, to the maximum capable
30
- # brightness, 255. Note a brightness of 0 is not off.
27
+ # brightness, 254. Note a brightness of 0 is not off.
31
28
  attr_reader :brightness
32
29
 
33
30
  # The x coordinate of a color in CIE color space. Between 0 and 1.
@@ -84,6 +81,15 @@ module Hue
84
81
  # Reserved for future functionality.
85
82
  attr_reader :point_symbol
86
83
 
84
+ # The unique ID of the light.
85
+ attr_reader :uid
86
+
87
+ # The hash of capabilities of the light
88
+ attr_reader :capabilities
89
+
90
+ # The config hash
91
+ attr_reader :config
92
+
87
93
  def initialize(client, bridge, id, hash)
88
94
  @client = client
89
95
  @bridge = bridge
@@ -92,21 +98,21 @@ module Hue
92
98
  end
93
99
 
94
100
  def name=(new_name)
95
- unless (1..32).include?(new_name.length)
96
- raise InvalidValueForParameter, 'name must be between 1 and 32 characters.'
101
+ unless (1..32).cover?(new_name.length)
102
+ raise InvalidValueForParameter, "name must be between 1 and 32 characters."
97
103
  end
98
104
 
99
105
  body = {
100
- :name => new_name
106
+ name: new_name
101
107
  }
102
108
 
103
109
  uri = URI.parse(base_url)
104
110
  http = Net::HTTP.new(uri.host)
105
111
  response = http.request_put(uri.path, JSON.dump(body))
106
112
  response = JSON(response.body).first
107
- if response['success']
113
+ if response["success"]
108
114
  @name = new_name
109
- # else
115
+ # else
110
116
  # TODO: Error
111
117
  end
112
118
  end
@@ -115,7 +121,7 @@ module Hue
115
121
  # always returns true, functionality will be added in a future
116
122
  # patch.
117
123
  def reachable?
118
- @state['reachable']
124
+ @state["reachable"]
119
125
  end
120
126
 
121
127
  # @param transition The duration of the transition from the light’s current
@@ -126,7 +132,7 @@ module Hue
126
132
  body = translate_keys(attributes, STATE_KEYS_MAP)
127
133
 
128
134
  # Add transition
129
- body.merge!({:transitiontime => transition}) if transition
135
+ body[:transitiontime] = transition if transition
130
136
 
131
137
  uri = URI.parse("#{base_url}/state")
132
138
  http = Net::HTTP.new(uri.host)
@@ -140,34 +146,37 @@ module Hue
140
146
  unpack(json)
141
147
  end
142
148
 
143
- private
149
+ private
144
150
 
145
151
  KEYS_MAP = {
146
- :state => :state,
147
- :type => :type,
148
- :name => :name,
149
- :model => :modelid,
150
- :software_version => :swversion,
151
- :point_symbol => :pointsymbol
152
+ state: :state,
153
+ type: :type,
154
+ name: :name,
155
+ model: :modelid,
156
+ software_version: :swversion,
157
+ point_symbol: :pointsymbol,
158
+ uid: :uniqueid,
159
+ capabilities: :capabilities,
160
+ config: :config
152
161
  }
153
162
 
154
163
  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,
164
+ on: :on,
165
+ brightness: :bri,
166
+ hue: :hue,
167
+ saturation: :sat,
168
+ xy: :xy,
169
+ color_temperature: :ct,
170
+ alert: :alert,
171
+ effect: :effect,
172
+ color_mode: :colormode,
173
+ reachable: :reachable
165
174
  }
166
175
 
167
176
  def unpack(hash)
168
177
  unpack_hash(hash, KEYS_MAP)
169
178
  unpack_hash(@state, STATE_KEYS_MAP)
170
- @x, @y = @state['xy']
179
+ @x, @y = @state["xy"]
171
180
  end
172
181
 
173
182
  def base_url
data/lib/hue/scene.rb CHANGED
@@ -24,19 +24,17 @@ module Hue
24
24
  end
25
25
 
26
26
  def lights
27
- @lights ||= begin
28
- @light_ids.map do |light_id|
29
- @client.light(light_id)
30
- end
27
+ @lights ||= @light_ids.map do |light_id|
28
+ @client.light(light_id)
31
29
  end
32
30
  end
33
31
 
34
32
  private
35
33
 
36
34
  SCENE_KEYS_MAP = {
37
- :name => :name,
38
- :light_ids => :lights,
39
- :active => :active,
35
+ name: :name,
36
+ light_ids: :lights,
37
+ active: :active
40
38
  }
41
39
 
42
40
  def unpack(data)
@@ -14,7 +14,7 @@ module Hue
14
14
  map.each do |local_key, remote_key|
15
15
  value = hash[remote_key.to_s]
16
16
  next unless value
17
- instance_variable_set("@#{local_key}", value)
17
+ instance_variable_set(:"@#{local_key}", value)
18
18
  end
19
19
  end
20
20
  end
data/lib/hue/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Hue
2
- VERSION = '0.3.0'
2
+ VERSION = "0.3.1"
3
3
  end
data/lib/hue.rb CHANGED
@@ -1,12 +1,12 @@
1
- require 'hue/version'
2
- require 'hue/errors'
3
- require 'hue/client'
4
- require 'hue/bridge'
5
- require 'hue/editable_state'
6
- require 'hue/translate_keys'
7
- require 'hue/light'
8
- require 'hue/group'
9
- require 'hue/scene'
1
+ require "hue/version"
2
+ require "hue/errors"
3
+ require "hue/client"
4
+ require "hue/bridge"
5
+ require "hue/editable_state"
6
+ require "hue/translate_keys"
7
+ require "hue/light"
8
+ require "hue/group"
9
+ require "hue/scene"
10
10
 
11
11
  module Hue
12
12
  USERNAME_RANGE = 10..40
@@ -1,25 +1,26 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class ClientTest < Minitest::Test
4
4
  def before_setup
5
5
  super
6
6
 
7
- stub_request(:get, "https://discovery.meethue.com/").
8
- to_return(:body => '[{"id":"ffa57b3b257200065704","internalipaddress":"192.168.0.1"},{"id":"63c2fc01391276a319f9","internalipaddress":"192.168.0.2"}]')
7
+ stub_request(:get, "https://discovery.meethue.com/")
8
+ .to_return(body: '[{"id":"ffa57b3b257200065704","internalipaddress":"192.168.0.1"},{"id":"63c2fc01391276a319f9","internalipaddress":"192.168.0.2"}]')
9
9
 
10
- stub_request(:get, %r{http://192.168.0.1/api/*}).to_return(:body => '[{"success":true}]')
11
- stub_request(:get, %r{http://192.168.0.2/api/*}).to_return(:body => '[{"success":true}]')
10
+ stub_request(:get, %r{http://192.168.0.1/api}).to_return(body: '[{"success":true}]')
11
+ stub_request(:get, %r{http://192.168.0.1/api/*}).to_return(body: '[{"success":true}]')
12
+ stub_request(:get, %r{http://192.168.0.2/api/*}).to_return(body: '[{"success":true}]')
12
13
  end
13
14
 
14
15
  def test_with_bridge_id
15
16
  client = Hue::Client.new(use_mdns: false)
16
- client.stub :find_bridge_id, '63c2fc01391276a319f9' do
17
- assert_equal '63c2fc01391276a319f9', client.bridge.id
17
+ client.stub :find_bridge_id, "63c2fc01391276a319f9" do
18
+ assert_equal "63c2fc01391276a319f9", client.bridge.id
18
19
  end
19
20
  end
20
21
 
21
22
  def test_without_bridge_id
22
23
  client = Hue::Client.new(use_mdns: false)
23
- assert_equal 'ffa57b3b257200065704', client.bridge.id
24
+ assert_equal "ffa57b3b257200065704", client.bridge.id
24
25
  end
25
26
  end
@@ -1,24 +1,44 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class LightTest < Minitest::Test
4
4
  def before_setup
5
5
  super
6
6
 
7
- stub_request(:get, "https://discovery.meethue.com/").
8
- to_return(:body => '[{"internalipaddress":"localhost"}]')
7
+ stub_request(:get, "https://discovery.meethue.com/")
8
+ .to_return(body: '[{"internalipaddress":"localhost"}]')
9
9
 
10
- stub_request(:get, %r{http://localhost/api/*}).to_return(:body => '[{"success":true}]')
11
- stub_request(:post, 'http://localhost/api').to_return(:body => '[{"success":{"username":"ruby"}}]')
12
- stub_request(:put, %r{http://localhost/api*}).to_return(:body => '[{}]')
10
+ stub_request(:get, %r{http://localhost/api/*}).to_return(body: '[{"success":true}]')
11
+ stub_request(:post, "http://localhost/api").to_return(body: '[{"success":{"username":"ruby"}}]')
12
+ stub_request(:put, %r{http://localhost/api*}).to_return(body: "[{}]")
13
13
  end
14
14
 
15
- %w{on hue saturation brightness color_temperature alert effect}.each do |attribute|
16
- define_method "test_setting_#{attribute}" do
15
+ %w[on hue saturation brightness color_temperature alert effect].each do |attribute|
16
+ define_method :"test_setting_#{attribute}" do
17
17
  client = Hue::Client.new(use_mdns: false)
18
18
  light = Hue::Light.new(client, client.bridge, 0, {"state" => {}})
19
19
 
20
- light.send("#{attribute}=", 24)
20
+ light.send(:"#{attribute}=", 24)
21
21
  assert_requested :put, %r{http://localhost/api/.*/lights/0}
22
22
  end
23
23
  end
24
+
25
+ def test_toggle_while_off
26
+ client = Hue::Client.new(use_mdns: false)
27
+ light = Hue::Light.new(client, client.bridge, 0, {"state" => {}})
28
+ assert_equal false, light.on?
29
+
30
+ light.toggle!
31
+ assert_requested :put, %r{http://localhost/api/.*/lights/0}
32
+ assert_equal true, light.on?
33
+ end
34
+
35
+ def test_toggle_while_on
36
+ client = Hue::Client.new(use_mdns: false)
37
+ light = Hue::Light.new(client, client.bridge, 0, {"state" => {"on" => true}})
38
+ assert_equal true, light.on?
39
+
40
+ light.toggle!
41
+ assert_requested :put, %r{http://localhost/api/.*/lights/0}
42
+ assert_equal false, light.on?
43
+ end
24
44
  end
data/test/test_helper.rb CHANGED
@@ -1,6 +1,6 @@
1
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
- require 'hue'
1
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
2
+ require "hue"
3
3
 
4
- require 'minitest'
5
- require 'webmock/minitest'
6
- require 'minitest/autorun'
4
+ require "minitest"
5
+ require "webmock/minitest"
6
+ require "minitest/autorun"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Soffes
@@ -39,21 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: log_switch
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - '='
46
- - !ruby/object:Gem::Version
47
- version: 0.4.0
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - '='
53
- - !ruby/object:Gem::Version
54
- version: 0.4.0
55
- - !ruby/object:Gem::Dependency
56
- name: curb
42
+ name: color_conversion
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - ">="
@@ -66,48 +52,23 @@ dependencies:
66
52
  - - ">="
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: minitest
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '5.0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '5.0'
83
- - !ruby/object:Gem::Dependency
84
- name: webmock
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
55
  description: Work with Philips Hue light bulbs.
98
56
  email:
99
57
  - sam@soff.es
100
58
  executables:
59
+ - console
101
60
  - hue
102
61
  extensions: []
103
62
  extra_rdoc_files: []
104
63
  files:
105
64
  - ".github/workflows/main.yml"
106
65
  - ".gitignore"
66
+ - ".ruby-version"
107
67
  - Gemfile
108
68
  - LICENSE
109
69
  - README.md
110
70
  - Rakefile
71
+ - bin/console
111
72
  - bin/hue
112
73
  - hue.gemspec
113
74
  - lib/hue.rb
@@ -147,7 +108,4 @@ rubygems_version: 3.4.22
147
108
  signing_key:
148
109
  specification_version: 4
149
110
  summary: Work with Philips Hue light bulbs from Ruby.
150
- test_files:
151
- - test/hue/client_test.rb
152
- - test/hue/light_test.rb
153
- - test/test_helper.rb
111
+ test_files: []