处理OTA下发无回执超时
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user