hue-lib 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
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.1'
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 = 10 # Slower timeout on read fail, but way faster than the default.
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
- 'none' == self['alert']
152
+ NONE == alert
113
153
  end
114
154
 
115
155
  def blink
116
- update_state(alert: 'lselect')
156
+ self.alert = 'lselect'
117
157
  end
118
158
 
119
159
  def solid
120
- update_state(alert: 'none')
160
+ self.alert = NONE
121
161
  end
122
162
 
123
163
  def flash
124
- update_state(alert: 'select')
164
+ self.alert = 'select'
125
165
  # immediately update to expected state
126
- @status['state']['alert'] = 'none'
166
+ @status['state']['alert'] = NONE
127
167
  end
128
168
 
169
+ # transition time in seconds
129
170
  def transition_time
130
- # transition time in seconds
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
- # transition time in seconds
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
@@ -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 Hash.new
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 'uuid'
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
- Digest::MD5.hexdigest(UUID.generate)
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 uuid = /uuid:(.{36})/.match(message)
73
+ if uuid_match = /uuid:(.{36})/.match(message)
75
74
  # Assume this is Philips Hue for now.
76
- bridges[uuid.captures.first] = "http://#{ip_add}/api"
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
+ --- {}
@@ -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
@@ -21,7 +21,7 @@ describe Hue::Config::Bridge do
21
21
  end
22
22
 
23
23
  context 'given an new config' do
24
- uuid = UUID.generate
24
+ uuid = Hue.one_time_uuid
25
25
  uri = 'http://someip/api'
26
26
  config = described_class.new(uuid, uri)
27
27
 
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.1
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-02-06 00:00:00.000000000 Z
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: