Skip to content

Commit

Permalink
Add socket support (#45)
Browse files Browse the repository at this point in the history
* Add socket support

* Revert removal version file
  • Loading branch information
jbouwh authored Jan 4, 2024
1 parent 6f6942b commit 40989ad
Show file tree
Hide file tree
Showing 18 changed files with 331 additions and 11 deletions.
2 changes: 1 addition & 1 deletion custom_components/elro_connects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

_LOGGER = logging.getLogger(__name__)

PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.SIREN]
PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.SIREN, Platform.SWITCH]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions custom_components/elro_connects/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"integration_type": "hub",
"iot_class": "local_polling",
"issue_tracker": "https://github.com/jbouwh/ha-elro-connects/issues",
"requirements": ["lib-elro-connects==0.5.4.1"],
"version": "v0.2.1-2"
"requirements": ["lib-elro-connects==0.6.0.1"],
"version": "v0.2.3"
}
5 changes: 5 additions & 0 deletions custom_components/elro_connects/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
"alarm_water": {
"name": "Water Alarm"
}
},
"switch": {
"socket": {
"name": "Socket"
}
}
}
}
119 changes: 119 additions & 0 deletions custom_components/elro_connects/switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
"""The Elro Connects switch platform."""
from __future__ import annotations

from dataclasses import dataclass
import logging

from elro.command import SOCKET_OFF, SOCKET_ON, CommandAttributes
from elro.device import (
ATTR_DEVICE_STATE,
ATTR_DEVICE_VALUE,
DEVICE_VALUE_OFF,
DEVICE_VALUE_ON,
SOCKET,
STATES_OFFLINE,
)

