From 24d64ac9e78d2b6775addb30bfea582a88dd6c27 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 8 Dec 2025 18:50:17 -0800 Subject: [PATCH] improved ip addr detection --- async_mass_deploy.py | 69 +++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/async_mass_deploy.py b/async_mass_deploy.py index bdd7146..3fd3cab 100755 --- a/async_mass_deploy.py +++ b/async_mass_deploy.py @@ -50,8 +50,9 @@ class DeployWorker: # Regex Patterns self.regex_ready = re.compile(r'Initialization complete|GPS synced|No WiFi config found', re.IGNORECASE) - self.regex_got_ip = re.compile(r'got ip:(\d+\.\d+\.\d+\.\d+)', re.IGNORECASE) - self.regex_error = re.compile(r'Error:|Failed|Disconnect|Auth Expire', re.IGNORECASE) + # Match output from 'mode_status' command + self.regex_status_connected = re.compile(r'WiFi connected: Yes', re.IGNORECASE) + self.regex_status_ip = re.compile(r'Got IP: (\d+\.\d+\.\d+\.\d+)', re.IGNORECASE) async def run(self): try: @@ -118,9 +119,9 @@ class DeployWorker: return False try: + # A. Boot Wait self.log.info("Waiting for boot...") booted = False - # Increased boot timeout slightly end_time = time.time() + 10 while time.time() < end_time: try: @@ -133,8 +134,9 @@ class DeployWorker: continue if not booted: - self.log.warning("Boot prompt missed, sending config blind...") + self.log.warning("Boot prompt missed, attempting config anyway...") + # B. Send Config self.log.info(f"Sending config for {self.target_ip}...") config_str = (f"CFG\nSSID:{self.args.ssid}\nPASS:{self.args.password}\n" f"IP:{self.target_ip}\nMASK:{self.args.netmask}\nGW:{self.args.gateway}\n" @@ -142,32 +144,48 @@ class DeployWorker: writer.write(config_str.encode('utf-8')) await writer.drain() - self.log.info("Verifying IP (Timeout: 30s)...") + # C. Active Polling Verification + self.log.info("Verifying configuration (Polling)...") start_verify = time.time() - # INCREASED TIMEOUT to 30s while time.time() < start_verify + 30: + # 1. Clear buffer try: - line_b = await asyncio.wait_for(reader.readline(), timeout=1.0) - line = line_b.decode('utf-8', errors='ignore').strip() - - # Success Check - m = self.regex_got_ip.search(line) - if m: - if m.group(1) == self.target_ip: - self.log.info(f"{Colors.GREEN}SUCCESS: Configured & Connected{Colors.RESET}") - return True - else: - self.log.warning(f"IP Mismatch: Got {m.group(1)}, Wanted {self.target_ip}") - - # Failure Check - if self.regex_error.search(line): - self.log.warning(f"Device Reported Error: {line}") - + while True: + await asyncio.wait_for(reader.read(1024), timeout=0.01) except asyncio.TimeoutError: - continue + pass - self.log.error("Timeout: Config sent, but device did not connect.") + # 2. Send status request + writer.write(b"\nmode_status\n") + await writer.drain() + + # 3. Read response for ~2 seconds + poll_end = time.time() + 2.0 + while time.time() < poll_end: + try: + line_b = await asyncio.wait_for(reader.readline(), timeout=0.5) + line = line_b.decode('utf-8', errors='ignore').strip() + + # Check for success indicators in status output + if self.regex_status_connected.search(line): + self.log.info(f"{Colors.GREEN}SUCCESS: Connected{Colors.RESET}") + return True + + # Also catch passive "Got IP" logs if they appear + m = self.regex_status_ip.search(line) + if m: + if m.group(1) == self.target_ip: + self.log.info(f"{Colors.GREEN}SUCCESS: IP Confirmed ({m.group(1)}){Colors.RESET}") + return True + + except asyncio.TimeoutError: + break + + # Wait a bit before next poll + await asyncio.sleep(1.0) + + self.log.error("Timeout: Device did not confirm connection.") return False except Exception as e: @@ -181,7 +199,7 @@ def parse_args(): parser = argparse.ArgumentParser(description='Async ESP32 Mass Deployment') parser.add_argument('-d', '--dir', default=os.getcwd(), help='Project dir') parser.add_argument('-s', '--ssid', help='WiFi SSID') - parser.add_argument('-P', '--password', help='WiFi Password') # Standardized -P + parser.add_argument('-P', '--password', help='WiFi Password') parser.add_argument('--start-ip', default='192.168.1.51', help='Start IP') parser.add_argument('-b', '--baud', type=int, default=460800, help='Flash baud') parser.add_argument('--erase', action='store_true', help='Full erase first') @@ -225,7 +243,6 @@ async def run_deployment(args): # 3. Deploy print(f"{Colors.YELLOW}[3/3] Deploying to {len(devices)} devices...{Colors.RESET}") - try: start_ip_obj = ipaddress.IPv4Address(args.start_ip) except: