diff --git a/solax/__init__.py b/solax/__init__.py index 5953b06..a13385c 100644 --- a/solax/__init__.py +++ b/solax/__init__.py @@ -4,7 +4,7 @@ from async_timeout import timeout -from solax.discovery import discover +from solax.discovery import discover, discover_single_inverter from solax.inverter import Inverter, InverterResponse _LOGGER = logging.getLogger(__name__) @@ -36,6 +36,12 @@ async def real_time_api(ip_address, port=80, pwd=""): return RealTimeAPI(i) +# bypass the full discovery process, and only do it for the specified inverter type +async def real_time_api_inverter(inverter_name, ip_address, port=80, pwd=""): + i = await discover_single_inverter(inverter_name, ip_address, port, pwd) + return RealTimeAPI(i) + + class RealTimeAPI: """Solax inverter real time API""" diff --git a/solax/discovery.py b/solax/discovery.py index 9cfdd60..9d62d01 100644 --- a/solax/discovery.py +++ b/solax/discovery.py @@ -92,6 +92,37 @@ async def discover(self, host, port, pwd="") -> Inverter: ) raise DiscoveryError(msg) + async def discover_single_inverter( + self, inverter_name, host, port, pwd="" + ) -> Inverter: + found = False + for invclass in REGISTRY: + if invclass.__name__ == inverter_name: + found = True + for i in invclass.build_all_variants(host, port, pwd): + task = asyncio.create_task(self._discovery_task(i), name=f"{i}") + task.add_done_callback(self._task_handler) + self._tasks.add(task) + + if not found: + raise DiscoveryError(f"Unknown inverter type {inverter_name}") + + while len(self._tasks) > 0: + logging.debug("%d discovery tasks are still running...", len(self._tasks)) + await asyncio.sleep(0.5) + + if self._discovered_inverter is not None: + logging.info("Discovered inverter: %s", self._discovered_inverter) + return self._discovered_inverter + + msg = ( + "Unable to connect to the inverter at " + f"host={host} port={port} of type {inverter_name}.\n" + "Please see https://github.com/squishykid/solax/wiki/DiscoveryError\n" + f"Failures={str(self._failures)}" + ) + raise DiscoveryError(msg) + class DiscoveryError(Exception): """Raised when unable to discover inverter""" @@ -101,3 +132,9 @@ async def discover(host, port, pwd="") -> Inverter: discover_state = DiscoveryState() await discover_state.discover(host, port, pwd) return discover_state.get_discovered_inverter() + + +async def discover_single_inverter(inverter, host, port, pwd="") -> Inverter: + discover_state = DiscoveryState() + await discover_state.discover_single_inverter(inverter, host, port, pwd) + return discover_state.get_discovered_inverter() diff --git a/tests/test_discovery.py b/tests/test_discovery.py index 2f57b50..5246c30 100644 --- a/tests/test_discovery.py +++ b/tests/test_discovery.py @@ -11,12 +11,31 @@ async def test_discovery(inverters_fixture): assert rt_api.inverter.__class__ == inverter_class +@pytest.mark.asyncio +async def test_discovery_single_inverter(inverters_fixture): + conn, inverter_class, _ = inverters_fixture + rt_api = await solax.real_time_api_inverter(inverter_class.__name__, *conn) + assert rt_api.inverter.__class__ == inverter_class + + +@pytest.mark.asyncio +async def test_discovery_unsupported_inverter(): + with pytest.raises(DiscoveryError): + await solax.real_time_api_inverter("doesnotexist", "localhost", 2) + + @pytest.mark.asyncio async def test_discovery_no_host(): with pytest.raises(DiscoveryError): await solax.real_time_api("localhost", 2) +@pytest.mark.asyncio +async def test_discovery_single_inverter_no_host(): + with pytest.raises(DiscoveryError): + await solax.real_time_api_inverter("X1HybridGen4", "localhost", 2) + + @pytest.mark.asyncio async def test_discovery_no_host_with_pwd(): with pytest.raises(DiscoveryError):