mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Migrate to using aioesphomeapi for the log runner to fix multiple issues (#5733)
This commit is contained in:
		| @@ -1,71 +1,65 @@ | |||||||
|  | from __future__ import annotations | ||||||
|  |  | ||||||
| import asyncio | import asyncio | ||||||
| import logging | import logging | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| from typing import Optional | from typing import Any | ||||||
|  |  | ||||||
| from aioesphomeapi import APIClient, ReconnectLogic, APIConnectionError, LogLevel | from aioesphomeapi import APIClient | ||||||
| import zeroconf | from aioesphomeapi.api_pb2 import SubscribeLogsResponse | ||||||
|  | from aioesphomeapi.log_runner import async_run | ||||||
|  | from zeroconf.asyncio import AsyncZeroconf | ||||||
|  |  | ||||||
|  | from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__ | ||||||
|  | from esphome.core import CORE | ||||||
|  |  | ||||||
| from esphome.const import CONF_KEY, CONF_PORT, CONF_PASSWORD, __version__ |  | ||||||
| from esphome.util import safe_print |  | ||||||
| from . import CONF_ENCRYPTION | from . import CONF_ENCRYPTION | ||||||
|  |  | ||||||
| _LOGGER = logging.getLogger(__name__) | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def async_run_logs(config, address): | async def async_run_logs(config, address): | ||||||
|  |     """Run the logs command in the event loop.""" | ||||||
|     conf = config["api"] |     conf = config["api"] | ||||||
|     port: int = int(conf[CONF_PORT]) |     port: int = int(conf[CONF_PORT]) | ||||||
|     password: str = conf[CONF_PASSWORD] |     password: str = conf[CONF_PASSWORD] | ||||||
|     noise_psk: Optional[str] = None |     noise_psk: str | None = None | ||||||
|     if CONF_ENCRYPTION in conf: |     if CONF_ENCRYPTION in conf: | ||||||
|         noise_psk = conf[CONF_ENCRYPTION][CONF_KEY] |         noise_psk = conf[CONF_ENCRYPTION][CONF_KEY] | ||||||
|     _LOGGER.info("Starting log output from %s using esphome API", address) |     _LOGGER.info("Starting log output from %s using esphome API", address) | ||||||
|  |     aiozc = AsyncZeroconf() | ||||||
|  |  | ||||||
|     cli = APIClient( |     cli = APIClient( | ||||||
|         address, |         address, | ||||||
|         port, |         port, | ||||||
|         password, |         password, | ||||||
|         client_info=f"ESPHome Logs {__version__}", |         client_info=f"ESPHome Logs {__version__}", | ||||||
|         noise_psk=noise_psk, |         noise_psk=noise_psk, | ||||||
|  |         zeroconf_instance=aiozc.zeroconf, | ||||||
|     ) |     ) | ||||||
|     first_connect = True |     dashboard = CORE.dashboard | ||||||
|  |  | ||||||
|     def on_log(msg): |     def on_log(msg: SubscribeLogsResponse) -> None: | ||||||
|         time_ = datetime.now().time().strftime("[%H:%M:%S]") |         """Handle a new log message.""" | ||||||
|         text = msg.message.decode("utf8", "backslashreplace") |         time_ = datetime.now() | ||||||
|         safe_print(time_ + text) |         message: bytes = msg.message | ||||||
|  |         text = message.decode("utf8", "backslashreplace") | ||||||
|     async def on_connect(): |         if dashboard: | ||||||
|         nonlocal first_connect |             text = text.replace("\033", "\\033") | ||||||
|         try: |         print(f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}]{text}") | ||||||
|             await cli.subscribe_logs( |  | ||||||
|                 on_log, |  | ||||||
|                 log_level=LogLevel.LOG_LEVEL_VERY_VERBOSE, |  | ||||||
|                 dump_config=first_connect, |  | ||||||
|             ) |  | ||||||
|             first_connect = False |  | ||||||
|         except APIConnectionError: |  | ||||||
|             cli.disconnect() |  | ||||||
|  |  | ||||||
|     async def on_disconnect(expected_disconnect: bool) -> None: |  | ||||||
|         _LOGGER.warning("Disconnected from API") |  | ||||||
|  |  | ||||||
|     zc = zeroconf.Zeroconf() |  | ||||||
|     reconnect = ReconnectLogic( |  | ||||||
|         client=cli, |  | ||||||
|         on_connect=on_connect, |  | ||||||
|         on_disconnect=on_disconnect, |  | ||||||
|         zeroconf_instance=zc, |  | ||||||
|     ) |  | ||||||
|     await reconnect.start() |  | ||||||
|  |  | ||||||
|  |     stop = await async_run(cli, on_log, aio_zeroconf_instance=aiozc) | ||||||
|     try: |     try: | ||||||
|         while True: |         while True: | ||||||
|             await asyncio.sleep(60) |             await asyncio.sleep(60) | ||||||
|     except KeyboardInterrupt: |     finally: | ||||||
|         await reconnect.stop() |         await aiozc.async_close() | ||||||
|         zc.close() |         await stop() | ||||||
|  |  | ||||||
|  |  | ||||||
| def run_logs(config, address): | def run_logs(config: dict[str, Any], address: str) -> None: | ||||||
|  |     """Run the logs command.""" | ||||||
|  |     try: | ||||||
|         asyncio.run(async_run_logs(config, address)) |         asyncio.run(async_run_logs(config, address)) | ||||||
|  |     except KeyboardInterrupt: | ||||||
|  |         pass | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user