Skip to content

Commit

Permalink
Migrate elkm1 to use a dataclass for integration data (#99830)
Browse files Browse the repository at this point in the history
* Migrate elkm1 to use a dataclass for integration data

* fix unsaved

* slotted

* missing coveragerc

* Revert "missing coveragerc"

This reverts commit 3397b40.
  • Loading branch information
bdraco authored Sep 8, 2023
1 parent 3d403c9 commit d624bbb
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 47 deletions.
58 changes: 31 additions & 27 deletions homeassistant/components/elkm1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
from __future__ import annotations

import asyncio
from collections.abc import Iterable
from enum import Enum
import logging
import re
from types import MappingProxyType
from typing import Any, cast
from typing import Any

from elkm1_lib.elements import Element
from elkm1_lib.elk import Elk
Expand Down Expand Up @@ -65,6 +66,7 @@
async_trigger_discovery,
async_update_entry_from_discovery,
)
from .models import ELKM1Data

SYNC_TIMEOUT = 120

Expand Down Expand Up @@ -303,14 +305,16 @@ def _keypad_changed(keypad: Element, changeset: dict[str, Any]) -> None:
else:
temperature_unit = UnitOfTemperature.FAHRENHEIT
config["temperature_unit"] = temperature_unit
hass.data[DOMAIN][entry.entry_id] = {
"elk": elk,
"prefix": conf[CONF_PREFIX],
"mac": entry.unique_id,
"auto_configure": conf[CONF_AUTO_CONFIGURE],
"config": config,
"keypads": {},
}
prefix: str = conf[CONF_PREFIX]
auto_configure: bool = conf[CONF_AUTO_CONFIGURE]
hass.data[DOMAIN][entry.entry_id] = ELKM1Data(
elk=elk,
prefix=prefix,
mac=entry.unique_id,
auto_configure=auto_configure,
config=config,
keypads={},
)

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

Expand All @@ -326,21 +330,23 @@ def _included(ranges: list[tuple[int, int]], set_to: bool, values: list[bool]) -

def _find_elk_by_prefix(hass: HomeAssistant, prefix: str) -> Elk | None:
"""Search all config entries for a given prefix."""
for entry_id in hass.data[DOMAIN]:
if hass.data[DOMAIN][entry_id]["prefix"] == prefix:
return cast(Elk, hass.data[DOMAIN][entry_id]["elk"])
all_elk: dict[str, ELKM1Data] = hass.data[DOMAIN]
for elk_data in all_elk.values():
if elk_data.prefix == prefix:
return elk_data.elk
return None


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
all_elk: dict[str, ELKM1Data] = hass.data[DOMAIN]

# disconnect cleanly
hass.data[DOMAIN][entry.entry_id]["elk"].disconnect()
all_elk[entry.entry_id].elk.disconnect()

if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
all_elk.pop(entry.entry_id)

return unload_ok

Expand Down Expand Up @@ -421,27 +427,27 @@ def _set_time_service(service: ServiceCall) -> None:


def create_elk_entities(
elk_data: dict[str, Any],
elk_elements: list[Element],
elk_data: ELKM1Data,
elk_elements: Iterable[Element],
element_type: str,
class_: Any,
entities: list[ElkEntity],
) -> list[ElkEntity] | None:
"""Create the ElkM1 devices of a particular class."""
auto_configure = elk_data["auto_configure"]
auto_configure = elk_data.auto_configure

if not auto_configure and not elk_data["config"][element_type]["enabled"]:
if not auto_configure and not elk_data.config[element_type]["enabled"]:
return None

elk = elk_data["elk"]
elk = elk_data.elk
_LOGGER.debug("Creating elk entities for %s", elk)

for element in elk_elements:
if auto_configure:
if not element.configured:
continue
# Only check the included list if auto configure is not
elif not elk_data["config"][element_type]["included"][element.index]:
elif not elk_data.config[element_type]["included"][element.index]:
continue

entities.append(class_(element, elk, elk_data))
Expand All @@ -454,13 +460,13 @@ class ElkEntity(Entity):
_attr_has_entity_name = True
_attr_should_poll = False

