hue 0.1.5 → 0.3.0

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
- SHA1:
3
- metadata.gz: 392c6116951d5bc531a34f0ef2c52d5fb5f82ad8
4
- data.tar.gz: 3a5e4de39857bd328c5e69deb2866266d709fcc7
2
+ SHA256:
3
+ metadata.gz: af74df93c5514679bab0613c9c6c87b0a0dfae19b919fc903ad42a8fafe9b681
4
+ data.tar.gz: 0afb9bd5b7ee11be0a1dce6b56846c6d13fa7cd9a9b67e2f9c8014c8d03f0fb7
5
5
  SHA512:
6
- metadata.gz: e21f6cc541aa058b4a5502f7699f0bb67c46ecf63d07c45c4ea036b037a20ced5372db75cb6d2b9d06fa3796badab290eb2639d3d2084487f9038c09e98899e4
7
- data.tar.gz: 2d95c4b7a772fbbb966f368f0967ea1d20a9c36b6ee677927a6644548ffde7d93cff812cea376b691f11d72c1180972e31d63bd71e07b0373b1bdb2c0ec5a1f7
6
+ metadata.gz: 00f64a5fdad18722af090747e6a2dfe2a5fefb556bcd634ee7b498f54df80e23e94975c295a2925a46cf2166e88df0af07dee1999e26446f7e42e66ebbc8778b
7
+ data.tar.gz: f54f5552bceb7456b0a1d6ccdc29f7ca3cb01636231d83a5f0d7d93b907defce6bfbfcb0e2f96444e49543fbb85f7cda66586f72eedaea912c7a18f5ededb570
@@ -0,0 +1,14 @@
1
+ name: Tests
2
+ on: [push]
3
+ jobs:
4
+ test:
5
+ name: Test Swift Package
6
+ runs-on: ubuntu-latest
7
+ timeout-minutes: 5
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'
14
+ run: bundle exec rake test
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013-2014 Sam Soffes, http://soff.es
1
+ Copyright (c) 2013-2024 Sam Soffes, https://soff.es
2
2
 
3
3
  MIT License
4
4
 
@@ -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
 
@@ -64,7 +63,7 @@ group = client.group(1)
64
63
 
65
64
  # Accessing group lights
66
65
  group.lights.first.on!
67
- group.lights.each { |light| light.hue = rand(0...65535) }
66
+ group.lights.each { |light| light.hue = rand(Hue::Light::HUE_RANGE) }
68
67
 
69
68
  # Creating groups
70
69
  group = client.group # Don't specify an ID
@@ -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 +1,10 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
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
- Hue::Cli.start
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
@@ -18,9 +18,11 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.required_ruby_version = '>= 1.9.3'
21
+ spec.required_ruby_version = '>= 2.1.0'
22
22
  spec.add_dependency 'thor'
23
23
  spec.add_dependency 'json'
24
24
  spec.add_dependency 'log_switch', '0.4.0'
25
25
  spec.add_dependency 'curb'
26
+ spec.add_development_dependency 'minitest', '~> 5.0'
27
+ spec.add_development_dependency 'webmock'
26
28
  end
data/lib/hue/bridge.rb CHANGED
@@ -66,6 +66,9 @@ module Hue
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
data/lib/hue/client.rb CHANGED
@@ -1,28 +1,35 @@
1
1
  require 'net/http'
2
2
  require 'json'
3
+ require 'resolv'
3
4
  require 'curb'
4
5
 
5
6
  module Hue
6
7
  class Client
7
8
  attr_reader :username
8
9
 
9
- def initialize(username = '1234567890')
10
- unless USERNAME_RANGE.include?(username.length)
11
- raise InvalidUsername, "Usernames must be between #{USERNAME_RANGE.first} and #{USERNAME_RANGE.last}."
12
- end
13
-
14
- @username = username
10
+ def initialize(username = nil, use_mdns: true)
11
+ @bridge_id = nil
12
+ @username = username || find_username
13
+ @use_mdns = use_mdns
15
14
 
