ewelink 3.2.0 → 4.0.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 +4 -4
- data/README.mdown +3 -0
- data/VERSION +1 -1
- data/bin/ewelink +1 -1
- data/ewelink.gemspec +9 -6
- data/lib/ewelink/api.rb +95 -82
- data/lib/ewelink/runner.rb +10 -12
- data/lib/ewelink.rb +1 -0
- metadata +75 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b8e686b44abcc1c59621d612a64b930f89a0041ac4607070bd47c801f04148ac
|
|
4
|
+
data.tar.gz: 3990a53b5d57e0c0523ba83050e7af904dd54a96337692a5fc800e6e3d0edaa9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 41aaa80ba63866bf04728c60489ed91b3b8294a61dc7e7d78779628b7530006bd41d306adb4e6a72ccdb1e72ed8322dd94efe897053ed02ce1da977e7560319a
|
|
7
|
+
data.tar.gz: c6af766c67c28efffd27a4186c3b603e9c4d3ab48e5fb8bc8ca1b52b5ce7aec8969297b932134c3c640ca5ece581ab70c6932ffb8a5597ebb54cc831b9bbfb98
|
data/README.mdown
CHANGED
|
@@ -77,6 +77,9 @@ api.press_rf_bridge_button!(button[:uuid])
|
|
|
77
77
|
|
|
78
78
|
### Additional options
|
|
79
79
|
|
|
80
|
+
- `async_actions` (`true` | `false`): To perform actions (pressing an RF
|
|
81
|
+
bridge button or turning a switch on/off) in asynchronous mode. (default:
|
|
82
|
+
`false`).
|
|
80
83
|
- `update_devices_status_on_connect` (`true` | `false`): To update devices
|
|
81
84
|
status (on, off) when connecting to Ewelink API (default: `false`).
|
|
82
85
|
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
4.0.0
|
data/bin/ewelink
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative '../lib/ewelink'
|
|
4
4
|
|
|
5
|
-
Ewelink.logger = Logger.new(
|
|
5
|
+
Ewelink.logger = Logger.new($stdout, formatter: lambda { |_severity, _time, progname, message|
|
|
6
6
|
text = ''
|
|
7
7
|
text << "[#{progname}] " if progname.present?
|
|
8
8
|
text << message.to_s << "\n"
|
data/ewelink.gemspec
CHANGED
|
@@ -9,16 +9,19 @@ Gem::Specification.new do |s|
|
|
|
9
9
|
s.description = 'Manage eWeLink smart home devices'
|
|
10
10
|
s.license = 'MIT'
|
|
11
11
|
|
|
12
|
-
s.files =
|
|
13
|
-
s.executables =
|
|
12
|
+
s.files = %x(git ls-files | grep -vE '^(spec/|test/|\\.|Gemfile|Rakefile)').split("\n")
|
|
13
|
+
s.executables = %x(git ls-files -- bin/*).split("\n").map { |f| File.basename(f) }
|
|
14
14
|
s.require_paths = ['lib']
|
|
15
15
|
|
|
16
|
-
s.required_ruby_version = '>=
|
|
16
|
+
s.required_ruby_version = '>= 3.1.0'
|
|
17
17
|
|
|
18
|
-
s.add_dependency 'activesupport', '>=
|
|
18
|
+
s.add_dependency 'activesupport', '>= 7.0.0', '< 8.0.0'
|
|
19
19
|
s.add_dependency 'faye-websocket', '>= 0.11.0', '< 0.12.0'
|
|
20
|
-
s.add_dependency 'httparty', '>= 0.
|
|
20
|
+
s.add_dependency 'httparty', '>= 0.20.0', '< 0.21.0'
|
|
21
|
+
s.add_dependency 'thread', '>= 0.2.0', '< 0.3.0'
|
|
21
22
|
|
|
22
23
|
s.add_development_dependency 'byebug', '>= 11.0.0', '< 12.0.0'
|
|
23
|
-
s.add_development_dependency 'rake', '>=
|
|
24
|
+
s.add_development_dependency 'rake', '>= 13.0.0', '< 14.0.0'
|
|
25
|
+
s.add_development_dependency 'rubocop', '>= 1.25.0', '< 2.0.0'
|
|
26
|
+
s.add_development_dependency 'rubocop-rake', '>= 0.6.0', '< 1.0.0'
|
|
24
27
|
end
|
data/lib/ewelink/api.rb
CHANGED
|
@@ -2,14 +2,13 @@ module Ewelink
|
|
|
2
2
|
|
|
3
3
|
class Api
|
|
4
4
|
|
|
5
|
-
APP_ID = 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq'
|
|
6
|
-
APP_SECRET = '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM'
|
|
7
|
-
DEFAULT_REGION = 'us'
|
|
5
|
+
APP_ID = 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq'.freeze
|
|
6
|
+
APP_SECRET = '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM'.freeze
|
|
7
|
+
DEFAULT_REGION = 'us'.freeze
|
|
8
8
|
REQUEST_TIMEOUT = 10.seconds
|
|
9
9
|
RF_BRIDGE_DEVICE_UIID = 28
|
|
10
|
-
SWITCH_DEVICES_UIIDS = [1, 5, 6, 24]
|
|
11
|
-
URL = 'https://#{region}-api.coolkit.cc:8080'
|
|
12
|
-
UUID_NAMESPACE = 'e25750fb-3710-41af-b831-23224f4dd609';
|
|
10
|
+
SWITCH_DEVICES_UIIDS = [1, 5, 6, 24].freeze
|
|
11
|
+
URL = 'https://#{region}-api.coolkit.cc:8080'.freeze
|
|
13
12
|
VERSION = 8
|
|
14
13
|
WEB_SOCKET_CHECK_AUTHENTICATION_TIMEOUT = 30.seconds
|
|
15
14
|
WEB_SOCKET_PING_TOLERANCE_FACTOR = 1.5
|
|
@@ -18,10 +17,11 @@ module Ewelink
|
|
|
18
17
|
|
|
19
18
|
attr_reader :email, :password, :phone_number
|
|
20
19
|
|
|
21
|
-
def initialize(email: nil,
|
|
20
|
+
def initialize(password:, async_actions: false, email: nil, phone_number: nil, update_devices_status_on_connect: false)
|
|
21
|
+
@async_actions = async_actions.present?
|
|
22
22
|
@email = email.presence.try(:strip)
|
|
23
23
|
@mutexs = {}
|
|
24
|
-
@password = password.presence || raise(Error.new(
|
|
24
|
+
@password = password.presence || raise(Error.new(':password must be specified'))
|
|
25
25
|
@phone_number = phone_number.presence.try(:strip)
|
|
26
26
|
@update_devices_status_on_connect = update_devices_status_on_connect.present?
|
|
27
27
|
@web_socket_authenticated = false
|
|
@@ -32,25 +32,31 @@ module Ewelink
|
|
|
32
32
|
start_web_socket_authentication_check_thread
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
def async_actions?
|
|
36
|
+
@async_actions
|
|
37
|
+
end
|
|
38
|
+
|
|
35
39
|
def press_rf_bridge_button!(uuid)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
'
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
process_action do
|
|
41
|
+
synchronize(:press_rf_bridge_button) do
|
|
42
|
+
button = find_rf_bridge_button!(uuid)
|
|
43
|
+
web_socket_wait_for(-> { web_socket_authenticated? }, initialize_web_socket: true) do
|
|
44
|
+
params = {
|
|
45
|
+
'action' => 'update',
|
|
46
|
+
'apikey' => button[:api_key],
|
|
47
|
+
'deviceid' => button[:device_id],
|
|
48
|
+
'params' => {
|
|
49
|
+
'cmd' => 'transmit',
|
|
50
|
+
'rfChl' => button[:channel],
|
|
51
|
+
},
|
|
52
|
+
'sequence' => web_socket_sequence,
|
|
53
|
+
'ts' => 0,
|
|
54
|
+
'userAgent' => 'app',
|
|
55
|
+
}
|
|
56
|
+
Ewelink.logger.debug(self.class.name) { "Pressing RF bridge button #{button[:uuid].inspect}" }
|
|
57
|
+
send_to_web_socket(JSON.generate(params))
|
|
58
|
+
true
|
|
59
|
+
end
|
|
54
60
|
end
|
|
55
61
|
end
|
|
56
62
|
end
|
|
@@ -78,19 +84,19 @@ module Ewelink
|
|
|
78
84
|
end
|
|
79
85
|
end
|
|
80
86
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
%i(
|
|
88
|
+
@authentication_infos
|
|
89
|
+
@devices
|
|
90
|
+
@last_web_socket_pong_at
|
|
91
|
+
@region
|
|
92
|
+
@rf_bridge_buttons
|
|
93
|
+
@switches
|
|
94
|
+
@web_socket_ping_interval
|
|
95
|
+
@web_socket_ping_thread
|
|
96
|
+
@web_socket_thread
|
|
97
|
+
@web_socket_url
|
|
98
|
+
@web_socket
|
|
99
|
+
).each do |variable|
|
|
94
100
|
remove_instance_variable(variable) if instance_variable_defined?(variable)
|
|
95
101
|
end
|
|
96
102
|
self
|
|
@@ -108,10 +114,10 @@ module Ewelink
|
|
|
108
114
|
device_name = device['name'].presence || next
|
|
109
115
|
buttons = device['params']['rfList'].each do |rf|
|
|
110
116
|
button = {
|
|
111
|
-
api_key
|
|
117
|
+
api_key:,
|
|
112
118
|
channel: rf['rfChl'],
|
|
113
|
-
device_id
|
|
114
|
-
device_name
|
|
119
|
+
device_id:,
|
|
120
|
+
device_name:,
|
|
115
121
|
}
|
|
116
122
|
remote_info = device['tags']['zyx_info'].find { |info| info['buttonName'].find { |data| data.key?(button[:channel].to_s) } }.presence || next
|
|
117
123
|
remote_name = remote_info['name'].try(:squish).presence || next
|
|
@@ -119,10 +125,10 @@ module Ewelink
|
|
|
119
125
|
button_name = button_info.values.first.try(:squish).presence || next
|
|
120
126
|
button.merge!({
|
|
121
127
|
name: button_name,
|
|
122
|
-
remote_name
|
|
128
|
+
remote_name:,
|
|
123
129
|
remote_type: remote_info['remote_type'],
|
|
124
130
|
})
|
|
125
|
-
button[:uuid] = Digest::UUID.uuid_v5(
|
|
131
|
+
button[:uuid] = Digest::UUID.uuid_v5(Digest::UUID::DNS_NAMESPACE, "#{button[:device_id]}/#{button[:channel]}")
|
|
126
132
|
buttons << button
|
|
127
133
|
end
|
|
128
134
|
end
|
|
@@ -160,11 +166,11 @@ module Ewelink
|
|
|
160
166
|
device_id = device['deviceid'].presence || next
|
|
161
167
|
name = device['name'].presence || next
|
|
162
168
|
switch = {
|
|
163
|
-
api_key
|
|
164
|
-
device_id
|
|
165
|
-
name
|
|
169
|
+
api_key:,
|
|
170
|
+
device_id:,
|
|
171
|
+
name:,
|
|
166
172
|
}
|
|
167
|
-
switch[:uuid] = Digest::UUID.uuid_v5(
|
|
173
|
+
switch[:uuid] = Digest::UUID.uuid_v5(Digest::UUID::DNS_NAMESPACE, switch[:device_id])
|
|
168
174
|
switches << switch
|
|
169
175
|
end
|
|
170
176
|
end.tap { |switches| Ewelink.logger.debug(self.class.name) { "Found #{switches.size} switch(es)" } }
|
|
@@ -172,31 +178,33 @@ module Ewelink
|
|
|
172
178
|
end
|
|
173
179
|
|
|
174
180
|
def turn_switch!(uuid, on)
|
|
175
|
-
|
|
176
|
-
on
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
'
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
181
|
+
process_action do
|
|
182
|
+
if ['on', :on, 'true'].include?(on)
|
|
183
|
+
on = true
|
|
184
|
+
elsif ['off', :off, 'false'].include?(on)
|
|
185
|
+
on = false
|
|
186
|
+
end
|
|
187
|
+
switch = find_switch!(uuid)
|
|
188
|
+
@web_socket_switches_statuses[switch[:uuid]] = nil
|
|
189
|
+
web_socket_wait_for(-> { web_socket_authenticated? }, initialize_web_socket: true) do
|
|
190
|
+
params = {
|
|
191
|
+
'action' => 'update',
|
|
192
|
+
'apikey' => switch[:api_key],
|
|
193
|
+
'deviceid' => switch[:device_id],
|
|
194
|
+
'params' => {
|
|
195
|
+
'switch' => on ? 'on' : 'off',
|
|
196
|
+
},
|
|
197
|
+
'sequence' => web_socket_sequence,
|
|
198
|
+
'ts' => 0,
|
|
199
|
+
'userAgent' => 'app',
|
|
200
|
+
}
|
|
201
|
+
Ewelink.logger.debug(self.class.name) { "Turning switch #{switch[:uuid].inspect} #{on ? 'on' : 'off'}" }
|
|
202
|
+
send_to_web_socket(JSON.generate(params))
|
|
203
|
+
end
|
|
204
|
+
sleep(SWITCH_STATUS_CHANGE_CHECK_TIMEOUT)
|
|
205
|
+
switch_on?(switch[:uuid]) # Waiting for switch status update
|
|
206
|
+
true
|
|
196
207
|
end
|
|
197
|
-
sleep(SWITCH_STATUS_CHANGE_CHECK_TIMEOUT)
|
|
198
|
-
switch_on?(switch[:uuid]) # Waiting for switch status update
|
|
199
|
-
true
|
|
200
208
|
end
|
|
201
209
|
|
|
202
210
|
def update_devices_status_on_connect?
|
|
@@ -246,7 +254,7 @@ module Ewelink
|
|
|
246
254
|
params['phoneNumber'] = phone_number
|
|
247
255
|
end
|
|
248
256
|
body = JSON.generate(params)
|
|
249
|
-
response = rest_request(:post, '/api/user/login', { body
|
|
257
|
+
response = rest_request(:post, '/api/user/login', { body:, headers: { 'Authorization' => "Sign #{Base64.encode64(OpenSSL::HMAC.digest('SHA256', APP_SECRET, body))}" } })
|
|
250
258
|
raise(Error.new('Authentication token not found')) if response['at'].blank?
|
|
251
259
|
raise(Error.new('API key not found')) if response['user'].blank? || response['user']['apikey'].blank?
|
|
252
260
|
{
|
|
@@ -289,6 +297,13 @@ module Ewelink
|
|
|
289
297
|
SecureRandom.hex[0, 8]
|
|
290
298
|
end
|
|
291
299
|
|
|
300
|
+
def process_action(&block)
|
|
301
|
+
return yield unless async_actions?
|
|
302
|
+
@async_actions_thread_pool ||= Thread.pool(1)
|
|
303
|
+
@async_actions_thread_pool.process(&block)
|
|
304
|
+
true
|
|
305
|
+
end
|
|
306
|
+
|
|
292
307
|
def region
|
|
293
308
|
@region ||= DEFAULT_REGION
|
|
294
309
|
end
|
|
@@ -298,7 +313,7 @@ module Ewelink
|
|
|
298
313
|
method = method.to_s.upcase
|
|
299
314
|
headers = (options[:headers] || {}).reverse_merge('Content-Type' => 'application/json')
|
|
300
315
|
Ewelink.logger.debug(self.class.name) { "#{method} #{url}" }
|
|
301
|
-
response = HTTParty.send(method.downcase, url, options.merge(headers:
|
|
316
|
+
response = HTTParty.send(method.downcase, url, options.merge(headers:).reverse_merge(timeout: REQUEST_TIMEOUT))
|
|
302
317
|
raise(Error.new("#{method} #{url}: #{response.code}")) unless response.success?
|
|
303
318
|
if response['error'] == 301 && response['region'].present?
|
|
304
319
|
@region = response['region']
|
|
@@ -375,12 +390,12 @@ module Ewelink
|
|
|
375
390
|
EventMachine.run do
|
|
376
391
|
@web_socket = Faye::WebSocket::Client.new(web_socket_url)
|
|
377
392
|
|
|
378
|
-
@web_socket.on(:close) do
|
|
393
|
+
@web_socket.on(:close) do
|
|
379
394
|
Ewelink.logger.debug(self.class.name) { 'WebSocket closed' }
|
|
380
395
|
reload
|
|
381
396
|
end
|
|
382
397
|
|
|
383
|
-
@web_socket.on(:open) do
|
|
398
|
+
@web_socket.on(:open) do
|
|
384
399
|
Ewelink.logger.debug(self.class.name) { 'WebSocket opened' }
|
|
385
400
|
@last_web_socket_pong_at = Time.now
|
|
386
401
|
authenticate_web_socket_api_key
|
|
@@ -397,7 +412,7 @@ module Ewelink
|
|
|
397
412
|
|
|
398
413
|
begin
|
|
399
414
|
json = JSON.parse(message)
|
|
400
|
-
rescue
|
|
415
|
+
rescue
|
|
401
416
|
Ewelink.logger.error(self.class.name) { 'WebSocket JSON parse error' }
|
|
402
417
|
reload
|
|
403
418
|
next
|
|
@@ -420,7 +435,7 @@ module Ewelink
|
|
|
420
435
|
end
|
|
421
436
|
|
|
422
437
|
if json['deviceid'].present? && json['params'].is_a?(Hash) && json['params']['switch'].present?
|
|
423
|
-
switch = switches.find { |
|
|
438
|
+
switch = switches.find { |item| item[:device_id] == json['deviceid'] }
|
|
424
439
|
if switch.present?
|
|
425
440
|
@web_socket_switches_statuses[switch[:uuid]] = json['params']['switch']
|
|
426
441
|
Ewelink.logger.debug(self.class.name) { "Switch #{switch[:uuid].inspect} is #{@web_socket_switches_statuses[switch[:uuid]]}" }
|
|
@@ -467,13 +482,11 @@ module Ewelink
|
|
|
467
482
|
end
|
|
468
483
|
end
|
|
469
484
|
|
|
470
|
-
def web_socket_wait_for(condition, initialize_web_socket: false
|
|
485
|
+
def web_socket_wait_for(condition, initialize_web_socket: false)
|
|
471
486
|
web_socket if initialize_web_socket
|
|
472
487
|
begin
|
|
473
488
|
Timeout.timeout(REQUEST_TIMEOUT) do
|
|
474
|
-
|
|
475
|
-
sleep(WEB_SOCKET_WAIT_INTERVAL)
|
|
476
|
-
end
|
|
489
|
+
sleep(WEB_SOCKET_WAIT_INTERVAL) until condition.call
|
|
477
490
|
block_given? ? yield : true
|
|
478
491
|
end
|
|
479
492
|
rescue => e
|
data/lib/ewelink/runner.rb
CHANGED
|
@@ -3,13 +3,13 @@ module Ewelink
|
|
|
3
3
|
class Runner
|
|
4
4
|
|
|
5
5
|
def run
|
|
6
|
-
api = Api.new(options.slice(:email, :password, :phone_number))
|
|
6
|
+
api = Api.new(**options.slice(:email, :password, :phone_number))
|
|
7
7
|
puts(JSON.pretty_generate(api.switches)) if options[:list_switches]
|
|
8
8
|
puts(JSON.pretty_generate(api.rf_bridge_buttons)) if options[:list_rf_bridge_buttons]
|
|
9
9
|
options[:turn_switches_on_uuids].each { |uuid| api.turn_switch!(uuid, :on) }
|
|
10
10
|
options[:turn_switches_off_uuids].each { |uuid| api.turn_switch!(uuid, :off) }
|
|
11
11
|
options[:press_rf_bridge_buttons_uuids].each { |uuid| api.press_rf_bridge_button!(uuid) }
|
|
12
|
-
puts(JSON.pretty_generate(options[:switch_status_uuids].
|
|
12
|
+
puts(JSON.pretty_generate(options[:switch_status_uuids].to_h { |uuid| [uuid, api.switch_on?(uuid) ? 'on' : 'off'] })) if options[:switch_status_uuids].present?
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
private
|
|
@@ -56,23 +56,21 @@ module Ewelink
|
|
|
56
56
|
end
|
|
57
57
|
arguments = parser.parse!
|
|
58
58
|
if arguments.any?
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
warn("Invalid option specified: #{arguments.first}")
|
|
60
|
+
warn(parser.summarize)
|
|
61
61
|
exit(1)
|
|
62
62
|
end
|
|
63
63
|
if options[:email].blank? && options[:phone_number].blank?
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
warn('Email or phone number must be specified')
|
|
65
|
+
warn(parser.summarize)
|
|
66
66
|
exit(1)
|
|
67
67
|
end
|
|
68
|
-
if
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
if %i(list_switches list_rf_bridge_buttons turn_switches_on_uuids turn_switches_off_uuids press_rf_bridge_buttons_uuids switch_status_uuids).map { |action| options[action] }.all?(&:blank?)
|
|
69
|
+
warn('An action must be specified (listing switches, press RF bridge button, etc.)')
|
|
70
|
+
warn(parser.summarize)
|
|
71
71
|
exit(1)
|
|
72
72
|
end
|
|
73
|
-
while options[:password].blank?
|
|
74
|
-
options[:password] = IO::console.getpass("Enter eWeLink account's password: ")
|
|
75
|
-
end
|
|
73
|
+
options[:password] = IO.console.getpass("Enter eWeLink account's password: ") while options[:password].blank?
|
|
76
74
|
options
|
|
77
75
|
end
|
|
78
76
|
end
|
data/lib/ewelink.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ewelink
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 4.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexis Toulotte
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-02-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -16,20 +16,20 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 7.0.0
|
|
20
20
|
- - "<"
|
|
21
21
|
- !ruby/object:Gem::Version
|
|
22
|
-
version:
|
|
22
|
+
version: 8.0.0
|
|
23
23
|
type: :runtime
|
|
24
24
|
prerelease: false
|
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
26
26
|
requirements:
|
|
27
27
|
- - ">="
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
|
-
version:
|
|
29
|
+
version: 7.0.0
|
|
30
30
|
- - "<"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version:
|
|
32
|
+
version: 8.0.0
|
|
33
33
|
- !ruby/object:Gem::Dependency
|
|
34
34
|
name: faye-websocket
|
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -56,20 +56,40 @@ dependencies:
|
|
|
56
56
|
requirements:
|
|
57
57
|
- - ">="
|
|
58
58
|
- !ruby/object:Gem::Version
|
|
59
|
-
version: 0.
|
|
59
|
+
version: 0.20.0
|
|
60
60
|
- - "<"
|
|
61
61
|
- !ruby/object:Gem::Version
|
|
62
|
-
version: 0.
|
|
62
|
+
version: 0.21.0
|
|
63
63
|
type: :runtime
|
|
64
64
|
prerelease: false
|
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
|
66
66
|
requirements:
|
|
67
67
|
- - ">="
|
|
68
68
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: 0.
|
|
69
|
+
version: 0.20.0
|
|
70
70
|
- - "<"
|
|
71
71
|
- !ruby/object:Gem::Version
|
|
72
|
-
version: 0.
|
|
72
|
+
version: 0.21.0
|
|
73
|
+
- !ruby/object:Gem::Dependency
|
|
74
|
+
name: thread
|
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
|
76
|
+
requirements:
|
|
77
|
+
- - ">="
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
version: 0.2.0
|
|
80
|
+
- - "<"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 0.3.0
|
|
83
|
+
type: :runtime
|
|
84
|
+
prerelease: false
|
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: 0.2.0
|
|
90
|
+
- - "<"
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: 0.3.0
|
|
73
93
|
- !ruby/object:Gem::Dependency
|
|
74
94
|
name: byebug
|
|
75
95
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -96,20 +116,60 @@ dependencies:
|
|
|
96
116
|
requirements:
|
|
97
117
|
- - ">="
|
|
98
118
|
- !ruby/object:Gem::Version
|
|
99
|
-
version:
|
|
119
|
+
version: 13.0.0
|
|
100
120
|
- - "<"
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: 14.0.0
|
|
123
|
+
type: :development
|
|
124
|
+
prerelease: false
|
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - ">="
|
|
101
128
|
- !ruby/object:Gem::Version
|
|
102
129
|
version: 13.0.0
|
|
130
|
+
- - "<"
|
|
131
|
+
- !ruby/object:Gem::Version
|
|
132
|
+
version: 14.0.0
|
|
133
|
+
- !ruby/object:Gem::Dependency
|
|
134
|
+
name: rubocop
|
|
135
|
+
requirement: !ruby/object:Gem::Requirement
|
|
136
|
+
requirements:
|
|
137
|
+
- - ">="
|
|
138
|
+
- !ruby/object:Gem::Version
|
|
139
|
+
version: 1.25.0
|
|
140
|
+
- - "<"
|
|
141
|
+
- !ruby/object:Gem::Version
|
|
142
|
+
version: 2.0.0
|
|
103
143
|
type: :development
|
|
104
144
|
prerelease: false
|
|
105
145
|
version_requirements: !ruby/object:Gem::Requirement
|
|
106
146
|
requirements:
|
|
107
147
|
- - ">="
|
|
108
148
|
- !ruby/object:Gem::Version
|
|
109
|
-
version:
|
|
149
|
+
version: 1.25.0
|
|
110
150
|
- - "<"
|
|
111
151
|
- !ruby/object:Gem::Version
|
|
112
|
-
version:
|
|
152
|
+
version: 2.0.0
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: rubocop-rake
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - ">="
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: 0.6.0
|
|
160
|
+
- - "<"
|
|
161
|
+
- !ruby/object:Gem::Version
|
|
162
|
+
version: 1.0.0
|
|
163
|
+
type: :development
|
|
164
|
+
prerelease: false
|
|
165
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
166
|
+
requirements:
|
|
167
|
+
- - ">="
|
|
168
|
+
- !ruby/object:Gem::Version
|
|
169
|
+
version: 0.6.0
|
|
170
|
+
- - "<"
|
|
171
|
+
- !ruby/object:Gem::Version
|
|
172
|
+
version: 1.0.0
|
|
113
173
|
description: Manage eWeLink smart home devices
|
|
114
174
|
email: al@alweb.org
|
|
115
175
|
executables:
|
|
@@ -137,14 +197,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
137
197
|
requirements:
|
|
138
198
|
- - ">="
|
|
139
199
|
- !ruby/object:Gem::Version
|
|
140
|
-
version:
|
|
200
|
+
version: 3.1.0
|
|
141
201
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
202
|
requirements:
|
|
143
203
|
- - ">="
|
|
144
204
|
- !ruby/object:Gem::Version
|
|
145
205
|
version: '0'
|
|
146
206
|
requirements: []
|
|
147
|
-
rubygems_version: 3.
|
|
207
|
+
rubygems_version: 3.3.3
|
|
148
208
|
signing_key:
|
|
149
209
|
specification_version: 4
|
|
150
210
|
summary: Manage eWeLink devices
|