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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0fba630fc8ea0be922637f79d4618baccf676775fc37e35ffbd9847e479930f4
4
- data.tar.gz: 8e03090c2c1f9e469b25a9b3ff4dc21da74fd150c6432196038c464cca1608bb
3
+ metadata.gz: f2f26d6875823958f38a894377c7dfbce3531d7f98b1c1c69b18bd88caf44c1d
4
+ data.tar.gz: d25335eb91529c57d2780c42e8cef5856cb7bfa7f222e5282816bff122854b08
5
5
  SHA512:
6
- metadata.gz: 854c5679733f93e5a54c3085858315874db86319b0d81898a64f807d6780f146cfe1f0767ce5b6e4c9ed576adcab59b3154a35399a2cae77a2d4bcac338e8d58
7
- data.tar.gz: 328c7a4e3c10ca31d1b4d636c97c12e6a8af6358401aac77fea2739a0300cac162fa85ee1028dcf5097e42989a5d3035d39f8abf832030b3eabf0037dd43f244
6
+ metadata.gz: 42786625ddc6d8482a5d85922e25b4b650e080866148b378aeb579ad25e0dcee00d4f12b8ebf74492e207d80e6ed0d65b6f0c71ccdaf5c3f81280b1efbd4bc7b
7
+ data.tar.gz: 8eb9cc344312a30a7b0924ff02b052516bf5123a7d706acb15e000b91db2c91ecf56a2173d22543403f7fbbc31773e30d97d3c5379ad37ab42e34b55f8f67366
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.3.2
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(STDOUT, formatter: -> (severity, time, progname, message) {
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 = `git ls-files | grep -vE '^(spec/|test/|\\.|Gemfile|Rakefile)'`.split("\n")
13
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
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 = '>= 2.0.0'
16
+ s.required_ruby_version = '>= 3.1.0'
17
17
 
18
- s.add_dependency 'activesupport', '>= 6.0.0', '< 7.0.0'
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.18.0', '< 0.19.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 = 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq'
6
- APP_SECRET = '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM'
7
- DEFAULT_REGION = 'us'
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}-api.coolkit.cc:8080'
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, password:, phone_number: nil, update_devices_status_on_connect: false)
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(":password must be specified"))
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
- web_socket_wait_for(-> { web_socket_authenticated? }, initialize_web_socket: true) do
45
- params = {
46
- 'action' => 'update',
47
- 'apikey' => button[:api_key],
48
- 'deviceid' => button[:device_id],
49
- 'params' => {
50
- 'cmd' => 'transmit',
51
- 'rfChl' => button[:channel],
52
- },
53
- 'sequence' => web_socket_sequence,
54
- 'ts' => 0,
55
- 'userAgent' => 'app',
56
- }
57
- Ewelink.logger.debug(self.class.name) { "Pressing RF bridge button #{button[:uuid].inspect}" }
58
- send_to_web_socket(JSON.generate(params))
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
- :@authentication_infos,
90
- :@devices,
91
- :@last_web_socket_pong_at,
92
- :@region,
93
- :@rf_bridge_buttons,
94
- :@switches,
95
- :@web_socket_ping_interval,
96
- :@web_socket_ping_thread,
97
- :@web_socket_thread,
98
- :@web_socket_url,
99
- :@web_socket,
100
- ].each do |variable|
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: api_key,
117
+ api_key:,
119
118
  channel: rf['rfChl'],
120
- device_id: device_id,
121
- device_name: 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: remote_name,
128
+ remote_name:,
130
129
  remote_type: remote_info['remote_type'],
131
130
  })
132
- button[:uuid] = Digest::UUID.uuid_v5(UUID_NAMESPACE, "#{button[:device_id]}/#{button[:channel]}")
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: api_key,
171
- device_id: device_id,
172
- name: name,
169
+ api_key:,
170
+ device_id:,
171
+ model: device['itemData']['productModel'],
172
+ name:,
173
173
  }
174
- switch[:uuid] = Digest::UUID.uuid_v5(UUID_NAMESPACE, switch[:device_id])
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
- 'appid' => APP_ID,
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, '/api/user/login', { body: body, headers: { 'Authorization' => "Sign #{Base64.encode64(OpenSSL::HMAC.digest('SHA256', APP_SECRET, body))}" } })
259
- raise(Error.new('Authentication token not found')) if response['at'].blank?
260
- raise(Error.new('API key not found')) if response['user'].blank? || response['user']['apikey'].blank?
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
- authentication_token: response['at'].tap { Ewelink.logger.debug(self.class.name) { 'Authentication token found' } },
263
- api_key: response['user']['apikey'].tap { Ewelink.logger.debug(self.class.name) { 'API key found' } },
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
- params = {
277
- 'appid' => APP_ID,
278
- 'getTags' => 1,
279
- 'nonce' => nonce,
280
- 'ts' => Time.now.to_i,
281
- 'version' => VERSION,
282
- }
283
- response = rest_request(:get, '/api/user/device', headers: authentication_headers, query: params)
284
- response['devicelist'].tap { |devices| Ewelink.logger.debug(self.class.name) { "Found #{devices.size} device(s)" } }
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: headers).reverse_merge(timeout: REQUEST_TIMEOUT))
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'] == 301 && response['region'].present?
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 |event|
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 |event|
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 => e
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 { |switch| switch[:device_id] == json['deviceid'] }
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, &block)
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
- while !condition.call
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
@@ -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].map { |uuid| [uuid, api.switch_on?(uuid) ? 'on' : 'off'] }.to_h)) if options[:switch_status_uuids].present?
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
- STDERR.puts("Invalid option specified: #{arguments.first}")
60
- STDERR.puts(parser.summarize)
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
- STDERR.puts('Email or phone number must be specified')
65
- STDERR.puts(parser.summarize)
64
+ warn('Email or phone number must be specified')
65
+ warn(parser.summarize)
66
66
  exit(1)
67
67
  end
68
- if [: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
- STDERR.puts('An action must be specified (listing switches, press RF bridge button, etc.)')
70
- STDERR.puts(parser.summarize)
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: 3.3.2
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: 2021-09-26 00:00:00.000000000 Z
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: 6.0.0
19
+ version: 7.0.0
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 7.0.0
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: 6.0.0
29
+ version: 7.0.0
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 7.0.0
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.18.0
59
+ version: 0.20.0
60
60
  - - "<"
61
61
  - !ruby/object:Gem::Version
62
- version: 0.19.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.18.0
69
+ version: 0.20.0
70
70
  - - "<"
71
71
  - !ruby/object:Gem::Version
72
- version: 0.19.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: 2.0.0
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.2.15
207
+ rubygems_version: 3.3.3
168
208
  signing_key:
169
209
  specification_version: 4
170
210
  summary: Manage eWeLink devices