milight 0.2.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 +9 -0
- data/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/LICENSE +22 -0
- data/README.md +61 -0
- data/Rakefile +10 -0
- data/bin/milight +36 -0
- data/lib/milight.rb +7 -0
- data/lib/milight/bridge_box.rb +168 -0
- data/lib/milight/bulb.rb +179 -0
- data/lib/milight/color.rb +21 -0
- data/lib/milight/command.rb +49 -0
- data/lib/milight/util.rb +21 -0
- data/lib/milight/version.rb +3 -0
- data/milight.gemspec +25 -0
- data/sample/light.rb +32 -0
- data/sample/wakeup_light.rb +41 -0
- metadata +104 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: e3e8344aaa8ad7deb994a84f912d00f7ff12cf25
|
|
4
|
+
data.tar.gz: 50464a893318e56f13339df22857df680e7834f3
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ec1ff3073876baa5deabd457ab963901b09452067e64263d48df8ec378258d5ad684dce52d7c0e69f991f6e61a7f20852f84d337cb045388888b97f1148b689f
|
|
7
|
+
data.tar.gz: 569487c0539325798cf7124038d88ef9df7a157b736ff2baf1930a10bc6bb14e78cc8b0ab4b0488e5e373d33cef76ad9231ad8801020d4d3383c529fa1797201
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Ippei Kato
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Milight
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/beco-ippei/ruby-milight)
|
|
4
|
+
[](https://coveralls.io/github/beco-ippei/ruby-milight)
|
|
5
|
+
|
|
6
|
+
A ruby wrapper project for milight api.
|
|
7
|
+
|
|
8
|
+
controller ruby-api for milight or limitless-led
|
|
9
|
+
(milight and limitless-led and easy-bulb is
|
|
10
|
+
same bridge-box controllable products)
|
|
11
|
+
|
|
12
|
+
## API Document
|
|
13
|
+
http://www.limitlessled.com/dev/
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Add this line to your application's Gemfile:
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
gem 'milight'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
And then execute:
|
|
24
|
+
|
|
25
|
+
$ bundle
|
|
26
|
+
|
|
27
|
+
Or install it yourself as:
|
|
28
|
+
|
|
29
|
+
$ gem install milight
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# components
|
|
33
|
+
* local controller (working on LAN)
|
|
34
|
+
* [may be not] gateway server (working on Internet)
|
|
35
|
+
|
|
36
|
+
components messaging each other.
|
|
37
|
+
use web-socket ??
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
# TODO
|
|
42
|
+
setup
|
|
43
|
+
---
|
|
44
|
+
* ?) connect bridge-box and setup wifi config
|
|
45
|
+
or configure by Appli
|
|
46
|
+
* ~~get bridge-box IP-Address (from LAN)~~
|
|
47
|
+
* configure this app (make or overwrite config file ?)
|
|
48
|
+
|
|
49
|
+
boot local-controller / env
|
|
50
|
+
---
|
|
51
|
+
* load config
|
|
52
|
+
* get bridge-box network segment (24bit)
|
|
53
|
+
* server url
|
|
54
|
+
* bulb controller
|
|
55
|
+
* lib/bulb.rb
|
|
56
|
+
* and tests
|
|
57
|
+
* sample app
|
|
58
|
+
* controll by groups
|
|
59
|
+
|
|
60
|
+
... writing.
|
|
61
|
+
|
data/Rakefile
ADDED
data/bin/milight
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
4
|
+
|
|
5
|
+
SETUP = %w[setup]
|
|
6
|
+
CONSOLE = %w[console c]
|
|
7
|
+
all_cmd = SETUP + CONSOLE
|
|
8
|
+
|
|
9
|
+
cmd = ARGV[0]
|
|
10
|
+
unless cmd
|
|
11
|
+
puts <<-DESC
|
|
12
|
+
sub-command must set
|
|
13
|
+
valid commands are #{all_cmd.join ','}
|
|
14
|
+
DESC
|
|
15
|
+
exit
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
require 'milight'
|
|
19
|
+
|
|
20
|
+
#TODO add group to bulb
|
|
21
|
+
case cmd.downcase.to_sym
|
|
22
|
+
when :setup
|
|
23
|
+
require 'milight/bridge_box'
|
|
24
|
+
Milight::BridgeBox.setup
|
|
25
|
+
|
|
26
|
+
when :console, :c
|
|
27
|
+
require "irb"
|
|
28
|
+
IRB.start
|
|
29
|
+
|
|
30
|
+
else
|
|
31
|
+
puts <<-DESC
|
|
32
|
+
sub-command '#{cmd}' is invalid.
|
|
33
|
+
valid commands are #{all_cmd.join ','}
|
|
34
|
+
DESC
|
|
35
|
+
end
|
|
36
|
+
|
data/lib/milight.rb
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
require 'milight'
|
|
2
|
+
require 'readline'
|
|
3
|
+
require "socket"
|
|
4
|
+
|
|
5
|
+
module Milight::BridgeBox
|
|
6
|
+
MILIGHT_WIFI = /^10\.10\.100\.[0-9]+$/
|
|
7
|
+
SERVER_IP = '10.10.100.254'
|
|
8
|
+
RECEIVE_IP = "0.0.0.0"
|
|
9
|
+
PORT = '48899'
|
|
10
|
+
|
|
11
|
+
def self.setup
|
|
12
|
+
puts "-- Please connect wifi 'milight_XXXXXXX'."
|
|
13
|
+
|
|
14
|
+
if self.wait_connection true
|
|
15
|
+
puts '... milight connected.'
|
|
16
|
+
else
|
|
17
|
+
puts <<DESC
|
|
18
|
+
milight wifi connection timeout (1min)
|
|
19
|
+
if milight wifi not found, initialize your controller box.
|
|
20
|
+
DESC
|
|
21
|
+
exit 1
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
sock = self.socket
|
|
25
|
+
|
|
26
|
+
t1 = Thread.new do
|
|
27
|
+
self.wait_wscan_results
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
sleep 1
|
|
31
|
+
puts '-- send command: WSCAN ....'
|
|
32
|
+
sock.command "Link_Wi-Fi"
|
|
33
|
+
sock.command "+ok"
|
|
34
|
+
sock.command "AT+WSCAN\r"
|
|
35
|
+
|
|
36
|
+
t1.join
|
|
37
|
+
|
|
38
|
+
wlans = t1.value.split "\n"
|
|
39
|
+
|
|
40
|
+
wlans.shift # ignore header
|
|
41
|
+
ssids = wlans.map do |line|
|
|
42
|
+
ch, ssid, _, sec, _ = line.split ','
|
|
43
|
+
if ssid.is_a?(String) && ssid.length > 1
|
|
44
|
+
{ch: ch, ssid: ssid, sec: sec}
|
|
45
|
+
end
|
|
46
|
+
end.compact
|
|
47
|
+
|
|
48
|
+
ssid = self.choice_ssid ssids
|
|
49
|
+
puts "-- set wifi SSID : '#{ssid[:ssid]}'"
|
|
50
|
+
sock.command "AT+WSSSID=#{ssid[:ssid]}\r"
|
|
51
|
+
|
|
52
|
+
key = self.security_key
|
|
53
|
+
puts "-- set wifi security key : '#{key}'"
|
|
54
|
+
sock.command "AT+WSKEY=WPA2PSK,AES,#{key}\r"
|
|
55
|
+
|
|
56
|
+
sock.command "AT+WMODE=STA\r"
|
|
57
|
+
sock.command "AT+Z\r"
|
|
58
|
+
sock.command "AT+Q\r"
|
|
59
|
+
|
|
60
|
+
sock.close
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if self.wait_connection false
|
|
64
|
+
puts <<DESC
|
|
65
|
+
... miligt wifi disconnected.
|
|
66
|
+
check your controller box led!
|
|
67
|
+
|
|
68
|
+
DESC
|
|
69
|
+
else
|
|
70
|
+
puts ' milight wifi connection still connected'
|
|
71
|
+
exit 1
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.wait_connection(milight = true)
|
|
76
|
+
20.times do
|
|
77
|
+
sleep 3
|
|
78
|
+
if ipaddr = Milight::Util.current_ipaddr
|
|
79
|
+
print '.'
|
|
80
|
+
else
|
|
81
|
+
print '-'
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if self.milight_wifi?(ipaddr) == milight
|
|
85
|
+
return true
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
false
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.milight_wifi? ipaddr
|
|
92
|
+
!(ipaddr && MILIGHT_WIFI =~ ipaddr).nil?
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.socket
|
|
96
|
+
sock = UDPSocket.open
|
|
97
|
+
sock.setsockopt(
|
|
98
|
+
Socket::SOL_SOCKET,
|
|
99
|
+
Socket::SO_BROADCAST,
|
|
100
|
+
1
|
|
101
|
+
)
|
|
102
|
+
def sock.command msg
|
|
103
|
+
self.send msg, 0, SERVER_IP, PORT
|
|
104
|
+
end
|
|
105
|
+
sock
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def self.wait_wscan_results
|
|
109
|
+
puts '-- waiting receive response: WSCAN ....'
|
|
110
|
+
rsock = UDPSocket.new
|
|
111
|
+
rsock.bind(RECEIVE_IP, PORT)
|
|
112
|
+
string = nil
|
|
113
|
+
|
|
114
|
+
sel = IO::select([rsock])
|
|
115
|
+
if sel != nil
|
|
116
|
+
sel[0].each do |s|
|
|
117
|
+
data = s.recvfrom_nonblock(65535)
|
|
118
|
+
string = data[0].chomp!
|
|
119
|
+
end
|
|
120
|
+
else
|
|
121
|
+
puts '-- not received ....'
|
|
122
|
+
exit 1
|
|
123
|
+
end
|
|
124
|
+
rsock.close
|
|
125
|
+
string.gsub(/\+ok=\n/, '')
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def self.choice_ssid ssids
|
|
129
|
+
puts '', '-'*20
|
|
130
|
+
puts " no: 'ssid' (security types)"
|
|
131
|
+
ssids.each.with_index do |s, idx|
|
|
132
|
+
num = '%#2d' % (idx+1)
|
|
133
|
+
puts " #{num}: '#{s[:ssid]}' (#{s[:sec]})"
|
|
134
|
+
end
|
|
135
|
+
puts '-'*20, ''
|
|
136
|
+
puts <<-DESC
|
|
137
|
+
Choise your SSID(no).
|
|
138
|
+
but if your Access point not found, restart app
|
|
139
|
+
DESC
|
|
140
|
+
|
|
141
|
+
while true
|
|
142
|
+
msg = ">> input your SSID no(1-#{ssids.size-1}) > "
|
|
143
|
+
num = Readline.readline(msg).chomp.to_i
|
|
144
|
+
if num == 0
|
|
145
|
+
next # 0 or nil (not a number)
|
|
146
|
+
elsif !(1..ssids.size).cover? num
|
|
147
|
+
puts <<-MSG
|
|
148
|
+
invalid number : '#{num}'
|
|
149
|
+
exit.
|
|
150
|
+
MSG
|
|
151
|
+
exit 0
|
|
152
|
+
end
|
|
153
|
+
return ssids[num-1]
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def self.security_key
|
|
158
|
+
while true
|
|
159
|
+
msg = '>> Input security key > '
|
|
160
|
+
key = Readline.readline(msg).chomp
|
|
161
|
+
if key != ""
|
|
162
|
+
return key
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
end
|
|
168
|
+
|
data/lib/milight/bulb.rb
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
require 'ipaddr'
|
|
3
|
+
|
|
4
|
+
module Milight
|
|
5
|
+
class Bulb
|
|
6
|
+
def initialize(group: :all, ip: nil, port: 8899)
|
|
7
|
+
self.group = group
|
|
8
|
+
self.ip = ip
|
|
9
|
+
@port = port
|
|
10
|
+
|
|
11
|
+
@debugger = lambda {|_| }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#TODO: move to anywhere...
|
|
15
|
+
def debugger=(type)
|
|
16
|
+
@debugger = case type
|
|
17
|
+
when :puts
|
|
18
|
+
lambda {|msg|
|
|
19
|
+
puts " - debug :: #{msg}"
|
|
20
|
+
}
|
|
21
|
+
else
|
|
22
|
+
lambda {|_| }
|
|
23
|
+
end
|
|
24
|
+
debug "set debug - #{type}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def debug(msg)
|
|
28
|
+
@debugger.call msg
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def on
|
|
32
|
+
command Command::LED_ON[@group]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def disco(attr = nil)
|
|
36
|
+
case attr && attr.to_sym
|
|
37
|
+
when nil
|
|
38
|
+
command Command::DISCO_MODE
|
|
39
|
+
when :faster, :fast
|
|
40
|
+
command Command::DISCO_SPEED_FASTER
|
|
41
|
+
when :slower, :slow
|
|
42
|
+
command Command::DISCO_SPEED_SLOWER
|
|
43
|
+
else
|
|
44
|
+
debug "invalid disco attribute: '#{attr}'"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def off
|
|
49
|
+
command Command::LED_OFF[@group]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# white-command 100ms followed by 'on-command'
|
|
53
|
+
def white
|
|
54
|
+
self.on
|
|
55
|
+
command Command::WHITE[@group]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# night-command 100ms followed by 'off-command'
|
|
59
|
+
def night
|
|
60
|
+
self.off
|
|
61
|
+
command Command::NIGHT[@group]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# for colors
|
|
65
|
+
Color.constants.each do |color|
|
|
66
|
+
color_name = color.downcase
|
|
67
|
+
define_method color_name.to_sym do
|
|
68
|
+
color_code = defined_color color
|
|
69
|
+
self.on
|
|
70
|
+
command Command::SET_COLOR, color_code
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def color_value=(val)
|
|
75
|
+
if code = color_code(val)
|
|
76
|
+
self.on
|
|
77
|
+
command Command::SET_COLOR, code
|
|
78
|
+
else
|
|
79
|
+
debug "invalid color value '#{val}'"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def bright(persent)
|
|
84
|
+
if val = brightness(persent.to_i)
|
|
85
|
+
self.on
|
|
86
|
+
command Command::BRIGHTENESS, val
|
|
87
|
+
else
|
|
88
|
+
debug "invalid persent value '#{persent}'"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def full_bright
|
|
93
|
+
self.bright 50
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def dark
|
|
97
|
+
self.bright 0
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def ip=(ipaddr)
|
|
103
|
+
unless ipaddr
|
|
104
|
+
raise "ip is not allowed nil"
|
|
105
|
+
end
|
|
106
|
+
IPAddr.new ipaddr # just validate
|
|
107
|
+
@ipaddr = ipaddr
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def group=(group)
|
|
111
|
+
if group == :all
|
|
112
|
+
@group = :all
|
|
113
|
+
elsif (1..5).cover? group
|
|
114
|
+
@group = "group#{group}".to_sym
|
|
115
|
+
else
|
|
116
|
+
raise 'invalid group. use :all or 1..5'
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def brightness(persent)
|
|
121
|
+
if (0..100).cover? persent
|
|
122
|
+
sprintf(
|
|
123
|
+
'%02d',
|
|
124
|
+
2 + 25 * persent.to_i / 100
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def defined_color(method)
|
|
130
|
+
name = method.upcase.to_sym
|
|
131
|
+
if Color.constants.include? name
|
|
132
|
+
Color.const_get(name)
|
|
133
|
+
else
|
|
134
|
+
nil
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# parse color code ("00" .. "ff")
|
|
139
|
+
# valid color-value is 0..255
|
|
140
|
+
def color_code(val)
|
|
141
|
+
if val.is_a? String
|
|
142
|
+
code = val
|
|
143
|
+
val = code.hex
|
|
144
|
+
val = -1 if val == 0 && code != '00'
|
|
145
|
+
elsif val.is_a? Fixnum
|
|
146
|
+
code = val
|
|
147
|
+
val = val.to_i
|
|
148
|
+
code = '%02x' % val
|
|
149
|
+
else
|
|
150
|
+
return nil
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
if (0..255).cover? val
|
|
154
|
+
code
|
|
155
|
+
else
|
|
156
|
+
nil
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def command(cmd, value = '00')
|
|
161
|
+
debug "cmd : #{cmd} / #{value}"
|
|
162
|
+
msg = message cmd, value
|
|
163
|
+
|
|
164
|
+
#TODO: initialize first ?
|
|
165
|
+
sock = UDPSocket.open
|
|
166
|
+
sock.setsockopt(
|
|
167
|
+
Socket::SOL_SOCKET,
|
|
168
|
+
Socket::SO_BROADCAST,
|
|
169
|
+
1
|
|
170
|
+
)
|
|
171
|
+
sock.send(msg, 0, @ipaddr, @port)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def message(cmd, value)
|
|
175
|
+
[cmd, value, "55"].map(&:to_s)
|
|
176
|
+
.map(&:hex).pack "C*"
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Milight
|
|
2
|
+
module Color
|
|
3
|
+
VIOLET = '00'
|
|
4
|
+
ROYAL_BLUE = '10'
|
|
5
|
+
BLUE = ROYAL_BLUE # alias
|
|
6
|
+
BABY_BLUE = '20'
|
|
7
|
+
AQUA = '30'
|
|
8
|
+
MINT = '40'
|
|
9
|
+
SEAFOAM_GREEN = '50'
|
|
10
|
+
GREEN = '60'
|
|
11
|
+
LIME_GREEN = '70'
|
|
12
|
+
YELLOW = '80'
|
|
13
|
+
YELLOW_ORANGE = '90'
|
|
14
|
+
ORANGE = 'a0'
|
|
15
|
+
RED = 'b0'
|
|
16
|
+
PINK = 'c0'
|
|
17
|
+
FUSIA = 'd0'
|
|
18
|
+
LILAC = 'e0'
|
|
19
|
+
LAVENDAR = 'f0'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Milight
|
|
2
|
+
module Command
|
|
3
|
+
SET_COLOR = '40'
|
|
4
|
+
|
|
5
|
+
LED_ON = {
|
|
6
|
+
all: '42',
|
|
7
|
+
group1: '45',
|
|
8
|
+
group2: '47',
|
|
9
|
+
group3: '49',
|
|
10
|
+
group4: '4B',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
LED_OFF = {
|
|
14
|
+
all: '41',
|
|
15
|
+
group1: '46',
|
|
16
|
+
group2: '48',
|
|
17
|
+
group3: '4A',
|
|
18
|
+
group4: '4C',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
DISCO_SPEED_SLOWER = '43'
|
|
22
|
+
DISCO_SPEED_FASTER = '44'
|
|
23
|
+
DISCO_MODE = '4D'
|
|
24
|
+
DISCO_MODE_NEXT = '27'
|
|
25
|
+
DISCO_MODE_PREVIOUS = '28'
|
|
26
|
+
|
|
27
|
+
#TODO: not RGB?
|
|
28
|
+
WARM_WHITE_INCREASE = '3E'
|
|
29
|
+
COOL_WHITE_INCREASE = '3F'
|
|
30
|
+
|
|
31
|
+
BRIGHTENESS = '4E'
|
|
32
|
+
|
|
33
|
+
NIGHT = {
|
|
34
|
+
all: 'C1',
|
|
35
|
+
group1: 'C6',
|
|
36
|
+
group2: 'C8',
|
|
37
|
+
group3: 'CA',
|
|
38
|
+
group4: 'CC',
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
WHITE = {
|
|
42
|
+
all: 'C2',
|
|
43
|
+
group1: 'C5',
|
|
44
|
+
group2: 'C7',
|
|
45
|
+
group3: 'C9',
|
|
46
|
+
group4: 'CB',
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/milight/util.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Milight
|
|
2
|
+
module Util
|
|
3
|
+
def self.current_ipaddr
|
|
4
|
+
matched = /inet\ addr:([0-9\.]*)/.match wlan_config
|
|
5
|
+
matched[1] if matched
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.broadcast_addr
|
|
9
|
+
matched = /Bcast:([0-9\.]*)/.match wlan_config
|
|
10
|
+
matched[1] if matched
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
#TODO: modularize for env/os.
|
|
16
|
+
def self.wlan_config
|
|
17
|
+
%x[LANG=C ifconfig wlan]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
data/milight.gemspec
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'milight/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "milight"
|
|
8
|
+
spec.version = Milight::VERSION
|
|
9
|
+
spec.authors = ["beco-ippei"]
|
|
10
|
+
spec.email = ["beco.ippei@gmail.com"]
|
|
11
|
+
|
|
12
|
+
spec.summary = %q{A ruby controller for Mi-Light LED bulb.}
|
|
13
|
+
spec.description = %q{}
|
|
14
|
+
spec.homepage = "https://github.com/beco-ippei/ruby-milight"
|
|
15
|
+
spec.license = "MIT"
|
|
16
|
+
|
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
18
|
+
spec.bindir = "bin"
|
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
20
|
+
spec.require_paths = ["lib"]
|
|
21
|
+
|
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
24
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
25
|
+
end
|
data/sample/light.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
2
|
+
|
|
3
|
+
require 'milight'
|
|
4
|
+
|
|
5
|
+
ipaddr = ENV['IPADDR']
|
|
6
|
+
|
|
7
|
+
group = (g = ARGV.shift) == 'all' ? :all : g.to_i
|
|
8
|
+
bulb = Milight::Bulb.new ip: ipaddr, group: group
|
|
9
|
+
|
|
10
|
+
cmd = ARGV.shift
|
|
11
|
+
val = ARGV.shift
|
|
12
|
+
|
|
13
|
+
case cmd.downcase
|
|
14
|
+
when 'on'
|
|
15
|
+
bulb.on
|
|
16
|
+
when 'off'
|
|
17
|
+
bulb.off
|
|
18
|
+
when 'color'
|
|
19
|
+
bulb.send val.to_sym
|
|
20
|
+
when 'color-list'
|
|
21
|
+
puts Milight::Color.constants
|
|
22
|
+
.map(&:downcase).join ', '
|
|
23
|
+
when 'dark'
|
|
24
|
+
bulb.dark
|
|
25
|
+
when 'bright'
|
|
26
|
+
bulb.bright val.to_i
|
|
27
|
+
when 'night'
|
|
28
|
+
bulb.night
|
|
29
|
+
when 'disco'
|
|
30
|
+
bulb.disco val
|
|
31
|
+
end
|
|
32
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
2
|
+
|
|
3
|
+
require 'milight'
|
|
4
|
+
|
|
5
|
+
ipaddr = ENV['IPADDR']
|
|
6
|
+
interval = 3 * 60 # 3min
|
|
7
|
+
|
|
8
|
+
bulb = Milight::Bulb.new ip: ipaddr
|
|
9
|
+
|
|
10
|
+
if ARGV[0] == 'prepare'
|
|
11
|
+
puts 'prepare for wakeup-light'
|
|
12
|
+
[:on, :dark, :lime_green, :off].each do |cmd|
|
|
13
|
+
bulb.send(cmd)
|
|
14
|
+
sleep 2
|
|
15
|
+
end
|
|
16
|
+
exit
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# light on (night-mode)
|
|
20
|
+
[
|
|
21
|
+
[:night],
|
|
22
|
+
[:on, :dark, :lime_green],
|
|
23
|
+
[[:bright, 10]],
|
|
24
|
+
[[:bright, 20]],
|
|
25
|
+
[:white],
|
|
26
|
+
[[:bright, 30]],
|
|
27
|
+
[:full_bright],
|
|
28
|
+
[:disco],
|
|
29
|
+
].each do |commands|
|
|
30
|
+
commands.each do |cmd|
|
|
31
|
+
bulb.send(*cmd)
|
|
32
|
+
sleep 1.5
|
|
33
|
+
end
|
|
34
|
+
sleep interval
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
sleep 10 * 60 # 10min
|
|
38
|
+
bulb.dark
|
|
39
|
+
sleep 2
|
|
40
|
+
bulb.off
|
|
41
|
+
|
metadata
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: milight
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- beco-ippei
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-02-19 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.11'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.11'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: minitest
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '5.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '5.0'
|
|
55
|
+
description: ''
|
|
56
|
+
email:
|
|
57
|
+
- beco.ippei@gmail.com
|
|
58
|
+
executables:
|
|
59
|
+
- milight
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- ".gitignore"
|
|
64
|
+
- ".travis.yml"
|
|
65
|
+
- Gemfile
|
|
66
|
+
- LICENSE
|
|
67
|
+
- README.md
|
|
68
|
+
- Rakefile
|
|
69
|
+
- bin/milight
|
|
70
|
+
- lib/milight.rb
|
|
71
|
+
- lib/milight/bridge_box.rb
|
|
72
|
+
- lib/milight/bulb.rb
|
|
73
|
+
- lib/milight/color.rb
|
|
74
|
+
- lib/milight/command.rb
|
|
75
|
+
- lib/milight/util.rb
|
|
76
|
+
- lib/milight/version.rb
|
|
77
|
+
- milight.gemspec
|
|
78
|
+
- sample/light.rb
|
|
79
|
+
- sample/wakeup_light.rb
|
|
80
|
+
homepage: https://github.com/beco-ippei/ruby-milight
|
|
81
|
+
licenses:
|
|
82
|
+
- MIT
|
|
83
|
+
metadata: {}
|
|
84
|
+
post_install_message:
|
|
85
|
+
rdoc_options: []
|
|
86
|
+
require_paths:
|
|
87
|
+
- lib
|
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - ">="
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '0'
|
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '0'
|
|
98
|
+
requirements: []
|
|
99
|
+
rubyforge_project:
|
|
100
|
+
rubygems_version: 2.5.1
|
|
101
|
+
signing_key:
|
|
102
|
+
specification_version: 4
|
|
103
|
+
summary: A ruby controller for Mi-Light LED bulb.
|
|
104
|
+
test_files: []
|