16
- begin
17
- validate_user
18
- rescue Hue::UnauthorizedUser
15
+ if @username
16
+ begin
17
+ validate_user
18
+ rescue Hue::UnauthorizedUser
19
+ register_user
20
+ end
21
+ else
19
22
  register_user
20
23
  end
21
24
  end
22
25
 
23
26
  def bridge
24
- # Pick the first one for now. In theory, they should all do the same thing.
25
- bridge = bridges.first
27
+ @bridge_id = find_bridge_id unless @bridge_id
28
+ if @bridge_id
29
+ bridge = bridges.select { |b| b.id == @bridge_id }.first
30
+ else
31
+ bridge = bridges.first
32
+ end
26
33
  raise NoBridgeFound unless bridge
27
34
  bridge
28
35
  end
@@ -30,14 +37,8 @@ module Hue
30
37
  def bridges
31
38
  @bridges ||= begin
32
39
  bs = []
33
- easy = Curl::Easy.new
34
- easy.follow_location = true
35
- easy.max_redirects = 10
36
- easy.url = 'https://www.meethue.com/api/nupnp'
37
- easy.perform
38
- JSON(easy.body).each do |hash|
39
- bs << Bridge.new(self, hash)
40
- end
40
+ discovery_mdns(bs) if @use_mdns
41
+ discovery_meethue(bs) if bs.empty?
41
42
  bs
42
43
  end
43
44
  end
@@ -75,44 +76,89 @@ module Hue
75
76
  scenes.select { |s| s.id == id }.first
76
77
  end
77
78
 
78
- private
79
+ private
79
80
 
80
- def validate_user
81
- response = JSON(Net::HTTP.get(URI.parse("http://#{bridge.ip}/api/#{@username}")))
81
+ def find_username
82
+ return ENV['HUE_USERNAME'] if ENV['HUE_USERNAME']
82
83
 
83
- if response.is_a? Array
84
- response = response.first
84
+ json = JSON(File.read(File.expand_path('~/.hue')))
85
+ json['username']
86
+ rescue
87
+ return nil
85
88
  end
86
89
 
87
- if error = response['error']
88
- raise get_error(error)
90
+ def validate_user
91
+ response = JSON(Net::HTTP.get(URI.parse("http://#{bridge.ip}/api/#{@username}")))
92
+
93
+ if response.is_a? Array
94
+ response = response.first
95
+ end
96
+
97
+ if error = response['error']
98
+ raise get_error(error)
99
+ end
100
+
101
+ response['success']
89
102
  end
90
103
 
91
- response['success']
92
- end
104
+ def register_user
105
+ body = JSON.dump({
106
+ devicetype: 'Ruby'
107
+ })
108
+
109
+ uri = URI.parse("http://#{bridge.ip}/api")
110
+ http = Net::HTTP.new(uri.host)
111
+ response = JSON(http.request_post(uri.path, body).body).first
112
+
113
+ if error = response['error']
114
+ raise get_error(error)
115
+ end
93
116
 
94
- def register_user
95
- body = JSON.dump({
96
- devicetype: 'Ruby',
97
- username: @username
98
- })
117
+ if @username = response['success']['username']
118
+ File.write(File.expand_path('~/.hue'), JSON.dump({username: @username}))
119
+ end
120
+ end
99
121
 
100
- uri = URI.parse("http://#{bridge.ip}/api")
101
- http = Net::HTTP.new(uri.host)
102
- response = JSON(http.request_post(uri.path, body).body).first
122
+ def find_bridge_id
123
+ return ENV['HUE_BRIDGE_ID'] if ENV['HUE_BRIDGE_ID']
103
124
 
104
- if error = response['error']
105
- raise get_error(error)
125
+ json = JSON(File.read(File.expand_path('~/.hue')))
126
+ json['bridge_id']
127
+ rescue
128
+ return nil
106
129
  end
107
130
 
108
- response['success']
109
- end
131
+ def discovery_mdns(bs)
132
+ resolver = Resolv::MDNS.new
133
+ resolver.timeouts = 10
110
134
 
