Skip to content

Commit

Permalink
Merge pull request #228 from gjohansson-ST/gj-20241113-3
Browse files Browse the repository at this point in the history
Improve naming and binary sensor entity description
  • Loading branch information
gjohansson-ST authored Nov 13, 2024
2 parents 2568e65 + cb037ca commit b560629
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 136 deletions.
6 changes: 3 additions & 3 deletions custom_components/sector/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ class SectorAlarmControlPanel(SectorAlarmBaseEntity, AlarmControlPanelEntity):
def __init__(self, coordinator: SectorDataUpdateCoordinator) -> None:
"""Initialize the control panel."""
panel_status = coordinator.data.get("panel_status", {})
serial_no = panel_status.get("SerialNo") or coordinator.config_entry.data.get(
"panel_id"
serial_no = (
panel_status.get("SerialNo") or coordinator.config_entry.data["panel_id"]
)
super().__init__(coordinator, serial_no, {"name": "Sector Alarm Panel"})
super().__init__(coordinator, serial_no, "Sector Alarm Panel", "Alarm panel")

self._attr_unique_id = f"{self._serial_no}_alarm_panel"
_LOGGER.debug(
Expand Down
183 changes: 90 additions & 93 deletions custom_components/sector/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,46 @@
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .coordinator import SectorAlarmConfigEntry
from .coordinator import SectorAlarmConfigEntry, SectorDataUpdateCoordinator
from .entity import SectorAlarmBaseEntity

_LOGGER = logging.getLogger(__name__)


BINARY_SENSOR_TYPES: tuple[BinarySensorEntityDescription, ...] = (
BinarySensorEntityDescription(
key="low_battery",
name="Low battery",
device_class=BinarySensorDeviceClass.BATTERY,
),
BinarySensorEntityDescription(
key="closed",
name="Closed",
device_class=BinarySensorDeviceClass.DOOR,
),
BinarySensorEntityDescription(
key="leak_detected",
name="Leak detected",
device_class=BinarySensorDeviceClass.MOISTURE,
),
BinarySensorEntityDescription(
key="alarm",
name="Alarm",
device_class=BinarySensorDeviceClass.SAFETY,
),
BinarySensorEntityDescription(
key="online",
name="Online",
device_class=BinarySensorDeviceClass.CONNECTIVITY,
),
)


async def async_setup_entry(
hass: HomeAssistant,
entry: SectorAlarmConfigEntry,
Expand All @@ -27,48 +57,57 @@ async def async_setup_entry(
coordinator = entry.runtime_data
await coordinator.async_refresh()
devices: dict[str, Any] = coordinator.data.get("devices", {})
entities: list[SectorAlarmBinarySensor] = []
entities: list[
SectorAlarmBinarySensor
| SectorAlarmPanelOnlineBinarySensor
| SectorAlarmClosedSensor
] = []

for device in devices.values():
serial_no = device["serial_no"]
sensors = device.get("sensors", {})
device_info = {
"name": device.get("name", "Unknown Device"),
"model": device.get("model", ""),
}

if "low_battery" in sensors:
entities.append(
SectorAlarmLowBatterySensor(coordinator, serial_no, device_info)
)
_LOGGER.debug("Added low battery sensor for device %s", serial_no)

if "closed" in sensors:
entities.append(
SectorAlarmClosedSensor(coordinator, serial_no, device_info)
)
_LOGGER.debug("Added closed sensor for device %s", serial_no)

if "leak_detected" in sensors:
entities.append(SectorAlarmLeakSensor(coordinator, serial_no, device_info))
_LOGGER.debug("Added leak detected sensor for device %s", serial_no)

if "alarm" in sensors:
entities.append(SectorAlarmAlarmSensor(coordinator, serial_no, device_info))
_LOGGER.debug("Added alarm sensor for device %s", serial_no)

# Add panel online status sensor
panel_status = coordinator.data.get("panel_status", {})
panel_id = entry.data.get("panel_id")
serial_no = panel_status.get("SerialNo") or panel_id
entities.append(
SectorAlarmPanelOnlineBinarySensor(
coordinator,
serial_no,
"online",
BinarySensorDeviceClass.CONNECTIVITY,
)
)

for device in devices.values():
serial_no = device["serial_no"]
sensors = device.get("sensors", {})
device_name = device.get("name", "Unknown Device")
device_model = device.get("model", "")

for description in BINARY_SENSOR_TYPES:
if description.key == "online":
entities.append(
SectorAlarmPanelOnlineBinarySensor(
coordinator,
serial_no,
description,
device_name,
device_model,
)
)
continue

if description.key in sensors:
if "closed" in sensors:
entities.append(
SectorAlarmClosedSensor(
coordinator,
serial_no,
description,
device_name,
device_model,
)
)
_LOGGER.debug("Added closed sensor for device %s", serial_no)
continue

entities.append(
SectorAlarmBinarySensor(
coordinator, serial_no, description, device_name, device_model
)
)
_LOGGER.debug(
"Added %s sensor for device %s", description.name, serial_no
)

if entities:
async_add_entities(entities)
Expand All @@ -79,15 +118,20 @@ async def async_setup_entry(
class SectorAlarmBinarySensor(SectorAlarmBaseEntity, BinarySensorEntity):
"""Base class for a Sector Alarm binary sensor."""

entity_description: BinarySensorEntityDescription

def __init__(
self, coordinator, serial_no, device_info, sensor_type, device_class
self,
coordinator: SectorDataUpdateCoordinator,
serial_no: str,
entity_description: BinarySensorEntityDescription,
device_name: str,
device_model: str,
) -> None:
"""Initialize the sensor with device info."""
super().__init__(coordinator, serial_no, device_info)
self._sensor_type = sensor_type
self._attr_device_class = device_class
self._attr_unique_id = f"{serial_no}_{sensor_type}"
self._attr_name = f"{sensor_type.replace('_', ' ').capitalize()}"
super().__init__(coordinator, serial_no, device_name, device_model)
self._sensor_type = entity_description.key
self._attr_unique_id = f"{serial_no}_{entity_description.key}"

@property
def is_on(self) -> bool:
Expand All @@ -99,66 +143,19 @@ def is_on(self) -> bool:
return False


class SectorAlarmLowBatterySensor(SectorAlarmBinarySensor):
"""Binary sensor for detecting low battery status."""

def __init__(self, coordinator, serial_no, device_info) -> None:
super().__init__(
coordinator,
serial_no,
device_info,
"low_battery",
BinarySensorDeviceClass.BATTERY,
)


class SectorAlarmClosedSensor(SectorAlarmBinarySensor):
"""Binary sensor for detecting closed status of doors/windows."""

def __init__(self, coordinator, serial_no, device_info) -> None:
super().__init__(
coordinator, serial_no, device_info, "closed", BinarySensorDeviceClass.DOOR
)

@property
def is_on(self) -> bool:
"""Return True if the door/window is open (closed: False)."""
device = self.coordinator.data["devices"].get(self._serial_no)
return not device["sensors"].get("closed", True) if device else False


class SectorAlarmLeakSensor(SectorAlarmBinarySensor):
"""Binary sensor for detecting leaks."""

def __init__(self, coordinator, serial_no, device_info) -> None:
super().__init__(
coordinator,
serial_no,
device_info,
"leak_detected",
BinarySensorDeviceClass.MOISTURE,
)


class SectorAlarmAlarmSensor(SectorAlarmBinarySensor):
"""Binary sensor for detecting alarms."""

def __init__(self, coordinator, serial_no, device_info):
super().__init__(
coordinator, serial_no, device_info, "alarm", BinarySensorDeviceClass.SAFETY
)


class SectorAlarmPanelOnlineBinarySensor(SectorAlarmBaseEntity, BinarySensorEntity):
class SectorAlarmPanelOnlineBinarySensor(SectorAlarmBinarySensor, BinarySensorEntity):
"""Binary sensor for the Sector Alarm panel online status."""

def __init__(self, coordinator, serial_no, sensor_type, device_class):
super().__init__(coordinator, serial_no, {"name": "Sector Alarm Panel"})
self._sensor_type = sensor_type
self._attr_unique_id = f"{serial_no}_{sensor_type}"
self._attr_name = "Online"
self._attr_device_class = device_class

@property
def is_on(self):
"""Return True if the panel is online."""
Expand Down
17 changes: 8 additions & 9 deletions custom_components/sector/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from __future__ import annotations

import logging
from typing import Any

from homeassistant.components.camera import Camera
from homeassistant.core import HomeAssistant
Expand All @@ -28,15 +27,14 @@ async def async_setup_entry(

for camera_data in cameras:
serial_no = str(camera_data.get("SerialNo") or camera_data.get("Serial"))
device_info = {
"name": camera_data.get("Label", "Sector Camera"),
"model": "Camera",
}
entities.append(SectorAlarmCamera(coordinator, serial_no, device_info))
device_name = camera_data.get("Label", "Sector Camera")
entities.append(
SectorAlarmCamera(coordinator, serial_no, device_name, "Camera")
)
_LOGGER.debug(
"Added camera entity with serial: %s and name: %s",
serial_no,
device_info["name"],
device_name,
)

if entities:
Expand All @@ -54,10 +52,11 @@ def __init__(
self,
coordinator: SectorDataUpdateCoordinator,
serial_no: str,
device_info: dict[str, Any],
device_name: str,
device_model: str | None,
) -> None:
"""Initialize the camera entity with device info."""
super().__init__(coordinator, serial_no, device_info)
super().__init__(coordinator, serial_no, device_name, device_model)
Camera.__init__(self)
self._attr_unique_id = f"{self._serial_no}_camera"
_LOGGER.debug(
Expand Down
3 changes: 3 additions & 0 deletions custom_components/sector/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
class SectorDataUpdateCoordinator(DataUpdateCoordinator):
"""Coordinator to manage data fetching from Sector Alarm."""

config_entry: SectorAlarmConfigEntry

def __init__(self, hass: HomeAssistant, entry: SectorAlarmConfigEntry) -> None:
"""Initialize the coordinator."""
self.hass = hass
Expand All @@ -33,6 +35,7 @@ def __init__(self, hass: HomeAssistant, entry: SectorAlarmConfigEntry) -> None:
super().__init__(
hass,
_LOGGER,
config_entry=entry,
name=DOMAIN,
update_interval=timedelta(seconds=60),
)
Expand Down
11 changes: 6 additions & 5 deletions custom_components/sector/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ def __init__(
self,
coordinator: SectorDataUpdateCoordinator,
serial_no: str,
device_info: dict[str, Any],
device_name: str,
device_model: str | None,
) -> None:
"""Initialize the base entity with device info."""
super().__init__(coordinator)
self._serial_no = serial_no
self._device_info = device_info # Store device info centrally
self._attr_unique_id = f"{serial_no}_{self.__class__.__name__.lower()}"
self.device_name = device_name
self.device_model = device_model
_LOGGER.debug(
"Initialized entity %s with serial number: %s",
self.__class__.__name__,
Expand All @@ -41,9 +42,9 @@ def device_info(self) -> DeviceInfo:
"""Return device info for integration."""
return DeviceInfo(
identifiers={(DOMAIN, self._serial_no)},
name=self._device_info.get("name"),
name=self.device_name,
manufacturer="Sector Alarm",
model=self._device_info.get("model"),
model=self.device_model,
serial_number=self._serial_no,
)

Expand Down
Loading

0 comments on commit b560629

Please sign in to comment.