|  | @ -50,18 +50,22 @@ def handle_camera_status(status: int): | 
		
	
		
			
				|  |  | # Helper class to track client connection status |  |  | # Helper class to track client connection status | 
		
	
		
			
				|  |  | class ConnectionTracker: |  |  | class ConnectionTracker: | 
		
	
		
			
				|  |  |     def __init__(self): |  |  |     def __init__(self): | 
		
	
		
			
				|  |  |         self.last_message_time = time.time()  # Use time.time() to get the current time |  |  |  | 
		
	
		
			
				|  |  |         self.timeout = 15  # Timeout in seconds (adjust as needed) |  |  |  | 
		
	
		
			
				|  |  | 
 |  |  |  | 
		
	
		
			
				|  |  |     def update_last_message_time(self): |  |  |  | 
		
	
		
			
				|  |  |         self.last_message_time = time.time()  # Update with the current time |  |  |  | 
		
	
		
			
				|  |  | 
 |  |  |  | 
		
	
		
			
				|  |  |     def is_client_connected(self): |  |  |  | 
		
	
		
			
				|  |  |         return (time.time() - self.last_message_time) < self.timeout  # Use time.time() |  |  |  | 
		
	
		
			
				|  |  | 
 |  |  |  | 
		
	
		
			
				|  |  |  |  |  |         self.last_message_time = time.time() | 
		
	
		
			
				|  |  |  |  |  |         self.timeout = 30  # 30-second timeout | 
		
	
		
			
				|  |  |  |  |  |         self.last_client_ip = None  # Track last connected client IP | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     def update_last_message_time(self, client_ip=None): | 
		
	
		
			
				|  |  |  |  |  |         self.last_message_time = time.time() | 
		
	
		
			
				|  |  |  |  |  |         if client_ip: | 
		
	
		
			
				|  |  |  |  |  |             self.last_client_ip = client_ip  # Update last known client | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     def is_client_active(self): | 
		
	
		
			
				|  |  |  |  |  |         """Check if the last client is still active within the last 30 seconds.""" | 
		
	
		
			
				|  |  |  |  |  |         return (time.time() - self.last_message_time) < self.timeout | 
		
	
		
			
				|  |  | # Create an instance of ConnectionTracker |  |  | # Create an instance of ConnectionTracker | 
		
	
		
			
				|  |  | connection_tracker = ConnectionTracker() |  |  | connection_tracker = ConnectionTracker() | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  | class ConnectionThread(threading.Thread): |  |  | class ConnectionThread(threading.Thread): | 
		
	
		
			
				|  |  |     def __init__(self): |  |  |     def __init__(self): | 
		
	
		
			
				|  |  |         super().__init__() |  |  |         super().__init__() | 
		
	
	
		
			
				|  | @ -69,18 +73,55 @@ class ConnectionThread(threading.Thread): | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |     def run(self): |  |  |     def run(self): | 
		
	
		
			
				|  |  |         while self.running: |  |  |         while self.running: | 
		
	
		
			
				|  |  |             if not connection_tracker.is_client_connected(): |  |  |  | 
		
	
		
			
				|  |  |                 print("Client disconnected. Searching for another client...") |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             if connection_tracker.last_client_ip: | 
		
	
		
			
				|  |  |  |  |  |                 print(f"Checking if last client {connection_tracker.last_client_ip} is still available...") | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |                 if self.query_last_client(connection_tracker.last_client_ip): | 
		
	
		
			
				|  |  |  |  |  |                     connection_tracker.update_last_message_time() | 
		
	
		
			
				|  |  |  |  |  |                     print(f"Last client {connection_tracker.last_client_ip} responded. Continuing...") | 
		
	
		
			
				|  |  |  |  |  |                     continue  # Skip discovering a new client | 
		
	
		
			
				|  |  |  |  |  |             if not connection_tracker.is_client_active(): | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |                 print("Client inactive for 30 seconds. Searching for another client...") | 
		
	
		
			
				|  |  |                 cl_ip, _ = self.start_discovery_service(12345) |  |  |                 cl_ip, _ = self.start_discovery_service(12345) | 
		
	
		
			
				|  |  |                 print(cl_ip) |  |  |  | 
		
	
		
			
				|  |  |  |  |  |                 print(f"New client found: {cl_ip}") | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |                 # Reinitialize the Manager with the new client address |  |  |                 # Reinitialize the Manager with the new client address | 
		
	
		
			
				|  |  |                 global manager |  |  |                 global manager | 
		
	
		
			
				|  |  |                 manager = Manager(f"tcp://{cl_ip}:5558", f"tcp://{cl_ip}:5557") |  |  |                 manager = Manager(f"tcp://{cl_ip}:5558", f"tcp://{cl_ip}:5557") | 
		
	
		
			
				|  |  |                 manager.start(manager_callback)  # Restart the Manager and re-register the callback |  |  |  | 
		
	
		
			
				|  |  |  |  |  |                 manager.start(manager_callback) | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |                 connection_tracker.update_last_message_time(cl_ip)  # Update with new client | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     def query_last_client(self, client_ip): | 
		
	
		
			
				|  |  |  |  |  |         """Send a heartbeat packet to the last known client IP on port 29170 and wait for a response.""" | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         print(f"Sending heartbeat to {client_ip}:29170")  # Debugging | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | 
		
	
		
			
				|  |  |  |  |  |         sock.settimeout(5)  # 5-second timeout | 
		
	
		
			
				|  |  |  |  |  |         heartbeat_port = 29170  # New port for heartbeat | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         try: | 
		
	
		
			
				|  |  |  |  |  |             sock.sendto(b"HEARTBEAT", (client_ip, heartbeat_port))  # Send heartbeat message | 
		
	
		
			
				|  |  |  |  |  |             data, addr = sock.recvfrom(1024)  # Wait for response | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             print(f"Received response from {addr}: {data.decode()}")  # Debugging | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             if data.decode() == "HEARTBEAT_ACK": | 
		
	
		
			
				|  |  |  |  |  |                 print(f"Client {client_ip} is still responding.") | 
		
	
		
			
				|  |  |  |  |  |                 return True | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         except socket.timeout: | 
		
	
		
			
				|  |  |  |  |  |             print(f"Client {client_ip} did not respond. Marking as inactive.") | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         finally: | 
		
	
		
			
				|  |  |  |  |  |             sock.close() | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         return False  # Client did not respond | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |                 connection_tracker.update_last_message_time()  # Reset the timer after reconnecting |  |  |  | 
		
	
		
			
				|  |  |             time.sleep(10)  # Check every 10 seconds |  |  |  | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |     def start_discovery_service(self, port): |  |  |     def start_discovery_service(self, port): | 
		
	
		
			
				|  |  |         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |  |  |         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | 
		
	
	
		
			
				|  | @ -95,9 +136,13 @@ class ConnectionThread(threading.Thread): | 
		
	
		
			
				|  |  |                 break |  |  |                 break | 
		
	
		
			
				|  |  |         return addr |  |  |         return addr | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |     def stop(self): |  |  |     def stop(self): | 
		
	
		
			
				|  |  |         self.running = False |  |  |         self.running = False | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  | if __name__ == '__main__': |  |  | if __name__ == '__main__': | 
		
	
		
			
				|  |  |     QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling) |  |  |     QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling) | 
		
	
		
			
				|  |  |     app = QCoreApplication(sys.argv) |  |  |     app = QCoreApplication(sys.argv) | 
		
	
	
		
			
				|  | 
 |