195 lines
6.0 KiB
Python
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()
|