def __init__(self, element: Element, elk: Elk, elk_data: dict[str, Any]) -> None:
def __init__(self, element: Element, elk: Elk, elk_data: ELKM1Data) -> None:
"""Initialize the base of all Elk devices."""
self._elk = elk
self._element = element
self._mac = elk_data["mac"]
self._prefix = elk_data["prefix"]
self._temperature_unit: str = elk_data["config"]["temperature_unit"]
self._mac = elk_data.mac
self._prefix = elk_data.prefix
self._temperature_unit: str = elk_data.config["temperature_unit"]
# unique_id starts with elkm1_ iff there is no prefix
# it starts with elkm1m_{prefix} iff there is a prefix
# this is to avoid a conflict between
Expand Down Expand Up @@ -496,9 +502,7 @@ def available(self) -> bool:

def initial_attrs(self) -> dict[str, Any]:
"""Return the underlying element's attributes as a dict."""
attrs = {}
attrs["index"] = self._element.index + 1
return attrs
return {"index": self._element.index + 1}

def _element_changed(self, element: Element, changeset: dict[str, Any]) -> None:
pass
Expand Down
8 changes: 5 additions & 3 deletions homeassistant/components/elkm1/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
DOMAIN,
ELK_USER_CODE_SERVICE_SCHEMA,
)
from .models import ELKM1Data

