lifx-lan 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +8 -0
- data/.yardopts +3 -0
- data/CHANGES.md +45 -0
- data/Gemfile +19 -0
- data/LICENSE.txt +23 -0
- data/README.md +15 -0
- data/Rakefile +20 -0
- data/bin/lifx-snoop +50 -0
- data/examples/auto-off/auto-off.rb +34 -0
- data/examples/blink/blink.rb +19 -0
- data/examples/identify/identify.rb +69 -0
- data/examples/travis-build-light/build-light.rb +57 -0
- data/lib/bindata_ext/bool.rb +30 -0
- data/lib/bindata_ext/record.rb +11 -0
- data/lib/lifx-lan.rb +27 -0
- data/lib/lifx/lan/client.rb +149 -0
- data/lib/lifx/lan/color.rb +199 -0
- data/lib/lifx/lan/config.rb +17 -0
- data/lib/lifx/lan/firmware.rb +60 -0
- data/lib/lifx/lan/gateway_connection.rb +185 -0
- data/lib/lifx/lan/light.rb +440 -0
- data/lib/lifx/lan/light_collection.rb +111 -0
- data/lib/lifx/lan/light_target.rb +185 -0
- data/lib/lifx/lan/logging.rb +14 -0
- data/lib/lifx/lan/message.rb +168 -0
- data/lib/lifx/lan/network_context.rb +188 -0
- data/lib/lifx/lan/observable.rb +66 -0
- data/lib/lifx/lan/protocol/address.rb +25 -0
- data/lib/lifx/lan/protocol/device.rb +387 -0
- data/lib/lifx/lan/protocol/header.rb +24 -0
- data/lib/lifx/lan/protocol/light.rb +142 -0
- data/lib/lifx/lan/protocol/message.rb +19 -0
- data/lib/lifx/lan/protocol/metadata.rb +23 -0
- data/lib/lifx/lan/protocol/payload.rb +12 -0
- data/lib/lifx/lan/protocol/sensor.rb +31 -0
- data/lib/lifx/lan/protocol/type.rb +204 -0
- data/lib/lifx/lan/protocol/wan.rb +51 -0
- data/lib/lifx/lan/protocol/wifi.rb +102 -0
- data/lib/lifx/lan/protocol_path.rb +85 -0
- data/lib/lifx/lan/required_keyword_arguments.rb +12 -0
- data/lib/lifx/lan/routing_manager.rb +114 -0
- data/lib/lifx/lan/routing_table.rb +48 -0
- data/lib/lifx/lan/seen.rb +25 -0
- data/lib/lifx/lan/site.rb +97 -0
- data/lib/lifx/lan/tag_manager.rb +111 -0
- data/lib/lifx/lan/tag_table.rb +49 -0
- data/lib/lifx/lan/target.rb +24 -0
- data/lib/lifx/lan/thread.rb +13 -0
- data/lib/lifx/lan/timers.rb +29 -0
- data/lib/lifx/lan/transport.rb +46 -0
- data/lib/lifx/lan/transport/tcp.rb +91 -0
- data/lib/lifx/lan/transport/udp.rb +87 -0
- data/lib/lifx/lan/transport_manager.rb +43 -0
- data/lib/lifx/lan/transport_manager/lan.rb +169 -0
- data/lib/lifx/lan/utilities.rb +36 -0
- data/lib/lifx/lan/version.rb +5 -0
- data/lifx-lan.gemspec +26 -0
- data/spec/color_spec.rb +43 -0
- data/spec/gateway_connection_spec.rb +30 -0
- data/spec/integration/client_spec.rb +42 -0
- data/spec/integration/light_spec.rb +56 -0
- data/spec/integration/tags_spec.rb +42 -0
- data/spec/light_collection_spec.rb +37 -0
- data/spec/message_spec.rb +183 -0
- data/spec/protocol_path_spec.rb +109 -0
- data/spec/routing_manager_spec.rb +25 -0
- data/spec/routing_table_spec.rb +23 -0
- data/spec/spec_helper.rb +56 -0
- data/spec/transport/udp_spec.rb +44 -0
- data/spec/transport_spec.rb +14 -0
- metadata +187 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LIFX
|
4
|
+
module LAN
|
5
|
+
describe 'tags', integration: true do
|
6
|
+
let(:color) { Color.hsb(rand(360), 0.3, 0.3) }
|
7
|
+
|
8
|
+
specify 'Clearing, setting and using tags' do
|
9
|
+
light.add_tag('Foo')
|
10
|
+
expect(light.tags).to include('Foo')
|
11
|
+
|
12
|
+
test_tag = lights.with_tag('Foo')
|
13
|
+
test_tag.turn_on
|
14
|
+
test_tag.set_color(color, duration: 0)
|
15
|
+
flush
|
16
|
+
sleep 1 # Set messages are scheduled 250ms if no at_time is set
|
17
|
+
# It also returns the current light state rather than the
|
18
|
+
# final state
|
19
|
+
light.refresh
|
20
|
+
wait { expect(light.color).to be_similar_to(color) }
|
21
|
+
|
22
|
+
light.remove_tag('Foo')
|
23
|
+
wait { expect(light.tags).not_to include('Foo') }
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'deletes tags when no longer assigned to a light' do
|
27
|
+
light.add_tag('TempTag')
|
28
|
+
light.remove_tag('TempTag')
|
29
|
+
expect(lifx.unused_tags).to include('TempTag')
|
30
|
+
lifx.purge_unused_tags!
|
31
|
+
expect(lifx.unused_tags).to be_empty
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'handles non-ascii tags' do
|
35
|
+
light.add_tag('_tést')
|
36
|
+
expect(light.tags).to include('_tést')
|
37
|
+
light.remove_tag('_tést')
|
38
|
+
lifx.purge_unused_tags!
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LIFX
|
4
|
+
module LAN
|
5
|
+
describe LightCollection do
|
6
|
+
subject(:collection) { LightCollection.new(context: double) }
|
7
|
+
|
8
|
+
describe '#with_id' do
|
9
|
+
let(:light) { double(Light, id: 'id') }
|
10
|
+
before { allow(collection).to receive(:lights).and_return([light]) }
|
11
|
+
|
12
|
+
it 'returns a Light with matching id' do
|
13
|
+
expect(collection.with_id('id')).to eq light
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns nil when none matches' do
|
17
|
+
ret = collection.with_id('wrong id')
|
18
|
+
expect(ret).to eq nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#with_label' do
|
23
|
+
let(:light) { double(Light, label: 'label') }
|
24
|
+
before { allow(collection).to receive(:lights).and_return([light]) }
|
25
|
+
|
26
|
+
it 'returns a Light with matching label' do
|
27
|
+
expect(collection.with_label('label')).to eq light
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns nil' do
|
31
|
+
ret = collection.with_label('wrong label')
|
32
|
+
expect(ret).to eq nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LIFX::LAN::Message do
|
4
|
+
context 'unpacking' do
|
5
|
+
let(:data) do
|
6
|
+
"\x39\x00\x00\x34\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x31" \
|
7
|
+
"\x6c\x69\x66\x78\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x67\x00" \
|
8
|
+
"\x00\x00\x00\x01\x00\x00\xff\xff\xff\xff\xac\x0d\xc8\x00\x00\x00\x00" \
|
9
|
+
"\x00\x80\x3f\x00\x00\x00".b
|
10
|
+
end
|
11
|
+
let(:msg) { LIFX::LAN::Message.unpack(data) }
|
12
|
+
|
13
|
+
it 'unpacks without errors' do
|
14
|
+
expect(msg).not_to be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns the correct frame data' do
|
18
|
+
expect(msg.msg_size).to eq 57
|
19
|
+
expect(msg.protocol).to eq 1024
|
20
|
+
expect(msg).to be_addressable
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns the correct address data' do
|
24
|
+
expect(msg.raw_site).to eq '1lifx1'
|
25
|
+
expect(msg.raw_target).to eq "\x00" * 8
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'has correct ProtocolPath data' do
|
29
|
+
expect(msg.path).to be_a(LIFX::LAN::ProtocolPath)
|
30
|
+
expect(msg.path.site_id).to eq '316c69667831'
|
31
|
+
expect(msg.path.tag_ids).to eq []
|
32
|
+
expect(msg.path.device_id).to be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns the correct metadata' do
|
36
|
+
expect(msg.at_time).to eq 0
|
37
|
+
expect(msg.type_).to eq 103
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:payload) { msg.payload }
|
41
|
+
it 'returns the payload' do
|
42
|
+
expect(payload.class).to eq LIFX::LAN::Protocol::Light::SetWaveform
|
43
|
+
expect(payload.stream).to eq 0
|
44
|
+
expect(payload.transient).to eq(true)
|
45
|
+
expect(payload.color.hue).to eq 0
|
46
|
+
expect(payload.color.saturation).to eq 65_535
|
47
|
+
expect(payload.color.brightness).to eq 65_535
|
48
|
+
expect(payload.color.kelvin).to eq 3_500
|
49
|
+
expect(payload.period).to eq 200
|
50
|
+
expect(payload.cycles).to eq 1.0
|
51
|
+
expect(payload.skew_ratio).to eq 0
|
52
|
+
expect(payload.waveform).to eq 0
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'repacks to the same data' do
|
56
|
+
expect(msg.pack).to eq data
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'packing' do
|
61
|
+
context 'no attributes' do
|
62
|
+
let(:msg) { LIFX::LAN::Message.new }
|
63
|
+
|
64
|
+
it 'throws an exception' do
|
65
|
+
expect { msg.pack }.to raise_error(LIFX::LAN::Message::NoPayload)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'no path' do
|
70
|
+
let(:msg) { LIFX::LAN::Message.new(payload: LIFX::LAN::Protocol::Device::SetPower.new) }
|
71
|
+
|
72
|
+
it 'defaults to null site and target' do
|
73
|
+
unpacked = LIFX::LAN::Message.unpack(msg.pack)
|
74
|
+
expect(unpacked.path.site_id).to eq('000000000000')
|
75
|
+
expect(unpacked.path.device_id).to eq('000000000000')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'passed in via hash' do
|
80
|
+
let(:msg) do
|
81
|
+
LIFX::LAN::Message.new({
|
82
|
+
path: LIFX::LAN::ProtocolPath.new(tagged: false, raw_target: 'abcdefgh'),
|
83
|
+
at_time: 9001,
|
84
|
+
payload: LIFX::LAN::Protocol::Wifi::SetAccessPoint.new(
|
85
|
+
interface: 1,
|
86
|
+
ssid: 'who let the dogs out',
|
87
|
+
pass: 'woof, woof, woof woof!',
|
88
|
+
security: 1
|
89
|
+
)
|
90
|
+
})
|
91
|
+
end
|
92
|
+
# let(:unpacked) { LIFX::Message.unpack(msg.pack) }
|
93
|
+
|
94
|
+
it 'sets the size' do
|
95
|
+
expect(msg.msg_size).to eq 134
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'packs correctly' do
|
99
|
+
expect(msg.pack).to eq "\x86\x00\x00\x14\x00\x00\x00\x00abcdefgh\x00" \
|
100
|
+
"\x00\x00\x00\x00\x00\x00\x00)#\x00\x00\x00" \
|
101
|
+
"\x00\x00\x001\x01\x00\x00\x01who let the " \
|
102
|
+
"dogs out\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
103
|
+
"\x00\x00\x00woof, woof, woof woof!\x00\x00" \
|
104
|
+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
105
|
+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
106
|
+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
107
|
+
"\x00\x00\x00\x00\x00\x00\x00\x01".b
|
108
|
+
expect(msg.protocol).to eq 1024
|
109
|
+
expect(msg.path).not_to be_tagged
|
110
|
+
expect(msg).to be_addressable
|
111
|
+
expect(msg.path.raw_target).to eq 'abcdefgh'
|
112
|
+
expect(msg.at_time).to eq 9001
|
113
|
+
expect(msg.type_).to eq 305
|
114
|
+
expect(msg.payload.class).to eq LIFX::LAN::Protocol::Wifi::SetAccessPoint
|
115
|
+
expect(msg.payload.interface).to eq 1
|
116
|
+
expect(msg.payload.ssid).to eq 'who let the dogs out'
|
117
|
+
expect(msg.payload.pass).to eq 'woof, woof, woof woof!'
|
118
|
+
expect(msg.payload.security).to eq 1
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'packing with tags' do
|
123
|
+
let(:msg) do
|
124
|
+
LIFX::LAN::Message.new({
|
125
|
+
path: LIFX::LAN::ProtocolPath.new(tag_ids: [0, 1]),
|
126
|
+
at_time: 9001,
|
127
|
+
payload: LIFX::LAN::Protocol::Device::GetTime.new
|
128
|
+
})
|
129
|
+
end
|
130
|
+
|
131
|
+
let(:unpacked) { LIFX::LAN::Message.unpack(msg.pack) }
|
132
|
+
|
133
|
+
it 'packs the tag correctly' do
|
134
|
+
expect(msg.pack).to eq "$\x00\x004\x00\x00\x00\x00\x03\x00\x00\x00" \
|
135
|
+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
136
|
+
"\x00)#\x00\x00\x00\x00\x00\x00\x04\x00\x00" \
|
137
|
+
"\x00".b
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'sets tagged' do
|
141
|
+
expect(unpacked.path).to be_tagged
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'sets tags' do
|
145
|
+
expect(unpacked.path.tag_ids).to eq [0, 1]
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'device should be nil' do
|
149
|
+
expect(unpacked.path.device_id).to be_nil
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'packing with device' do
|
154
|
+
let(:msg) do
|
155
|
+
LIFX::LAN::Message.new({
|
156
|
+
path: LIFX::LAN::ProtocolPath.new(device_id: '0123456789ab', site_id: '0' * 12),
|
157
|
+
at_time: 9001,
|
158
|
+
payload: LIFX::LAN::Protocol::Device::GetTime.new
|
159
|
+
})
|
160
|
+
end
|
161
|
+
|
162
|
+
let(:unpacked) { LIFX::LAN::Message.unpack(msg.pack) }
|
163
|
+
|
164
|
+
it 'packs the tag correctly' do
|
165
|
+
expect(msg.pack).to eq "$\x00\x00\x14\x00\x00\x00\x00\x01#Eg\x89\xAB" \
|
166
|
+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)#" \
|
167
|
+
"\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00".b
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'sets tagged to false' do
|
171
|
+
expect(unpacked.path).not_to be_tagged
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'sets device' do
|
175
|
+
expect(unpacked.path.device_id).to eq '0123456789ab'
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'tags should be nil' do
|
179
|
+
expect(unpacked.path.tag_ids).to be_nil
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LIFX
|
4
|
+
module LAN
|
5
|
+
describe ProtocolPath do
|
6
|
+
describe 'initializing from raw data' do
|
7
|
+
subject do
|
8
|
+
ProtocolPath.new(raw_site: '1lifx1', raw_target: target, tagged: tagged)
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'device target' do
|
12
|
+
let(:target) { "\xAB\xCD\xEF\x12\x34\x56\x00\x00" }
|
13
|
+
let(:tagged) { false }
|
14
|
+
|
15
|
+
it 'returns site_id in hex' do
|
16
|
+
expect(subject.site_id).to eq '316c69667831'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns device_id in hex' do
|
20
|
+
expect(subject.device_id).to eq 'abcdef123456'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns tagged as false' do
|
24
|
+
expect(subject).not_to be_tagged
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns nil for tag_ids' do
|
28
|
+
expect(subject.tag_ids).to be_nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'tagged target' do
|
33
|
+
let(:target) { "\x03\x00\x00\x00\x00\x00\x00\x00" }
|
34
|
+
let(:tagged) { true }
|
35
|
+
|
36
|
+
it 'returns site_id in hex' do
|
37
|
+
expect(subject.site_id).to eq '316c69667831'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns device_id as nil' do
|
41
|
+
expect(subject.device_id).to be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns tagged as true' do
|
45
|
+
expect(subject).to be_tagged
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns the tag_ids' do
|
49
|
+
expect(subject.tag_ids).to eq [0, 1]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'initializing from strings' do
|
55
|
+
context 'device target' do
|
56
|
+
subject do
|
57
|
+
ProtocolPath.new(site_id: '316c69667831', device_id: 'abcdef123456')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'sets raw_site correctly' do
|
61
|
+
expect(subject.raw_site).to eq '1lifx1'
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'sets raw_target correctly' do
|
65
|
+
expect(subject.raw_target).to eq "\xAB\xCD\xEF\x12\x34\x56\x00\x00".b
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'sets tagged to false' do
|
69
|
+
expect(subject).to_not be_tagged
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'tagged target' do
|
74
|
+
subject do
|
75
|
+
ProtocolPath.new(site_id: '316c69667831', tag_ids: [0, 1])
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'sets raw_site properly' do
|
79
|
+
expect(subject.raw_site).to eq '1lifx1'
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'sets raw_target correctly' do
|
83
|
+
expect(subject.raw_target).to eq "\x03\x00\x00\x00\x00\x00\x00\x00".b
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'returns tagged as true' do
|
87
|
+
expect(subject).to be_tagged
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'tagged target with no site' do
|
92
|
+
subject { ProtocolPath.new(tagged: true) }
|
93
|
+
|
94
|
+
it 'raw_site should be null string' do
|
95
|
+
expect(subject.raw_site).to eq "\x00\x00\x00\x00\x00\x00".b
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'sets raw_target correctly' do
|
99
|
+
expect(subject.raw_target).to eq "\x00\x00\x00\x00\x00\x00\x00\x00".b
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns tagged as true' do
|
103
|
+
expect(subject).to be_tagged
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LIFX
|
4
|
+
module LAN
|
5
|
+
describe RoutingManager do
|
6
|
+
describe '#tags_for_device_id' do
|
7
|
+
subject(:manager) { RoutingManager.new(context: double(timers: double(every: double))) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
['Some label', 'Another label', 'Much label'].each_with_index do |lbl, i|
|
11
|
+
manager.tag_table.update_table(device_id: 'device', tag_id: i, label: lbl)
|
12
|
+
end
|
13
|
+
|
14
|
+
manager.routing_table
|
15
|
+
.update_table(site_id: 'site', device_id: 'device', tag_ids: [0, 2])
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'resolves tags' do
|
19
|
+
tags = manager.tags_for_device_id('device')
|
20
|
+
expect(tags).to eq ['Some label', 'Much label']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LIFX
|
4
|
+
module LAN
|
5
|
+
describe RoutingTable do
|
6
|
+
describe '#clear_stale_entries' do
|
7
|
+
subject(:table) { RoutingTable.new }
|
8
|
+
|
9
|
+
before do
|
10
|
+
table.update_table(site_id: 'site', device_id: 'stale device', last_seen: Time.now - 305)
|
11
|
+
table.update_table(site_id: 'site', device_id: 'recent device', last_seen: Time.now)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'clears only entries older than 5 minutes' do
|
15
|
+
expect(table.entries.count).to eq(2)
|
16
|
+
table.clear_stale_entries
|
17
|
+
expect(table.entries.count).to eq(1)
|
18
|
+
expect(table.entries.first.device_id).to eq('recent device')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
begin
|
4
|
+
require 'pry'
|
5
|
+
rescue LoadError
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'lifx-lan'
|
9
|
+
require 'lifx/lan/utilities'
|
10
|
+
|
11
|
+
shared_context 'integration', integration: true do
|
12
|
+
def lifx
|
13
|
+
$lifx ||= begin
|
14
|
+
c = LIFX::LAN::Client.lan
|
15
|
+
begin
|
16
|
+
c.discover! do
|
17
|
+
c.tags.include?('_Test') && c.lights.with_tag('_Test').count > 0
|
18
|
+
end
|
19
|
+
rescue LIFX::Client::DiscoveryTimeout
|
20
|
+
raise "Could not find any lights with tag _Test in #{c.lights.inspect}"
|
21
|
+
end
|
22
|
+
c
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def flush
|
27
|
+
lifx.flush
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:lights) { lifx.lights.with_tag('_Test') }
|
31
|
+
let(:light) { lights.first }
|
32
|
+
end
|
33
|
+
|
34
|
+
module SpecHelpers
|
35
|
+
def wait(timeout: 5, retry_wait: 0.1, &block)
|
36
|
+
Timeout.timeout(timeout) do
|
37
|
+
begin
|
38
|
+
block.call
|
39
|
+
rescue RSpec::Expectations::ExpectationNotMetError
|
40
|
+
lights.refresh
|
41
|
+
sleep(retry_wait)
|
42
|
+
retry
|
43
|
+
end
|
44
|
+
end
|
45
|
+
rescue Timeout::Error
|
46
|
+
block.call
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
LIFX::LAN::Config.logger = Yell.new(STDERR) if ENV['DEBUG']
|
51
|
+
|
52
|
+
RSpec.configure do |config|
|
53
|
+
config.include(SpecHelpers)
|
54
|
+
config.formatter = 'documentation'
|
55
|
+
config.color = true
|
56
|
+
end
|