ewelink 3.3.1 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d4567a179d6caccebab59ae35e794c4826419b6147461a9f6d9aaf268dea875
4
- data.tar.gz: d79d86055e3a9c2d5dbc9d2a89be4f4fc60b2a53cd863084a17b13740d7db02e
3
+ metadata.gz: 8cba69a24adaf18a0be08cbf1618b612d6d0e90fd788d8b9f2360f7d19f67406
4
+ data.tar.gz: adc650eac1533d343320490132302827a79f0fc4a0571d0dcba91ef926e5f682
5
5
  SHA512:
6
- metadata.gz: b79ebc640d8452951fc967ba52a99f6c5d09ccd486b3a6fdf17e10e23abdec94b2933d54566324f214972b6d7c22484c70ab76f0dbc8266a2c806c207f65373b
7
- data.tar.gz: 42a11ae61affa75e02924cfa8408851568e0a67c33ba9a21d7a7fe3a42d2b025e0909720b371d6cf9b21bc53ad75862ff91216df8a760dd391b1a1b1e5653da1
6
+ metadata.gz: 39ab9a66085401bb70f34f74b9220e70ad691c5db65b180816d5a284462162064364d6e6ed3f2b5d990f9c3fa3450472fb0b13ba0b3ecbca1a22042de3926d28
7
+ data.tar.gz: 19b1627d07a411ef4fe04578f924a7d339413d65d7132b8cd7614877b1e72300b5cbd51f1f9a6469807fe3179e37a65c048f1e699601c4eb3b4f05b82b0e663f
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.3.1
1
+ 4.1.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,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,11 +17,11 @@ module Ewelink
18
17
 
19
18
  attr_reader :email, :password, :phone_number
20
19
 
21
- def initialize(async_actions: false, email: nil, password:, phone_number: nil, update_devices_status_on_connect: false)
20
+ def initialize(password:, async_actions: false, email: nil, phone_number: nil, update_devices_status_on_connect: false)
22
21
  @async_actions = async_actions.present?
23
22
  @email = email.presence.try(:strip)
24
23
  @mutexs = {}
25
- @password = password.presence || raise(Error.new(":password must be specified"))
24
+ @password = password.presence || raise(Error.new(':password must be specified'))
26
25
  @phone_number = phone_number.presence.try(:strip)
27
26
  @update_devices_status_on_connect = update_devices_status_on_connect.present?
28
27
  @web_socket_authenticated = false
@@ -85,19 +84,19 @@ module Ewelink
85
84
  end
86
85
  end
87
86
 
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|
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|
101
100
  remove_instance_variable(variable) if instance_variable_defined?(variable)
102
101
  end
103
102
  self
@@ -115,10 +114,10 @@ module Ewelink
115
114
  device_name = device['name'].presence || next
116
115
  buttons = device['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
122
  remote_info = device['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
@@ -126,10 +125,10 @@ module Ewelink
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
@@ -167,11 +166,12 @@ module Ewelink
167
166
  device_id = device['deviceid'].presence || next
168
167
  name = device['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['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)" } }
@@ -255,7 +255,7 @@ module Ewelink
255
255
  params['phoneNumber'] = phone_number
256
256
  end
257
257
  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))}" } })
258
+ response = rest_request(:post, '/api/user/login', { body:, headers: { 'Authorization' => "Sign #{Base64.encode64(OpenSSL::HMAC.digest('SHA256', APP_SECRET, body))}" } })
259
259
  raise(Error.new('Authentication token not found')) if response['at'].blank?
260
260
  raise(Error.new('API key not found')) if response['user'].blank? || response['user']['apikey'].blank?
261
261
  {
@@ -302,7 +302,7 @@ module Ewelink
302
302
  return yield unless async_actions?
303
303
  @async_actions_thread_pool ||= Thread.pool(1)
304
304
  @async_actions_thread_pool.process(&block)
305
- nil
305
+ true
306
306
  end
307
307
 
308
308
  def region
@@ -314,7 +314,7 @@ module Ewelink
314
314
  method = method.to_s.upcase
315
315
  headers = (options[:headers] || {}).reverse_merge('Content-Type' => 'application/json')
316
316
  Ewelink.logger.debug(self.class.name) { "#{method} #{url}" }
317
- response = HTTParty.send(method.downcase, url, options.merge(headers: headers).reverse_merge(timeout: REQUEST_TIMEOUT))
317
+ response = HTTParty.send(method.downcase, url, options.merge(headers:).reverse_merge(timeout: REQUEST_TIMEOUT))
318
318
  raise(Error.new("#{method} #{url}: #{response.code}")) unless response.success?
319
319
  if response['error'] == 301 && response['region'].present?
320
320
  @region = response['region']
@@ -391,12 +391,12 @@ module Ewelink
391
391
  EventMachine.run do
392
392
  @web_socket = Faye::WebSocket::Client.new(web_socket_url)
393
393
 
394
- @web_socket.on(:close) do |event|
394
+ @web_socket.on(:close) do
395
395
  Ewelink.logger.debug(self.class.name) { 'WebSocket closed' }
396
396
  reload
397
397
  end
398
398
 
399
- @web_socket.on(:open) do |event|
399
+ @web_socket.on(:open) do
400
400
  Ewelink.logger.debug(self.class.name) { 'WebSocket opened' }
401
401
  @last_web_socket_pong_at = Time.now
402
402
  authenticate_web_socket_api_key
@@ -413,7 +413,7 @@ module Ewelink
413
413
 
414
414
  begin
415
415
  json = JSON.parse(message)
416
- rescue => e
416
+ rescue
417
417
  Ewelink.logger.error(self.class.name) { 'WebSocket JSON parse error' }
418
418
  reload
419
419
  next
@@ -436,7 +436,7 @@ module Ewelink
436
436
  end
437
437
 
438
438
  if json['deviceid'].present? && json['params'].is_a?(Hash) && json['params']['switch'].present?
439
- switch = switches.find { |switch| switch[:device_id] == json['deviceid'] }
439
+ switch = switches.find { |item| item[:device_id] == json['deviceid'] }
440
440
  if switch.present?
441
441
  @web_socket_switches_statuses[switch[:uuid]] = json['params']['switch']
442
442
  Ewelink.logger.debug(self.class.name) { "Switch #{switch[:uuid].inspect} is #{@web_socket_switches_statuses[switch[:uuid]]}" }
@@ -483,13 +483,11 @@ module Ewelink
483
483
  end
484
484
  end
485
485
 
486
- def web_socket_wait_for(condition, initialize_web_socket: false, &block)
486
+ def web_socket_wait_for(condition, initialize_web_socket: false)
487
487
  web_socket if initialize_web_socket
488
488
  begin
489
489
  Timeout.timeout(REQUEST_TIMEOUT) do
490
- while !condition.call
491
- sleep(WEB_SOCKET_WAIT_INTERVAL)
492
- end
490
+ sleep(WEB_SOCKET_WAIT_INTERVAL) until condition.call
493
491
  block_given? ? yield : true
494
492
  end
495
493
  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.1
4
+ version: 4.1.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-06-15 00:00:00.000000000 Z
11
+ date: 2022-03-20 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