111
- def get_error(error)
112
- # Find error class and return instance
113
- klass = Hue::ERROR_MAP[error['type']] || UnknownError unless klass
114
- klass.new(error['description'])
115
- end
135
+ resolver.each_resource("_hue._tcp.local", Resolv::DNS::Resource::IN::PTR) do |bridge_ptr|
136
+ bridge_target = resolver.getresource(bridge_ptr.name, Resolv::DNS::Resource::IN::SRV).target
137
+
138
+ 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
141
+ }
116
142
 
143
+ bs << Bridge.new(self, bridge_hash)
144
+ end
145
+ end
146
+
147
+ 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|
154
+ bs << Bridge.new(self, hash)
155
+ end
156
+ end
157
+
158
+ def get_error(error)
159
+ # Find error class and return instance
160
+ klass = Hue::ERROR_MAP[error['type']] || UnknownError unless klass
161
+ klass.new(error['description'])
162
+ end
117
163
  end
118
164
  end
data/lib/hue/light.rb CHANGED
@@ -19,16 +19,16 @@ module Hue
19
19
 
20
20
  # Hue of the light. This is a wrapping value between 0 and 65535.
21
21
  # Both 0 and 65535 are red, 25500 is green and 46920 is blue.
22
- attr_accessor :hue
22
+ attr_reader :hue
23
23
 
24
24
  # Saturation of the light. 255 is the most saturated (colored)
25
25
  # and 0 is the least saturated (white).
26
- attr_accessor :saturation
26
+ attr_reader :saturation
27
27
 
28
28
  # Brightness of the light. This is a scale from the minimum
29
29
  # brightness the light is capable of, 0, to the maximum capable
30
30
  # brightness, 255. Note a brightness of 0 is not off.
31
- attr_accessor :brightness
31
+ attr_reader :brightness
32
32
 
33
33
  # The x coordinate of a color in CIE color space. Between 0 and 1.
34
34
  #
@@ -44,7 +44,7 @@ module Hue
44
44
  # are capable of 153 (6500K) to 500 (2000K).
45
45
  #
46
46
  # @see http://en.wikipedia.org/wiki/Mired
47
- attr_accessor :color_temperature
47
+ attr_reader :color_temperature
48
48
 
49
49
  # The alert effect, which is a temporary change to the bulb’s state.
50
50
  # This can take one of the following values:
@@ -58,12 +58,12 @@ module Hue
58
58
  # current state in an upcoming patch.
59
59
  #
60
60
  # @see http://developers.meethue.com/coreconcepts.html#some_extra_fun_stuff
61
- attr_accessor :alert
61
+ attr_reader :alert
62
62
 
63
63
  # The dynamic effect of the light, can either be `none` or
64
64
  # `colorloop`. If set to colorloop, the light will cycle through
65
65
  # all hues using the current brightness and saturation settings.
66
- attr_accessor :effect
66
+ attr_reader :effect
67
67
 
68
68
  # Indicates the color mode in which the light is working, this is
69
69
  # the last command type it received. Values are `hs` for Hue and
