xilight 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ce53988463217566f59a2fa28f43f7ff7c30db7369f9ed0a7cd25ef8b6520879
4
+ data.tar.gz: 745ad2da23c60506e338cda6e416e3fe2df96f52e0dc24ed1894416653755a50
5
+ SHA512:
6
+ metadata.gz: 3fa8807399f9f59b3e54a0471b44fce63da16ad899ced9bc5d00f2080ad4752ae55d3a3da2cd379432ec3fa532baaecd16029fae20d29a60b02595676605f22e
7
+ data.tar.gz: 4517600df4f14337fb0686bf6fb00c5b633a7bd10f9dc62f85c5f44f516f2ddef87529329dcb3b24e69a7fa2dbbaf4c7da78bafdfa25c9f3bf2fa39afaae15df
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at wouter@youdo.co.nz. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in yeelight.gemspec
4
+ gemspec
@@ -0,0 +1,36 @@
1
+ # Yeelight
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/xilight`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'xilight'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install xilight
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/xilight. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
+
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "xilight"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+ require 'pry-byebug'
13
+ # You can add fixtures and/or initialization code here to make experimenting
14
+ # with your gem easier. You can also use a different console, if you like.
15
+
16
+ # (If you use this, don't forget to add pry to your Gemfile!)
17
+ # require "pry"
18
+ # Pry.start
19
+
20
+ Pry.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/yee ADDED
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env ruby
2
+ require "bundler/setup"
3
+ require "xilight"
4
+ require "dry/cli"
5
+
6
+ module Xilight
7
+ module CLI
8
+
9
+ def self.config_path
10
+ File.join(Dir.home, ".config", ".yeelights")
11
+ end
12
+
13
+ def self.config=(config)
14
+ IO.write(config_path, JSON.dump(config))
15
+ end
16
+
17
+ def self.config
18
+ JSON.load(IO.read(config_path))
19
+ rescue
20
+ {}
21
+ end
22
+
23
+ def self.get_light(index, name=nil)
24
+ lights = ::Xilight::CLI.config['yeelights']
25
+ light_attribs = if name && name != ''
26
+ lights.find{|l| l['name'].downcase.strip == name.downcase.strip }
27
+ else
28
+ lights[index.to_i]
29
+ end
30
+ ::Xilight::Yeelight.new(light_attribs.map{|k,v| [k.to_sym, v]}.to_h)
31
+ rescue
32
+ puts "Couldn't find light with " + ((name && name != '') ? "name #{name}" : "ID #{index}")
33
+ puts "Known lights:"
34
+ puts self.config.fetch('yeelights', []).map.with_index{|light, i| "\tLight ##{i} => #{(light['name'] || light['id'])}@#{light['host']}"}
35
+ exit(1)
36
+ end
37
+
38
+ module Commands
39
+ extend Dry::CLI::Registry
40
+
41
+ class Version < Dry::CLI::Command
42
+ desc "Print version"
43
+
44
+ example [
45
+ ""
46
+ ]
47
+
48
+ def call(*)
49
+ puts ::Xilight::VERSION
50
+ end
51
+ end
52
+
53
+ class Discover < Dry::CLI::Command
54
+ desc "Discover Yeelights and save to ~/.config/.yeelights"
55
+
56
+ example [
57
+ ""
58
+ ]
59
+
60
+ def call(**)
61
+ current_config = ::Xilight::CLI.config
62
+ current_lights = current_config.fetch('yeelights', [])
63
+ ::Xilight::Yeelight.discover.each do |light|
64
+ current_lights.reject!{|l| l['id'] == light.id}
65
+ current_lights << light.instance_variables.map{|v| [v.to_s[1..-1], light.instance_variable_get(v)] }.to_h
66
+ end
67
+ current_config['yeelights'] = current_lights
68
+ current_lights.each_with_index do |light, index|
69
+ puts "Light ##{index} => #{(light['name'] || light['id'])}@#{light['host']}"
70
+ end
71
+ ::Xilight::CLI.config = current_config
72
+ end
73
+ end
74
+
75
+ class List < Dry::CLI::Command
76
+ desc "List known Yeelights"
77
+
78
+ example [
79
+ ""
80
+ ]
81
+
82
+ def call(**)
83
+ current_config = ::Xilight::CLI.config
84
+ current_lights = current_config.fetch('yeelights', [])
85
+ current_lights.each_with_index do |light, index|
86
+ puts "Light ##{index} => #{(light['name'] || light['id'])}@#{light['host']}"
87
+ end
88
+ end
89
+ end
90
+
91
+ class Rgb < Dry::CLI::Command
92
+ desc "Set RGB for Yeelight"
93
+ argument :r, desc: "Red (0-255)", required: true
94
+ argument :g, desc: "Green (0-255)", required: true
95
+ argument :b, desc: "Blue (0-255)", required: true
96
+ option :light, desc: "ID/index of Yeelight to target", default: "0", aliases: ["-l"]
97
+ option :name, desc: "Name of Yeelight to target", default: nil, aliases: ["-n"]
98
+
99
+ example [
100
+ "255 0 0 # set light to red (red 255, green 0, blue 0)",
101
+ "0 0 180 -n foo# set light with name foo to blue (red 0, green 0, blue 180)",
102
+ "255 255 255 -l 3# set light #3 to white (red 255, green 255, blue 255)",
103
+ ]
104
+
105
+ def call(r:, g:, b:, light: 0, name: nil, **)
106
+ light =::Xilight::CLI.get_light(light, name)
107
+ as_hex = [r,g,b].map{|x| x.to_i.to_s(16).rjust(2, '0') }.join
108
+ light.rgb = as_hex.to_i(16)
109
+ end
110
+ end
111
+
112
+ class Hsv < Dry::CLI::Command
113
+ desc "Set HSV for Yeelight"
114
+ argument :h, desc: "Hue (0-359)", required: true, type: 'integer'
115
+ argument :s, desc: "Saturation (0-100)", required: true, type: 'integer'
116
+ option :light, desc: "ID/index of Yeelight to target", default: "0", aliases: ["-l"]
117
+ option :name, desc: "Name of Yeelight to target", default: nil, aliases: ["-n"]
118
+
119
+ example [
120
+ "180 40 # set hue to 180 and saturation to 40",
121
+ "200 20 -n foo# set light with name foo to hue: 200, saturation: 20",
122
+ "359 90 -l 3# set light #3 to hue: 359, saturation: 90",
123
+ ]
124
+
125
+ def call(h:, s:, light: 0, name: nil, **)
126
+ light =::Xilight::CLI.get_light(light, name)
127
+ light.set_hsv(h.to_i, s.to_i)
128
+ end
129
+ end
130
+
131
+ class Bright < Dry::CLI::Command
132
+ desc "Set Brightness for Yeelight"
133
+ argument :brightness, desc: "Brightness (0-100)", required: true
134
+ option :light, desc: "ID/index of Yeelight to target", default: "0", aliases: ["-l"]
135
+ option :name, desc: "Name of Yeelight to target", default: nil, aliases: ["-n"]
136
+
137
+ example [
138
+ "100 # full brightness",
139
+ "50 -n foo # 50% brightness for light with name foo ",
140
+ "25 -l 3 # 25% brightness for light#3 "
141
+ ]
142
+
143
+ def call(brightness:, light: 0, name: nil, **)
144
+ light =::Xilight::CLI.get_light(light, name)
145
+ light.bright = brightness.to_i
146
+ end
147
+ end
148
+
149
+ class On < Dry::CLI::Command
150
+ desc "Turn on Yeelight"
151
+ option :light, desc: "ID/index of Yeelight to target", default: "0", aliases: ["-l"]
152
+ option :name, desc: "Name of Yeelight to target", default: nil, aliases: ["-n"]
153
+
154
+ example [
155
+ "on # turn default/first light on",
156
+ "on -n kitchen # turn light with name 'kitchen' on",
157
+ "on -l 3 # turn light #3 on"
158
+ ]
159
+ def call(light: 0, name: nil, **)
160
+ light =::Xilight::CLI.get_light(light, name)
161
+ light.power = 'on'
162
+ end
163
+ end
164
+
165
+ class Off < Dry::CLI::Command
166
+ desc "Turn Off Yeelight"
167
+ option :light, desc: "ID/index of Yeelight to target", default: "0", aliases: ["-l"]
168
+ option :name, desc: "Name of Yeelight to target", default: nil, aliases: ["-n"]
169
+
170
+ example [
171
+ "off # turn default/first light off",
172
+ "off -n kitchen # turn light with name 'kitchen' off",
173
+ "off -l 3 # turn light #3 off"
174
+ ]
175
+
176
+ def call(light: 0, name: nil, **)
177
+ light =::Xilight::CLI.get_light(light, name)
178
+ light.power = 'off'
179
+ end
180
+ end
181
+
182
+ class Toggle < Dry::CLI::Command
183
+ desc "Toggle Yeelight"
184
+ option :light, desc: "ID/index of Yeelight to target", default: "0", aliases: ["-l"]
185
+ option :name, desc: "Name of Yeelight to target", default: nil, aliases: ["-n"]
186
+
187
+ example [
188
+ "toggle # toggle default/first light",
189
+ "toggle -n kitchen # toggle light with name 'kitchen'",
190
+ "toggle -l 3 # toggle light #3"
191
+ ]
192
+
193
+ def call(light: 0, name: nil, **)
194
+ light =::Xilight::CLI.get_light(light, name)
195
+ light.toggle
196
+ end
197
+ end
198
+
199
+ class Name < Dry::CLI::Command
200
+ desc "Set name for Yeelight"
201
+ argument :name, required: true, desc: "Name to set for light", default: nil, aliases: ["-n"]
202
+ option :light, desc: "ID/index of Yeelight to target", default: "0", aliases: ["-l"]
203
+
204
+ example [
205
+ "name -l 1 foo # Set the name for light#1 to \"foo\""
206
+ ]
207
+
208
+ def call(light: 0, name: nil, **)
209
+ yeelight =::Xilight::CLI.get_light(light)
210
+ yeelight.name = name
211
+ config = ::Xilight::CLI.config
212
+ config['yeelights'][light.to_i]['name'] = name
213
+ ::Xilight::CLI.config = config
214
+ end
215
+ end
216
+
217
+ COLORS = {
218
+ red: [255, 0, 0],
219
+ orange: [255, 128, 0],
220
+ yellow: [255, 255, 0],
221
+ lightgreen: [128, 255, 0],
222
+ green: [0, 255, 0],
223
+ turquoise: [0, 255, 128],
224
+ cyan: [0, 255, 255],
225
+ lightblue: [0, 128, 255],
226
+ blue: [0, 0, 255],
227
+ indigo: [128, 0, 255],
228
+ purple: [255, 0, 255],
229
+ magenta: [255, 0, 128],
230
+ silver: [128, 128, 128],
231
+ white: [255, 255, 255],
232
+ }
233
+
234
+ COLORS.each do |color, values|
235
+ class_name = color.to_s[0].upcase + color.to_s[1..-1]
236
+ Object.const_set(class_name, Class.new(Dry::CLI::Command) do
237
+ desc "Set yeelight to color #{color}"
238
+ example [
239
+ "#{color}"
240
+ ]
241
+
242
+ option :light, desc: "ID/index of Yeelight to target", default: "0", aliases: ["-l"]
243
+ option :name, desc: "Name of Yeelight to target", default: nil, aliases: ["-n"]
244
+
245
+ define_method(:call) do |light: 0, name: nil|
246
+ light =::Xilight::CLI.get_light(light, name)
247
+ as_hex = values.map{|x| x.to_i.to_s(16).rjust(2, '0') }.join
248
+ light.rgb = as_hex.to_i(16)
249
+ end
250
+ end)
251
+ end
252
+
253
+ register "color", aliases: ["c"] do |prefix|
254
+ COLORS.keys.each do |color|
255
+ class_name = color.to_s[0].upcase + color.to_s[1..-1]
256
+ prefix.register color.to_s, Object.const_get(class_name)
257
+ end
258
+ end
259
+
260
+ register "version", Version, aliases: ["v", "-v", "--version"]
261
+ register "discover", Discover, aliases: ["d"]
262
+ register "rgb", Rgb
263
+ register "hsv", Hsv
264
+ register "on", On, aliases: ["o"]
265
+ register "off", Off, aliases: ["x"]
266
+ register "toggle", Toggle, aliases: ["t"]
267
+ register "name", Name, aliases: ["n"]
268
+ register "list", List, aliases: ["ls"]
269
+ register "bright", Bright, aliases: ["brightness", "b"]
270
+ end
271
+ end
272
+ end
273
+
274
+ Dry::CLI.new(Xilight::CLI::Commands).call
@@ -0,0 +1,196 @@
1
+ require "xilight/version"
2
+
3
+ module Xilight
4
+ require 'socket'
5
+ require 'json'
6
+ require 'timeout'
7
+
8
+ class Yeelight
9
+
10
+ attr_reader :id
11
+
12
+ def initialize(location:, rgb: 0, hue: 0, sat: 0, ct: 0, color_mode: 0, bright: 0, power: :on, id:, name:, **kwargs)
13
+ @id = id
14
+ @rgb = rgb.to_i
15
+ @hue = hue.to_i
16
+ @sat = sat.to_i
17
+ @ct = ct.to_i
18
+ @color_mode = color_mode.to_i
19
+ @bright = bright.to_i
20
+ @power = power.to_sym
21
+ @location = location
22
+ @name = name
23
+ @host = location[/(?:\d+\.)+\d+/]
24
+ @port = location[/(?!<:)\d+$/]
25
+ end
26
+
27
+ def request(cmd)
28
+ s = TCPSocket.open(@host, @port)
29
+ s.puts "#{JSON.generate(cmd)}\r\n"
30
+ data = s.gets.chomp
31
+ s.close
32
+ JSON.parse(data)
33
+ end
34
+
35
+ # This method is used to retrieve current property of smart LED.
36
+ def get_prop(values)
37
+ request({id: 1,method: 'get_prop', params: values})
38
+ end
39
+
40
+ # This method is used to change the color temperature of a smart LED.
41
+ def set_ct_abx(ct_value, effect='smooth', duration=200)
42
+ request({id: 2,method: 'set_ct_abx', params: [ct_value,effect,duration]})
43
+ end
44
+
45
+ def ct_abx=ct_value
46
+ set_ct_abx(ct_value)
47
+ end
48
+
49
+ # This method is used to change the color RGB of a smart LED.
50
+ def set_rgb(rgb_value, effect='smooth', duration=200)
51
+ request({id: 3,method: 'set_rgb', params: [rgb_value,effect,duration]})
52
+ end
53
+
54
+ def rgb=rgb_value
55
+ set_rgb(rgb_value)
56
+ end
57
+
58
+ # This method is used to change the color HSV of a smart LED.
59
+ def set_hsv(hue, sat, effect='smooth', duration=200)
60
+ request({id: 4,method: 'set_hsv', params: [hue,sat,effect,duration]})
61
+ end
62
+
63
+ def hsv=hue
64
+ set_hsv(hue)
65
+ end
66
+
67
+ # This method is used to change the brightness of a smart LED.
68
+ def set_bright(brightness, effect='smooth', duration=200)
69
+ request({id: 5,method: 'set_bright', params: [brightness,effect,duration]})
70
+ end
71
+
72
+ def bright=brightness
73
+ set_bright(brightness)
74
+ end
75
+
76
+ # This method is used to switch on or off the smart LED (software managed on/off).
77
+ def set_power(power, effect='smooth', duration=200)
78
+ request({id: 6,method: 'set_power', params: [power,effect,duration]})
79
+ end
80
+
81
+ def power=power
82
+ set_power(power)
83
+ end
84
+
85
+ # This method is used to toggle the smart LED.
86
+ def toggle
87
+ request({id: 7,method: 'toggle', params: []})
88
+ end
89
+
90
+ # This method is used to save current state of smart LED in persistent memory.
91
+ # So if user powers off and then powers on the smart LED again (hard power reset),
92
+ # the smart LED will show last saved state.
93
+ # Note: The "automatic state saving" must be turn off
94
+ def set_default
95
+ request({id: 8,method: 'set_default', params: []})
96
+ end
97
+
98
+ # This method is used to start a color flow. Color flow is a series of smart
99
+ # LED visible state changing. It can be brightness changing, color changing
100
+ # or color temperature changing
101
+ def start_cf(count, action, flow_expression)
102
+ request({id: 9,method: 'set_power', params: [count,action,flow_expression]})
103
+ end
104
+
105
+ # This method is used to stop a running color flow.
106
+ def stop_cf
107
+ request({id: 10,method: 'stop_cf', params: []})
108
+ end
109
+
110
+ # This method is used to set the smart LED directly to specified state. If
111
+ # the smart LED is off, then it will turn on the smart LED firstly and then
112
+ # apply the specified scommand.
113
+ def set_scene(classe, val1, val2)
114
+ request({id: 11,method: 'set_scene', params: [classe,val1,val2]})
115
+ end
116
+
117
+ # This method is used to start a timer job on the smart LED
118
+ def cron_add(type, value)
119
+ request({id: 12,method: 'cron_add', params: [type,value]})
120
+ end
121
+
122
+ # This method is used to retrieve the setting of the current cron job
123
+ # of the specified type
124
+ def cron_get(type)
125
+ request({id: 13,method: 'cron_get', params: [type]})
126
+ end
127
+
128
+ # This method is used to stop the specified cron job.
129
+ def cron_del(type)
130
+ request({id: 14,method: 'cron_del', params: [type]})
131
+ end
132
+
133
+ # This method is used to change brightness, CT or color of a smart LED
134
+ # without knowing the current value, it's main used by controllers.
135
+ def set_adjust(action, prop)
136
+ request({id: 15,method: 'set_adjust', params: [action,prop]})
137
+ end
138
+
139
+ # This method is used to name the device. The name will be stored on the
140
+ # device and reported in discovering response. User can also read the name
141
+ # through “get_prop” method.
142
+ def set_name(name)
143
+ request({id: 16,method: 'set_name', params: [name]})
144
+ end
145
+
146
+ def name=(name)
147
+ set_name(name)
148
+ end
149
+
150
+ # This method is used to switch on the smart LED
151
+ def on
152
+ set_power("on", "smooth",1000)
153
+ end
154
+
155
+ # This method is used to switch off the smart LED
156
+ def off
157
+ set_power("off", "smooth",1000)
158
+ end
159
+
160
+
161
+ # This method is used to discover a smart LED in the network
162
+ def self.discover
163
+ host = "239.255.255.250"
164
+ port = 1982
165
+ socket = UDPSocket.new(Socket::AF_INET)
166
+
167
+ payload = []
168
+ payload << "M-SEARCH * HTTP/1.1\r\n"
169
+ payload << "HOST: #{host}:#{port}\r\n"
170
+ payload << "MAN: \"ssdp:discover\"\r\n"
171
+ payload << "ST: wifi_bulb"
172
+
173
+ socket.send(payload.join(), 0, host, port)
174
+
175
+ devices = []
176
+ begin
177
+ Timeout.timeout(0.5) do
178
+ loop do
179
+ devices << socket.recvfrom(2048)
180
+ end
181
+ end
182
+ rescue Timeout::Error => ex
183
+ ex
184
+ end
185
+ devices.map do |(description, params)|
186
+ options = description.split("\r\n")
187
+ .select{|x| x.include?(":")}
188
+ .map{|x| x.split(":", 2) }
189
+ .map do |key, value|
190
+ [key.downcase.strip.gsub(/[^a-z]+/,"_").to_sym, value.strip]
191
+ end.to_h
192
+ Yeelight.new(**options)
193
+ end.uniq{|yl| yl.id }
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,3 @@
1
+ module Yeelight
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'xilight/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "xilight"
8
+ spec.version = Yeelight::VERSION
9
+ spec.authors = ["Wouter Coppieters"]
10
+ spec.email = ["wouter@youdo.co.nz"]
11
+
12
+ spec.summary = "Ruby Xiaomi Yeelight gem"
13
+ spec.description = "Ruby Xiaomi Yeelight gem"
14
+
15
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
16
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
17
+ # if spec.respond_to?(:metadata)
18
+ # spec.metadata['allowed_push_host'] = "http://mygemserver.com"
19
+ # else
20
+ # raise "RubyGems 2.0 or newer is required to protect against " \
21
+ # "public gem pushes."
22
+ # end
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
25
+ f.match(%r{^(test|spec|features)/})
26
+ end
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+ spec.add_runtime_dependency "dry-cli"
31
+ spec.add_development_dependency "bundler", "~> 1.13"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "pry"
34
+ spec.add_development_dependency "pry-byebug"
35
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xilight
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Wouter Coppieters
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-06-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-cli
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.13'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.13'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-byebug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Ruby Xiaomi Yeelight gem
84
+ email:
85
+ - wouter@youdo.co.nz
86
+ executables:
87
+ - yee
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - CODE_OF_CONDUCT.md
93
+ - Gemfile
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
97
+ - bin/setup
98
+ - exe/yee
99
+ - lib/xilight.rb
100
+ - lib/xilight/version.rb
101
+ - xilight.gemspec
102
+ homepage:
103
+ licenses: []
104
+ metadata: {}
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubygems_version: 3.1.4
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: Ruby Xiaomi Yeelight gem
124
+ test_files: []