lifx-lan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +8 -0
  4. data/.yardopts +3 -0
  5. data/CHANGES.md +45 -0
  6. data/Gemfile +19 -0
  7. data/LICENSE.txt +23 -0
  8. data/README.md +15 -0
  9. data/Rakefile +20 -0
  10. data/bin/lifx-snoop +50 -0
  11. data/examples/auto-off/auto-off.rb +34 -0
  12. data/examples/blink/blink.rb +19 -0
  13. data/examples/identify/identify.rb +69 -0
  14. data/examples/travis-build-light/build-light.rb +57 -0
  15. data/lib/bindata_ext/bool.rb +30 -0
  16. data/lib/bindata_ext/record.rb +11 -0
  17. data/lib/lifx-lan.rb +27 -0
  18. data/lib/lifx/lan/client.rb +149 -0
  19. data/lib/lifx/lan/color.rb +199 -0
  20. data/lib/lifx/lan/config.rb +17 -0
  21. data/lib/lifx/lan/firmware.rb +60 -0
  22. data/lib/lifx/lan/gateway_connection.rb +185 -0
  23. data/lib/lifx/lan/light.rb +440 -0
  24. data/lib/lifx/lan/light_collection.rb +111 -0
  25. data/lib/lifx/lan/light_target.rb +185 -0
  26. data/lib/lifx/lan/logging.rb +14 -0
  27. data/lib/lifx/lan/message.rb +168 -0
  28. data/lib/lifx/lan/network_context.rb +188 -0
  29. data/lib/lifx/lan/observable.rb +66 -0
  30. data/lib/lifx/lan/protocol/address.rb +25 -0
  31. data/lib/lifx/lan/protocol/device.rb +387 -0
  32. data/lib/lifx/lan/protocol/header.rb +24 -0
  33. data/lib/lifx/lan/protocol/light.rb +142 -0
  34. data/lib/lifx/lan/protocol/message.rb +19 -0
  35. data/lib/lifx/lan/protocol/metadata.rb +23 -0
  36. data/lib/lifx/lan/protocol/payload.rb +12 -0
  37. data/lib/lifx/lan/protocol/sensor.rb +31 -0
  38. data/lib/lifx/lan/protocol/type.rb +204 -0
  39. data/lib/lifx/lan/protocol/wan.rb +51 -0
  40. data/lib/lifx/lan/protocol/wifi.rb +102 -0
  41. data/lib/lifx/lan/protocol_path.rb +85 -0
  42. data/lib/lifx/lan/required_keyword_arguments.rb +12 -0
  43. data/lib/lifx/lan/routing_manager.rb +114 -0
  44. data/lib/lifx/lan/routing_table.rb +48 -0
  45. data/lib/lifx/lan/seen.rb +25 -0
  46. data/lib/lifx/lan/site.rb +97 -0
  47. data/lib/lifx/lan/tag_manager.rb +111 -0
  48. data/lib/lifx/lan/tag_table.rb +49 -0
  49. data/lib/lifx/lan/target.rb +24 -0
  50. data/lib/lifx/lan/thread.rb +13 -0
  51. data/lib/lifx/lan/timers.rb +29 -0
  52. data/lib/lifx/lan/transport.rb +46 -0
  53. data/lib/lifx/lan/transport/tcp.rb +91 -0
  54. data/lib/lifx/lan/transport/udp.rb +87 -0
  55. data/lib/lifx/lan/transport_manager.rb +43 -0
  56. data/lib/lifx/lan/transport_manager/lan.rb +169 -0
  57. data/lib/lifx/lan/utilities.rb +36 -0
  58. data/lib/lifx/lan/version.rb +5 -0
  59. data/lifx-lan.gemspec +26 -0
  60. data/spec/color_spec.rb +43 -0
  61. data/spec/gateway_connection_spec.rb +30 -0
  62. data/spec/integration/client_spec.rb +42 -0
  63. data/spec/integration/light_spec.rb +56 -0
  64. data/spec/integration/tags_spec.rb +42 -0
  65. data/spec/light_collection_spec.rb +37 -0
  66. data/spec/message_spec.rb +183 -0
  67. data/spec/protocol_path_spec.rb +109 -0
  68. data/spec/routing_manager_spec.rb +25 -0
  69. data/spec/routing_table_spec.rb +23 -0
  70. data/spec/spec_helper.rb +56 -0
  71. data/spec/transport/udp_spec.rb +44 -0
  72. data/spec/transport_spec.rb +14 -0
  73. metadata +187 -0
@@ -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
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ bundler_args: --without development
3
+ notifications:
4
+ slack: lifx:z9PYWaIkFUpHw0aFu9mMQXDl
5
+ email: false
6
+ rvm:
7
+ - 2.0.0
8
+ - 2.1.1
@@ -0,0 +1,3 @@
1
+ --markup markdown
2
+ --no-private
3
+ --hide-api private
@@ -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
@@ -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.
@@ -0,0 +1,15 @@
1
+ # LIFX-lan
2
+
3
+ [![Build Status](https://travis-ci.org/juliancheal/lifx-lan.svg)](https://travis-ci.org/juliancheal/lifx-lan)
4
+ [![Code Climate](https://codeclimate.com/github/juliancheal/lifx-lan/badges/gpa.svg)](https://codeclimate.com/github/juliancheal/lifx-lan)
5
+ [![Coverage Status](https://coveralls.io/repos/juliancheal/lifx-lan/badge.svg?branch=master&service=github)](https://coveralls.io/github/juliancheal/lifx-lan?branch=master)
6
+ [![Dependency Status](https://gemnasium.com/juliancheal/lifx-lan.svg)](https://gemnasium.com/juliancheal/lifx-lan)
7
+ [![Security](https://hakiri.io/github/juliancheal/lifx-lan/master.svg)](https://hakiri.io/github/juliancheal/lifx-lan/master)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
10
+
11
+ [![Build history for master branch](https://buildstats.info/travisci/chart/ManageIQ/manageiq?branch=master&buildCount=50)](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/
@@ -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
@@ -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
@@ -0,0 +1,11 @@
1
+ require 'stringio'
2
+ BinData::Record
3
+ module BinData
4
+ class Record
5
+ def pack
6
+ s = StringIO.new
7
+ write(s)
8
+ s.string.b
9
+ end
10
+ end
11
+ end