data/lib/hue/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Hue
2
- VERSION = '0.1.5'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class ClientTest < Minitest::Test
4
+ def before_setup
5
+ super
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"}]')
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}]')
12
+ end
13
+
14
+ def test_with_bridge_id
15
+ client = Hue::Client.new(use_mdns: false)
16
+ client.stub :find_bridge_id, '63c2fc01391276a319f9' do
17
+ assert_equal '63c2fc01391276a319f9', client.bridge.id
18
+ end
19
+ end
20
+
21
+ def test_without_bridge_id
22
+ client = Hue::Client.new(use_mdns: false)
23
+ assert_equal 'ffa57b3b257200065704', client.bridge.id
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ class LightTest < Minitest::Test
4
+ def before_setup
5
+ super
6
+
7
+ stub_request(:get, "https://discovery.meethue.com/").
8
+ to_return(:body => '[{"internalipaddress":"localhost"}]')
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 => '[{}]')
13
+ end
14
+
15
+ %w{on hue saturation brightness color_temperature alert effect}.each do |attribute|
16
+ define_method "test_setting_#{attribute}" do
17
+ client = Hue::Client.new(use_mdns: false)
18
+ light = Hue::Light.new(client, client.bridge, 0, {"state" => {}})
19
+
20
+ light.send("#{attribute}=", 24)
21
+ assert_requested :put, %r{http://localhost/api/.*/lights/0}
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'hue'
3
+
4
+ require 'minitest'
5
+ require 'webmock/minitest'
6
+ require 'minitest/autorun'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Soffes
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-27 00:00:00.000000000 Z
11
+ date: 2024-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -66,6 +66,34 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  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'
69
97
  description: Work with Philips Hue light bulbs.
70
98
  email:
71
99
  - sam@soff.es
@@ -74,13 +102,12 @@ executables:
74
102
  extensions: []
75
103
  extra_rdoc_files: []
76
104
  files:
105
+ - ".github/workflows/main.yml"
77
106
  - ".gitignore"
78
- - Contributing.markdown
79
107
  - Gemfile
80
108
  - LICENSE
109
+ - README.md
81
110
  - Rakefile
82
- - Readme.markdown
83
- - Todo.markdown
84
111
  - bin/hue
85
112
  - hue.gemspec
86
113
  - lib/hue.rb
@@ -94,11 +121,14 @@ files:
94
121
  - lib/hue/scene.rb
95
122
  - lib/hue/translate_keys.rb
96
123
  - lib/hue/version.rb
124
+ - test/hue/client_test.rb
125
+ - test/hue/light_test.rb
126
+ - test/test_helper.rb
97
127
  homepage: https://github.com/soffes/hue
98
128
  licenses:
99
129
  - MIT
100
130
  metadata: {}
101
- post_install_message:
131
+ post_install_message:
102
132
  rdoc_options: []
103
133
  require_paths:
104
134
  - lib
@@ -106,16 +136,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
136
  requirements:
107
137
  - - ">="
108
138
  - !ruby/object:Gem::Version
109
- version: 1.9.3
139
+ version: 2.1.0
110
140
  required_rubygems_version: !ruby/object:Gem::Requirement
111
141
  requirements:
112
142
  - - ">="
113
143
  - !ruby/object:Gem::Version
114
144
  version: '0'
115
145
  requirements: []
116
- rubyforge_project:
117
- rubygems_version: 2.4.5
118
- signing_key:
146
+ rubygems_version: 3.4.22
147
+ signing_key:
119
148
  specification_version: 4
120
149
  summary: Work with Philips Hue light bulbs from Ruby.
121
- test_files: []
150
+ test_files:
151
+ - test/hue/client_test.rb
152
+ - test/hue/light_test.rb
153
+ - test/test_helper.rb
@@ -1,19 +0,0 @@
1
- ## Submitting a Pull Request
2
-
3
- 1. [Fork the repository.][fork]
4
- 2. [Create a topic branch.][branch]
5
- 3. Add tests for your unimplemented feature or bug fix.
6
- 4. Run `bundle exec rake`. If your tests pass, return to step 3.
7
- 5. Implement your feature or bug fix.
8
- 6. Run `bundle exec rake`. If your tests fail, return to step 5.
9
- 7. Run `open coverage/index.html`. If your changes are not completely covered
10
- by your tests, return to step 3.
11
- 8. Add documentation for your feature or bug fix.
12
- 9. Run `bundle exec rake doc`. If your changes are not 100% documented, go
13
- back to step 8.
14
- 10. Add, commit, and push your changes.
15
- 11. [Submit a pull request.][pr]
16
-
17
- [fork]: http://help.github.com/fork-a-repo/
18
- [branch]: http://learn.github.com/p/branching.html
19
- [pr]: http://help.github.com/send-pull-requests/
data/Todo.markdown DELETED
@@ -1,8 +0,0 @@
1
- # To Do
2
-
3
- * RGB translation
4
- * Hex translation
5
- * Scheduling
6
- * Effects
7
- * User management
8
- * Configuration