226 lines
6.7 KiB
Python
226 lines
6.7 KiB
Python
import logging
|
|
|
|
from homeassistant.const import ATTR_ATTRIBUTION, CONF_NAME, DEGREE, UnitOfLength
|
|
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity, SensorStateClass
|
|
from homeassistant.helpers.device_registry import DeviceEntryType
|
|
|
|
from .const import (
|
|
ATTR_LAT,
|
|
ATTR_LIGHTNING_AZIMUTH,
|
|
ATTR_LIGHTNING_COUNTER,
|
|
ATTR_LON,
|
|
ATTRIBUTION,
|
|
DOMAIN,
|
|
SERVER_STATS,
|
|
SW_VERSION,
|
|
)
|
|
|
|
ATTR_ICON = "icon"
|
|
ATTR_LABEL = "label"
|
|
ATTR_UNIT = "unit"
|
|
ATTR_LIGHTNING_PROPERTY = "lightning_prop"
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
|
integration_name = config_entry.data[CONF_NAME]
|
|
|
|
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
|
|
|
unique_prefix = config_entry.unique_id
|
|
|
|
sensors = [
|
|
klass(coordinator, integration_name, unique_prefix)
|
|
for klass in (DistanceSensor, AzimuthSensor, CounterSensor)
|
|
]
|
|
|
|
async_add_entities(sensors, False)
|
|
|
|
config = hass.data[DOMAIN].get("config") or {}
|
|
if config.get(SERVER_STATS):
|
|
server_stat_sensors = {}
|
|
|
|
def on_message(message):
|
|
if not message.topic.startswith("$SYS/broker/"):
|
|
return
|
|
topic = message.topic.replace("$SYS/broker/", "")
|
|
if topic.startswith("load") and not topic.endswith("/1min"):
|
|
return
|
|
if topic.startswith("clients") and topic != "clients/connected":
|
|
return
|
|
sensor = server_stat_sensors.get(topic)
|
|
if not sensor:
|
|
sensor = ServerStatSensor(
|
|
topic, coordinator, integration_name, unique_prefix
|
|
)
|
|
server_stat_sensors[topic] = sensor
|
|
async_add_entities([sensor], False)
|
|
sensor.on_message(topic, message)
|
|
|
|
coordinator.register_message_receiver(on_message)
|
|
|
|
|
|
class BlitzortungSensor(SensorEntity):
|
|
"""Define a Blitzortung sensor."""
|
|
|
|
def __init__(self, coordinator, integration_name, unique_prefix):
|
|
"""Initialize."""
|
|
self.coordinator = coordinator
|
|
self._integration_name = integration_name
|
|
self.entity_id = f"sensor.{integration_name}-{self.name}"
|
|
self._unique_id = f"{unique_prefix}-{self.kind}"
|
|
self._device_class = None
|
|
self._attrs = {ATTR_ATTRIBUTION: ATTRIBUTION}
|
|
|
|
should_poll = False
|
|
icon = "mdi:flash"
|
|
device_class = None
|
|
|
|
@property
|
|
def available(self):
|
|
return self.coordinator.is_connected
|
|
|
|
@property
|
|
def label(self):
|
|
return self.kind.capitalize()
|
|
|
|
@property
|
|
def name(self):
|
|
"""Return the name."""
|
|
return f"Lightning {self.label}"
|
|
|
|
@property
|
|
def extra_state_attributes(self):
|
|
"""Return the state attributes."""
|
|
return self._attrs
|
|
|
|
@property
|
|
def unique_id(self):
|
|
"""Return a unique_id for this entity."""
|
|
return self._unique_id
|
|
|
|
async def async_added_to_hass(self):
|
|
"""Connect to dispatcher listening for entity data notifications."""
|
|
# self.async_on_remove(self.coordinator.async_add_listener(self._update_sensor))
|
|
self.coordinator.register_sensor(self)
|
|
|
|
async def async_update(self):
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
@property
|
|
def device_info(self):
|
|
return {
|
|
"name": f"{self._integration_name} Lightning Detector",
|
|
"identifiers": {(DOMAIN, self._integration_name)},
|
|
"model": "Lightning Detector",
|
|
"sw_version": SW_VERSION,
|
|
"entry_type": DeviceEntryType.SERVICE,
|
|
}
|
|
|
|
def update_lightning(self, lightning):
|
|
pass
|
|
|
|
def on_message(self, message):
|
|
pass
|
|
|
|
def tick(self):
|
|
pass
|
|
|
|
|
|
class LightningSensor(BlitzortungSensor):
|
|
INITIAL_STATE = None
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self._attr_native_value = self.INITIAL_STATE
|
|
|
|
def tick(self):
|
|
if self._attr_native_value != self.INITIAL_STATE and self.coordinator.is_inactive:
|
|
self._attr_native_value = self.INITIAL_STATE
|
|
self.async_write_ha_state()
|
|
|
|
|
|
class DistanceSensor(LightningSensor):
|
|
kind = SensorDeviceClass.DISTANCE
|
|
device_class = SensorDeviceClass.DISTANCE
|
|
state_class = SensorStateClass.MEASUREMENT
|
|
_attr_native_unit_of_measurement = UnitOfLength.KILOMETERS
|
|
|
|
def update_lightning(self, lightning):
|
|
self._attr_native_value = lightning["distance"]
|
|
self._attrs[ATTR_LAT] = lightning[ATTR_LAT]
|
|
self._attrs[ATTR_LON] = lightning[ATTR_LON]
|
|
self.async_write_ha_state()
|
|
|
|
|
|
class AzimuthSensor(LightningSensor):
|
|
kind = ATTR_LIGHTNING_AZIMUTH
|
|
_attr_native_unit_of_measurement = DEGREE
|
|
|
|
def update_lightning(self, lightning):
|
|
self._attr_native_value = lightning["azimuth"]
|
|
self._attrs[ATTR_LAT] = lightning[ATTR_LAT]
|
|
self._attrs[ATTR_LON] = lightning[ATTR_LON]
|
|
self.async_write_ha_state()
|
|
|
|
|
|
class CounterSensor(LightningSensor):
|
|
kind = ATTR_LIGHTNING_COUNTER
|
|
_attr_native_unit_of_measurement = "↯"
|
|
INITIAL_STATE = 0
|
|
|
|
def update_lightning(self, lightning):
|
|
self._attr_native_value = self._attr_native_value + 1
|
|
self.async_write_ha_state()
|
|
|
|
|
|
class ServerStatSensor(BlitzortungSensor):
|
|
def __init__(self, topic, coordinator, integration_name, unique_prefix):
|
|
self._topic = topic
|
|
|
|
topic_parts = topic.replace("$SYS/broker/", "").split("/")
|
|
self.kind = "_".join(topic_parts)
|
|
if self.kind.startswith("load"):
|
|
self.data_type = float
|
|
elif self.kind in ("uptime", "version"):
|
|
self.data_type = str
|
|
else:
|
|
self.data_type = int
|
|
|
|
if self.kind == "clients_connected":
|
|
self.kind = "server_stats"
|
|
|
|
self._name = " ".join(part.capitalize() for part in topic_parts)
|
|
|
|
super().__init__(coordinator, integration_name, unique_prefix)
|
|
|
|
@property
|
|
def unit_of_measurement(self):
|
|
if self.data_type in (int, float):
|
|
return "." if self.kind == "server_stats" else " "
|
|
else:
|
|
return None
|
|
|
|
@classmethod
|
|
def for_topic(cls, topic, coordinator, integration_name, unique_prefix):
|
|
return cls(topic, coordinator, integration_name, unique_prefix)
|
|
|
|
def on_message(self, topic, message):
|
|
if topic == self._topic:
|
|
payload = message.payload.decode("utf-8")
|
|
try:
|
|
self._attr_native_value = self.data_type(payload)
|
|
except ValueError:
|
|
self._attr_native_value = str(payload)
|
|
if self.hass:
|
|
self.async_write_ha_state()
|
|
|
|
@property
|
|
def label(self):
|
|
return self._name
|
|
|
|
@property
|
|
def name(self):
|
|
return self._name
|