lifx / lifx-gem Goto Github PK
View Code? Open in Web Editor NEWA Ruby gem that gives you the ability to easily interact with your LIFX lights.
Home Page: http://lifx.co/
License: MIT License
A Ruby gem that gives you the ability to easily interact with your LIFX lights.
Home Page: http://lifx.co/
License: MIT License
Looking through everything I can't seem to see anything which addresses the issue of connecting the lightbulb to the wifi.
This is still seems completely useless for me since I do not have an iPhone or Android phone...
Flakey wifi can cause TCP connect to be slow or time out, which causes the GatewayConnection to not use UDP until the connection fails.
It'd be cool if you could attach event listeners to lights that get called on state changes:
light.listen(:on) { |target| target.set_color(favourite_colour) }
There might be some kind of a race condition in the code whereby something requires "time"
usually before a discovery packet is received.
$ irb -r lifx
irb(main):001:0> client = LIFX::Client.lan
=> #<LIFX::Client:0x007f2a2b6ddec0 @context=#<LIFX::NetworkContext connections=[]>>
irb(main):002:0> client.discover!
=> #<LIFX::Client:0x007f2a2b6ddec0 @context=#<LIFX::NetworkContext connections=[#<LIFX::GatewayConnection tcp=#<LIFX::Transport::TCP 192.168.11.57:56700> tcp_attempts=1 udp=#<LIFX::
Transport::UDP 192.168.11.57:56700>>]>>
irb(main):003:0> /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/firmware.rb:42:in `decode_time': undefined method `parse' for Time:Class (NoMethodError)
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/firmware.rb:8:in `initialize'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/light.rb:422:in `new'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/light.rb:422:in `block in add_hooks'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/light.rb:46:in `call'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/light.rb:46:in `block in handle_message'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/light.rb:45:in `each'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/light.rb:45:in `handle_message'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/network_context.rb:175:in `handle_message'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/network_context.rb:29:in `block in initialize'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/observable.rb:18:in `call'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/observable.rb:18:in `block in notify_observers'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/observable.rb:17:in `each'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/observable.rb:17:in `notify_observers'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/transport_manager/lan.rb:117:in `block in create_broadcast_transport'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/observable.rb:18:in `call'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/observable.rb:18:in `block in notify_observers'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/observable.rb:17:in `each'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/observable.rb:17:in `notify_observers'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/transport/udp.rb:42:in `block (2 levels) in listen'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/transport/udp.rb:38:in `loop'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.6/lib/lifx/transport/udp.rb:38:in `block in listen'
Time.parse
is only defined after requiring the stdlib additions for time:
irb(main):001:0> Time.parse
NoMethodError: undefined method `parse' for Time:Class
from (irb):1
from /volume1/@appstore/ruby/bin/irb:12:in `<main>'
irb(main):002:0> require 'time'
=> true
irb(main):003:0> Time.parse
ArgumentError: wrong number of arguments (0 for 1..2)
from /usr/local/ruby/lib/ruby/2.0.0/time.rb:323:in `parse'
from (irb):3
from /volume1/@appstore/ruby/bin/irb:12:in `<main>'
irb(main):004:0>
When tethering over Bluetooth, the broadcast packets to 255.255.255.255 only get sent out on the Bluetooth PAN instead of the WIFI.
[10] pry(#<LIFX::Client>)> lights.lights
=> [#<LIFX::Light id=d073d500c7c9 label=Out of the Closet power=on>,
#<LIFX::Light id=d073d5018fa3 label=Living Room power=on>,
#<LIFX::Light id=d073d500fe75 label=Adventure power=on>,
#<LIFX::Light id=d073d5014021 label=Falcon Friend power=on>,
#<LIFX::Light id=000000000000 label= power=unknown>]
I only have four lightbulbs, but consistently the ruby library thinks there is one more... Above example is from @chendo's lifx-console tool. The 000000000000 bulb is the first one the library thinks it finds too - before the library discovers any of the real lightbulbs, that one is there, lurking in the list.
running lifx-snoop 000000000000
and lifx-http
after a couple of days I see a lot of this sort of activity:
2014-04-05T10:02:24.63354+11:00 PEER: 10.0.1.6 #<LIFX::Message site=000000000000 device=000000000000 type=Device::GetMeshFirmware addressable=true tagged=false protocol=1024 payload={}>
2014-04-05T10:02:29.63346+11:00 BROADCAST: 10.0.1.6 #<LIFX::Message site=000000000000 device=000000000000 type=Device::GetMeshFirmware addressable=true tagged=false protocol=1024 payload={}>
2014-04-05T10:02:29.63467+11:00 PEER: 10.0.1.6 #<LIFX::Message site=000000000000 device=000000000000 type=Device::GetMeshFirmware addressable=true tagged=false protocol=1024 payload={}>
2014-04-05T10:02:30.03926+11:00 BROADCAST: 10.0.1.6 #<LIFX::Message site=000000000000 tags=all type=Device::GetPanGateway addressable=true tagged=true protocol=1024 payload={}>
2014-04-05T10:02:30.04076+11:00 PEER: 10.0.1.6 #<LIFX::Message site=000000000000 tags=all type=Device::GetPanGateway addressable=true tagged=true protocol=1024 payload={}>
2014-04-05T10:02:34.63450+11:00 BROADCAST: 10.0.1.6 #<LIFX::Message site=000000000000 device=000000000000 type=Device::GetMeshFirmware addressable=true tagged=false protocol=1024 payload={}>
2014-04-05T10:02:34.63554+11:00 PEER: 10.0.1.6 #<LIFX::Message site=000000000000 device=000000000000 type=Device::GetMeshFirmware addressable=true tagged=false protocol=1024 payload={}>
with new pairs of broadcast and peer GetMeshFirmware messages appearing, roughly one or two pairs per second, after running lifx-http for a couple of days. If I restart lifx-http, I don't have any GetMeshFirmware messages for a while, just GetPanGateway's, which presumably is just broadcast gateway discovery?
Anyway, even with lifx-http closed, launching any ruby lifx app which does a discovery and then tries to use client.lights finds a bulb with no label or tags, with the id 000000000000, which is totally unresponsive. If the ruby library is left discovering long enough to find all my bulbs (which takes about 30 seconds.. why?) then it still has one more bulb than the total number of actual bulbs on my network.. the 000000000000 bulb. What's the deal with that?
On a Synology NAS with Ruby 2.0.0. Possibly, this method is only defined when the system supports IPv6? I think the Synology does but it it either disabled or the Ruby is compiled without support.
Based on some googling, it seems like Ruby's ./configure
takes a --with-ipv6
option.
irb(main):001:0> client = LIFX::Client.lan
=> #<LIFX::Client:0x007f6a4543b320 @context=#<LIFX::NetworkContext connections=[]>>
irb(main):002:0> client.discover
NoMethodError: undefined method `ipv6_unique_local?' for #<Addrinfo: 127.0.0.1>
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport_manager/lan.rb:79:in `block in on_network?'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport_manager/lan.rb:77:in `each'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport_manager/lan.rb:77:in `any?'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport_manager/lan.rb:77:in `on_network?'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport_manager/lan.rb:59:in `write'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport_manager/lan.rb:39:in `block (2 levels) in discover'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport_manager/lan.rb:34:in `loop'
from /usr/local/ruby/lib/ruby/gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport_manager/lan.rb:34:in `block in discover'
Is it possible to have the light on one color (say, purple), then turn it off, and have it come on a different color (without first turning it on in purple mode, then sending another message to change the color.
i.e:
Bulb on
Bulb set color to purple
Bulb off
Bulb set color to dim orange
Bulb on
In other words, set the color of the bulb when its off, so when its turned on, it comes on in that color, rather than first displaying its previous color.
Not sure if I'm missing something obvious here...
I have a single LIFX light, I can see and control it in the iOS app. I've installed the gem, try client.discover!
, which times out, and doesn't have the light in lights
. Calling client.discover
and waiting minutes, still no love.
I only have the one wifi network (which both my phone and laptop are connected to)... how do I go about debugging this?
Hi, I try to get lifx-console running on FreeBSD. lifx-snoop does print out packets when I use the Android app, however when I start lifx-console:
root@geode:~# lifx-console
Could not find any LIFX devices.
and lifx-snoop does not show any packets. Could it be a problem that I have multiple network interfaces in this machine?
I have tried the same script on an Arch-Linux laptop and on a Windows 7 64-bit desktop, with different results.
The Arch machine is using Ruby 2.2.0 whereas the Windows machine is using Ruby 2.1.5 -- please let me know if this is the issue.
I'm not quite sure what is causing this, but I tried wiresharking on both computers and found that the packets coming from Arch Linux were sent both to and from port 56700 as indicated here:
https://github.com/LIFX/lifx-gem/blob/master/lib/lifx/transport_manager/lan.rb#L7
However, the packets coming from Windows were being sent to and from port 56721. A side effect of this is that the bulb does not reply to the broadcast and does not get discovered.
I am curious as to whether or not this is a bug in Ruby, or in the private implementation which is hidden from us. Please verify that this is not an error on the LIFX side and report the bug upstream to https://bugs.ruby-lang.org/.
Thank you for your support.
Hello,
I'm experiencing memory leaks on using this lib.
I wasn't sure it is LIFX.rb until i was trying the example given known as auto-off.rb
I keep looking the memory consumption on the command _ps -efa_
pi 3954 0.0 0.7 5984 3228 pts/3 Ss 16:25 0:01 _ /bin/bashSTY=2515.pts-0.raspberrypi TERM=screen TERMCAP=SC|screen|VT 100/ANSI X3.64 virt
pi 4005 11.5 13.7 77684 61404 pts/3 Sl+ 16:28 19:01 | _ ruby auto-off.rbrvm_bin_path=/usr/local/rvm/bin GEM_HOME=/usr/local/rvm/gems/ruby-2.
And seconds later ...
pi 3954 0.0 0.7 5984 3228 pts/3 Ss 16:25 0:01 _ /bin/bashSTY=2515.pts-0.raspberrypi TERM=screen TERMCAP=SC|screen|VT 100/ANSI X3.64 virt
pi 4005 12.0 14.7 82060 65932 pts/3 Sl+ 16:28 23:33 | _ ruby auto-off.rbrvm_bin_path=/usr/local/rvm/bin GEM_HOME=/usr/local/rvm/gems/ruby-2.
Until the total memory available on the raspberry is reached (512Mo) then it miserably crash...
I cannot be able to debug where the memory leak is, Ruby seems to be hard to debug ?
Because of this, a daemon using LIFX lib will always crash in about 24h or 48h on a raspberry.
Notice that i'm using it with 22 bulbs, and with raspbian.
It takes 30 seconds or so for lights that have been powered down to disappear from LightCollection#active, even if LightCollection#refresh is called. It also takes what seems to me to be an unreasonably long time (4-5 seconds) for lights that have been powered up to reappear.
I was trying to write a script that monitors lights and restores them to their last known state after a power cycle, but there's too much lag.
Hi,
The rspec log is below.
LIFX::GatewayConnection
write queue resiliency
does not send if there is no available connection
pushes message back into queue if unable to write (FAILED - 1)
Failures:
1) LIFX::GatewayConnection write queue resiliency pushes message back into queue if unable to write
Failure/Error: expect(gateway).to receive(:actually_write).and_return(false, true)
(#<LIFX::GatewayConnection tcp= tcp_attempts=0 udp=#<LIFX::Transport::UDP 127.0.0.1:35003>>).actually_write(any args)
expected: 2 times with any arguments
received: 0 times with any arguments
# ./spec/gateway_connection_spec.rb:22:in `block (3 levels) in <module:LIFX>'
Finished in 0.72379 seconds (files took 0.54662 seconds to load)
I have traced code of gateway_connection.rb
.
I think it is caused by thread of message queue pop message out before call actually_write(message)
method. At this moment, the queue is empty and flush
method check the queue size at the same time. it found queue is empty then return. Thus, actually_write(message)
method won't be called.
You can easy reproduce this issue by adding a long sleep right after message = @queue.pop
in initialize_write_queue
method.
I am new in Ruby world and interested in IoT, so I would like to solve this issue by myself for practicing more. A simple solution is only pop message out after actually_write(message)
succeed.
First of all, I need to write a test which can exactly reproduce this issue. But I think that run a large number of loops for trigger the issue is not a good way. Does anyone have suggestions? :D
The attr_reader :label
in the Light class is redundant. It's entirely eclipsed by the Light#label
method.
I would like to create an app where you can select and control multiple LIFX-Bulbs. Is there any way to create a custom LightCollection to set the color or the power state to all selected lights at the same time instead of setting it to every light individually?
I am not sure if I should add a tag like "CB-LightControl-Selected" to all selected bulbs. Would this be safe?
When calling client.lights.with_label('Nothing')
, if nothing matches, you get a nil
value which, if not dealt with, can cause an exception.
Maybe using the NullObject pattern and returning a NullLight
object instead of nil
could be a good idea. This way client.lights.with_label('Nothing').turn_on
would crash the program :)
What do you think?
This is in case a Light::State for the desired bulb doesn't return the first time.
I know this is not really an issue but there is no other places to ask this kind of questions so I just do it here.
I was asked to make them flickering based on certain events and time, no idea how to do this from code. Any examples ?
Does this library support the new 2.0 Firmware? (no mesh networking)
With this library, I'm unable to find my lights, while the Android app works without issue.
Falcon:~ bluebie$ sudo gem install lifx
Password:
Fetching: bindata-2.0.0.gem (100%)
Successfully installed bindata-2.0.0
Fetching: yell-2.0.4.gem (100%)
Successfully installed yell-2.0.4
Fetching: hitimes-1.2.1.gem (100%)
Building native extensions. This could take a while...
ERROR: Error installing lifx:
ERROR: Failed to build gem native extension.
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby extconf.rb
creating Makefile
make "DESTDIR="
compiling hitimes.c
compiling hitimes_instant_clock_gettime.c
compiling hitimes_instant_osx.c
compiling hitimes_instant_windows.c
compiling hitimes_interval.c
compiling hitimes_stats.c
linking shared-object hitimes/2.0/hitimes.bundle
clang: error: unknown argument: '-multiply_definedsuppress' [-Wunused-command-line-argument-hard-error-in-future]
clang: note: this will be a hard error (cannot be downgraded to a warning) in the future
make: *** [hitimes.bundle] Error 1
Gem files will remain installed in /Library/Ruby/Gems/2.0.0/gems/hitimes-1.2.1 for inspection.
Results logged to /Library/Ruby/Gems/2.0.0/gems/hitimes-1.2.1/ext/hitimes/c/gem_make.out
Makes it easier for people to install the gem (assuming they're on Mavericks).
Due to Apple shipping an install of clang
that breaks compiling ANY gem using the version of Ruby that they built, users will have to install the gem with the following:
ARCHFLAGS=-Wno-error=unused-command-line-argument-hard-error-in-future gem install lifx
I included the lifx gem in my rails 4 app and when I try creating an instance of client, I get the following:
uninitialized constant LIFX::Client
However, the LIFX module is present but the only constant/class that it contains is VERSION
$ rails console
Loading development environment (Rails 4.0.2)
> LIFX.constants
=> [:VERSION]
It works fine with normal irb:
irb(main):001:0> require 'lifx'
=> true
irb(main):002:0> LIFX.constants
=> [:VERSION, :Utilities, :Logging, :Protocol, :ProtocolPath, :Message, :Observable, :Transport, :Config, :Timers, :TransportManager, :Seen, :GatewayConnection, :Site, :RoutingTable, :TagTable, :RoutingManager, :TagManager, :Colors, :Color, :Target, :LightTarget, :Firmware, :Light, :NetworkContext, :LightCollection, :Client]
Hello,
ruby 2.1 on linux gentoo
here is the program :
require 'lifx'
client = LIFX::Client.lan
and it gives me this :
/usr/local/lib64/ruby/gems/2.1.0/gems/lifx-0.4.3/lib/lifx/transport/udp.rb:36:in `block in listen': uninitialized constant Socket::SO_REUSEPORT (NameError)
So i need something ?
I have experienced that occasionally, when trying to call LIFX::Client.lan.lights.refresh
, the function write
in gateway_connection.rb
hangs.
I have a cron-job which runs a script controlling my 10 bulbs every hour, and during a day, I end up with some of the runs just hanging. The exact line in the lifx-gem source code that fails to return is line 76 in gateway_connection.rb
, which reads as:
@queue.push(message)
The message is constructed in network_context.rb
as
Message.new(path: path, payload: payload, acknowledge: acknowledge, at_time: at_time)
These parameters come from light_collection.rb
from the following line:
context.send_message(target: Target.new(broadcast: true), payload: payload, acknowledge: acknowledge, at_time: at_time)
Which is being called by light_target.rb
in refresh
, setting payload
to Protocol::Light::Get.new
Below is the stack trace, here is the way I try to initialize the LIFX::Client.lan
. Am I using the API incorrectly?
def init
$lifx_client = LIFX::Client.lan
$lifx_client.discover
sleep 1.0
5.times do
$lifx_client.lights.refresh # <- This is Line 544
...
Here is the stack trace when I kill the script (this had been running for some minutes).
me@myplace:~$ ruby2.1 lifx
^C/home/pgd/lifx/lifx-gem/lib/lifx/gateway_connection.rb:76:in `push': Interrupt
from lifx/lifx-gem/lib/lifx/gateway_connection.rb:76:in `write'
from lifx/lifx-gem/lib/lifx/site.rb:29:in `block in write'
from lifx/lifx-gem/lib/lifx/site.rb:28:in `each'
from lifx/lifx-gem/lib/lifx/site.rb:28:in `write'
from lifx/lifx-gem/lib/lifx/transport_manager/lan.rb:77:in `write'
from lifx/lifx-gem/lib/lifx/network_context.rb:78:in `block in send_message'
from lifx/lifx-gem/lib/lifx/network_context.rb:77:in `each'
from lifx/lifx-gem/lib/lifx/network_context.rb:77:in `send_message'
from lifx/lifx-gem/lib/lifx/light_collection.rb:41:in `send_message'
from lifx/lifx-gem/lib/lifx/light_target.rb:180:in `refresh'
from lifx:544:in `init'
from lifx:655:in `<main>'
Onboarding should be done by the apps.
Discovery appears to be asynchronous, which is fine, but there is no way of determining whether it's finished or not.
Maybe this is intrinsically impossible, but it would be nice if, after calling LFX::Client.discover, we could rely on LFX::Client.lights containing all lights on the network.
Right now, any synchronous message that uses try_until
will throw a generic Timeout::Error
which is not descriptive. Ideally, the exception should be in the method where try_until
is called, and it should be a LIFX exception with the operation that failed.
Attempting to call reboot! on a light causes the following error:
/Library/Ruby/Gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport_manager/lan.rb:131:in handle_broadcast_message': undefined method
payload' for nil:NilClass (NoMethodError)
from /Library/Ruby/Gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport_manager/lan.rb:116:in block in create_broadcast_transport' from /Library/Ruby/Gems/2.0.0/gems/lifx-0.4.5/lib/lifx/observable.rb:18:in
call'
from /Library/Ruby/Gems/2.0.0/gems/lifx-0.4.5/lib/lifx/observable.rb:18:in block in notify_observers' from /Library/Ruby/Gems/2.0.0/gems/lifx-0.4.5/lib/lifx/observable.rb:17:in
each'
from /Library/Ruby/Gems/2.0.0/gems/lifx-0.4.5/lib/lifx/observable.rb:17:in notify_observers' from /Library/Ruby/Gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport/udp.rb:42:in
block (2 levels) in listen'
from /Library/Ruby/Gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport/udp.rb:38:in loop' from /Library/Ruby/Gems/2.0.0/gems/lifx-0.4.5/lib/lifx/transport/udp.rb:38:in
block in listen'
It appears that sometimes a light can appear in the Client#lights
collection before its properties are fully loaded.
Ideally, only lights that are fully "loaded" should appear in Client#lights
. Perhaps lights that are known, but not loaded could be managed in a separate private collection.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.