2025-09-07 21:48:21 +08:00
|
|
|
"""传感器实体"""
|
|
|
|
|
|
|
|
|
|
import logging
|
2026-05-01 23:14:39 +08:00
|
|
|
from typing import Dict, Any, Optional, List
|
2025-09-07 21:48:21 +08:00
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
|
|
|
|
|
from homeassistant.components.sensor import SensorEntity
|
|
|
|
|
from homeassistant.config_entries import ConfigEntry
|
|
|
|
|
from homeassistant.const import CONF_NAME
|
|
|
|
|
from homeassistant.core import HomeAssistant, callback
|
|
|
|
|
from homeassistant.helpers.entity import EntityCategory
|
|
|
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
2026-05-01 23:14:39 +08:00
|
|
|
from homeassistant.helpers.update_coordinator import (
|
|
|
|
|
CoordinatorEntity,
|
|
|
|
|
DataUpdateCoordinator,
|
|
|
|
|
UpdateFailed,
|
|
|
|
|
)
|
2025-09-07 21:48:21 +08:00
|
|
|
|
2026-05-01 23:14:39 +08:00
|
|
|
from .const import (
|
|
|
|
|
DOMAIN,
|
|
|
|
|
CONF_PERSON_GROUP_ID,
|
|
|
|
|
DEFAULT_PERSON_GROUP_ID,
|
|
|
|
|
get_entry_value,
|
|
|
|
|
)
|
2025-09-07 21:48:21 +08:00
|
|
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
2026-05-01 23:14:39 +08:00
|
|
|
_LOGGER_POLLING = _LOGGER.getChild("polling")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TencentFaceCoordinator(DataUpdateCoordinator):
|
|
|
|
|
"""腾讯云人脸识别数据更新协调器"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, hass: HomeAssistant, entry: ConfigEntry, client):
|
|
|
|
|
super().__init__(
|
|
|
|
|
hass,
|
|
|
|
|
_LOGGER_POLLING,
|
|
|
|
|
name="Tencent Face Recognition",
|
|
|
|
|
update_interval=timedelta(minutes=5),
|
|
|
|
|
)
|
|
|
|
|
self.client = client
|
|
|
|
|
self.entry = entry
|
|
|
|
|
|
|
|
|
|
async def _async_update_data(self):
|
|
|
|
|
"""获取最新数据"""
|
|
|
|
|
try:
|
|
|
|
|
group_id = get_entry_value(
|
|
|
|
|
self.entry, CONF_PERSON_GROUP_ID, DEFAULT_PERSON_GROUP_ID
|
|
|
|
|
)
|
|
|
|
|
|
2026-05-02 00:18:57 +08:00
|
|
|
group_result = await self.hass.async_add_executor_job(
|
2026-05-01 23:14:39 +08:00
|
|
|
self.client.get_group_info, group_id
|
|
|
|
|
)
|
2026-05-02 00:18:57 +08:00
|
|
|
group_info = group_result if group_result.get("success", False) else {}
|
2026-05-01 23:14:39 +08:00
|
|
|
|
2026-05-02 00:18:57 +08:00
|
|
|
persons_result = await self.hass.async_add_executor_job(
|
2026-05-01 23:14:39 +08:00
|
|
|
self.client.get_person_list_all, group_id
|
|
|
|
|
)
|
2026-05-02 00:18:57 +08:00
|
|
|
persons = persons_result.get("persons", []) if persons_result.get("success", False) else []
|
2026-05-01 23:14:39 +08:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
"group_info": group_info,
|
|
|
|
|
"persons": persons,
|
|
|
|
|
"person_count": len(persons),
|
|
|
|
|
}
|
|
|
|
|
except Exception as ex:
|
|
|
|
|
_LOGGER_POLLING.debug("数据更新失败: %s", ex)
|
|
|
|
|
raise UpdateFailed(f"数据更新失败: {ex}") from ex
|
2025-09-07 21:48:21 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
async def async_setup_entry(
|
|
|
|
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
|
|
|
|
) -> None:
|
|
|
|
|
"""设置传感器实体"""
|
|
|
|
|
_LOGGER.debug("设置腾讯云人脸识别传感器实体")
|
|
|
|
|
|
|
|
|
|
client = hass.data[DOMAIN][entry.entry_id]["client"]
|
2026-05-01 23:14:39 +08:00
|
|
|
name = entry.data.get(CONF_NAME, "腾讯云人脸识别")
|
|
|
|
|
|
|
|
|
|
coordinator = TencentFaceCoordinator(hass, entry, client)
|
|
|
|
|
|
|
|
|
|
await coordinator.async_config_entry_first_refresh()
|
|
|
|
|
|
|
|
|
|
hass.data[DOMAIN][entry.entry_id]["coordinator"] = coordinator
|
|
|
|
|
|
|
|
|
|
entities = [
|
|
|
|
|
TencentFaceRecognitionStatusSensor(coordinator, entry, name),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
for person in coordinator.data.get("persons", []):
|
|
|
|
|
entities.append(
|
|
|
|
|
TencentFaceRecognitionPersonSensor(coordinator, entry, person)
|
2025-09-07 21:48:21 +08:00
|
|
|
)
|
2026-05-01 23:14:39 +08:00
|
|
|
|
|
|
|
|
async_add_entities(entities)
|
2025-09-07 21:48:21 +08:00
|
|
|
|
|
|
|
|
|
2026-05-01 23:14:39 +08:00
|
|
|
class TencentFaceRecognitionPersonSensor(CoordinatorEntity, SensorEntity):
|
2025-09-07 21:48:21 +08:00
|
|
|
"""腾讯云人脸识别人员传感器"""
|
|
|
|
|
|
|
|
|
|
_attr_icon = "mdi:account"
|
2026-05-01 23:14:39 +08:00
|
|
|
_attr_has_entity_name = True
|
2025-09-07 21:48:21 +08:00
|
|
|
|
2026-05-01 23:14:39 +08:00
|
|
|
def __init__(self, coordinator, entry: ConfigEntry, person: Dict[str, Any]):
|
2025-09-07 21:48:21 +08:00
|
|
|
"""初始化传感器"""
|
2026-05-01 23:14:39 +08:00
|
|
|
super().__init__(coordinator)
|
2025-09-07 21:48:21 +08:00
|
|
|
self._entry = entry
|
2026-05-01 23:14:39 +08:00
|
|
|
self._person_id = person.get("person_id")
|
|
|
|
|
person_name = person.get("person_name", "未知人员")
|
|
|
|
|
self._attr_name = person_name
|
|
|
|
|
self._attr_unique_id = f"{entry.entry_id}_{self._person_id}"
|
|
|
|
|
self._attr_translation_key = "person_sensor"
|
2025-09-07 21:48:21 +08:00
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def state(self) -> str:
|
|
|
|
|
"""返回传感器状态"""
|
2026-05-01 23:14:39 +08:00
|
|
|
if self.coordinator.data is None:
|
|
|
|
|
return "未知"
|
|
|
|
|
for person in self.coordinator.data.get("persons", []):
|
|
|
|
|
if person.get("person_id") == self._person_id:
|
|
|
|
|
return person.get("person_name", "未知")
|
|
|
|
|
return "已删除"
|
2025-09-07 21:48:21 +08:00
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def extra_state_attributes(self) -> Dict[str, Any]:
|
|
|
|
|
"""返回传感器属性"""
|
2026-05-01 23:14:39 +08:00
|
|
|
if self.coordinator.data is None:
|
|
|
|
|
return {"person_id": self._person_id}
|
|
|
|
|
|
|
|
|
|
for person in self.coordinator.data.get("persons", []):
|
|
|
|
|
if person.get("person_id") == self._person_id:
|
|
|
|
|
return {
|
|
|
|
|
"person_id": person.get("person_id"),
|
|
|
|
|
"gender": "男" if person.get("gender") == 1 else "女",
|
|
|
|
|
"face_ids": person.get("face_ids"),
|
|
|
|
|
"face_count": len(person.get("face_ids", [])),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {"person_id": self._person_id, "status": "已删除"}
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def available(self) -> bool:
|
|
|
|
|
"""传感器是否可用"""
|
|
|
|
|
if self.coordinator.data is None:
|
|
|
|
|
return False
|
|
|
|
|
for person in self.coordinator.data.get("persons", []):
|
|
|
|
|
if person.get("person_id") == self._person_id:
|
|
|
|
|
return True
|
|
|
|
|
return False
|
2025-09-07 21:48:21 +08:00
|
|
|
|
|
|
|
|
|
2026-05-01 23:14:39 +08:00
|
|
|
class TencentFaceRecognitionStatusSensor(CoordinatorEntity, SensorEntity):
|
2025-09-07 21:48:21 +08:00
|
|
|
"""腾讯云人脸识别状态传感器"""
|
|
|
|
|
|
|
|
|
|
_attr_icon = "mdi:face-recognition"
|
|
|
|
|
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
2026-05-01 23:14:39 +08:00
|
|
|
_attr_has_entity_name = True
|
|
|
|
|
_attr_translation_key = "status_sensor"
|
2025-09-07 21:48:21 +08:00
|
|
|
|
2026-05-01 23:14:39 +08:00
|
|
|
def __init__(self, coordinator, entry: ConfigEntry, name: str):
|
2025-09-07 21:48:21 +08:00
|
|
|
"""初始化传感器"""
|
2026-05-01 23:14:39 +08:00
|
|
|
super().__init__(coordinator)
|
2025-09-07 21:48:21 +08:00
|
|
|
self._entry = entry
|
|
|
|
|
self._name = name
|
|
|
|
|
self._attr_name = f"{name} 状态"
|
|
|
|
|
self._attr_unique_id = f"{entry.entry_id}_status"
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def state(self) -> str:
|
|
|
|
|
"""返回传感器状态"""
|
2026-05-01 23:14:39 +08:00
|
|
|
if self.coordinator.data is None:
|
|
|
|
|
return "未连接"
|
|
|
|
|
if self.coordinator.last_update_success:
|
|
|
|
|
return "已连接"
|
|
|
|
|
return "连接错误"
|
2025-09-07 21:48:21 +08:00
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def extra_state_attributes(self) -> Dict[str, Any]:
|
|
|
|
|
"""返回传感器属性"""
|
2026-05-01 23:14:39 +08:00
|
|
|
attrs = {
|
|
|
|
|
"last_updated": (
|
|
|
|
|
self.coordinator.data.get("last_updated")
|
|
|
|
|
if self.coordinator.data
|
|
|
|
|
else None
|
|
|
|
|
),
|
|
|
|
|
"api_status": "正常" if self.coordinator.last_update_success else "错误",
|
|
|
|
|
"person_count": (
|
|
|
|
|
self.coordinator.data.get("person_count", 0)
|
|
|
|
|
if self.coordinator.data
|
|
|
|
|
else 0
|
|
|
|
|
),
|
|
|
|
|
"last_error": None,
|
|
|
|
|
}
|
2025-09-07 21:48:21 +08:00
|
|
|
|
2026-05-01 23:14:39 +08:00
|
|
|
if self.coordinator.data and self.coordinator.data.get("group_info"):
|
|
|
|
|
group_info = self.coordinator.data["group_info"]
|
|
|
|
|
attrs["group_name"] = group_info.get("group_name", "")
|
|
|
|
|
attrs["face_model_version"] = group_info.get("face_model_version", "")
|
2025-09-07 21:48:21 +08:00
|
|
|
|
2026-05-01 23:14:39 +08:00
|
|
|
return attrs
|
2025-09-07 21:48:21 +08:00
|
|
|
|
2026-05-01 23:14:39 +08:00
|
|
|
@property
|
|
|
|
|
def available(self) -> bool:
|
|
|
|
|
"""状态传感器始终可用"""
|
|
|
|
|
return True
|