hue 0.1.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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