ewelink 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/ewelink/api.rb +77 -9
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c58323e838b9fbbdca7c7ee0fdf22d1e7950c627fb4fcf8851b3263e69ce883
|
4
|
+
data.tar.gz: 475d05f731b079f7734fde4dd93ec8f151077d6e5b716a86e611f11bdbb8d49b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50ba5474e9012f219e380c47515d599da29a72b50cc26c36a19e253623c997e429a32c1b279619eef0e2d8b7f454fccde519500f998575c38d028ac86e6c1ba4
|
7
|
+
data.tar.gz: 122f2997897893b395cd04204e3e169d90bac15fc1a9eaabbf31def8da1c7f754bd502341411727364a79011379791a89031e9d42090d22bf96be233a24a5958
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.1.0
|
data/lib/ewelink/api.rb
CHANGED
@@ -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
|
-
[
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|