ewelink 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/ewelink/api.rb +77 -9
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97046b44715a988f6ae92d986c0fad17ab4d5cae6420a125c10f23854cfaadc9
4
- data.tar.gz: b95e52d88f8d57d5bf9f54b67d5a8c0779d26b66faadbc252e13eadb80854292
3
+ metadata.gz: 2c58323e838b9fbbdca7c7ee0fdf22d1e7950c627fb4fcf8851b3263e69ce883
4
+ data.tar.gz: 475d05f731b079f7734fde4dd93ec8f151077d6e5b716a86e611f11bdbb8d49b
5
5
  SHA512:
6
- metadata.gz: f153a280ff50b245434b2039cd3bb88341da6bd7688556a8a7c3fe4558a2b13a6be5c1497f5b06dc381495cb63d8c26d4d3f2625ea5bd4148e4c55a2f28b2faf
7
- data.tar.gz: e3b69fa1607599325ea0f2867fbd0d32fd3abd56a4e7bd8d07107e083d4ebbfaf919bc4af34b28948163d1fb5340a53489aec1839cc59ba238f2917a8db03cc5
6
+ metadata.gz: 50ba5474e9012f219e380c47515d599da29a72b50cc26c36a19e253623c997e429a32c1b279619eef0e2d8b7f454fccde519500f998575c38d028ac86e6c1ba4
7
+ data.tar.gz: 122f2997897893b395cd04204e3e169d90bac15fc1a9eaabbf31def8da1c7f754bd502341411727364a79011379791a89031e9d42090d22bf96be233a24a5958
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.0
1
+ 2.1.0
@@ -11,6 +11,7 @@ module Ewelink
11
11
  URL = 'https://#{region}-api.coolkit.cc:8080'
12
12
  UUID_NAMESPACE = 'e25750fb-3710-41af-b831-23224f4dd609';
13
13
  VERSION = 8
14
+ WEB_SOCKET_PING_TOLERANCE_FACTOR = 1.5
14
15
  WEB_SOCKET_WAIT_INTERVAL = 0.2.seconds
15
16
 
16
17
  attr_reader :email, :password, :phone_number
@@ -41,6 +42,7 @@ module Ewelink
41
42
  'ts' => 0,
42
43
  'userAgent' => 'app',
43
44
  }
45
+ Ewelink.logger.debug(self.class.name) { "Pressing RF bridge button #{button[:uuid].inspect}" }
44
46
  send_to_web_socket(JSON.generate(params))
45
47
  true
46
48
  end
@@ -48,10 +50,17 @@ module Ewelink
48
50
  end
49
51
 
50
52
  def reload
51
- Ewelink.logger.debug(self.class.name) { 'Reloading API (authentication token, devices, region,...)' }
53
+ Ewelink.logger.debug(self.class.name) { 'Reloading API (authentication token, devices, region, connections,...)' }
52
54
  dispose_web_socket
53
55
  @switches_statuses.clear
54
- [:@api_keys, :@authentication_token, :@devices, :@rf_bridge_buttons, :@region, :@switches, :@web_socket, :@web_socket_url].each do |variable|
56
+ [
57
+ :@api_keys,
58
+ :@authentication_token,
59
+ :@devices,
60
+ :@region,
61
+ :@rf_bridge_buttons,
62
+ :@switches,
63
+ ].each do |variable|
55
64
  remove_instance_variable(variable) if instance_variable_defined?(variable)
56
65
  end
57
66
  self
@@ -103,10 +112,12 @@ module Ewelink
103
112
  'userAgent' => 'app',
104
113
  }
105
114
  web_socket_wait_for(-> { web_socket_authenticated? }) do
115
+ Ewelink.logger.debug(self.class.name) { "Checking switch #{switch[:uuid].inspect} status" }
106
116
  send_to_web_socket(JSON.generate(params))
107
117
  end
108
118
  end
109
119
  web_socket_wait_for(-> { !@switches_statuses[switch[:uuid]].nil? }) do
120
+ Ewelink.logger.debug(self.class.name) { "Switch #{switch[:uuid].inspect} is #{@switches_statuses[switch[:uuid]]}" }
110
121
  @switches_statuses[switch[:uuid]] == 'on'
111
122
  end
112
123
  end
@@ -151,9 +162,11 @@ module Ewelink
151
162
  'ts' => 0,
152
163
  'userAgent' => 'app',
153
164
  }
165
+ Ewelink.logger.debug(self.class.name) { "Turning switch #{switch[:uuid].inspect} #{on ? 'on' : 'off'}" }
154
166
  send_to_web_socket(JSON.generate(params))
155
- true
156
167
  end
168
+ switch_on?(switch[:uuid]) # Waiting for switch status update
169
+ true
157
170
  end
158
171
 
159
172
  private
@@ -210,13 +223,31 @@ module Ewelink
210
223
 
211
224
  def dispose_web_socket
212
225
  @web_socket_authenticated_api_keys = Set.new
