1414
1515printable = re .compile (r"[^\x20-\x7E]" )
1616
17+ shutdown_event = threading .Event ()
18+
1719
1820class 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¤t=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):
649652def 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):
678682def 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
685688if __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 ("\n Shutting down..." )
0 commit comments