处理OTA下发无回执超时

This commit is contained in:
stu2not
2026-06-16 11:36:33 +08:00
parent 5ef67d71f6
commit 9ae5bc8f83
2 changed files with 39 additions and 1 deletions

View File

@@ -1,5 +1,5 @@
from collections.abc import Mapping
from datetime import datetime, time, timedelta
from datetime import datetime, timezone, time, timedelta
from typing import Any, List, Literal
from services.database_service_base import DatabaseServiceBase
@@ -8,6 +8,7 @@ from fastapi import HTTPException
from banban.dao.device import DeviceDAO
from banban.service.device_setting import device_setting_service
from banban.service.ota_firmware import ota_firmware_service
from config import settings
from services.device_update_manager import device_firmware_update_manager
@@ -301,6 +302,29 @@ class DeviceService(DatabaseServiceBase):
latest_parts.extend([0] * (max_len - len(latest_parts)))
return latest_parts > current_parts
def _firmware_sent_timed_out(self, updated_at: Any) -> bool:
timeout_seconds = max(0, int(settings.ota_sent_timeout_seconds or 0))
if timeout_seconds <= 0 or not updated_at:
return False
if isinstance(updated_at, str):
text = updated_at.strip()
if not text:
return False
try:
updated_at = datetime.fromisoformat(text.replace("Z", "+00:00"))
except ValueError:
try:
updated_at = datetime.strptime(text, "%Y-%m-%d %H:%M:%S")
except ValueError:
return False
if not isinstance(updated_at, datetime):
return False
now = datetime.now(timezone.utc) if updated_at.tzinfo else datetime.now()
return (now - updated_at).total_seconds() >= timeout_seconds
async def get_firmware_status(
self,
*,
@@ -320,6 +344,18 @@ class DeviceService(DatabaseServiceBase):
progress = update_record.get("progress") if update_record else 0.0
target_version = update_record.get("firmware_version") if update_record else None
updated_at = update_record.get("updated_at") if update_record else None
if str(update_status or "").strip().lower() == "sent" and self._firmware_sent_timed_out(updated_at):
update_status = "failed"
progress = 0.0
await device_firmware_update_manager.update_firmware_update(
device_id=device_id,
firmware_version=target_version or latest_version or current_version or "unknown",
update_status="failed",
progress=0.0,
)
update_record = await device_firmware_update_manager.get_firmware_update_dict(device_id)
if update_record:
updated_at = update_record.get("updated_at") or updated_at
return {
"device_id": device_id,

View File

@@ -78,6 +78,8 @@ class Settings(BaseSettings):
talkingq_mqtt_keepalive: int = Field(default=60, validation_alias="TALKINGQ_MQTT_KEEPALIVE")
talkingq_mqtt_nfc_notice_interval: int = Field(default=600, validation_alias="TALKINGQ_MQTT_NFC_NOTICE_INTERVAL")
ota_sent_timeout_seconds: int = Field(default=300, validation_alias="OTA_SENT_TIMEOUT_SECONDS")
admin_api_key: str = Field(default="", validation_alias="ADMIN_API_KEY")
client_api_key: str = Field(default="", validation_alias="CLIENT_API_KEY")