213
- if instance_variable_defined?(:@web_socket)
226
+
227
+ if @web_socket_ping_thread
228
+ if Thread.current == @web_socket_ping_thread
229
+ Thread.current[:stop] = true
230
+ else
231
+ @web_socket_ping_thread.kill
232
+ end
233
+ end
234
+
235
+ if @web_socket.present?
214
236
  begin
215
237
  @web_socket.close if @web_socket.open?
216
238
  rescue
217
239
  # Ignoring close errors
218
240
  end
219
- remove_instance_variable(:@web_socket) if instance_variable_defined?(:@web_socket)
241
+ end
242
+
243
+ [
244
+ :@last_web_socket_pong_at,
245
+ :@web_socket_ping_interval,
246
+ :@web_socket_ping_thread,
247
+ :@web_socket_url,
248
+ :@web_socket,
249
+ ].each do |variable|
250
+ remove_instance_variable(variable) if instance_variable_defined?(variable)
220
251
  end
221
252
  end
222
253
 
@@ -256,6 +287,10 @@ module Ewelink
256
287
  end
257
288
 
258
289
  def send_to_web_socket(data)
290
+ if web_socket_outdated_ping?
291
+ Ewelink.logger.warn(self.class.name) { 'WebSocket ping is outdated' }
292
+ dispose_web_socket
293
+ end
259
294
  web_socket.send(data)
260
295
  rescue
261
296
  dispose_web_socket
@@ -290,16 +325,42 @@ module Ewelink
290
325
 
291
326
  web_socket.on(:message) do |message|
292
327
  api.instance_eval do
293
- response = JSON.parse(message.data)
328
+ if message.data == 'pong'
329
+ Ewelink.logger.debug(self.class.name) { "Received WebSocket #{message.data.inspect} message" }
330
+ @last_web_socket_pong_at = Time.now
331
+ next
332
+ end
333
+
334
+ begin
335
+ response = JSON.parse(message.data)
336
+ rescue => e
337
+ Ewelink.logger.error(self.class.name) { "WebSocket JSON parse error" }
338
+ next
339
+ end
294
340
 
295
341
  if response.key?('error') && response['error'] != 0
296
342
  Ewelink.logger.error(self.class.name) { "WebSocket message error: #{message.data}" }
297
343
  next
298
344
  end
299
345
 
346
+ if !@web_socket_ping_thread && response.key?('config') && response['config'].key?('hbInterval')
347
+ @last_web_socket_pong_at = Time.now
348
+ # @web_socket_ping_interval = response['config']['hbInterval']
349
+ @web_socket_ping_interval = 30.seconds
350
+ Ewelink.logger.debug(self.class.name) { "Creating thread for WebSocket ping every #{@web_socket_ping_interval} seconds" }
351
+ @web_socket_ping_thread = Thread.new do
352
+ loop do
353
+ break if Thread.current[:stop]
354
+ sleep(@web_socket_ping_interval)
355
+ Ewelink.logger.debug(self.class.name) { 'Sending WebSocket ping' }
356
+ send_to_web_socket('ping')
357
+ end
358
+ end
359
+ end
360
+
300
361
  if response['apikey'].present? && !@web_socket_authenticated_api_keys.include?(response['apikey'])
301
362
  @web_socket_authenticated_api_keys << response['apikey']
302
- Ewelink.logger.debug(self.class.name) { "WebSocket successfully authenticated API key: #{response['apikey'].inspect}" }
363
+ Ewelink.logger.debug(self.class.name) { "WebSocket successfully authenticated API key: #{response['apikey'].truncate(16).inspect}" }
303
364
  end
304
365
 
305
366
  if response['deviceid'].present? && response['params'].is_a?(Hash) && response['params']['switch'].present?
@@ -324,7 +385,7 @@ module Ewelink
324
385
  'userAgent' => 'app',
325
386
  'version' => VERSION,
326
387
  }
327
- Ewelink.logger.debug(self.class.name) { "Authenticating WebSocket API key: #{api_key.inspect}" }
388
+ Ewelink.logger.debug(self.class.name) { "Authenticating WebSocket API key: #{api_key.truncate(16).inspect}" }
328
389
  send_to_web_socket(JSON.generate(params))
329
390
  end
330
391
  end
@@ -338,6 +399,10 @@ module Ewelink
338
399
  api_keys == @web_socket_authenticated_api_keys
339
400
  end
340
401
 
402
+ def web_socket_outdated_ping?
403
+ @last_web_socket_pong_at.present? && @web_socket_ping_interval.present? && @last_web_socket_pong_at < (@web_socket_ping_interval * WEB_SOCKET_PING_TOLERANCE_FACTOR).seconds.ago
404
+ end
405
+
341
406
  def web_socket_sequence
342
407
  (Time.now.to_f * 1000).round.to_s
343
408
  end
@@ -365,7 +430,10 @@ module Ewelink
365
430
  web_socket # Initializes WebSocket
366
431
  Timeout.timeout(TIMEOUT) do
367
432
  loop do
368
- return yield if condition.call
433
+ if condition.call
434
+ return yield if block_given?
435
+ return true
436
+ end
369
437
  sleep(WEB_SOCKET_WAIT_INTERVAL)
370
438
  end
371
439
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ewelink
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexis Toulotte