ewelink 3.3.2 → 4.0.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: 0fba630fc8ea0be922637f79d4618baccf676775fc37e35ffbd9847e479930f4
4
- data.tar.gz: 8e03090c2c1f9e469b25a9b3ff4dc21da74fd150c6432196038c464cca1608bb
3
+ metadata.gz: b8e686b44abcc1c59621d612a64b930f89a0041ac4607070bd47c801f04148ac
4
+ data.tar.gz: 3990a53b5d57e0c0523ba83050e7af904dd54a96337692a5fc800e6e3d0edaa9
5
5
  SHA512:
6
- metadata.gz: 854c5679733f93e5a54c3085858315874db86319b0d81898a64f807d6780f146cfe1f0767ce5b6e4c9ed576adcab59b3154a35399a2cae77a2d4bcac338e8d58
7
- data.tar.gz: 328c7a4e3c10ca31d1b4d636c97c12e6a8af6358401aac77fea2739a0300cac162fa85ee1028dcf5097e42989a5d3035d39f8abf832030b3eabf0037dd43f244
6
+ metadata.gz: 41aaa80ba63866bf04728c60489ed91b3b8294a61dc7e7d78779628b7530006bd41d306adb4e6a72ccdb1e72ed8322dd94efe897053ed02ce1da977e7560319a
7
+ data.tar.gz: c6af766c67c28efffd27a4186c3b603e9c4d3ab48e5fb8bc8ca1b52b5ce7aec8969297b932134c3c640ca5ece581ab70c6932ffb8a5597ebb54cc831b9bbfb98
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.3.2
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(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,11 @@ 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
+ name:,
173
172
  }
174
- switch[:uuid] = Digest::UUID.uuid_v5(UUID_NAMESPACE, switch[:device_id])
173
+ switch[:uuid] = Digest::UUID.uuid_v5(Digest::UUID::DNS_NAMESPACE, switch[:device_id])
175
174
  switches << switch
176
175
  end
177
176
  end.tap { |switches| Ewelink.logger.debug(self.class.name) { "Found #{switches.size} switch(es)" } }
@@ -255,7 +254,7 @@ module Ewelink
255
254
  params['phoneNumber'] = phone_number
256
255
  end
257
256
  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))}" } })
257
+ response = rest_request(:post, '/api/user/login', { body:, headers: { 'Authorization' => "Sign #{Base64.encode64(OpenSSL::HMAC.digest('SHA256', APP_SECRET, body))}" } })
259
258
  raise(Error.new('Authentication token not found')) if response['at'].blank?
260
259
  raise(Error.new('API key not found')) if response['user'].blank? || response['user']['apikey'].blank?
261
260
  {
@@ -314,7 +313,7 @@ module Ewelink
314
313
  method = method.to_s.upcase
315
314
  headers = (options[:headers] || {}).reverse_merge('Content-Type' => 'application/json')
316
315
  Ewelink.logger.debug(self.class.name) { "#{method} #{url}" }
317
- response = HTTParty.send(method.downcase, url, options.merge(headers: headers).reverse_merge(timeout: REQUEST_TIMEOUT))
316
+ response = HTTParty.send(method.downcase, url, options.merge(headers:).reverse_merge(timeout: REQUEST_TIMEOUT))
318
317
  raise(Error.new("#{method} #{url}: #{response.code}")) unless response.success?
319
318
  if response['error'] == 301 && response['region'].present?
320
319
  @region = response['region']
@@ -391,12 +390,12 @@ module Ewelink
391
390
  EventMachine.run do
392
391
  @web_socket = Faye::WebSocket::Client.new(web_socket_url)
393
392
 
394
- @web_socket.on(:close) do |event|
393
+ @web_socket.on(:close) do
395
394
  Ewelink.logger.debug(self.class.name) { 'WebSocket closed' }
396
395
  reload
397
396
  end
398
397
 
399
- @web_socket.on(:open) do |event|
398
+ @web_socket.on(:open) do
400
399
  Ewelink.logger.debug(self.class.name) { 'WebSocket opened' }
401
400
  @last_web_socket_pong_at = Time.now
402
401
  authenticate_web_socket_api_key
@@ -413,7 +412,7 @@ module Ewelink
413
412
 
414
413
  begin
415
414
  json = JSON.parse(message)
416
- rescue => e
415
+ rescue
417
416
  Ewelink.logger.error(self.class.name) { 'WebSocket JSON parse error' }
418
417
  reload
419
418
  next
@@ -436,7 +435,7 @@ module Ewelink
436
435
  end
437
436
 
438
437
  if json['deviceid'].present? && json['params'].is_a?(Hash) && json['params']['switch'].present?
439
- switch = switches.find { |switch| switch[:device_id] == json['deviceid'] }
438
+ switch = switches.find { |item| item[:device_id] == json['deviceid'] }
440
439
  if switch.present?
441
440
  @web_socket_switches_statuses[switch[:uuid]] = json['params']['switch']
442
441
  Ewelink.logger.debug(self.class.name) { "Switch #{switch[:uuid].inspect} is #{@web_socket_switches_statuses[switch[:uuid]]}" }
@@ -483,13 +482,11 @@ module Ewelink
483
482
  end
484
483
  end
485
484
 
486
- def web_socket_wait_for(condition, initialize_web_socket: false, &block)
485
+ def web_socket_wait_for(condition, initialize_web_socket: false)
487
486
  web_socket if initialize_web_socket
488
487
  begin
489
488
  Timeout.timeout(REQUEST_TIMEOUT) do
490
- while !condition.call
491
- sleep(WEB_SOCKET_WAIT_INTERVAL)
492
- end
489
+ sleep(WEB_SOCKET_WAIT_INTERVAL) until condition.call
493
490
  block_given? ? yield : true
494
491
  end
495
492
  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: 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: 2021-09-26 00:00:00.000000000 Z
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: 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