from homeassistant.components.switch import (
SwitchDeviceClass,
SwitchEntity,
SwitchEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .device import ElroConnectsEntity, ElroConnectsK1
from .helpers import async_set_up_discovery_helper


@dataclass
class ElroSwitchEntityDescription(SwitchEntityDescription):
"""A class that describes elro siren entities."""

turn_on: CommandAttributes | None = None
turn_off: CommandAttributes | None = None


_LOGGER = logging.getLogger(__name__)

SWITCH_DEVICE_TYPES = {
SOCKET: ElroSwitchEntityDescription(
key=SOCKET,
translation_key="socket",
device_class=SwitchDeviceClass.OUTLET,
turn_on=SOCKET_ON,
turn_off=SOCKET_OFF,
),
}


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the sensor platform."""
current: set[int] = set()

async_set_up_discovery_helper(
hass,
ElroConnectsSwitch,
config_entry,
current,
SWITCH_DEVICE_TYPES,
async_add_entities,
)


class ElroConnectsSwitch(ElroConnectsEntity, SwitchEntity):
"""Elro Connects Fire Alarm Entity."""

def __init__(
self,
elro_connects_api: ElroConnectsK1,
entry: ConfigEntry,
device_id: int,
description: ElroSwitchEntityDescription,
) -> None:
"""Initialize a Fire Alarm Entity."""
self._attr_has_entity_name = True
self._device_id = device_id
self._elro_connects_api = elro_connects_api
self._description = description
ElroConnectsEntity.__init__(
self,
elro_connects_api,
entry,
device_id,
description,
)

@property
def is_on(self) -> bool | None:
"""Return true if device is on or none if the device is offline."""
if not self.data or self.data[ATTR_DEVICE_STATE] in STATES_OFFLINE:
return None
if self.data[ATTR_DEVICE_VALUE] not in (DEVICE_VALUE_OFF, DEVICE_VALUE_ON):
return None
return self.data[ATTR_DEVICE_VALUE] == DEVICE_VALUE_ON

async def async_turn_on(self, **kwargs) -> None:
"""Turn switch on."""
_LOGGER.debug("Sending turn_on request for entity %s", self.entity_id)
await self._elro_connects_api.async_command(
self._description.turn_on, device_ID=self._device_id
)

self.data[ATTR_DEVICE_VALUE] = DEVICE_VALUE_ON
self.async_write_ha_state()

async def async_turn_off(self, **kwargs) -> None:
"""Turn switch off."""
_LOGGER.debug("Sending turn_off request for entity %s", self.entity_id)
await self._elro_connects_api.async_command(
self._description.turn_off, device_ID=self._device_id
)

self.data[ATTR_DEVICE_VALUE] = DEVICE_VALUE_OFF
self.async_write_ha_state()
5 changes: 5 additions & 0 deletions custom_components/elro_connects/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
"alarm_water": {
"name": "Wasseralarm"
}
},
"switch": {
"socket": {
"name": "Wandsteckdose"
}
}
}
}
5 changes: 5 additions & 0 deletions custom_components/elro_connects/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
"alarm_water": {
"name": "Water Alarm"
}
},
"switch": {
"socket": {
"name": "Socket"
}
}
}
}
5 changes: 5 additions & 0 deletions custom_components/elro_connects/translations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
"alarm_water": {
"name": "Alarma de agua"
}
},
"switch": {
"socket": {
"name": "Toma de pared"
}
}
}
}
5 changes: 5 additions & 0 deletions custom_components/elro_connects/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
"alarm_water": {
"name": "Alarme d'eau"
}
},
"switch": {
"socket": {
"name": "La prise électrique"
}
}
}
}
5 changes: 5 additions & 0 deletions custom_components/elro_connects/translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
"alarm_water": {
"name": "Wateralarm"
}
},
"switch": {
"socket": {
"name": "Stopcontact"
}
}
}
}
5 changes: 5 additions & 0 deletions custom_components/elro_connects/translations/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
"alarm_water": {
"name": "Alarme de água"
}
},
"switch": {
"socket": {
"name": "Tomada de parede"
}
}
}
}
5 changes: 5 additions & 0 deletions custom_components/elro_connects/translations/uk.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
"alarm_water": {
"name": "Сигналізація води"
}
},
"switch": {
"socket": {
"name": "Розетка"
}
}
}
}
2 changes: 1 addition & 1 deletion requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pre-commit==3.3.1
lib-elro-connects==0.5.4.1
lib-elro-connects==0.6.0.1
homeassistant==2023.7.2
pytest-homeassistant-custom-component==0.13.44
2 changes: 1 addition & 1 deletion requirements_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fnvhash==0.1.0

lru-dict==1.2.0

lib-elro-connects==0.5.4.1
lib-elro-connects==0.6.0.1

pytest-homeassistant-custom-component==0.13.44

9 changes: 4 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
requirements = [
"sqlalchemy",
]
with open("requirements_test.txt") as f:
with open("requirements_test.txt", encoding="utf-8") as f:
for line in f:
if "txt" not in line and "#" not in line:
requirements.append(line)

with open("version") as f:
with open("version", encoding="utf-8") as f:
__version__ = f.read()

setup(
Expand All @@ -26,13 +26,12 @@
author_email="[email protected]",
description="Add Elro Connects alarm devices to Home Assistant",
classifiers=[
"Development Status :: 3 - Alpha",
"Development Status :: 4 - Beta",
"Framework :: Pytest",
"Intended Audience :: Developers",
"Intended Audience :: Information Technology",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 3.9",
"Topic :: Software Development :: Testing",
],
entry_points={
"pytest11": ["homeassistant = pytest_homeassistant_custom_component.plugins"]
Expand Down
38 changes: 38 additions & 0 deletions tests/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
"device_name": "0013",
"device_status": "0364AAFF",
},
"device_value": "0xff",
"device_value_data": 255,
"name": "Beganegrond",
},
2: {
Expand All @@ -25,6 +27,8 @@
"device_name": "0013",
"device_status": "044B55FF",
},
"device_value": "0xff",
"device_value_data": 255,
"name": "Eerste etage",
},
4: {
Expand All @@ -38,6 +42,8 @@
"device_name": "0013",
"device_status": "0105FEFF",
},
"device_value": "0xff",
"device_value_data": 255,
"name": "Zolder",
},
5: {
Expand All @@ -51,11 +57,43 @@
"device_name": "2008",
"device_status": "FFFFFFFF",
},
"device_value": "0xff",
"device_value_data": 255,
"name": "Corner",
},
6: {
"name": "Device with unknown state",
},
7: {
"device_type": "SOCKET",
"signal": 255,
"battery": 255,
"device_state": "NORMAL",
"device_status_data": {
"cmdId": 19,
"device_ID": 5,
"device_name": "1200",
"device_status": "04FF0100",
},
"device_value": "off",
"device_value_data": 1,
"name": "Wall switch off",
},
8: {
"device_type": "SOCKET",
"signal": 255,
"battery": 255,
"device_state": "NORMAL",
"device_status_data": {
"cmdId": 19,
"device_ID": 5,
"device_name": "1200",
"device_status": "04FF0101",
},
"device_value": "on",
"device_value_data": 1,
"name": "Wall switch on",
},
}


Expand Down
7 changes: 7 additions & 0 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from custom_components.elro_connects import async_remove_config_entry_device
from custom_components.elro_connects.const import DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import format_mac
Expand Down Expand Up @@ -107,6 +108,8 @@ async def test_configure_platforms_dynamically(
assert hass.states.get("siren.beganegrond_fire_alarm") is not None
assert hass.states.get("siren.eerste_etage_fire_alarm") is not None
assert hass.states.get("siren.zolder_fire_alarm") is None
assert hass.states.get("switch.wall_switch_off_socket") is not None
assert hass.states.get("switch.wall_switch_on_socket") is not None

# Simulate a dynamic discovery update resulting in 3 siren entities
mock_k1_connector["result"].return_value = updated_status_data
Expand All @@ -118,6 +121,8 @@ async def test_configure_platforms_dynamically(
assert hass.states.get("siren.beganegrond_fire_alarm") is not None
assert hass.states.get("siren.eerste_etage_fire_alarm") is not None
assert hass.states.get("siren.zolder_fire_alarm") is not None
assert hass.states.get("switch.wall_switch_off_socket") is not None
assert hass.states.get("switch.wall_switch_on_socket") is not None

# Remove device 1 from api data, entity should appear offline with an unknown state
updated_status_data.pop(1)
Expand All @@ -130,6 +135,8 @@ async def test_configure_platforms_dynamically(
assert hass.states.get("siren.beganegrond_fire_alarm").state == "off"
assert hass.states.get("siren.eerste_etage_fire_alarm") is not None
assert hass.states.get("siren.zolder_fire_alarm") is not None
assert hass.states.get("switch.wall_switch_off_socket").state == STATE_OFF
assert hass.states.get("switch.wall_switch_on_socket").state == STATE_ON


async def test_remove_device_from_config_entry(
Expand Down
Loading

0 comments on commit 40989ad

Please sign in to comment.