36
36
from random import randint
37
37
38
38
from adafruit_connection_manager import get_connection_manager
39
+ from adafruit_ticks import ticks_ms , ticks_diff
39
40
40
41
try :
41
42
from typing import List , Optional , Tuple , Type , Union
@@ -133,8 +134,6 @@ class MQTT:
133
134
This works with all callbacks but the "on_message" and those added via add_topic_callback();
134
135
for those, to get access to the user_data use the 'user_data' member of the MQTT object
135
136
passed as 1st argument.
136
- :param bool use_imprecise_time: on boards without time.monotonic_ns() one has to set
137
- this to True in order to operate correctly over more than 24 days or so
138
137
139
138
"""
140
139
@@ -156,7 +155,6 @@ def __init__(
156
155
socket_timeout : int = 1 ,
157
156
connect_retries : int = 5 ,
158
157
user_data = None ,
159
- use_imprecise_time : Optional [bool ] = None ,
160
158
) -> None :
161
159
self ._connection_manager = get_connection_manager (socket_pool )
162
160
self ._socket_pool = socket_pool
@@ -165,20 +163,6 @@ def __init__(
165
163
self ._backwards_compatible_sock = False
166
164
self ._use_binary_mode = use_binary_mode
167
165
168
- self .use_monotonic_ns = False
169
- try :
170
- time .monotonic_ns ()
171
- self .use_monotonic_ns = True
172
- except AttributeError :
173
- if use_imprecise_time :
174
- self .use_monotonic_ns = False
175
- else :
176
- raise MMQTTException ( # pylint: disable=raise-missing-from
177
- "time.monotonic_ns() is not available. "
178
- "Will use imprecise time however only if the"
179
- "use_imprecise_time argument is set to True."
180
- )
181
-
182
166
if recv_timeout <= socket_timeout :
183
167
raise MMQTTException (
184
168
"recv_timeout must be strictly greater than socket_timeout"
@@ -191,7 +175,7 @@ def __init__(
191
175
self ._is_connected = False
192
176
self ._msg_size_lim = MQTT_MSG_SZ_LIM
193
177
self ._pid = 0
194
- self ._last_msg_sent_timestamp : float = 0
178
+ self ._last_msg_sent_timestamp : int = 0
195
179
self .logger = NullLogger ()
196
180
"""An optional logging attribute that can be set with with a Logger
197
181
to enable debug logging."""
@@ -230,7 +214,7 @@ def __init__(
230
214
self .client_id = client_id
231
215
else :
232
216
# assign a unique client_id
233
- time_int = int (self . get_monotonic_time () * 100 ) % 1000
217
+ time_int = int (ticks_ms () / 10 ) % 1000
234
218
self .client_id = f"cpy{ randint (0 , time_int )} { randint (0 , 99 )} "
235
219
# generated client_id's enforce spec.'s length rules
236
220
if len (self .client_id .encode ("utf-8" )) > 23 or not self .client_id :
@@ -254,17 +238,6 @@ def __init__(
254
238
self .on_subscribe = None
255
239
self .on_unsubscribe = None
256
240
257
- def get_monotonic_time (self ) -> float :
258
- """
259
- Provide monotonic time in seconds. Based on underlying implementation
260
- this might result in imprecise time, that will result in the library
261
- not being able to operate if running contiguously for more than 24 days or so.
262
- """
263
- if self .use_monotonic_ns :
264
- return time .monotonic_ns () / 1000000000
265
-
266
- return time .monotonic ()
267
-
268
241
def __enter__ (self ):
269
242
return self
270
243
@@ -546,9 +519,9 @@ def _connect(
546
519
if self ._username is not None :
547
520
self ._send_str (self ._username )
548
521
self ._send_str (self ._password )
549
- self ._last_msg_sent_timestamp = self . get_monotonic_time ()
522
+ self ._last_msg_sent_timestamp = ticks_ms ()
550
523
self .logger .debug ("Receiving CONNACK packet from broker" )
551
- stamp = self . get_monotonic_time ()
524
+ stamp = ticks_ms ()
552
525
while True :
553
526
op = self ._wait_for_msg ()
554
527
if op == 32 :
@@ -564,7 +537,7 @@ def _connect(
564
537
return result
565
538
566
539
if op is None :
567
- if self . get_monotonic_time () - stamp > self ._recv_timeout :
540
+ if ticks_diff ( ticks_ms (), stamp ) / 1000 > self ._recv_timeout :
568
541
raise MMQTTException (
569
542
f"No data received from broker for { self ._recv_timeout } seconds."
570
543
)
@@ -618,15 +591,16 @@ def ping(self) -> list[int]:
618
591
self ._connected ()
619
592
self .logger .debug ("Sending PINGREQ" )
620
593
self ._sock .send (MQTT_PINGREQ )
621
- ping_timeout = self ._recv_timeout
622
- stamp = self .get_monotonic_time ()
594
+ ping_timeout = self .keep_alive
595
+ stamp = ticks_ms ()
596
+
623
597
self ._last_msg_sent_timestamp = stamp
624
598
rc , rcs = None , []
625
599
while rc != MQTT_PINGRESP :
626
600
rc = self ._wait_for_msg ()
627
601
if rc :
628
602
rcs .append (rc )
629
- if self . get_monotonic_time () - stamp > ping_timeout :
603
+ if ticks_diff ( ticks_ms (), stamp ) / 1000 > ping_timeout :
630
604
raise MMQTTException (
631
605
f"PINGRESP not returned from broker within { ping_timeout } seconds."
632
606
)
@@ -697,11 +671,11 @@ def publish(
697
671
self ._sock .send (pub_hdr_fixed )
698
672
self ._sock .send (pub_hdr_var )
699
673
self ._sock .send (msg )
700
- self ._last_msg_sent_timestamp = self . get_monotonic_time ()
674
+ self ._last_msg_sent_timestamp = ticks_ms ()
701
675
if qos == 0 and self .on_publish is not None :
702
676
self .on_publish (self , self .user_data , topic , self ._pid )
703
677
if qos == 1 :
704
- stamp = self . get_monotonic_time ()
678
+ stamp = ticks_ms ()
705
679
while True :
706
680
op = self ._wait_for_msg ()
707
681
if op == 0x40 :
@@ -715,7 +689,7 @@ def publish(
715
689
return
716
690
717
691
if op is None :
718
- if self . get_monotonic_time () - stamp > self ._recv_timeout :
692
+ if ticks_diff ( ticks_ms (), stamp ) / 1000 > self ._recv_timeout :
719
693
raise MMQTTException (
720
694
f"No data received from broker for { self ._recv_timeout } seconds."
721
695
)
@@ -774,12 +748,12 @@ def subscribe(self, topic: Optional[Union[tuple, str, list]], qos: int = 0) -> N
774
748
self .logger .debug (f"SUBSCRIBING to topic { t } with QoS { q } " )
775
749
self .logger .debug (f"payload: { payload } " )
776
750
self ._sock .send (payload )
777
- stamp = self . get_monotonic_time ()
751
+ stamp = ticks_ms ()
778
752
self ._last_msg_sent_timestamp = stamp
779
753
while True :
780
754
op = self ._wait_for_msg ()
781
755
if op is None :
782
- if self . get_monotonic_time () - stamp > self ._recv_timeout :
756
+ if ticks_diff ( ticks_ms (), stamp ) / 1000 > self ._recv_timeout :
783
757
raise MMQTTException (
784
758
f"No data received from broker for { self ._recv_timeout } seconds."
785
759
)
@@ -851,13 +825,13 @@ def unsubscribe(self, topic: Optional[Union[str, list]]) -> None:
851
825
for t in topics :
852
826
self .logger .debug (f"UNSUBSCRIBING from topic { t } " )
853
827
self ._sock .send (payload )
854
- self ._last_msg_sent_timestamp = self . get_monotonic_time ()
828
+ self ._last_msg_sent_timestamp = ticks_ms ()
855
829
self .logger .debug ("Waiting for UNSUBACK..." )
856
830
while True :
857
- stamp = self . get_monotonic_time ()
831
+ stamp = ticks_ms ()
858
832
op = self ._wait_for_msg ()
859
833
if op is None :
860
- if self . get_monotonic_time () - stamp > self ._recv_timeout :
834
+ if ticks_diff ( ticks_ms (), stamp ) / 1000 > self ._recv_timeout :
861
835
raise MMQTTException (
862
836
f"No data received from broker for { self ._recv_timeout } seconds."
863
837
)
@@ -957,12 +931,12 @@ def loop(self, timeout: float = 0) -> Optional[list[int]]:
957
931
self ._connected ()
958
932
self .logger .debug (f"waiting for messages for { timeout } seconds" )
959
933
960
- stamp = self . get_monotonic_time ()
934
+ stamp = ticks_ms ()
961
935
rcs = []
962
936
963
937
while True :
964
938
if (
965
- self . get_monotonic_time () - self ._last_msg_sent_timestamp
939
+ ticks_diff ( ticks_ms (), self ._last_msg_sent_timestamp ) / 1000
966
940
>= self .keep_alive
967
941
):
968
942
# Handle KeepAlive by expecting a PINGREQ/PINGRESP from the server
@@ -972,22 +946,21 @@ def loop(self, timeout: float = 0) -> Optional[list[int]]:
972
946
rcs .extend (self .ping ())
973
947
# ping() itself contains a _wait_for_msg() loop which might have taken a while,
974
948
# so check here as well.
975
- if self . get_monotonic_time () - stamp > timeout :
949
+ if ticks_diff ( ticks_ms (), stamp ) / 1000 > timeout :
976
950
self .logger .debug (f"Loop timed out after { timeout } seconds" )
977
951
break
978
952
979
953
rc = self ._wait_for_msg ()
980
954
if rc is not None :
981
955
rcs .append (rc )
982
- if self . get_monotonic_time () - stamp > timeout :
956
+ if ticks_diff ( ticks_ms (), stamp ) / 1000 > timeout :
983
957
self .logger .debug (f"Loop timed out after { timeout } seconds" )
984
958
break
985
959
986
960
return rcs if rcs else None
987
961
988
962
def _wait_for_msg (self , timeout : Optional [float ] = None ) -> Optional [int ]:
989
963
# pylint: disable = too-many-return-statements
990
-
991
964
"""Reads and processes network events.
992
965
Return the packet type or None if there is nothing to be received.
993
966
@@ -1086,7 +1059,7 @@ def _sock_exact_recv(
1086
1059
:param float timeout: timeout, in seconds. Defaults to keep_alive
1087
1060
:return: byte array
1088
1061
"""
1089
- stamp = self . get_monotonic_time ()
1062
+ stamp = ticks_ms ()
1090
1063
if not self ._backwards_compatible_sock :
1091
1064
# CPython, socketpool, esp32spi, wiznet5k
1092
1065
rc = bytearray (bufsize )
@@ -1101,7 +1074,7 @@ def _sock_exact_recv(
1101
1074
recv_len = self ._sock .recv_into (mv , to_read )
1102
1075
to_read -= recv_len
1103
1076
mv = mv [recv_len :]
1104
- if self . get_monotonic_time () - stamp > read_timeout :
1077
+ if ticks_diff ( ticks_ms (), stamp ) / 1000 > read_timeout :
1105
1078
raise MMQTTException (
1106
1079
f"Unable to receive { to_read } bytes within { read_timeout } seconds."
1107
1080
)
@@ -1121,7 +1094,7 @@ def _sock_exact_recv(
1121
1094
recv = self ._sock .recv (to_read )
1122
1095
to_read -= len (recv )
1123
1096
rc += recv
1124
- if self . get_monotonic_time () - stamp > read_timeout :
1097
+ if ticks_diff ( ticks_ms (), stamp ) / 1000 > read_timeout :
1125
1098
raise MMQTTException (
1126
1099
f"Unable to receive { to_read } bytes within { read_timeout } seconds."
1127
1100
)
0 commit comments