# sender/client.py — TCP socket client, connects to receiver and sends data import socket import time import logging import sys import os import argparse from config import HOST, PORT, SEND_INTERVAL, ACK_BYTE, RECONNECT_DELAY, BUFFER_SIZE from generator import generate_data parser = argparse.ArgumentParser() parser.add_argument("--id", required=True, help="Device ID") args = parser.parse_args() DEVICE_ID = args.id logging.basicConfig( level=logging.INFO, format="[SENDER] %(asctime)s — %(message)s", datefmt="%H:%M:%S" ) log = logging.getLogger(__name__) def connect_to_server() -> socket.socket: """Keep trying to connect until server is available.""" while True: try: client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((HOST, PORT)) log.info(f"Connected to server at {HOST}:{PORT}") return client except ConnectionRefusedError: log.warning(f"Server not available. Retrying in {RECONNECT_DELAY}s...") time.sleep(RECONNECT_DELAY) def run(): log.info(f"Sender starting with DEVICE_ID={DEVICE_ID}...") while True: client = connect_to_server() try: while True: # 1. Generate data string with unique ID data = generate_data(DEVICE_ID) display = data.replace('\0', '\\0') log.info(f"Sending → {display}") # 2. Send encoded bytes client.sendall(data.encode('utf-8')) # 3. Wait for ACK try: client.settimeout(5.0) ack = client.recv(BUFFER_SIZE) if ack == ACK_BYTE: log.info("ACK received") else: log.warning(f"Unexpected response: {ack}") except socket.timeout: log.error("ACK timeout — server may be down") break # 4. Wait before next send time.sleep(SEND_INTERVAL) except (ConnectionResetError, BrokenPipeError, OSError) as e: log.error(f"Connection lost: {e}. Reconnecting...") finally: client.close() if __name__ == "__main__": run()