plate-config-app/app/services/firmware_service.py
Danil Iarosh add8aff0af feat: release version 2.0.0
- Добавлена обратная совместимость с прошивками, содержащими маркер no_auth.

- Повторная авторизация после команды 04 и успешного обновления прошивки приведена к требуемому порядку.

- В терминал команд добавлена ручная кнопка авторизации.

- Реализовано OTA-обновление приложения с загрузкой платформенного артефакта, безопасной заменой и перезапуском.

- Проверка обновлений учитывает только более новые версии по схеме major, minor и patch.

- Обновлены имена Windows и Linux сборок, документация и тестовое покрытие.
2026-09-16 10:01:35 +03:00

101 lines
3.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Запуск OTA с повторной авторизацией после обновления контроллера."""
from __future__ import annotations
import time
from collections.abc import Callable
from dataclasses import dataclass
from .auth_service import (
AuthResult,
AuthStatus,
READY_TIMEOUT_SECONDS,
STARTUP_BANNER_TIMEOUT_SECONDS,
STARTUP_DELAY_SECONDS,
perform_startup_handshake,
)
from .com_service import ComConnection
OTA_TIMEOUT_SECONDS = 60.0
@dataclass
class FirmwareUpdateResult:
success: bool
detail: str
post_auth: AuthResult | None = None
def perform_authenticated_ota(
conn: ComConnection,
*,
log_message: Callable[[str], None] | None = None,
ota_timeout: float = OTA_TIMEOUT_SECONDS,
banner_timeout: float = STARTUP_BANNER_TIMEOUT_SECONDS,
startup_delay: float = STARTUP_DELAY_SECONDS,
handshake_timeout: float = 2.0,
ready_timeout: float = READY_TIMEOUT_SECONDS,
sleep_fn: Callable[[float], None] = time.sleep,
) -> FirmwareUpdateResult:
"""Выполнить ``04`` и полностью авторизоваться после успешного OTA."""
emit = log_message or (lambda _message: None)
if not conn.is_connected:
return FirmwareUpdateResult(False, "Порт не подключён")
try:
conn.send_command("04")
emit("→ 04")
deadline = time.monotonic() + ota_timeout
update_confirmed = False
while time.monotonic() < deadline and conn.is_connected:
remaining = max(deadline - time.monotonic(), 0.1)
response = conn.read_response(timeout=min(remaining, 2.0))
if response is None:
continue
emit(f"← {response}")
if "successful update" in response.lower():
update_confirmed = True
break
if not update_confirmed:
return FirmwareUpdateResult(
False,
"Таймаут ожидания подтверждения успешного обновления",
)
emit("✓ Обновление подтверждено. Ожидание перезагрузки платы…")
post_auth = perform_startup_handshake(
conn,
banner_timeout=banner_timeout,
startup_delay=startup_delay,
handshake_timeout=handshake_timeout,
ready_timeout=ready_timeout,
sleep_fn=sleep_fn,
)
if post_auth.status != AuthStatus.OK:
return FirmwareUpdateResult(
False,
f"Авторизация после OTA не выполнена: {post_auth.detail}",
post_auth=post_auth,
)
if post_auth.auth_skipped:
emit("✓ Прошивка no_auth: авторизация после OTA не требуется.")
detail = "Прошивка обновлена, плата готова без авторизации"
else:
emit("✓ Авторизация после OTA выполнена.")
detail = "Прошивка обновлена, плата перезагружена и авторизована"
return FirmwareUpdateResult(
True,
detail,
post_auth=post_auth,
)
except Exception as exc:
return FirmwareUpdateResult(
False,
f"Ошибка OTA: {exc}",
)
finally:
conn.release()