lifx-lan 0.1.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 +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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4ef94c0b7aaaa1efaf0ed5510237c2f8e8638c69
|
4
|
+
data.tar.gz: 24ecd96f704325934c37882f5bd7f7417dbb4287
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 87d2775a26c2104f0789d07a9bb38ea1dda76ca5d03ac3031bdd41190f76cabc34e932a5785edc940e67458fdab064874a10d50f6a06a0d41da159d8f596157a
|
7
|
+
data.tar.gz: 18691da3eb56988e02c2a3fb94ec9f74b1271a901ea80b76a80e6c91e85bad86b32ea7c5c77051687df06495a88e406810a8fbea5dfa6f48bd6ca53d20c1bc36
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/CHANGES.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
### 0.4.10
|
2
|
+
|
3
|
+
- Fix `message_rate` visibility bug
|
4
|
+
|
5
|
+
### 0.4.9
|
6
|
+
|
7
|
+
- Message rate checker only runs when connection is idle
|
8
|
+
- Now uses `LIFX::TimeoutError` rather than `Timeout::Error` for internal timeout exceptions
|
9
|
+
|
10
|
+
### 0.4.8
|
11
|
+
|
12
|
+
- Routing table is only updated from State messages
|
13
|
+
- Fix memory leaks
|
14
|
+
|
15
|
+
### 0.4.7
|
16
|
+
|
17
|
+
- Only create Light devices when a Light::State is received
|
18
|
+
- Message rate checker only checks lights considered alive
|
19
|
+
|
20
|
+
### 0.4.6.1
|
21
|
+
|
22
|
+
- Fix `Time.parse` issue
|
23
|
+
|
24
|
+
### 0.4.6
|
25
|
+
|
26
|
+
- `Color#==` has been renamed to `Color#similar_to?`
|
27
|
+
- Broadcast IP configurable through `LIFX::Config.broadcast_ip`
|
28
|
+
- Removed Yell gem. Use stdlib Logger instead
|
29
|
+
- Uninitialized lights no longer shows up in `Client#lights`
|
30
|
+
- Handle Rubies that don't have IPv6 enabled
|
31
|
+
|
32
|
+
### 0.4.5
|
33
|
+
|
34
|
+
- Now supports Ruby 2.0
|
35
|
+
- Light#label can be nil
|
36
|
+
- Light#set_power and Light#set_power! now take :on and :off rather than magic number
|
37
|
+
- Use timers 1.x so no compilation is required
|
38
|
+
|
39
|
+
### 0.4.4
|
40
|
+
|
41
|
+
- Fix SO_REUSEPORT issue on older Linux kernels.
|
42
|
+
|
43
|
+
### 0.4.3
|
44
|
+
|
45
|
+
- Initial public release
|
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
group :development do
|
4
|
+
gem 'redcarpet'
|
5
|
+
gem 'erubis'
|
6
|
+
gem 'ruby-prof'
|
7
|
+
gem 'pry-byebug'
|
8
|
+
gem 'pry-rescue'
|
9
|
+
gem 'pry-stack_explorer'
|
10
|
+
gem 'yard'
|
11
|
+
end
|
12
|
+
|
13
|
+
group :test do
|
14
|
+
gem 'rake', '~> 10.1'
|
15
|
+
gem 'rspec', '~> 3.0.0'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Specify your gem's dependencies in lifx.gemspec
|
19
|
+
gemspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2012-2014 LIFX Labs
|
2
|
+
Copyright (c) 2017-2018 Julian Cheal
|
3
|
+
|
4
|
+
MIT License
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# LIFX-lan
|
2
|
+
|
3
|
+
[](https://travis-ci.org/juliancheal/lifx-lan)
|
4
|
+
[](https://codeclimate.com/github/juliancheal/lifx-lan)
|
5
|
+
[](https://coveralls.io/github/juliancheal/lifx-lan?branch=master)
|
6
|
+
[](https://gemnasium.com/juliancheal/lifx-lan)
|
7
|
+
[](https://hakiri.io/github/juliancheal/lifx-lan/master)
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
9
|
+
|
10
|
+
|
11
|
+
[](https://travis-ci.org/juliancheal/lifx-lan/branches)
|
12
|
+
|
13
|
+
LIFX-lan is a fork of the [lifx-gem](https://github.com/LIFX/lifx-gem). This gem is based on the [Lifx LAN](https://api.developer.lifx.com/) protocol.
|
14
|
+
|
15
|
+
Lifx have a Developer Zone over on their community site https://community.lifx.com/
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
5
|
+
t.rspec_opts = "--tag ~integration"
|
6
|
+
end
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
task :console do
|
10
|
+
$LOAD_PATH << "lib"
|
11
|
+
require "lifx"
|
12
|
+
require "pry"
|
13
|
+
if ENV['DEBUG']
|
14
|
+
LIFX::LAN::Config.logger.level = Logger::DEBUG
|
15
|
+
end
|
16
|
+
LIFX::LAN::Client.lan.discover! do |c|
|
17
|
+
c.lights.count > 0
|
18
|
+
end
|
19
|
+
LIFX::LAN::Client.lan.pry
|
20
|
+
end
|
data/bin/lifx-snoop
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# lifx-snoop is a utility that snoops on LIFX UDP traffic on both the broadcast port
|
3
|
+
# and the peer broadcast port.
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
# lifx-snoop [regexp, ...]
|
7
|
+
#
|
8
|
+
# By default, it will show all messages. Any arguments passed in will become
|
9
|
+
# regular expressions, which will then match on the string representation of the
|
10
|
+
# message.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# lifx-snoop Light::Get # Shows only Light::Get messages
|
14
|
+
# lifx-snoop Light::State site=d073d5000000 # Shows only Light::State messages matching site d073d5000000
|
15
|
+
|
16
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "..", "lib")
|
17
|
+
require 'lifx-lan'
|
18
|
+
require 'time'
|
19
|
+
|
20
|
+
matchers = ARGV.map do |arg|
|
21
|
+
Regexp.new(arg, Regexp::IGNORECASE)
|
22
|
+
end
|
23
|
+
|
24
|
+
if matchers.empty?
|
25
|
+
matchers << //
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
light_udp = LIFX::LAN::Transport::UDP.new('0.0.0.0', 56700)
|
30
|
+
light_udp.add_observer(self, :message_received) do |message: nil, ip: nil, transport: nil|
|
31
|
+
if matchers.all? { |m| message.to_s =~ m }
|
32
|
+
puts "#{Time.now.iso8601(5)} BROADCAST: #{ip} #{message}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
light_udp.listen
|
36
|
+
|
37
|
+
peer_udp = LIFX::LAN::Transport::UDP.new('0.0.0.0', 56750)
|
38
|
+
peer_udp.add_observer(self, :message_received) do |message: nil, ip: nil, transport: nil|
|
39
|
+
if matchers.all? { |m| message.to_s =~ m }
|
40
|
+
puts "#{Time.now.iso8601(5)} PEER: #{ip} #{message}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
peer_udp.listen
|
44
|
+
rescue LIFX::LAN::Message::UnsupportedProtocolVersion
|
45
|
+
end
|
46
|
+
|
47
|
+
puts "Listening on 56700 and 56750..."
|
48
|
+
puts "^C to quit."
|
49
|
+
|
50
|
+
sleep
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Auto-off script
|
2
|
+
#
|
3
|
+
# This script will turn a light off after 10 seconds when it has detected it has turned on.
|
4
|
+
# To run: bundle; bundle ruby auto-off.rb [light label]
|
5
|
+
|
6
|
+
require 'lifx-lan'
|
7
|
+
|
8
|
+
AUTO_OFF_DELAY = 10
|
9
|
+
|
10
|
+
label = ARGV.first
|
11
|
+
lifx = LIFX::LAN::Client.lan
|
12
|
+
lifx.discover! do
|
13
|
+
label ? lifx.lights.with_label(label) : lifx.lights.first
|
14
|
+
end
|
15
|
+
|
16
|
+
light = label ? lifx.lights.with_label(label) : lifx.lights.first
|
17
|
+
|
18
|
+
puts "#{light} will be automatically turned off after #{AUTO_OFF_DELAY} seconds"
|
19
|
+
|
20
|
+
thr = Thread.new do
|
21
|
+
loop do
|
22
|
+
if light.on? && !(@off_thr && @off_thr.alive?)
|
23
|
+
puts "Light detected on. Turning off in #{AUTO_OFF_DELAY}"
|
24
|
+
@off_thr = Thread.new do
|
25
|
+
sleep AUTO_OFF_DELAY
|
26
|
+
light.turn_off
|
27
|
+
puts "Turning off"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
sleep 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
thr.join
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'lifx-lan'
|
2
|
+
|
3
|
+
lifx = LIFX::LAN::Client.lan
|
4
|
+
lifx.discover!
|
5
|
+
|
6
|
+
light = lifx.lights.first
|
7
|
+
light.set_color LIFX::LAN::Color.white, duration: 0
|
8
|
+
|
9
|
+
sleep(0.5)
|
10
|
+
|
11
|
+
light.set_color LIFX::LAN::Color.red, duration: 0
|
12
|
+
|
13
|
+
sleep(0.5)
|
14
|
+
|
15
|
+
light.set_color LIFX::LAN::Color.white, duration: 0
|
16
|
+
|
17
|
+
sleep(0.5)
|
18
|
+
|
19
|
+
light.set_color LIFX::LAN::Color.red, duration: 0
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Identify
|
2
|
+
#
|
3
|
+
# This example uses a divide and conquer search algorithm to identify a light visually.
|
4
|
+
# It will set all lights to white, then partition them by colour.
|
5
|
+
# On each iteration, it will ask you what colour the bulb you're trying to identify is showing
|
6
|
+
# until it narrows it down to a single bulb.
|
7
|
+
# Please note it does not restore the light state before identification.
|
8
|
+
|
9
|
+
require 'lifx-lan'
|
10
|
+
|
11
|
+
COLOURS = {
|
12
|
+
'red' => [0, 1, 1],
|
13
|
+
'yellow' => [50, 1, 1],
|
14
|
+
'green' => [120, 1, 1],
|
15
|
+
'blue' => [220, 1, 1]
|
16
|
+
}
|
17
|
+
|
18
|
+
LIFX::LAN::Config.logger = Logger.new(STDERR)
|
19
|
+
c = LIFX::Client.lan
|
20
|
+
c.discover
|
21
|
+
5.times do
|
22
|
+
c.lights.refresh
|
23
|
+
c.flush
|
24
|
+
sleep 1
|
25
|
+
puts "Lights found: #{c.lights.count}"
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def partition(list, partitions)
|
30
|
+
[].tap do |array|
|
31
|
+
list.each_slice((list.count / partitions.to_f).ceil) do |chunk|
|
32
|
+
array << chunk
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
lights = c.lights.to_a
|
38
|
+
mapping = {}
|
39
|
+
|
40
|
+
while lights.count > 1
|
41
|
+
puts "Searching through #{lights.count} lights..."
|
42
|
+
c.lights.set_color(LIFX::LAN::Color.white)
|
43
|
+
partitions = partition(lights, COLOURS.values.count)
|
44
|
+
COLOURS.keys.each_with_index do |color_name, index|
|
45
|
+
color = LIFX::LAN::Color.hsb(*COLOURS[color_name])
|
46
|
+
mapping[color_name] = partitions[index]
|
47
|
+
next if partitions[index].nil?
|
48
|
+
partitions[index].each do |l|
|
49
|
+
l.set_color(color, duration: 0)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
puts "Waiting for flush."
|
53
|
+
c.flush
|
54
|
+
puts "What colour is the bulb you're trying to identify? (#{COLOURS.keys.join(', ')})"
|
55
|
+
resp = gets.strip
|
56
|
+
if mapping.has_key?(resp)
|
57
|
+
lights = mapping[resp]
|
58
|
+
else
|
59
|
+
puts "Colour not found. Iterating again"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if lights.count == 1
|
64
|
+
puts "Light identified: #{lights.first}"
|
65
|
+
else
|
66
|
+
puts "No bulbs found."
|
67
|
+
end
|
68
|
+
|
69
|
+
c.flush
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# A Travis CI Build Light
|
2
|
+
#
|
3
|
+
# To run: bundle; bundle ruby build-light.rb [user/repo]
|
4
|
+
# Please note this doesn't have error handling yet.
|
5
|
+
|
6
|
+
require 'travis'
|
7
|
+
require 'lifx-lan'
|
8
|
+
|
9
|
+
lifx = LIFX::LAN::Client.lan
|
10
|
+
lifx.discover!
|
11
|
+
sleep 2 # Wait for tag data to come back
|
12
|
+
|
13
|
+
light = if lifx.tags.include?('Build Light')
|
14
|
+
lights = lifx.lights.with_tag('Build Light')
|
15
|
+
if lights.empty?
|
16
|
+
puts "No lights in the Build Light tag, using the first light found."
|
17
|
+
lifx.lights.first
|
18
|
+
else
|
19
|
+
lights
|
20
|
+
end
|
21
|
+
else
|
22
|
+
lifx.lights.first
|
23
|
+
end
|
24
|
+
|
25
|
+
if !light
|
26
|
+
puts "No LIFX lights found."
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
|
30
|
+
puts "Using light(s): #{light}"
|
31
|
+
repo_path = ARGV.first || 'rails/rails'
|
32
|
+
|
33
|
+
repo = Travis::Repository.find(repo_path)
|
34
|
+
puts "Watching repository #{repo.slug}"
|
35
|
+
|
36
|
+
def update_light(light, repository)
|
37
|
+
color = case repository.color
|
38
|
+
when 'green'
|
39
|
+
LIFX::LAN::Color.hsb(120, 1, 1)
|
40
|
+
when 'yellow'
|
41
|
+
LIFX::LAN::Color.hsb(60, 1, 1)
|
42
|
+
when 'red'
|
43
|
+
LIFX::LAN::Color.hsb(0, 1, 1)
|
44
|
+
end
|
45
|
+
|
46
|
+
light.turn_on!
|
47
|
+
light.set_color(color, duration: 0.2)
|
48
|
+
puts "#{Time.now}: Build ##{repository.last_build.number} is #{repository.color}."
|
49
|
+
end
|
50
|
+
|
51
|
+
update_light(light, repo)
|
52
|
+
|
53
|
+
Travis.listen(repo) do |stream|
|
54
|
+
stream.on('build:started', 'build:finished') do |event|
|
55
|
+
update_light(light, event.repository)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# @private
|
2
|
+
module BinData
|
3
|
+
class Bool < Primitive
|
4
|
+
uint8 :_value
|
5
|
+
|
6
|
+
def get
|
7
|
+
(self._value || 0) > 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def set(value)
|
11
|
+
self._value = value ? 1 : 0
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class BoolBit1 < Primitive
|
16
|
+
bit1le :_value
|
17
|
+
|
18
|
+
def get
|
19
|
+
(self._value || 0) > 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def set(value)
|
23
|
+
self._value = value ? 1 : 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def !
|
27
|
+
!get
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|