diff --git a/examples/bluetooth/ble_uart_service/README.md b/examples/bluetooth/ble_uart_service/README.md index 8b0169ad7b5..be4235d9af8 100644 --- a/examples/bluetooth/ble_uart_service/README.md +++ b/examples/bluetooth/ble_uart_service/README.md @@ -1,7 +1,7 @@ # BLE UART Service Example — NimBLE / Bluedroid -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | A turnkey serial-over-BLE peripheral that implements the de-facto **Nordic UART Service** GATT layout (RX write, TX notify), so any diff --git a/tools/ble/ble_uart_bridge/src/console/api.py b/tools/ble/ble_uart_bridge/src/console/api.py index e8e01ebb058..6df91665d95 100644 --- a/tools/ble/ble_uart_bridge/src/console/api.py +++ b/tools/ble/ble_uart_bridge/src/console/api.py @@ -1,19 +1,21 @@ # SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - from __future__ import annotations import asyncio +from typing import Union from .console import BLEUARTConsole from .console import ConsoleEncoding from .console import ConsoleTerminator +# Keep annotations compatible with Python 3.9. +# ruff: noqa: UP007 def run_console( device_id: str, - terminator: ConsoleTerminator | str = ConsoleTerminator.lf, - encoding: ConsoleEncoding | str = ConsoleEncoding.text, + terminator: Union[ConsoleTerminator, str] = ConsoleTerminator.lf, + encoding: Union[ConsoleEncoding, str] = ConsoleEncoding.text, with_response: bool = False, ) -> None: # Initialize BLE UART Console diff --git a/tools/ble/ble_uart_bridge/src/console/console.py b/tools/ble/ble_uart_bridge/src/console/console.py index ffa8079689c..814da221f71 100644 --- a/tools/ble/ble_uart_bridge/src/console/console.py +++ b/tools/ble/ble_uart_bridge/src/console/console.py @@ -1,11 +1,11 @@ # SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - from __future__ import annotations import asyncio import codecs from enum import Enum +from typing import Union from loguru import logger from rich.highlighter import Highlighter @@ -22,6 +22,8 @@ from textual.widgets import Input from textual.widgets import Log from ..core import BLEUARTBridge +# Keep annotations compatible with Python 3.9. +# ruff: noqa: UP007 CONSOLE_TEXT_ENCODING = 'utf-8' @@ -93,8 +95,8 @@ class BLEUARTConsole(App): def __init__( self, device_id: str, - terminator: ConsoleTerminator | str = ConsoleTerminator.lf, - encoding: ConsoleEncoding | str = ConsoleEncoding.text, + terminator: Union[ConsoleTerminator, str] = ConsoleTerminator.lf, + encoding: Union[ConsoleEncoding, str] = ConsoleEncoding.text, with_response: bool = False, ) -> None: super().__init__() @@ -109,7 +111,7 @@ class BLEUARTConsole(App): self._ui_ready = False @staticmethod - def _parse_terminator(terminator: ConsoleTerminator | str) -> bytes: + def _parse_terminator(terminator: Union[ConsoleTerminator, str]) -> bytes: try: return TERMINATORS[ConsoleTerminator(terminator)] except ValueError: @@ -117,7 +119,7 @@ class BLEUARTConsole(App): raise ValueError(f'Unsupported terminator: {terminator}. Expected one of: {choices}') from None @staticmethod - def _parse_encoding(encoding: ConsoleEncoding | str) -> ConsoleEncoding: + def _parse_encoding(encoding: Union[ConsoleEncoding, str]) -> ConsoleEncoding: try: return ConsoleEncoding(encoding) except ValueError: diff --git a/tools/ble/ble_uart_bridge/src/daemon/api.py b/tools/ble/ble_uart_bridge/src/daemon/api.py index a2e5f2ea15e..7b107e6adae 100644 --- a/tools/ble/ble_uart_bridge/src/daemon/api.py +++ b/tools/ble/ble_uart_bridge/src/daemon/api.py @@ -1,8 +1,10 @@ # SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - +# Keep annotations compatible with Python 3.9. +# ruff: noqa: UP007 import json from typing import Any +from typing import Optional from urllib.error import HTTPError from urllib.error import URLError from urllib.request import Request @@ -20,7 +22,7 @@ def _daemon_url(host: str, port: int, path: str) -> str: def _request_json( method: str, url: str, - payload: dict[str, Any] | None = None, + payload: Optional[dict[str, Any]] = None, timeout: float = 10.0, ) -> dict[str, Any]: data = json.dumps(payload).encode() if payload is not None else None diff --git a/tools/ble/ble_uart_bridge/src/daemon/jsonl.py b/tools/ble/ble_uart_bridge/src/daemon/jsonl.py index 5e0702426dc..4f0ad3aa4b6 100644 --- a/tools/ble/ble_uart_bridge/src/daemon/jsonl.py +++ b/tools/ble/ble_uart_bridge/src/daemon/jsonl.py @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - import asyncio import json from json import JSONDecodeError diff --git a/tools/ble/ble_uart_bridge/src/daemon/models.py b/tools/ble/ble_uart_bridge/src/daemon/models.py index 99e8bce2d74..4d0d7045efd 100644 --- a/tools/ble/ble_uart_bridge/src/daemon/models.py +++ b/tools/ble/ble_uart_bridge/src/daemon/models.py @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - from typing import Any from pydantic import BaseModel diff --git a/tools/ble/ble_uart_bridge/src/daemon/server.py b/tools/ble/ble_uart_bridge/src/daemon/server.py index b4bb915c038..47b9bc0f036 100644 --- a/tools/ble/ble_uart_bridge/src/daemon/server.py +++ b/tools/ble/ble_uart_bridge/src/daemon/server.py @@ -1,10 +1,12 @@ # SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - +# Keep annotations compatible with Python 3.9. +# ruff: noqa: UP007 import asyncio import json from collections.abc import AsyncIterator from contextlib import asynccontextmanager +from typing import Optional from uuid import uuid4 from fastapi import FastAPI @@ -12,13 +14,13 @@ from fastapi import HTTPException from loguru import logger from ..core import BLEUARTBridge -from .jsonl import PROTOCOL_VERSION from .jsonl import drain_jsonl_messages from .jsonl import encode_jsonl_request +from .jsonl import PROTOCOL_VERSION from .jsonl import resolve_pending_response -from .models import MAX_REQUEST_DATA_BYTES from .models import BLEUARTNotifyPayload from .models import BLEUARTRequestPayload +from .models import MAX_REQUEST_DATA_BYTES @asynccontextmanager @@ -66,8 +68,8 @@ def _request_data_size(data: object) -> int: @app.get('/status') async def status() -> dict: - bridge: BLEUARTBridge | None = getattr(app.state, 'bridge', None) - pending_requests: dict | None = getattr(app.state, 'pending_requests', None) + bridge: Optional[BLEUARTBridge] = getattr(app.state, 'bridge', None) + pending_requests: Optional[dict] = getattr(app.state, 'pending_requests', None) return { 'device_id': getattr(app.state, 'device_id', None),