mirror of
https://github.com/home-assistant/core.git
synced 2026-06-30 19:26:31 +01:00
163 lines
5.1 KiB
Python
163 lines
5.1 KiB
Python
"""Support for collecting data from the ARWN project."""
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from arwn_client import parse_message
|
|
|
|
from homeassistant.components import mqtt
|
|
from homeassistant.components.sensor import (
|
|
SensorDeviceClass,
|
|
SensorEntity,
|
|
SensorStateClass,
|
|
)
|
|
from homeassistant.core import HomeAssistant, callback
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|
from homeassistant.util.json import json_loads_object
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
DOMAIN = "arwn"
|
|
DATA_ARWN = "arwn"
|
|
TOPIC = "arwn/#"
|
|
|
|
|
|
async def async_setup_platform(
|
|
hass: HomeAssistant,
|
|
config: ConfigType,
|
|
async_add_entities: AddEntitiesCallback,
|
|
discovery_info: DiscoveryInfoType | None = None,
|
|
) -> None:
|
|
"""Set up the ARWN platform."""
|
|
|
|
if not await mqtt.async_wait_for_mqtt_client(hass):
|
|
_LOGGER.error("MQTT integration is not available")
|
|
return
|
|
|
|
@callback
|
|
def async_sensor_event_received(msg: mqtt.ReceiveMessage) -> None:
|
|
"""Process MQTT events as sensors."""
|
|
try:
|
|
event = json_loads_object(msg.payload)
|
|
device = parse_message(msg.topic, event)
|
|
except Exception: # noqa: BLE001
|
|
_LOGGER.debug(
|
|
"Failed to parse ARWN message on topic %s",
|
|
msg.topic,
|
|
exc_info=True,
|
|
)
|
|
return
|
|
|
|
if device is None:
|
|
return
|
|
|
|
if (store := hass.data.get(DATA_ARWN)) is None:
|
|
store = hass.data[DATA_ARWN] = {}
|
|
|
|
if "timestamp" in event:
|
|
del event["timestamp"]
|
|
|
|
new_sensors: list[ArwnSensor] = []
|
|
for reading in device.readings:
|
|
if not reading.expose:
|
|
continue
|
|
|
|
unique_id = (
|
|
f"{msg.topic}/{reading.sensor_key}"
|
|
if len(device.readings) > 1
|
|
else msg.topic
|
|
)
|
|
|
|
try:
|
|
device_class = (
|
|
SensorDeviceClass(reading.device_class)
|
|
if reading.device_class
|
|
else None
|
|
)
|
|
except ValueError:
|
|
_LOGGER.debug(
|
|
"Unknown device_class=%s for sensor %s",
|
|
reading.device_class,
|
|
reading.sensor_name,
|
|
)
|
|
device_class = None
|
|
|
|
try:
|
|
state_class = (
|
|
SensorStateClass(reading.state_class)
|
|
if reading.state_class
|
|
else None
|
|
)
|
|
except ValueError:
|
|
_LOGGER.debug(
|
|
"Unknown state_class=%s for sensor %s",
|
|
reading.state_class,
|
|
reading.sensor_name,
|
|
)
|
|
state_class = None
|
|
|
|
if unique_id not in store:
|
|
sensor = ArwnSensor(
|
|
unique_id=unique_id,
|
|
name=reading.sensor_name,
|
|
state_key=reading.sensor_key,
|
|
units=reading.unit,
|
|
icon=reading.icon,
|
|
device_class=device_class,
|
|
state_class=state_class,
|
|
event=event,
|
|
)
|
|
store[unique_id] = sensor
|
|
_LOGGER.debug(
|
|
"Registering sensor %(name)s => %(event)s",
|
|
{"name": reading.sensor_name, "event": event},
|
|
)
|
|
new_sensors.append(sensor)
|
|
else:
|
|
_LOGGER.debug(
|
|
"Recording sensor %(name)s => %(event)s",
|
|
{"name": reading.sensor_name, "event": event},
|
|
)
|
|
store[unique_id].set_event(event)
|
|
|
|
if new_sensors:
|
|
async_add_entities(new_sensors, True)
|
|
|
|
await mqtt.async_subscribe(hass, TOPIC, async_sensor_event_received, 0)
|
|
|
|
|
|
class ArwnSensor(SensorEntity):
|
|
"""Representation of an ARWN sensor."""
|
|
|
|
_attr_should_poll = False
|
|
|
|
def __init__(
|
|
self,
|
|
unique_id: str,
|
|
name: str,
|
|
state_key: str,
|
|
units: str,
|
|
icon: str | None = None,
|
|
device_class: SensorDeviceClass | None = None,
|
|
state_class: SensorStateClass | None = None,
|
|
event: dict[str, Any] | None = None,
|
|
) -> None:
|
|
"""Initialize the sensor."""
|
|
self._attr_name = name
|
|
self._attr_unique_id = unique_id
|
|
self._state_key = state_key
|
|
self._attr_native_unit_of_measurement = units
|
|
self._attr_icon = icon
|
|
self._attr_device_class = device_class
|
|
self._attr_state_class = state_class
|
|
if event is not None:
|
|
self._attr_extra_state_attributes = dict(event)
|
|
self._attr_native_value = event.get(state_key)
|
|
|
|
def set_event(self, event: dict[str, Any]) -> None:
|
|
"""Update the sensor with the most recent event."""
|
|
self._attr_extra_state_attributes = dict(event)
|
|
self._attr_native_value = event.get(self._state_key)
|
|
self.async_write_ha_state()
|