ewelink 3.3.2 → 5.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/VERSION +1 -1
- data/bin/ewelink +1 -1
- data/ewelink.gemspec +7 -5
- data/lib/ewelink/api.rb +112 -90
- data/lib/ewelink/runner.rb +9 -11
- metadata +52 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2f26d6875823958f38a894377c7dfbce3531d7f98b1c1c69b18bd88caf44c1d
|
|
4
|
+
data.tar.gz: d25335eb91529c57d2780c42e8cef5856cb7bfa7f222e5282816bff122854b08
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 42786625ddc6d8482a5d85922e25b4b650e080866148b378aeb579ad25e0dcee00d4f12b8ebf74492e207d80e6ed0d65b6f0c71ccdaf5c3f81280b1efbd4bc7b
|
|
7
|
+
data.tar.gz: 8eb9cc344312a30a7b0924ff02b052516bf5123a7d706acb15e000b91db2c91ecf56a2173d22543403f7fbbc31773e30d97d3c5379ad37ab42e34b55f8f67366
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
5.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,17 +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
21
|
s.add_dependency 'thread', '>= 0.2.0', '< 0.3.0'
|
|
22
22
|
|
|
23
23
|
s.add_development_dependency 'byebug', '>= 11.0.0', '< 12.0.0'
|
|
24
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'
|
|
25
27
|
end
|
data/lib/ewelink/api.rb
CHANGED
|
@@ -2,14 +2,14 @@ module Ewelink
|
|
|
2
2
|
|
|
3
3
|
class Api
|
|
4
4
|
|
|
5
|
-
APP_ID = '
|
|
6
|
-
APP_SECRET = '
|
|
7
|
-
|
|
5
|
+
APP_ID = 'Uw83EKZFxdif7XFXEsrpduz5YyjP7nTl'.freeze
|
|
6
|
+
APP_SECRET = 'mXLOjea0woSMvK9gw7Fjsy7YlFO4iSu6'.freeze
|
|
7
|
+
DEFAULT_COUNTRY_CODE = '+44'.freeze
|
|
8
|
+
DEFAULT_REGION = 'us'.freeze
|
|
8
9
|
REQUEST_TIMEOUT = 10.seconds
|
|
9
10
|
RF_BRIDGE_DEVICE_UIID = 28
|
|
10
|
-
SWITCH_DEVICES_UIIDS = [1, 5, 6, 24]
|
|
11
|
-
URL = 'https://#{region}-
|
|
12
|
-
UUID_NAMESPACE = 'e25750fb-3710-41af-b831-23224f4dd609';
|
|
11
|
+
SWITCH_DEVICES_UIIDS = [1, 5, 6, 24].freeze
|
|
12
|
+
URL = 'https://#{region}-apia.coolkit.cc'.freeze
|
|
13
13
|
VERSION = 8
|
|
14
14
|
WEB_SOCKET_CHECK_AUTHENTICATION_TIMEOUT = 30.seconds
|
|
15
15
|
WEB_SOCKET_PING_TOLERANCE_FACTOR = 1.5
|
|
@@ -18,11 +18,11 @@ module Ewelink
|
|
|
18
18
|
|
|
19
19
|
attr_reader :email, :password, :phone_number
|
|
20
20
|
|
|
21
|
-
def initialize(async_actions: false, email: nil,
|
|
21
|
+
def initialize(password:, async_actions: false, email: nil, phone_number: nil, update_devices_status_on_connect: false)
|
|
22
22
|
@async_actions = async_actions.present?
|
|
23
23
|
@email = email.presence.try(:strip)
|
|
24
24
|
@mutexs = {}
|
|
25
|
-
@password = password.presence || raise(Error.new(
|
|
25
|
+
@password = password.presence || raise(Error.new(':password must be specified'))
|
|
26
26
|
@phone_number = phone_number.presence.try(:strip)
|
|
27
27
|
@update_devices_status_on_connect = update_devices_status_on_connect.present?
|
|
28
28
|
@web_socket_authenticated = false
|
|
@@ -41,23 +41,21 @@ module Ewelink
|
|
|
41
41
|
process_action do
|
|
42
42
|
synchronize(:press_rf_bridge_button) do
|
|
43
43
|
button = find_rf_bridge_button!(uuid)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
'
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
true
|
|
60
|
-
end
|
|
44
|
+
headers = authentication_headers.merge(
|
|
45
|
+
'X-CK-Appid' => APP_ID,
|
|
46
|
+
'X-CK-Nonce' => nonce,
|
|
47
|
+
)
|
|
48
|
+
params = {
|
|
49
|
+
'type' => 1,
|
|
50
|
+
'id' => button[:device_id],
|
|
51
|
+
'params' => {
|
|
52
|
+
'cmd' => 'transmit',
|
|
53
|
+
'rfChl' => button[:channel],
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
body = JSON.generate(params)
|
|
57
|
+
response = rest_request(:post, '/v2/device/thing/status', headers:, body:)
|
|
58
|
+
response['error'] == 0
|
|
61
59
|
end
|
|
62
60
|
end
|
|
63
61
|
end
|
|
@@ -85,19 +83,20 @@ module Ewelink
|
|
|
85
83
|
end
|
|
86
84
|
end
|
|
87
85
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
%i(
|
|
87
|
+
@authentication_infos
|
|
88
|
+
@devices
|
|
89
|
+
@homes_ids
|
|
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|
|
|
101
100
|
remove_instance_variable(variable) if instance_variable_defined?(variable)
|
|
102
101
|
end
|
|
103
102
|
self
|
|
@@ -106,30 +105,30 @@ module Ewelink
|
|
|
106
105
|
def rf_bridge_buttons
|
|
107
106
|
synchronize(:rf_bridge_buttons) do
|
|
108
107
|
@rf_bridge_buttons ||= [].tap do |buttons|
|
|
109
|
-
rf_bridge_devices = devices.select { |device| device['uiid'] == RF_BRIDGE_DEVICE_UIID }.tap do |devices|
|
|
108
|
+
rf_bridge_devices = devices.select { |device| device['itemData']['extra']['uiid'] == RF_BRIDGE_DEVICE_UIID }.tap do |devices|
|
|
110
109
|
Ewelink.logger.debug(self.class.name) { "Found #{devices.size} RF 433MHz bridge device(s)" }
|
|
111
110
|
end
|
|
112
111
|
rf_bridge_devices.each do |device|
|
|
113
|
-
api_key = device['apikey'].presence || next
|
|
114
|
-
device_id = device['deviceid'].presence || next
|
|
115
|
-
device_name = device['name'].presence || next
|
|
116
|
-
buttons = device['params']['rfList'].each do |rf|
|
|
112
|
+
api_key = device['itemData']['apikey'].presence || next
|
|
113
|
+
device_id = device['itemData']['deviceid'].presence || next
|
|
114
|
+
device_name = device['itemData']['name'].presence || next
|
|
115
|
+
buttons = device['itemData']['params']['rfList'].each do |rf|
|
|
117
116
|
button = {
|
|
118
|
-
api_key
|
|
117
|
+
api_key:,
|
|
119
118
|
channel: rf['rfChl'],
|
|
120
|
-
device_id
|
|
121
|
-
device_name
|
|
119
|
+
device_id:,
|
|
120
|
+
device_name:,
|
|
122
121
|
}
|
|
123
|
-
remote_info = device['tags']['zyx_info'].find { |info| info['buttonName'].find { |data| data.key?(button[:channel].to_s) } }.presence || next
|
|
122
|
+
remote_info = device['itemData']['tags']['zyx_info'].find { |info| info['buttonName'].find { |data| data.key?(button[:channel].to_s) } }.presence || next
|
|
124
123
|
remote_name = remote_info['name'].try(:squish).presence || next
|
|
125
124
|
button_info = remote_info['buttonName'].find { |info| info.key?(button[:channel].to_s) }.presence || next
|
|
126
125
|
button_name = button_info.values.first.try(:squish).presence || next
|
|
127
126
|
button.merge!({
|
|
128
127
|
name: button_name,
|
|
129
|
-
remote_name
|
|
128
|
+
remote_name:,
|
|
130
129
|
remote_type: remote_info['remote_type'],
|
|
131
130
|
})
|
|
132
|
-
button[:uuid] = Digest::UUID.uuid_v5(
|
|
131
|
+
button[:uuid] = Digest::UUID.uuid_v5(Digest::UUID::DNS_NAMESPACE, "#{button[:device_id]}/#{button[:channel]}")
|
|
133
132
|
buttons << button
|
|
134
133
|
end
|
|
135
134
|
end
|
|
@@ -161,17 +160,18 @@ module Ewelink
|
|
|
161
160
|
def switches
|
|
162
161
|
synchronize(:switches) do
|
|
163
162
|
@switches ||= [].tap do |switches|
|
|
164
|
-
switch_devices = devices.select { |device| SWITCH_DEVICES_UIIDS.include?(device['uiid']) }
|
|
163
|
+
switch_devices = devices.select { |device| SWITCH_DEVICES_UIIDS.include?(device['itemData']['extra']['uiid']) }
|
|
165
164
|
switch_devices.each do |device|
|
|
166
|
-
api_key = device['apikey'].presence || next
|
|
167
|
-
device_id = device['deviceid'].presence || next
|
|
168
|
-
name = device['name'].presence || next
|
|
165
|
+
api_key = device['itemData']['apikey'].presence || next
|
|
166
|
+
device_id = device['itemData']['deviceid'].presence || next
|
|
167
|
+
name = device['itemData']['name'].presence || next
|
|
169
168
|
switch = {
|
|
170
|
-
api_key
|
|
171
|
-
device_id
|
|
172
|
-
|
|
169
|
+
api_key:,
|
|
170
|
+
device_id:,
|
|
171
|
+
model: device['itemData']['productModel'],
|
|
172
|
+
name:,
|
|
173
173
|
}
|
|
174
|
-
switch[:uuid] = Digest::UUID.uuid_v5(
|
|
174
|
+
switch[:uuid] = Digest::UUID.uuid_v5(Digest::UUID::DNS_NAMESPACE, switch[:device_id])
|
|
175
175
|
switches << switch
|
|
176
176
|
end
|
|
177
177
|
end.tap { |switches| Ewelink.logger.debug(self.class.name) { "Found #{switches.size} switch(es)" } }
|
|
@@ -242,12 +242,8 @@ module Ewelink
|
|
|
242
242
|
synchronize(:authentication_infos) do
|
|
243
243
|
@authentication_infos ||= begin
|
|
244
244
|
params = {
|
|
245
|
-
'
|
|
246
|
-
'imei' => SecureRandom.uuid.upcase,
|
|
247
|
-
'nonce' => nonce,
|
|
245
|
+
'countryCode' => DEFAULT_COUNTRY_CODE,
|
|
248
246
|
'password' => password,
|
|
249
|
-
'ts' => Time.now.to_i,
|
|
250
|
-
'version' => VERSION,
|
|
251
247
|
}
|
|
252
248
|
if email.present?
|
|
253
249
|
params['email'] = email
|
|
@@ -255,12 +251,20 @@ module Ewelink
|
|
|
255
251
|
params['phoneNumber'] = phone_number
|
|
256
252
|
end
|
|
257
253
|
body = JSON.generate(params)
|
|
258
|
-
response = rest_request(:post, '/
|
|
259
|
-
|
|
260
|
-
|
|
254
|
+
response = rest_request(:post, '/v2/user/login', {
|
|
255
|
+
body:,
|
|
256
|
+
headers: {
|
|
257
|
+
'Authorization' => "Sign #{Base64.encode64(OpenSSL::HMAC.digest('SHA256', APP_SECRET, body))}",
|
|
258
|
+
'X-CK-Appid': APP_ID,
|
|
259
|
+
'X-CK-Nonce': nonce,
|
|
260
|
+
},
|
|
261
|
+
})
|
|
262
|
+
raise(Error.new('Invalid authentication response')) unless response['data'].is_a?(Hash) && response['data']['user'].is_a?(Hash)
|
|
263
|
+
raise(Error.new('Authentication token not found')) unless response['data']['at'].present?
|
|
264
|
+
raise(Error.new('API key not found')) unless response['data']['user']['apikey'].present?
|
|
261
265
|
{
|
|
262
|
-
|
|
263
|
-
|
|
266
|
+
api_key: response['data']['user']['apikey'].tap { Ewelink.logger.debug(self.class.name) { 'API key found' } },
|
|
267
|
+
authentication_token: response['data']['at'].tap { Ewelink.logger.debug(self.class.name) { 'Authentication token found' } },
|
|
264
268
|
}
|
|
265
269
|
end
|
|
266
270
|
end
|
|
@@ -273,15 +277,22 @@ module Ewelink
|
|
|
273
277
|
def devices
|
|
274
278
|
synchronize(:devices) do
|
|
275
279
|
@devices ||= begin
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
280
|
+
devices = []
|
|
281
|
+
homes_ids.each do |home_id|
|
|
282
|
+
params = {
|
|
283
|
+
'familyid' => home_id,
|
|
284
|
+
'num' => 0,
|
|
285
|
+
}
|
|
286
|
+
headers = authentication_headers.merge(
|
|
287
|
+
'X-CK-Appid' => APP_ID,
|
|
288
|
+
'X-CK-Nonce' => nonce,
|
|
289
|
+
)
|
|
290
|
+
response = rest_request(:get, '/v2/device/thing', headers:, query: params)
|
|
291
|
+
raise('Invalid devices response') unless response['data'].is_a?(Hash) && response['data']['thingList'].is_a?(Array)
|
|
292
|
+
devices += response['data']['thingList']
|
|
293
|
+
end
|
|
294
|
+
Ewelink.logger.debug(self.class.name) { "Found #{devices.size} device(s)" }
|
|
295
|
+
devices
|
|
285
296
|
end
|
|
286
297
|
end
|
|
287
298
|
end
|
|
@@ -294,6 +305,20 @@ module Ewelink
|
|
|
294
305
|
switches.find { |switch| switch[:uuid] == uuid } || raise(Error.new("No such switch with UUID: #{uuid.inspect}"))
|
|
295
306
|
end
|
|
296
307
|
|
|
308
|
+
def homes_ids
|
|
309
|
+
synchronize(:homes_ids) do
|
|
310
|
+
@homes_ids ||= begin
|
|
311
|
+
headers = authentication_headers.merge(
|
|
312
|
+
'X-CK-Appid' => APP_ID,
|
|
313
|
+
'X-CK-Nonce' => nonce,
|
|
314
|
+
)
|
|
315
|
+
response = rest_request(:get, '/v2/family', headers:)
|
|
316
|
+
raise('Invalid homes response') unless response['data'].is_a?(Hash) && response['data']['familyList'].is_a?(Array)
|
|
317
|
+
response['data']['familyList'].map { |home| home['id'] }.compact.uniq
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
297
322
|
def nonce
|
|
298
323
|
SecureRandom.hex[0, 8]
|
|
299
324
|
end
|
|
@@ -311,17 +336,17 @@ module Ewelink
|
|
|
311
336
|
|
|
312
337
|
def rest_request(method, path, options = {})
|
|
313
338
|
url = "#{URL.gsub('#{region}', region)}#{path}"
|
|
339
|
+
url.gsub!(/#{Regexp.escape("#{region}-api")}/, "#{region}-disp") if options[:dispatch].present?
|
|
314
340
|
method = method.to_s.upcase
|
|
315
341
|
headers = (options[:headers] || {}).reverse_merge('Content-Type' => 'application/json')
|
|
316
342
|
Ewelink.logger.debug(self.class.name) { "#{method} #{url}" }
|
|
317
|
-
response = HTTParty.send(method.downcase, url, options.merge(headers:
|
|
343
|
+
response = HTTParty.send(method.downcase, url, options.merge(headers:).reverse_merge(timeout: REQUEST_TIMEOUT))
|
|
318
344
|
raise(Error.new("#{method} #{url}: #{response.code}")) unless response.success?
|
|
319
|
-
if response['error'] ==
|
|
320
|
-
@region = response['region']
|
|
345
|
+
if response['error'] == 10_004 && response['data'].present? && response['data']['region'].present?
|
|
346
|
+
@region = response['data']['region']
|
|
321
347
|
Ewelink.logger.debug(self.class.name) { "Switched to region #{region.inspect}" }
|
|
322
348
|
return rest_request(method, path, options)
|
|
323
349
|
end
|
|
324
|
-
remove_instance_variable(:@authentication_infos) if instance_variable_defined?(:@authentication_infos) && [401, 403].include?(response['error'])
|
|
325
350
|
raise(Error.new("#{method} #{url}: #{response['error']} #{response['msg']}".strip)) if response['error'].present? && response['error'] != 0
|
|
326
351
|
response.to_h
|
|
327
352
|
rescue Errno::ECONNREFUSED, OpenSSL::OpenSSLError, SocketError, Timeout::Error => e
|
|
@@ -391,12 +416,12 @@ module Ewelink
|
|
|
391
416
|
EventMachine.run do
|
|
392
417
|
@web_socket = Faye::WebSocket::Client.new(web_socket_url)
|
|
393
418
|
|
|
394
|
-
@web_socket.on(:close) do
|
|
419
|
+
@web_socket.on(:close) do
|
|
395
420
|
Ewelink.logger.debug(self.class.name) { 'WebSocket closed' }
|
|
396
421
|
reload
|
|
397
422
|
end
|
|
398
423
|
|
|
399
|
-
@web_socket.on(:open) do
|
|
424
|
+
@web_socket.on(:open) do
|
|
400
425
|
Ewelink.logger.debug(self.class.name) { 'WebSocket opened' }
|
|
401
426
|
@last_web_socket_pong_at = Time.now
|
|
402
427
|
authenticate_web_socket_api_key
|
|
@@ -413,7 +438,7 @@ module Ewelink
|
|
|
413
438
|
|
|
414
439
|
begin
|
|
415
440
|
json = JSON.parse(message)
|
|
416
|
-
rescue
|
|
441
|
+
rescue
|
|
417
442
|
Ewelink.logger.error(self.class.name) { 'WebSocket JSON parse error' }
|
|
418
443
|
reload
|
|
419
444
|
next
|
|
@@ -436,7 +461,7 @@ module Ewelink
|
|
|
436
461
|
end
|
|
437
462
|
|
|
438
463
|
if json['deviceid'].present? && json['params'].is_a?(Hash) && json['params']['switch'].present?
|
|
439
|
-
switch = switches.find { |
|
|
464
|
+
switch = switches.find { |item| item[:device_id] == json['deviceid'] }
|
|
440
465
|
if switch.present?
|
|
441
466
|
@web_socket_switches_statuses[switch[:uuid]] = json['params']['switch']
|
|
442
467
|
Ewelink.logger.debug(self.class.name) { "Switch #{switch[:uuid].inspect} is #{@web_socket_switches_statuses[switch[:uuid]]}" }
|
|
@@ -468,13 +493,12 @@ module Ewelink
|
|
|
468
493
|
synchronize(:web_socket_url) do
|
|
469
494
|
@web_socket_url ||= begin
|
|
470
495
|
params = {
|
|
471
|
-
'accept' => 'ws',
|
|
472
496
|
'appid' => APP_ID,
|
|
473
497
|
'nonce' => nonce,
|
|
474
498
|
'ts' => Time.now.to_i,
|
|
475
499
|
'version' => VERSION,
|
|
476
500
|
}
|
|
477
|
-
response = rest_request(:post, '/dispatch/app', body: JSON.generate(params), headers: authentication_headers)
|
|
501
|
+
response = rest_request(:post, '/dispatch/app', body: JSON.generate(params), dispatch: true, headers: authentication_headers)
|
|
478
502
|
raise('Error while getting WebSocket URL') unless response['error'] == 0
|
|
479
503
|
domain = response['domain'].presence || raise("Can't get WebSocket server domain")
|
|
480
504
|
port = response['port'].presence || raise("Can't get WebSocket server port")
|
|
@@ -483,13 +507,11 @@ module Ewelink
|
|
|
483
507
|
end
|
|
484
508
|
end
|
|
485
509
|
|
|
486
|
-
def web_socket_wait_for(condition, initialize_web_socket: false
|
|
510
|
+
def web_socket_wait_for(condition, initialize_web_socket: false)
|
|
487
511
|
web_socket if initialize_web_socket
|
|
488
512
|
begin
|
|
489
513
|
Timeout.timeout(REQUEST_TIMEOUT) do
|
|
490
|
-
|
|
491
|
-
sleep(WEB_SOCKET_WAIT_INTERVAL)
|
|
492
|
-
end
|
|
514
|
+
sleep(WEB_SOCKET_WAIT_INTERVAL) until condition.call
|
|
493
515
|
block_given? ? yield : true
|
|
494
516
|
end
|
|
495
517
|
rescue => e
|
data/lib/ewelink/runner.rb
CHANGED
|
@@ -9,7 +9,7 @@ module Ewelink
|
|
|
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
|
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: 5.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-07-09 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,20 @@ 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
73
|
- !ruby/object:Gem::Dependency
|
|
74
74
|
name: thread
|
|
75
75
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -130,6 +130,46 @@ dependencies:
|
|
|
130
130
|
- - "<"
|
|
131
131
|
- !ruby/object:Gem::Version
|
|
132
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
|
|
143
|
+
type: :development
|
|
144
|
+
prerelease: false
|
|
145
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
146
|
+
requirements:
|
|
147
|
+
- - ">="
|
|
148
|
+
- !ruby/object:Gem::Version
|
|
149
|
+
version: 1.25.0
|
|
150
|
+
- - "<"
|
|
151
|
+
- !ruby/object:Gem::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
|
|
133
173
|
description: Manage eWeLink smart home devices
|
|
134
174
|
email: al@alweb.org
|
|
135
175
|
executables:
|
|
@@ -157,14 +197,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
157
197
|
requirements:
|
|
158
198
|
- - ">="
|
|
159
199
|
- !ruby/object:Gem::Version
|
|
160
|
-
version:
|
|
200
|
+
version: 3.1.0
|
|
161
201
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
162
202
|
requirements:
|
|
163
203
|
- - ">="
|
|
164
204
|
- !ruby/object:Gem::Version
|
|
165
205
|
version: '0'
|
|
166
206
|
requirements: []
|
|
167
|
-
rubygems_version: 3.
|
|
207
|
+
rubygems_version: 3.3.3
|
|
168
208
|
signing_key:
|
|
169
209
|
specification_version: 4
|
|
170
210
|
summary: Manage eWeLink devices
|