Files
ha-text-ai/custom_components/ha_text_ai/sensor.py
T

139 lines
4.8 KiB
Python
Raw Normal View History

2024-11-18 00:43:28 +03:00
"""Sensor platform for HA text AI."""
2024-11-19 12:45:26 +03:00
from datetime import datetime
import logging
2024-11-18 00:43:28 +03:00
from typing import Any, Callable, Dict, Optional
2024-11-19 12:45:26 +03:00
from homeassistant.components.sensor import (
SensorEntity,
SensorStateClass,
SensorDeviceClass,
)
2024-11-18 00:43:28 +03:00
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
2024-11-19 14:00:33 +03:00
from homeassistant.util import dt as dt_util
2024-11-18 00:43:28 +03:00
2024-11-19 14:00:33 +03:00
from .const import (
DOMAIN,
ATTR_QUESTION,
ATTR_RESPONSE,
ATTR_LAST_UPDATED,
ATTR_MODEL,
ATTR_TEMPERATURE,
ATTR_MAX_TOKENS,
ATTR_TOTAL_RESPONSES,
)
2024-11-18 00:43:28 +03:00
from .coordinator import HATextAICoordinator
2024-11-19 12:45:26 +03:00
_LOGGER = logging.getLogger(__name__)
2024-11-18 00:43:28 +03:00
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the HA text AI sensor."""
coordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities([HATextAISensor(coordinator, entry)], True)
class HATextAISensor(CoordinatorEntity, SensorEntity):
"""HA text AI Sensor."""
2024-11-19 12:45:26 +03:00
_attr_has_entity_name = True
_attr_state_class = SensorStateClass.MEASUREMENT
_attr_device_class = SensorDeviceClass.TIMESTAMP
_attr_icon = "mdi:robot"
2024-11-18 00:43:28 +03:00
def __init__(
self,
coordinator: HATextAICoordinator,
config_entry: ConfigEntry,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator)
self._config_entry = config_entry
self._attr_unique_id = f"{config_entry.entry_id}"
2024-11-19 12:45:26 +03:00
self._attr_name = "Last Response"
2024-11-19 14:00:33 +03:00
self._attr_suggested_display_precision = 0
2024-11-18 00:43:28 +03:00
2024-11-18 02:02:36 +03:00
@property
def state(self) -> StateType:
"""Return the state of the sensor."""
2024-11-19 14:00:33 +03:00
if not self.coordinator.data or not self.coordinator.last_update_success_time:
2024-11-19 12:45:26 +03:00
return None
2024-11-19 14:00:33 +03:00
# Convert to local time
if isinstance(self.coordinator.last_update_success_time, datetime):
return dt_util.as_local(self.coordinator.last_update_success_time)
2024-11-19 12:45:26 +03:00
return self.coordinator.last_update_success_time
2024-11-18 02:02:36 +03:00
@property
def extra_state_attributes(self) -> Optional[Dict[str, Any]]:
"""Return entity specific state attributes."""
if not self.coordinator.data:
2024-11-19 14:00:33 +03:00
return {
ATTR_TOTAL_RESPONSES: 0,
ATTR_MODEL: self.coordinator.model,
ATTR_TEMPERATURE: self.coordinator.temperature,
ATTR_MAX_TOKENS: self.coordinator.max_tokens,
}
2024-11-19 12:45:26 +03:00
try:
history = list(self.coordinator.data.items())
if not history:
2024-11-19 14:00:33 +03:00
return {
ATTR_TOTAL_RESPONSES: 0,
ATTR_MODEL: self.coordinator.model,
ATTR_TEMPERATURE: self.coordinator.temperature,
ATTR_MAX_TOKENS: self.coordinator.max_tokens,
}
2024-11-19 12:45:26 +03:00
last_question, last_data = history[-1]
2024-11-19 14:00:33 +03:00
# Handle different response formats
2024-11-19 12:45:26 +03:00
if isinstance(last_data, dict):
last_response = last_data.get("response", "")
2024-11-19 14:00:33 +03:00
last_updated = last_data.get("timestamp", self.coordinator.last_update_success_time)
2024-11-19 12:45:26 +03:00
else:
last_response = str(last_data)
2024-11-19 14:00:33 +03:00
last_updated = self.coordinator.last_update_success_time
# Convert timestamp to local time if needed
if isinstance(last_updated, datetime):
last_updated = dt_util.as_local(last_updated)
2024-11-19 12:45:26 +03:00
return {
ATTR_QUESTION: last_question,
ATTR_RESPONSE: last_response,
2024-11-19 14:00:33 +03:00
ATTR_LAST_UPDATED: last_updated,
ATTR_TOTAL_RESPONSES: len(history),
ATTR_MODEL: self.coordinator.model,
ATTR_TEMPERATURE: self.coordinator.temperature,
ATTR_MAX_TOKENS: self.coordinator.max_tokens,
}
except Exception as err:
_LOGGER.error("Error getting attributes: %s", err, exc_info=True)
return {
ATTR_TOTAL_RESPONSES: 0,
ATTR_MODEL: self.coordinator.model,
ATTR_TEMPERATURE: self.coordinator.temperature,
ATTR_MAX_TOKENS: self.coordinator.max_tokens,
2024-11-19 12:45:26 +03:00
}
@property
def available(self) -> bool:
"""Return if entity is available."""
return self.coordinator.last_update_success
@property
def should_poll(self) -> bool:
"""No need to poll. Coordinator notifies entity of updates."""
return False
2024-11-19 14:00:33 +03:00
async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
self._handle_coordinator_update()