Files
banban/talkingq-url/banban/service/device_alarm.py
2026-06-08 14:10:34 +08:00

195 lines
6.0 KiB
Python

from collections.abc import Mapping
from typing import Any
from banban.dao.device_alarm import DeviceAlarmDAO
from banban.service.amap_geocode import amap_geocode_service
from services.task_manager import task_manager
from services.database_service_base import DatabaseServiceBase
from utils.logger import session_logger
ADDRESS_RESOLVE_PENDING = 0
ADDRESS_RESOLVE_SUCCESS = 1
ADDRESS_RESOLVE_FAILED = 2
class DeviceAlarmService(DatabaseServiceBase):
def __init__(self):
super().__init__(service_name="device_alarm_service")
async def record_alarm_event(
self,
*,
device_id: str,
source_msg_id: str = "010",
resolve_address: bool = True,
) -> int | None:
db_session = await self.get_session()
try:
dao = DeviceAlarmDAO(db_session)
binding = await dao.get_active_binding_context(device_id=device_id)
if not binding:
return None
child_id = int(binding["child_id"]) if binding.get("child_id") is not None else None
location = None
if child_id is not None:
location = await dao.get_current_location_snapshot(child_id=child_id)
alarm_id = await dao.create(
device_id=device_id,
owner_user_id=int(binding["owner_user_id"]) if binding.get("owner_user_id") is not None else None,
child_id=child_id,
source_msg_id=source_msg_id,
location=location,
)
if resolve_address and alarm_id and location and location.get("lat") is not None and location.get("lng") is not None:
await task_manager.create_task(
self.resolve_alarm_address(
alarm_id=alarm_id,
device_id=device_id,
lat=float(location["lat"]),
lng=float(location["lng"]),
),
device_id=device_id,
task_type="alarm_address",
)
return alarm_id
finally:
await db_session.close()
async def get_alarm_event(
self,
*,
alarm_id: int,
device_id: str | None = None,
) -> Mapping[str, Any] | None:
db_session = await self.get_session()
try:
dao = DeviceAlarmDAO(db_session)
return await dao.get_by_id(alarm_id=alarm_id, device_id=device_id)
finally:
await db_session.close()
async def update_alarm_location(
self,
*,
alarm_id: int,
location: Mapping[str, Any],
) -> bool:
db_session = await self.get_session()
try:
dao = DeviceAlarmDAO(db_session)
return await dao.update_location_snapshot(alarm_id=alarm_id, location=location)
finally:
await db_session.close()
async def apply_alarm_location(
self,
*,
alarm_id: int,
device_id: str,
location: Mapping[str, Any],
) -> bool:
if location.get("lat") is None or location.get("lng") is None:
return False
updated = await self.update_alarm_location(alarm_id=alarm_id, location=location)
if not updated:
return False
address = str(location.get("address") or "").strip()
if address:
await self.update_alarm_address(
alarm_id=alarm_id,
address=address,
status=ADDRESS_RESOLVE_SUCCESS,
)
return True
await self.resolve_alarm_address(
alarm_id=alarm_id,
device_id=device_id,
lat=float(location["lat"]),
lng=float(location["lng"]),
)
return True
async def resolve_alarm_current_location(self, *, alarm_id: int, device_id: str) -> bool:
alarm = await self.get_alarm_event(alarm_id=alarm_id, device_id=device_id)
if not alarm or alarm.get("lat") is None or alarm.get("lng") is None:
return False
await self.resolve_alarm_address(
alarm_id=alarm_id,
device_id=device_id,
lat=float(alarm["lat"]),
lng=float(alarm["lng"]),
)
return True
async def resolve_alarm_address(
self,
*,
alarm_id: int,
device_id: str,
lat: float,
lng: float,
) -> None:
try:
result = await amap_geocode_service.reverse_geocode(lng=lng, lat=lat)
except Exception as exc:
session_logger.warning(
device_id,
"alarm_address",
f"告警地址解析失败: alarm_id={alarm_id}, error={exc}",
)
await self.update_alarm_address(
alarm_id=alarm_id,
address=None,
status=ADDRESS_RESOLVE_FAILED,
)
return
await self.update_alarm_address(
alarm_id=alarm_id,
address=result.address,
status=ADDRESS_RESOLVE_SUCCESS,
)
async def update_alarm_address(
self,
*,
alarm_id: int,
address: str | None,
status: int,
) -> bool:
db_session = await self.get_session()
try:
dao = DeviceAlarmDAO(db_session)
return await dao.update_resolved_address(
alarm_id=alarm_id,
address=address,
status=status,
)
finally:
await db_session.close()
async def list_device_alarms(
self,
*,
device_id: str,
limit: int,
) -> list[Mapping[str, Any]]:
db_session = await self.get_session()
try:
dao = DeviceAlarmDAO(db_session)
return await dao.list_by_device(
device_id=device_id,
limit=limit,
)
finally:
await db_session.close()
device_alarm_service = DeviceAlarmService()