22# Copyright (c) 2015-2019 Volodymyr Shymanskyy.
33# See the file LICENSE for copying permission.
44
5- __version__ = '0.2.5 '
5+ __version__ = '0.2.6 '
66
7- try :
8- import usocket as socket
9- import utime as time
10- import ustruct as struct
11- import uselect as select
12- from micropython import const
13-
14- ticks_ms = time .ticks_ms
15- sleep_ms = time .sleep_ms
16-
17- IOError = OSError
18- except ImportError :
19- import socket
20- import time
21- import struct
22- import select
23-
24- const = lambda x : x
25- ticks_ms = lambda : int (time .time () * 1000 )
26- sleep_ms = lambda x : time .sleep (x // 1000 )
7+ import socket
8+ import ssl
9+ import struct
10+ import time
2711
2812LOGO = """
2913 ___ __ __
@@ -37,6 +21,14 @@ def stub_log(*args):
3721 pass
3822
3923
24+ def ticks_ms ():
25+ return int (time .time () * 1000 )
26+
27+
28+ def sleep_ms (ms ):
29+ time .sleep (ms // 1000 )
30+
31+
4032class BlynkError (Exception ):
4133 pass
4234
@@ -48,32 +40,32 @@ def __init__(self, server, port):
4840
4941
5042class Protocol (object ):
51- MSG_RSP = const ( 0 )
52- MSG_LOGIN = const ( 2 )
53- MSG_PING = const ( 6 )
54- MSG_TWEET = const ( 12 )
55- MSG_EMAIL = const ( 13 )
56- MSG_NOTIFY = const ( 14 )
57- MSG_BRIDGE = const ( 15 )
58- MSG_HW_SYNC = const ( 16 )
59- MSG_INTERNAL = const ( 17 )
60- MSG_PROPERTY = const ( 19 )
61- MSG_HW = const ( 20 )
62- MSG_REDIRECT = const ( 41 )
63- MSG_HEAD_LEN = const ( 5 )
64-
65- STATUS_INVALID_TOKEN = const ( 9 )
66- STATUS_NO_DATA = const ( 17 )
67- STATUS_OK = const ( 200 )
68- VPIN_MAX_NUM = const ( 32 )
69-
70- _msg_id = 1
43+ MSG_RSP = 0
44+ MSG_LOGIN = 2
45+ MSG_PING = 6
46+ MSG_TWEET = 12
47+ MSG_EMAIL = 13
48+ MSG_NOTIFY = 14
49+ MSG_BRIDGE = 15
50+ MSG_HW_SYNC = 16
51+ MSG_INTERNAL = 17
52+ MSG_PROPERTY = 19
53+ MSG_HW = 20
54+ MSG_REDIRECT = 41
55+ MSG_HEAD_LEN = 5
56+
57+ STATUS_INVALID_TOKEN = 9
58+ STATUS_NO_DATA = 17
59+ STATUS_OK = 200
60+ VPIN_MAX_NUM = 32
61+
62+ _msg_id = 0
7163
7264 def _get_msg_id (self , ** kwargs ):
7365 if 'msg_id' in kwargs :
7466 return kwargs ['msg_id' ]
7567 self ._msg_id += 1
76- return self ._msg_id if self ._msg_id <= 0xFFFF else 1
68+ return self ._msg_id if self ._msg_id <= 0xFFFF else 0
7769
7870 def _pack_msg (self , msg_type , * args , ** kwargs ):
7971 data = ('\0 ' .join ([str (curr_arg ) for curr_arg in args ])).encode ('utf-8' )
@@ -134,40 +126,35 @@ def internal_msg(self, *args):
134126
135127
136128class Connection (Protocol ):
137- SOCK_MAX_TIMEOUT = const ( 5 )
129+ SOCK_MAX_TIMEOUT = 5
138130 SOCK_TIMEOUT = 0.05
139- EAGAIN = const (11 )
140- ETIMEDOUT = const (60 )
141- RETRIES_TX_DELAY = const (2 )
142- RETRIES_TX_MAX_NUM = const (3 )
143- RECONNECT_SLEEP = const (1 )
144- TASK_PERIOD_RES = const (50 )
145- DISCONNECTED = const (0 )
146- CONNECTING = const (1 )
147- AUTHENTICATING = const (2 )
148- AUTHENTICATED = const (3 )
131+ SOCK_SSL_TIMEOUT = 1
132+ EAGAIN = 11
133+ ETIMEDOUT = 60
134+ RETRIES_TX_DELAY = 2
135+ RETRIES_TX_MAX_NUM = 3
136+ RECONNECT_SLEEP = 1
137+ TASK_PERIOD_RES = 50
138+ DISCONNECTED = 0
139+ CONNECTING = 1
140+ AUTHENTICATING = 2
141+ AUTHENTICATED = 3
149142
150143 _state = None
151144 _socket = None
152145 _last_rcv_time = 0
153146 _last_ping_time = 0
154147 _last_send_time = 0
155148
156- def __init__ (self , token , server = 'blynk-cloud.com' , port = 80 , heartbeat = 10 , rcv_buffer = 1024 , log = stub_log ):
149+ def __init__ (self , token , server = 'blynk-cloud.com' , port = 80 , ssl_cert = None , heartbeat = 10 , rcv_buffer = 1024 ,
150+ log = stub_log ):
157151 self .token = token
158152 self .server = server
159153 self .port = port
160154 self .heartbeat = heartbeat
161155 self .rcv_buffer = rcv_buffer
162156 self .log = log
163-
164- def _set_socket_timeout (self , timeout ):
165- if getattr (self ._socket , 'settimeout' , None ):
166- self ._socket .settimeout (timeout )
167- else :
168- p = select .poll ()
169- p .register (self ._socket )
170- p .poll (int (timeout * 1000 ))
157+ self .ssl_cert = ssl_cert
171158
172159 def send (self , data ):
173160 retries = self .RETRIES_TX_MAX_NUM
@@ -182,13 +169,13 @@ def send(self, data):
182169 def receive (self , length , timeout ):
183170 d_buff = b''
184171 try :
185- self ._set_socket_timeout (timeout )
172+ self ._socket . settimeout (timeout )
186173 d_buff += self ._socket .recv (length )
187174 if len (d_buff ) >= length :
188175 d_buff = d_buff [:length ]
189176 return d_buff
190177 except (IOError , OSError ) as err :
191- if str ( err ) == 'timed out' :
178+ if 'timed out' in str ( err ) :
192179 return b''
193180 if str (self .EAGAIN ) in str (err ) or str (self .ETIMEDOUT ) in str (err ):
194181 return b''
@@ -213,7 +200,16 @@ def _get_socket(self):
213200 self ._state = self .CONNECTING
214201 self ._socket = socket .socket ()
215202 self ._socket .connect (socket .getaddrinfo (self .server , self .port )[0 ][4 ])
216- self ._set_socket_timeout (self .SOCK_TIMEOUT )
203+ self ._socket .settimeout (self .SOCK_TIMEOUT )
204+ if self .ssl_cert :
205+ # system’s default CA certificates case
206+ if self .ssl_cert == "default" :
207+ self .ssl_cert = None
208+ self .log ('Using SSL socket...' )
209+ ssl_context = ssl .create_default_context (cafile = self .ssl_cert )
210+ ssl_context .verify_mode = ssl .CERT_REQUIRED
211+ self ._socket .settimeout (self .SOCK_SSL_TIMEOUT )
212+ self ._socket = ssl_context .wrap_socket (sock = self ._socket , server_hostname = self .server )
217213 self .log ('Connected to blynk server' )
218214 except Exception as g_exc :
219215 raise BlynkError ('Connection with the Blynk server failed: {}' .format (g_exc ))
@@ -250,7 +246,7 @@ def connected(self):
250246
251247
252248class Blynk (Connection ):
253- _CONNECT_TIMEOUT = const ( 30 ) # 30sec
249+ _CONNECT_TIMEOUT = 30 # 30sec
254250 _VPIN_WILDCARD = '*'
255251 _VPIN_READ = 'read v'
256252 _VPIN_WRITE = 'write v'
@@ -300,6 +296,7 @@ def disconnect(self, err_msg=None):
300296 self ._state = self .DISCONNECTED
301297 if err_msg :
302298 self .log ('[ERROR]: {}\n Connection closed' .format (err_msg ))
299+ self ._msg_id = 0
303300 time .sleep (self .RECONNECT_SLEEP )
304301
305302 def virtual_write (self , v_pin , * val ):
@@ -351,11 +348,11 @@ def process(self, msg_type, msg_id, msg_len, msg_args):
351348 elif msg_type == self .MSG_PING :
352349 self .send (self .response_msg (self .STATUS_OK , msg_id = msg_id ))
353350 elif msg_type in (self .MSG_HW , self .MSG_BRIDGE , self .MSG_INTERNAL ):
354- if msg_type == self .MSG_INTERNAL and len (msg_args ) >= const ( 2 ) :
351+ if msg_type == self .MSG_INTERNAL and len (msg_args ) >= 2 :
355352 self .call_handler ("{}{}" .format (self ._INTERNAL , msg_args [0 ]), msg_args [1 :])
356- elif len (msg_args ) >= const ( 3 ) and msg_args [0 ] == 'vw' :
353+ elif len (msg_args ) >= 3 and msg_args [0 ] == 'vw' :
357354 self .call_handler ("{}{}" .format (self ._VPIN_WRITE , msg_args [1 ]), int (msg_args [1 ]), msg_args [2 :])
358- elif len (msg_args ) == const ( 2 ) and msg_args [0 ] == 'vr' :
355+ elif len (msg_args ) == 2 and msg_args [0 ] == 'vr' :
359356 self .call_handler ("{}{}" .format (self ._VPIN_READ , msg_args [1 ]), int (msg_args [1 ]))
360357
361358 def read_response (self , timeout = 0.5 ):
0 commit comments