From 1d4c2c0f7be0e247a65ac2b0cd8bfa1d10c0a889 Mon Sep 17 00:00:00 2001 From: nero150 <95982029+nero150@users.noreply.github.com> Date: Wed, 18 Mar 2026 11:11:42 +0100 Subject: [PATCH] Add files via upload --- custom_components/xt211_han/config_flow.py | 41 +++++++++++++++++----- custom_components/xt211_han/manifest.json | 2 +- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/custom_components/xt211_han/config_flow.py b/custom_components/xt211_han/config_flow.py index 1e47ca5..22f557c 100644 --- a/custom_components/xt211_han/config_flow.py +++ b/custom_components/xt211_han/config_flow.py @@ -100,22 +100,38 @@ async def _test_connection(host: str, port: int, timeout: float = 5.0) -> str | return "unknown" -async def _scan_network(port: int, timeout: float = 0.5) -> list[str]: +async def _scan_network(port: int, timeout: float = 1.0) -> list[str]: """ - Scan the local network for open TCP port (default 8899). + Scan the local network for open TCP port. Returns list of IP addresses that responded. """ - # Determine local subnet from hostname + # Get real local IP by connecting to a public address (no data sent) + local_ip = "192.168.1.1" try: - local_ip = socket.gethostbyname(socket.gethostname()) - except OSError: + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: + s.settimeout(0) + s.connect(("8.8.8.8", 80)) + local_ip = s.getsockname()[0] + except Exception: + try: + local_ip = socket.gethostbyname(socket.gethostname()) + except Exception: + pass + + _LOGGER.debug("XT211 scan: local IP detected as %s", local_ip) + + # Fallback if we still got loopback + if local_ip.startswith("127.") or local_ip == "0.0.0.0": local_ip = "192.168.1.1" + _LOGGER.warning("XT211 scan: loopback detected, falling back to %s", local_ip) try: network = IPv4Network(f"{local_ip}/24", strict=False) except ValueError: network = IPv4Network("192.168.1.0/24", strict=False) + _LOGGER.debug("XT211 scan: scanning %s on port %d", network, port) + found: list[str] = [] async def _probe(ip: str) -> None: @@ -125,14 +141,23 @@ async def _scan_network(port: int, timeout: float = 0.5) -> list[str]: timeout=timeout, ) writer.close() - await writer.wait_closed() + try: + await writer.wait_closed() + except Exception: + pass found.append(ip) + _LOGGER.debug("XT211 scan: found device at %s:%d", ip, port) except Exception: pass - # Probe all hosts in /24 concurrently (skip network and broadcast) + # Probe all hosts in /24 concurrently hosts = [str(h) for h in network.hosts()] - await asyncio.gather(*[_probe(ip) for ip in hosts]) + # Split into batches to avoid overwhelming the network stack + batch_size = 50 + for i in range(0, len(hosts), batch_size): + batch = hosts[i:i + batch_size] + await asyncio.gather(*[_probe(ip) for ip in batch]) + return sorted(found) diff --git a/custom_components/xt211_han/manifest.json b/custom_components/xt211_han/manifest.json index c04858b..be1724b 100644 --- a/custom_components/xt211_han/manifest.json +++ b/custom_components/xt211_han/manifest.json @@ -1,7 +1,7 @@ { "domain": "xt211_han", "name": "XT211 HAN (RS485 via Ethernet)", - "version": "0.7.1", + "version": "0.7.2", "documentation": "https://github.com/nero150/xt211-han-ha", "issue_tracker": "https://github.com/nero150/xt211-han-ha/issues", "dependencies": [],