Skip to content

Commit 31d5f06

Browse files
committed
fix: add shutdown event
1 parent 4f3d7dd commit 31d5f06

File tree

1 file changed

+26
-23
lines changed

1 file changed

+26
-23
lines changed

protocol-serial-bridge.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
printable = re.compile(r"[^\x20-\x7E]")
1616

17+
shutdown_event = threading.Event()
18+
1719

1820
class ProtocolSerialBridge:
1921
"""A serial communication bridge for LoCave communication system.
@@ -145,11 +147,11 @@ def _save_sequence(self, file_path=".sequence"):
145147
f.write(str(self.sequence_number))
146148

147149
def _receive_loop(self):
148-
while self.running:
150+
while self.running and not shutdown_event.is_set():
149151
try:
150152
if not self.ser_send or not self.ser_send.is_open:
151153
self._reconnect_serial()
152-
time.sleep(1)
154+
shutdown_event.wait(1)
153155
continue
154156
while self.ser_send.in_waiting:
155157
while (message := self.driver.get(block=False)) is None:
@@ -177,10 +179,10 @@ def _receive_loop(self):
177179
except (serial.SerialException, OSError) as e:
178180
print(f"[Serial Error] Lost connection: {e}")
179181
self.ser_send.close()
180-
time.sleep(1)
182+
shutdown_event.wait(1)
181183
except Exception as e:
182184
print(f"[Receive Loop Error] {e}")
183-
time.sleep(0.01)
185+
shutdown_event.wait(0.01)
184186

185187
def _reconnect_serial(self):
186188
while self.running:
@@ -191,7 +193,7 @@ def _reconnect_serial(self):
191193
return
192194
except (serial.SerialException, OSError) as e:
193195
print(f"Reconnect failed: {e}")
194-
time.sleep(2) # wait before retrying
196+
shutdown_event.wait(2) # wait before retrying
195197

196198
def _process_message(
197199
self,
@@ -359,7 +361,7 @@ def _send_weather_data(self):
359361
check_interval = 1 # check every 1 second
360362
waited = 0
361363

362-
while self.running:
364+
while self.running and not shutdown_event.is_set():
363365
try:
364366
r = requests.get(
365367
"https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&current=temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m"
@@ -371,11 +373,11 @@ def _send_weather_data(self):
371373

372374
waited = 0
373375
while self.running and waited < interval:
374-
time.sleep(check_interval)
376+
shutdown_event.wait(check_interval)
375377
waited += check_interval
376378

377379
def _forward_from_telegram(self):
378-
while True:
380+
while self.running and not shutdown_event.is_set():
379381
while not self.bot.rx_empty():
380382
msg = str(self.bot.pop_rx())
381383
self._send_message(
@@ -384,23 +386,23 @@ def _forward_from_telegram(self):
384386
msg,
385387
source=self.TELEGRAM_ADDRESS,
386388
)
387-
time.sleep(0.1)
388-
time.sleep(1)
389+
shutdown_event.wait(0.1)
390+
shutdown_event.wait(1)
389391

390392
def _ping_sweep_loop(self):
391393
while self.running:
392394
for node in range(1, 101): # Ping nodes 1-100
393395
if not self.running: # Check if we should stop
394396
break
395397
self.ping(node)
396-
time.sleep(0.01) # 10ms delay between pings
397-
time.sleep(10) # Wait 10 seconds before next sweep
398+
shutdown_event.wait(0.01) # 10ms delay between pings
399+
shutdown_event.wait(10) # Wait 10 seconds before next sweep
398400

399401
def _broadcast_ping_loop(self):
400-
while self.running:
402+
while self.running and not shutdown_event.is_set():
401403
# Send ping to broadcast address (255)
402404
self.ping(self.BROADCAST_ADDRESS)
403-
time.sleep(5) # Wait 10 seconds before next broadcast ping
405+
shutdown_event.wait(5) # Wait 10 seconds before next broadcast ping
404406

405407
def close(self):
406408
"""Gracefully shutdown the ProtocolSerialBridge."""
@@ -411,6 +413,7 @@ def close(self):
411413
pass
412414
self.receive_thread.join()
413415
self.weather_thread.join()
416+
self.forward_from_telegram_thread.join()
414417
if hasattr(self, "ping_sweep_thread"):
415418
self.ping_sweep_thread.join()
416419
self.broadcast_ping_thread.join()
@@ -629,7 +632,7 @@ def restart_bot():
629632
while bridge.bot.application is not None and bridge.bot.application.running:
630633
if time.time() - start_time > timeout:
631634
return jsonify({"error": "bot stop timeout reached!"}), 500
632-
time.sleep(0.1)
635+
shutdown_event.wait(0.1)
633636

634637
except Exception as e:
635638
return jsonify({"error": f"could not stop bot: {str(e)}"}), 500
@@ -649,7 +652,7 @@ def start_api_server(host="0.0.0.0", port=8080):
649652
def start_cli(bridge: ProtocolSerialBridge):
650653
"""Start command line interface for bridge."""
651654
try:
652-
while True:
655+
while not shutdown_event.is_set():
653656
cmd = input("> ").strip().split()
654657
if not cmd:
655658
continue
@@ -661,8 +664,9 @@ def start_cli(bridge: ProtocolSerialBridge):
661664
elif cmd[0] == "test" and len(cmd) > 1:
662665
for i in range(int(cmd[1]), int(cmd[2])):
663666
bridge.broadcast("test " + str(i))
664-
time.sleep(1)
667+
shutdown_event.wait(1)
665668
elif cmd[0] == "exit":
669+
shutdown_event.set()
666670
if bridge.running:
667671
bridge.close()
668672
break
@@ -678,12 +682,12 @@ def start_cli(bridge: ProtocolSerialBridge):
678682
def handle_sigterm(sig, frame):
679683
"""SIGTERM handler."""
680684
print("Received SIGTERM, exiting...")
681-
if bridge is ProtocolSerialBridge:
682-
bridge.close()
685+
shutdown_event.set()
683686

684687

685688
if __name__ == "__main__":
686689
signal.signal(signal.SIGTERM, handle_sigterm)
690+
signal.signal(signal.SIGINT, handle_sigterm)
687691
# Set up command line argument parsing
688692
parser = argparse.ArgumentParser(description="Linear Protocol Serial Bridge")
689693
parser.add_argument("--port", help="Serial port to send data (e.g., /dev/ttyUSB0)")
@@ -716,12 +720,11 @@ def handle_sigterm(sig, frame):
716720
cli_thread.start()
717721

718722
try:
719-
while True:
723+
while not shutdown_event.is_set():
720724
if not bridge.running:
721725
break
722726
try:
723727
bridge.bot.init()
724-
725728
if bridge.bot.application is not None:
726729
try:
727730
bridge.bot.run()
@@ -732,8 +735,8 @@ def handle_sigterm(sig, frame):
732735
except Exception as e:
733736
print("Unknown error:", e)
734737

735-
time.sleep(5)
736-
except KeyboardInterrupt:
738+
shutdown_event.wait(5)
739+
finally:
737740
if bridge.running:
738741
bridge.close()
739742
print("\nShutting down...")

0 commit comments

Comments
 (0)