76
76
}
77
77
78
78
79
+ _the_interface = None # pylint: disable=invalid-name
80
+ _the_sock = None # pylint: disable=invalid-name
81
+
79
82
class MMQTTException (Exception ):
80
83
"""MiniMQTT Exception class."""
81
84
82
85
# pylint: disable=unnecessary-pass
83
86
# pass
84
87
85
88
89
+ def set_socket (sock , iface = None ):
90
+ """Helper to set the global socket and optionally set the global network interface.
91
+ :param sock: socket object.
92
+ :param iface: internet interface object
93
+
94
+ """
95
+ global _the_sock # pylint: disable=invalid-name, global-statement
96
+ _the_sock = sock
97
+ if iface :
98
+ global _the_interface # pylint: disable=invalid-name, global-statement
99
+ _the_interface = iface
100
+ _the_sock .set_interface (iface )
101
+
86
102
class MQTT :
87
103
"""MQTT Client for CircuitPython
88
- :param socket: Socket object for provided network interface
89
104
:param str broker: MQTT Broker URL or IP Address.
90
105
:param int port: Optional port definition, defaults to 8883.
91
106
:param str username: Username for broker authentication.
@@ -95,33 +110,18 @@ class MQTT:
95
110
:param bool is_ssl: Sets a secure or insecure connection with the broker.
96
111
:param bool log: Attaches a logger to the MQTT client, defaults to logging level INFO.
97
112
:param int keep_alive: KeepAlive interval between the broker and the MiniMQTT client.
113
+
98
114
"""
99
115
100
116
# pylint: disable=too-many-arguments,too-many-instance-attributes, not-callable, invalid-name, no-member
101
- def __init__ (
102
- self ,
103
- socket ,
104
- broker ,
105
- port = None ,
106
- username = None ,
107
- password = None ,
108
- network_manager = None ,
109
- client_id = None ,
110
- is_ssl = True ,
111
- log = False ,
112
- keep_alive = 60 ,
113
- ):
114
- # network management
115
- self ._socket = socket
116
- network_manager_type = str (type (network_manager ))
117
- if "ESPSPI_WiFiManager" in network_manager_type :
118
- self ._wifi = network_manager
119
- else :
120
- raise TypeError ("This library requires a NetworkManager object." )
117
+ def __init__ (self , broker , port = None , username = None ,
118
+ password = None , client_id = None ,
119
+ is_ssl = True , log = False , keep_alive = 60 ):
120
+ self ._sock = None
121
121
# broker
122
- try : # set broker IP
123
- self .broker = self . _wifi . esp .unpretty_ip (broker )
124
- except ValueError : # set broker URL
122
+ try : # set broker IP
123
+ self .broker = _the_interface .unpretty_ip (broker )
124
+ except ValueError : # set broker URL
125
125
self .broker = broker
126
126
# port/ssl
127
127
self .port = MQTT_TCP_PORT
@@ -181,6 +181,7 @@ def __exit__(self, exception_type, exception_value, traceback):
181
181
def deinit (self ):
182
182
"""De-initializes the MQTT client and disconnects from
183
183
the mqtt broker.
184
+
184
185
"""
185
186
self .disconnect ()
186
187
@@ -190,6 +191,7 @@ def last_will(self, topic=None, message=None, qos=0, retain=False):
190
191
:param str message: Last will disconnection message.
191
192
:param int qos: Quality of Service level.
192
193
:param bool retain: Specifies if the message is to be retained when it is published.
194
+
193
195
"""
194
196
if self ._is_connected :
195
197
raise MMQTTException (
@@ -204,37 +206,45 @@ def last_will(self, topic=None, message=None, qos=0, retain=False):
204
206
self ._lw_msg = message
205
207
self ._lw_retain = retain
206
208
207
- # pylint: disable=too-many-branches, too-many-statements
209
+ # pylint: disable=too-many-branches, too-many-statements, too-many-locals
208
210
def connect (self , clean_session = True ):
209
211
"""Initiates connection with the MQTT Broker.
210
212
:param bool clean_session: Establishes a persistent session.
213
+
211
214
"""
212
- self ._set_interface ()
213
- if self .logger is not None :
214
- self .logger .debug ("Creating new socket" )
215
- self ._sock = self ._socket .socket ()
216
- self ._sock .settimeout (10 )
215
+ try :
216
+ proto , dummy , self .broker , path = self .broker .split ("/" , 3 )
217
+ # replace spaces in path
218
+ path = path .replace (" " , "%20" )
219
+ except ValueError :
220
+ proto , dummy , self .broker = self .broker .split ("/" , 2 )
221
+ path = ""
222
+ if proto == "http:" :
223
+ self .port = MQTT_TCP_PORT
224
+ elif proto == "https:" :
225
+ self .port = MQTT_TLS_PORT
226
+ else :
227
+ raise ValueError ("Unsupported protocol: " + proto )
228
+
229
+ if ":" in self .broker :
230
+ self .broker , port = self .broker .split (":" , 1 )
231
+ port = int (port )
232
+
233
+ addr = _the_sock .getaddrinfo (self .broker , self .port , 0 , _the_sock .SOCK_STREAM )[0 ]
234
+ self ._sock = _the_sock .socket (addr [0 ], addr [1 ], addr [2 ])
235
+ self ._sock .settimeout (15 )
217
236
if self .port == 8883 :
218
237
try :
219
238
if self .logger is not None :
220
- self .logger .debug (
221
- "Attempting to establish secure MQTT connection..."
222
- )
223
- self ._sock .connect ((self .broker , self .port ), TLS_MODE )
224
- except RuntimeError :
225
- raise MMQTTException ("Invalid broker address defined." )
239
+ self .logger .debug ('Attempting to establish secure MQTT connection...' )
240
+ self ._sock .connect ((self .broker , self .port ), _the_interface .TLS_MODE )
241
+ except RuntimeError as e :
242
+ raise MMQTTException ("Invalid broker address defined." , e )
226
243
else :
227
- if isinstance (self .broker , str ):
228
- addr = self ._socket .getaddrinfo (self .broker , self .port )[0 ][- 1 ]
229
- else :
230
- addr = (self .broker , self .port )
231
244
try :
232
245
if self .logger is not None :
233
- self .logger .debug (
234
- "Attempting to establish insecure MQTT connection..."
235
- )
236
- # self._sock.connect((self.broker, self.port), TCP_MODE)
237
- self ._sock .connect (addr , TCP_MODE )
246
+ self .logger .debug ('Attempting to establish insecure MQTT connection...' )
247
+ self ._sock .connect (addr [- 1 ], TCP_MODE )
238
248
except RuntimeError as e :
239
249
raise MMQTTException ("Invalid broker address defined." , e )
240
250
@@ -376,9 +386,9 @@ def publish(self, topic, msg, retain=False, qos=0):
376
386
raise MMQTTException ("Publish topic can not contain wildcards." )
377
387
# check msg/qos kwargs
378
388
if msg is None :
379
- raise MMQTTException (" Message can not be None." )
389
+ raise MMQTTException (' Message can not be None.' )
380
390
if isinstance (msg , (int , float )):
381
- msg = str (msg ).encode (" ascii" )
391
+ msg = str (msg ).encode (' ascii' )
382
392
elif isinstance (msg , str ):
383
393
msg = str (msg ).encode ("utf-8" )
384
394
else :
@@ -574,55 +584,6 @@ def unsubscribe(self, topic):
574
584
self ._subscribed_topics .remove (t )
575
585
return
576
586
577
- @property
578
- def is_wifi_connected (self ):
579
- """Returns if the ESP module is connected to
580
- an access point, resets module if False"""
581
- if self ._wifi :
582
- return self ._wifi .esp .is_connected
583
- raise MMQTTException ("MiniMQTT Client does not use a WiFi NetworkManager." )
584
-
585
- # pylint: disable=line-too-long, protected-access
586
- @property
587
- def is_sock_connected (self ):
588
- """Returns if the socket is connected."""
589
- return (
590
- self .is_wifi_connected
591
- and self ._sock
592
- and self ._wifi .esp .socket_connected (self ._sock ._socknum )
593
- )
594
-
595
- def reconnect_socket (self ):
596
- """Re-establishes the socket's connection with the MQTT broker.
597
- """
598
- try :
599
- if self .logger is not None :
600
- self .logger .debug ("Attempting to reconnect with MQTT Broker..." )
601
- self .reconnect ()
602
- except RuntimeError as err :
603
- if self .logger is not None :
604
- self .logger .debug (
605
- "Failed to reconnect with MQTT Broker, retrying..." , err
606
- )
607
- time .sleep (1 )
608
- self .reconnect_socket ()
609
-
610
- def reconnect_wifi (self ):
611
- """Reconnects to WiFi Access Point and socket, if disconnected.
612
- """
613
- while not self .is_wifi_connected :
614
- try :
615
- if self .logger is not None :
616
- self .logger .debug ("Connecting to WiFi AP..." )
617
- self ._wifi .connect ()
618
- except (RuntimeError , ValueError ):
619
- if self .logger is not None :
620
- self .logger .debug ("Failed to reset WiFi module, retrying..." )
621
- time .sleep (1 )
622
- # we just reconnected, is the socket still connected?
623
- if not self .is_sock_connected :
624
- self .reconnect_socket ()
625
-
626
587
def reconnect (self , resub_topics = True ):
627
588
"""Attempts to reconnect to the MQTT broker.
628
589
:param bool resub_topics: Resubscribe to previously subscribed topics.
@@ -645,37 +606,30 @@ def loop_forever(self):
645
606
"""Starts a blocking message loop. Use this
646
607
method if you want to run a program forever.
647
608
Code below a call to this method will NOT execute.
648
- Network reconnection is handled within this call.
609
+
610
+ NOTE: This method is depreciated and will be removed in the
611
+ next major release. Please see examples/minimqtt_pub_sub_blocking.py
612
+ for an example of creating a blocking loop which can handle wireless
613
+ network events.
649
614
650
615
"""
651
616
while True :
652
- # Check WiFi and socket status
653
- if self .is_sock_connected :
654
- try :
655
- self .loop ()
656
- except (RuntimeError , ValueError ):
657
- if self ._wifi :
658
- # Reconnect the WiFi module and the socket
659
- self .reconnect_wifi ()
660
- continue
617
+ if self ._sock .connected :
618
+ self .loop ()
661
619
662
620
def loop (self ):
663
621
"""Non-blocking message loop. Use this method to
664
622
check incoming subscription messages.
665
623
666
- This method does NOT handle networking or
667
- network hardware management, use loop_forever
668
- or handle in code instead.
669
624
"""
670
625
if self ._timestamp == 0 :
671
626
self ._timestamp = time .monotonic ()
672
627
current_time = time .monotonic ()
673
628
if current_time - self ._timestamp >= self .keep_alive :
674
629
# Handle KeepAlive by expecting a PINGREQ/PINGRESP from the server
675
630
if self .logger is not None :
676
- self .logger .debug (
677
- "KeepAlive period elapsed - requesting a PINGRESP from the server..."
678
- )
631
+ self .logger .debug ('KeepAlive period elapsed - \
632
+ requesting a PINGRESP from the server...' )
679
633
self .ping ()
680
634
self ._timestamp = 0
681
635
self ._sock .settimeout (0.1 )
@@ -745,10 +699,10 @@ def _check_topic(topic):
745
699
raise MMQTTException ("Topic may not be NoneType" )
746
700
# [MQTT-4.7.3-1]
747
701
if not topic :
748
- raise MMQTTException (" Topic may not be empty." )
702
+ raise MMQTTException (' Topic may not be empty.' )
749
703
# [MQTT-4.7.3-3]
750
- if len (topic .encode (" utf-8" )) > MQTT_TOPIC_LENGTH_LIMIT :
751
- raise MMQTTException (" Topic length is too large." )
704
+ if len (topic .encode (' utf-8' )) > MQTT_TOPIC_LENGTH_LIMIT :
705
+ raise MMQTTException (' Topic length is too large.' )
752
706
753
707
@staticmethod
754
708
def _check_qos (qos_level ):
0 commit comments