DISPLAY_MESSAGE_SERVICE_SCHEMA = {
vol.Optional("clear", default=2): vol.All(vol.Coerce(int), vol.In([0, 1, 2])),
Expand All @@ -65,8 +66,9 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the ElkM1 alarm platform."""
elk_data = hass.data[DOMAIN][config_entry.entry_id]
elk = elk_data["elk"]

elk_data: ELKM1Data = hass.data[DOMAIN][config_entry.entry_id]
elk = elk_data.elk
entities: list[ElkEntity] = []
create_elk_entities(elk_data, elk.areas, "area", ElkArea, entities)
async_add_entities(entities)
Expand Down Expand Up @@ -115,7 +117,7 @@ class ElkArea(ElkAttachedEntity, AlarmControlPanelEntity, RestoreEntity):
)
_element: Area

def __init__(self, element: Element, elk: Elk, elk_data: dict[str, Any]) -> None:
def __init__(self, element: Element, elk: Elk, elk_data: ELKM1Data) -> None:
"""Initialize Area as Alarm Control Panel."""
super().__init__(element, elk, elk_data)
self._elk = elk
Expand Down
12 changes: 6 additions & 6 deletions homeassistant/components/elkm1/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from . import ElkAttachedEntity, ElkEntity
from .const import DOMAIN
from .models import ELKM1Data


async def async_setup_entry(
Expand All @@ -22,21 +23,20 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Create the Elk-M1 sensor platform."""

elk_data = hass.data[DOMAIN][config_entry.entry_id]
auto_configure = elk_data["auto_configure"]
elk = elk_data["elk"]
elk_data: ELKM1Data = hass.data[DOMAIN][config_entry.entry_id]
elk = elk_data.elk
auto_configure = elk_data.auto_configure

entities: list[ElkEntity] = []
for element in elk.zones:
# Don't create binary sensors for zones that are analog
if element.definition in {ZoneType.TEMPERATURE, ZoneType.ANALOG_ZONE}:
if element.definition in {ZoneType.TEMPERATURE, ZoneType.ANALOG_ZONE}: # type: ignore[attr-defined]
continue

if auto_configure:
if not element.configured:
continue
elif not elk_data["config"]["zone"]["included"][element.index]:
elif not elk_data.config["zone"]["included"][element.index]:
continue

entities.append(ElkBinarySensor(element, elk, elk_data))
Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/elkm1/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

from . import ElkEntity, create_elk_entities
from .const import DOMAIN
from .models import ELKM1Data

SUPPORT_HVAC = [
HVACMode.OFF,
Expand Down Expand Up @@ -61,9 +62,9 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Create the Elk-M1 thermostat platform."""
elk_data = hass.data[DOMAIN][config_entry.entry_id]
elk_data: ELKM1Data = hass.data[DOMAIN][config_entry.entry_id]
elk = elk_data.elk
entities: list[ElkEntity] = []
elk = elk_data["elk"]
create_elk_entities(
elk_data, elk.thermostats, "thermostat", ElkThermostat, entities
)
Expand Down
7 changes: 4 additions & 3 deletions homeassistant/components/elkm1/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from . import ElkEntity, create_elk_entities
from .const import DOMAIN
from .models import ELKM1Data


async def async_setup_entry(
Expand All @@ -22,9 +23,9 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Elk light platform."""
elk_data = hass.data[DOMAIN][config_entry.entry_id]
elk_data: ELKM1Data = hass.data[DOMAIN][config_entry.entry_id]
elk = elk_data.elk
entities: list[ElkEntity] = []
elk = elk_data["elk"]
create_elk_entities(elk_data, elk.lights, "plc", ElkLight, entities)
async_add_entities(entities)

Expand All @@ -36,7 +37,7 @@ class ElkLight(ElkEntity, LightEntity):
_attr_supported_color_modes = {ColorMode.BRIGHTNESS}
_element: Light

def __init__(self, element: Element, elk: Elk, elk_data: dict[str, Any]) -> None:
def __init__(self, element: Element, elk: Elk, elk_data: ELKM1Data) -> None:
"""Initialize the Elk light."""
super().__init__(element, elk, elk_data)
self._brightness = self._element.status
Expand Down
19 changes: 19 additions & 0 deletions homeassistant/components/elkm1/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""The elkm1 integration models."""
from __future__ import annotations

from dataclasses import dataclass
from typing import Any

from elkm1_lib import Elk


@dataclass(slots=True)
class ELKM1Data:
"""Data for the elkm1 integration."""

elk: Elk
prefix: str
mac: str | None
auto_configure: bool
config: dict[str, Any]
keypads: dict[str, Any]
5 changes: 3 additions & 2 deletions homeassistant/components/elkm1/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from . import ElkAttachedEntity, ElkEntity, create_elk_entities
from .const import DOMAIN
from .models import ELKM1Data


async def async_setup_entry(
Expand All @@ -20,9 +21,9 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Create the Elk-M1 scene platform."""
elk_data = hass.data[DOMAIN][config_entry.entry_id]
elk_data: ELKM1Data = hass.data[DOMAIN][config_entry.entry_id]
elk = elk_data.elk
entities: list[ElkEntity] = []
elk = elk_data["elk"]
create_elk_entities(elk_data, elk.tasks, "task", ElkTask, entities)
async_add_entities(entities)

Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/elkm1/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

from . import ElkAttachedEntity, ElkEntity, create_elk_entities
from .const import ATTR_VALUE, DOMAIN, ELK_USER_CODE_SERVICE_SCHEMA
from .models import ELKM1Data

SERVICE_SENSOR_COUNTER_REFRESH = "sensor_counter_refresh"
SERVICE_SENSOR_COUNTER_SET = "sensor_counter_set"
Expand All @@ -41,9 +42,9 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Create the Elk-M1 sensor platform."""
elk_data = hass.data[DOMAIN][config_entry.entry_id]
elk_data: ELKM1Data = hass.data[DOMAIN][config_entry.entry_id]
elk = elk_data.elk
entities: list[ElkEntity] = []
elk = elk_data["elk"]
create_elk_entities(elk_data, elk.counters, "counter", ElkCounter, entities)
create_elk_entities(elk_data, elk.keypads, "keypad", ElkKeypad, entities)
create_elk_entities(elk_data, [elk.panel], "panel", ElkPanel, entities)
Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/elkm1/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from . import ElkAttachedEntity, ElkEntity, create_elk_entities
from .const import DOMAIN
from .models import ELKM1Data


async def async_setup_entry(
Expand All @@ -20,9 +21,9 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Create the Elk-M1 switch platform."""
elk_data = hass.data[DOMAIN][config_entry.entry_id]
elk_data: ELKM1Data = hass.data[DOMAIN][config_entry.entry_id]
elk = elk_data.elk
entities: list[ElkEntity] = []
elk = elk_data["elk"]
create_elk_entities(elk_data, elk.outputs, "output", ElkOutput, entities)
async_add_entities(entities)

Expand Down

0 comments on commit d624bbb

Please sign in to comment.