hue-lib 0.7.1 → 0.7.2
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.
- data/Rakefile +26 -0
- data/hue-lib.gemspec +1 -1
- data/lib/hue/bridge.rb +1 -1
- data/lib/hue/bulb.rb +48 -9
- data/lib/hue/config/abstract.rb +3 -1
- data/lib/hue/config/application.rb +1 -1
- data/lib/hue.rb +10 -5
- data/spec/config/empty.yml +1 -0
- data/spec/hue/bulb_spec.rb +43 -0
- data/spec/hue/config/abstract_spec.rb +10 -0
- data/spec/hue/config/application_spec.rb +11 -0
- data/spec/hue/config/bridge_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- data/test/connectivity.rb +44 -0
- metadata +4 -3
data/Rakefile
CHANGED
@@ -16,4 +16,30 @@ rescue LoadError
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
namespace :gem do
|
20
|
+
desc 'Build the gem'
|
21
|
+
task :build do
|
22
|
+
`mkdir -p pkg`
|
23
|
+
`gem build hue-lib.gemspec`
|
24
|
+
`mv *.gem pkg/`
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Publish the gem'
|
28
|
+
task :publish do
|
29
|
+
gem = `ls pkg`
|
30
|
+
# `gem push pkg/#{gem}`
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Install the gem locally'
|
34
|
+
task :install do
|
35
|
+
gem = `ls pkg`.split.sort
|
36
|
+
`gem install pkg/#{gem.last}`
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
desc 'Remove generated files'
|
41
|
+
task :clean do
|
42
|
+
`rm -rf pkg`
|
43
|
+
end
|
44
|
+
|
19
45
|
task :default => [:spec]
|
data/hue-lib.gemspec
CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "hue-lib"
|
6
|
-
s.version = '0.7.
|
6
|
+
s.version = '0.7.2'
|
7
7
|
s.authors = ["Birkir A. Barkarson", "Aaron Hurley"]
|
8
8
|
s.email = ["birkirb@stoicviking.net"]
|
9
9
|
s.homepage = "https://github.com/birkirb/hue-lib"
|
data/lib/hue/bridge.rb
CHANGED
@@ -104,7 +104,7 @@ module Hue
|
|
104
104
|
begin
|
105
105
|
http = Net::HTTP.new(url.host, url.port)
|
106
106
|
http.open_timeout = 3 # Quick timeout on connection fail.
|
107
|
-
http.read_timeout =
|
107
|
+
http.read_timeout = 8 # Slower timeout on read fail, but way faster than the default.
|
108
108
|
response = http.start { |http| http.request(request) }
|
109
109
|
rescue => err
|
110
110
|
Hue.logger.error(err.message)
|
data/lib/hue/bulb.rb
CHANGED
@@ -5,6 +5,8 @@ module Hue
|
|
5
5
|
class Bulb
|
6
6
|
|
7
7
|
BRIGHTNESS_MAX = 255
|
8
|
+
NONE = 'none'
|
9
|
+
COLOR_LOOP = 'colorloop'
|
8
10
|
|
9
11
|
include Animations::Candle
|
10
12
|
include Animations::Sunrise
|
@@ -34,6 +36,11 @@ module Hue
|
|
34
36
|
status['state']
|
35
37
|
end
|
36
38
|
|
39
|
+
# Free for all, no checking.
|
40
|
+
def state=(value)
|
41
|
+
update_state(value)
|
42
|
+
end
|
43
|
+
|
37
44
|
def [](item)
|
38
45
|
state[item.to_s]
|
39
46
|
end
|
@@ -104,36 +111,68 @@ module Hue
|
|
104
111
|
set_color
|
105
112
|
end
|
106
113
|
|
114
|
+
def effect
|
115
|
+
self['effect']
|
116
|
+
end
|
117
|
+
|
118
|
+
def effect=(value)
|
119
|
+
update_state(effect: value.to_s)
|
120
|
+
end
|
121
|
+
|
122
|
+
def effect?
|
123
|
+
NONE != self.effect
|
124
|
+
end
|
125
|
+
|
126
|
+
def color_loop
|
127
|
+
self.effect = COLOR_LOOP
|
128
|
+
end
|
129
|
+
alias :colorloop :color_loop
|
130
|
+
|
131
|
+
def color_loop?
|
132
|
+
COLOR_LOOP == self.effect
|
133
|
+
end
|
134
|
+
|
135
|
+
def clear_effect
|
136
|
+
self.effect = NONE
|
137
|
+
end
|
138
|
+
|
139
|
+
def alert
|
140
|
+
self['alert']
|
141
|
+
end
|
142
|
+
|
143
|
+
def alert=(value)
|
144
|
+
update_state(alert: value.to_s)
|
145
|
+
end
|
146
|
+
|
107
147
|
def blinking?
|
108
148
|
!solid?
|
109
149
|
end
|
110
150
|
|
111
151
|
def solid?
|
112
|
-
|
152
|
+
NONE == alert
|
113
153
|
end
|
114
154
|
|
115
155
|
def blink
|
116
|
-
|
156
|
+
self.alert = 'lselect'
|
117
157
|
end
|
118
158
|
|
119
159
|
def solid
|
120
|
-
|
160
|
+
self.alert = NONE
|
121
161
|
end
|
122
162
|
|
123
163
|
def flash
|
124
|
-
|
164
|
+
self.alert = 'select'
|
125
165
|
# immediately update to expected state
|
126
|
-
@status['state']['alert'] =
|
166
|
+
@status['state']['alert'] = NONE
|
127
167
|
end
|
128
168
|
|
169
|
+
# transition time in seconds
|
129
170
|
def transition_time
|
130
|
-
|
131
|
-
(options[:transitiontime] || 1).to_f / 10
|
171
|
+
(options[:transitiontime] || 0).to_f / 10
|
132
172
|
end
|
133
173
|
|
134
174
|
def transition_time=(time)
|
135
|
-
|
136
|
-
self.options[:transitiontime] = (time * 10).to_i
|
175
|
+
self.options[:transitiontime] = (time.to_f * 10).to_i
|
137
176
|
end
|
138
177
|
|
139
178
|
private
|
data/lib/hue/config/abstract.rb
CHANGED
@@ -18,7 +18,9 @@ module Hue
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def write(overwrite_existing_key = false)
|
21
|
-
yaml = YAML.load_file(self.path) rescue
|
21
|
+
yaml = YAML.load_file(self.path) rescue nil
|
22
|
+
yaml ||= Hash.new
|
23
|
+
|
22
24
|
if yaml.key?(name) && !overwrite_existing_key
|
23
25
|
raise "Key named '#{name}' already exists in config file '#{self.path}'.\nPlease remove it before creating a new one with the same name."
|
24
26
|
else
|
@@ -16,7 +16,7 @@ module Hue
|
|
16
16
|
|
17
17
|
def self.named(name)
|
18
18
|
yaml = read_file(file_path)
|
19
|
-
if named_yaml = yaml[name]
|
19
|
+
if yaml && named_yaml = yaml[name]
|
20
20
|
new(named_yaml[STRING_BRIDGE_ID], named_yaml[STRING_ID], name)
|
21
21
|
else
|
22
22
|
raise NotFound.new("Config named '#{name}' not found.")
|
data/lib/hue.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'net/http'
|
2
|
-
require 'digest/md5'
|
3
2
|
require 'json'
|
4
|
-
require '
|
3
|
+
require 'securerandom'
|
5
4
|
|
6
5
|
module Hue
|
7
6
|
|
@@ -15,7 +14,7 @@ module Hue
|
|
15
14
|
end
|
16
15
|
|
17
16
|
def self.one_time_uuid
|
18
|
-
|
17
|
+
SecureRandom.hex(16)
|
19
18
|
end
|
20
19
|
|
21
20
|
def self.register_default
|
@@ -71,10 +70,16 @@ ST: ssdp:all
|
|
71
70
|
loop do
|
72
71
|
message, (address_family, port, hostname, ip_add) = socket.recvfrom(1024)
|
73
72
|
if message =~ /IpBridge/ && location = /LOCATION: (.*)$/.match(message)
|
74
|
-
if
|
73
|
+
if uuid_match = /uuid:(.{36})/.match(message)
|
75
74
|
# Assume this is Philips Hue for now.
|
76
|
-
|
75
|
+
uuid = uuid_match.captures.first
|
76
|
+
if bridges[uuid].nil?
|
77
|
+
logger.info("Found bridge (#{hostname}:#{port}) with uuid: #{uuid}")
|
78
|
+
end
|
79
|
+
bridges[uuid] = "http://#{ip_add}/api"
|
77
80
|
end
|
81
|
+
else
|
82
|
+
logger.debug("Found #{hostname}:#{port}: #{message}")
|
78
83
|
end
|
79
84
|
end
|
80
85
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
--- {}
|
data/spec/hue/bulb_spec.rb
CHANGED
@@ -48,10 +48,21 @@ describe Hue::Bulb do
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it "should report the alert state" do
|
51
|
+
bulb.alert.should == 'none'
|
51
52
|
bulb.blinking?.should be_false
|
52
53
|
bulb.solid?.should be_true
|
53
54
|
end
|
54
55
|
|
56
|
+
it "should report the effect state" do
|
57
|
+
bulb.effect?.should be_false
|
58
|
+
bulb.effect.should == 'none'
|
59
|
+
bulb.color_loop?.should be_false
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should report the transition time" do
|
63
|
+
bulb.transition_time.should == 0
|
64
|
+
end
|
65
|
+
|
55
66
|
context 'by changing state' do
|
56
67
|
|
57
68
|
it 'should allow turning bulps on and off' do
|
@@ -107,6 +118,38 @@ describe Hue::Bulb do
|
|
107
118
|
bulb.flash
|
108
119
|
bulb.solid?.should be_true
|
109
120
|
end
|
121
|
+
|
122
|
+
with_fake_update('lights/1/state', alert: 'crap') do
|
123
|
+
bulb.alert = 'crap'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should allow setting colorloop, and effect' do
|
128
|
+
with_fake_update('lights/1/state', effect: 'new')
|
129
|
+
bulb.effect = 'new'
|
130
|
+
bulb.effect.should == 'new'
|
131
|
+
bulb.effect?.should be_true
|
132
|
+
|
133
|
+
with_fake_update('lights/1/state', effect: 'colorloop')
|
134
|
+
bulb.colorloop
|
135
|
+
bulb.effect.should == 'colorloop'
|
136
|
+
bulb.effect?.should be_true
|
137
|
+
bulb.color_loop?.should be_true
|
138
|
+
|
139
|
+
with_fake_update('lights/1/state', effect: 'none')
|
140
|
+
bulb.clear_effect
|
141
|
+
bulb.effect.should == 'none'
|
142
|
+
|
143
|
+
with_fake_update('lights/1/state', effect: 'colorloop')
|
144
|
+
bulb.color_loop
|
145
|
+
bulb.effect.should == 'colorloop'
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'should allow setting the transitions time, and employ it for a state change' do
|
149
|
+
bulb.transition_time = 10
|
150
|
+
|
151
|
+
with_fake_update('lights/1/state', transitiontime: 100, bri: 255)
|
152
|
+
bulb.brightness = 255
|
110
153
|
end
|
111
154
|
|
112
155
|
end
|
@@ -32,4 +32,14 @@ describe Hue::Config::Abstract do
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
context 'given an existing config' do
|
36
|
+
config = described_class.new('test', EMPTY_CONFIG_FILE)
|
37
|
+
|
38
|
+
it 'should allow writing to the file' do
|
39
|
+
config.write
|
40
|
+
YAML.load_file(config.path)['test'].should be_a(Hash)
|
41
|
+
config.delete
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
35
45
|
end
|
@@ -58,4 +58,15 @@ describe Hue::Config::Application do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
context 'given an non existing config' do
|
62
|
+
|
63
|
+
it "should throw and error if a named config doesn't exist" do
|
64
|
+
described_class.expects(:file_path).returns(EMPTY_CONFIG_FILE).once
|
65
|
+
|
66
|
+
lambda do
|
67
|
+
described_class.named('not_default')
|
68
|
+
end.should raise_error(Hue::Config::NotFound, /Config named (.*) not found/)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
61
72
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -36,6 +36,7 @@ def silence_warnings
|
|
36
36
|
end
|
37
37
|
|
38
38
|
SPEC_DIR = File.dirname(__FILE__)
|
39
|
+
Hue.logger.level = Logger::DEBUG
|
39
40
|
|
40
41
|
silence_warnings do
|
41
42
|
Hue.const_set(:DEFAULT_UDP_TIMEOUT, 0.01)
|
@@ -43,6 +44,7 @@ end
|
|
43
44
|
|
44
45
|
# APPLICATION CONFIG
|
45
46
|
|
47
|
+
EMPTY_CONFIG_FILE = File.join(SPEC_DIR, 'config', 'empty.yml')
|
46
48
|
TEST_CONFIG_APPLICATION_PATH = File.join(SPEC_DIR, 'config', 'applications.yml')
|
47
49
|
TEST_CONFIG_APPLICATION = YAML.load_file(TEST_CONFIG_APPLICATION_PATH)
|
48
50
|
TEST_JSON_DATA_PATH = File.join(SPEC_DIR, 'json')
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'hue'
|
2
|
+
|
3
|
+
bridge = Hue.application
|
4
|
+
|
5
|
+
MAX_LIGHTS = 4
|
6
|
+
|
7
|
+
@run = true
|
8
|
+
@command_count = 0
|
9
|
+
@error_count = 0
|
10
|
+
|
11
|
+
trap("SIGINT") do
|
12
|
+
@run = false
|
13
|
+
end
|
14
|
+
|
15
|
+
while(@run)
|
16
|
+
begin
|
17
|
+
@command_count += 1
|
18
|
+
number = rand(4)
|
19
|
+
light = rand(MAX_LIGHTS)
|
20
|
+
case number
|
21
|
+
when 0
|
22
|
+
puts bridge.status['config']['UTC']
|
23
|
+
when 1
|
24
|
+
print "#{light + 1} name: "
|
25
|
+
puts bridge.bulbs[light].refresh!['name']
|
26
|
+
when 2
|
27
|
+
print "#{light + 1} on: "
|
28
|
+
puts bridge.bulbs[light].on
|
29
|
+
when 3
|
30
|
+
print "#{light + 1} off: "
|
31
|
+
puts bridge.bulbs[light].off
|
32
|
+
else
|
33
|
+
raise "Unhandled case: #{number}"
|
34
|
+
end
|
35
|
+
rescue => err
|
36
|
+
puts err.message
|
37
|
+
@error_count += 1
|
38
|
+
end
|
39
|
+
sleep 1
|
40
|
+
end
|
41
|
+
|
42
|
+
puts "Command count: #{@command_count}"
|
43
|
+
puts "Fail count: #{@error_count}"
|
44
|
+
puts "Success rate: #{(1.0 - (@error_count/@command_count.to_f)) * 100}%"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hue-lib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-09-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: json
|
@@ -106,6 +106,7 @@ files:
|
|
106
106
|
- lib/hue/config/bridge.rb
|
107
107
|
- spec/config/applications.yml
|
108
108
|
- spec/config/bridges.yml
|
109
|
+
- spec/config/empty.yml
|
109
110
|
- spec/hue/bridge_spec.rb
|
110
111
|
- spec/hue/bulb_spec.rb
|
111
112
|
- spec/hue/colors/color_spec.rb
|
@@ -130,6 +131,7 @@ files:
|
|
130
131
|
- spec/json/schedules.json
|
131
132
|
- spec/json/unauthorized.json
|
132
133
|
- spec/spec_helper.rb
|
134
|
+
- test/connectivity.rb
|
133
135
|
homepage: https://github.com/birkirb/hue-lib
|
134
136
|
licenses: []
|
135
137
|
post_install_message:
|
@@ -155,4 +157,3 @@ signing_key:
|
|
155
157
|
specification_version: 3
|
156
158
|
summary: Ruby library for controlling the Philips Hue system's lights and bridge.
|
157
159
|
test_files: []
|
158
|
-
has_rdoc:
|