iAlarm XR integration refinements (#72616)

* fixing after MartinHjelmare review

* fixing after MartinHjelmare review conversion alarm state to hass state

* fixing after MartinHjelmare review conversion alarm state to hass state

* manage the status in the alarm control

* simplyfing return function
This commit is contained in:
BigMoby 2022-05-30 08:26:05 +02:00 committed by GitHub
parent 75669dba6e
commit 6e355e1074
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 32 additions and 57 deletions

View File

@ -24,7 +24,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN, IALARMXR_TO_HASS from .const import DOMAIN
from .utils import async_get_ialarmxr_mac from .utils import async_get_ialarmxr_mac
PLATFORMS = [Platform.ALARM_CONTROL_PANEL] PLATFORMS = [Platform.ALARM_CONTROL_PANEL]
@ -74,7 +74,7 @@ class IAlarmXRDataUpdateCoordinator(DataUpdateCoordinator):
def __init__(self, hass: HomeAssistant, ialarmxr: IAlarmXR, mac: str) -> None: def __init__(self, hass: HomeAssistant, ialarmxr: IAlarmXR, mac: str) -> None:
"""Initialize global iAlarm data updater.""" """Initialize global iAlarm data updater."""
self.ialarmxr: IAlarmXR = ialarmxr self.ialarmxr: IAlarmXR = ialarmxr
self.state: str | None = None self.state: int | None = None
self.host: str = ialarmxr.host self.host: str = ialarmxr.host
self.mac: str = mac self.mac: str = mac
@ -90,7 +90,7 @@ class IAlarmXRDataUpdateCoordinator(DataUpdateCoordinator):
status: int = self.ialarmxr.get_status() status: int = self.ialarmxr.get_status()
_LOGGER.debug("iAlarmXR status: %s", status) _LOGGER.debug("iAlarmXR status: %s", status)
self.state = IALARMXR_TO_HASS.get(status) self.state = status
async def _async_update_data(self) -> None: async def _async_update_data(self) -> None:
"""Fetch data from iAlarmXR.""" """Fetch data from iAlarmXR."""

View File

@ -1,11 +1,19 @@
"""Interfaces with iAlarmXR control panels.""" """Interfaces with iAlarmXR control panels."""
from __future__ import annotations from __future__ import annotations
from pyialarmxr import IAlarmXR
from homeassistant.components.alarm_control_panel import ( from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity, AlarmControlPanelEntity,
AlarmControlPanelEntityFeature, AlarmControlPanelEntityFeature,
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry from homeassistant.helpers import device_registry
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
@ -15,6 +23,13 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import IAlarmXRDataUpdateCoordinator from . import IAlarmXRDataUpdateCoordinator
from .const import DOMAIN from .const import DOMAIN
IALARMXR_TO_HASS = {
IAlarmXR.ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
IAlarmXR.ARMED_STAY: STATE_ALARM_ARMED_HOME,
IAlarmXR.DISARMED: STATE_ALARM_DISARMED,
IAlarmXR.TRIGGERED: STATE_ALARM_TRIGGERED,
}
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
@ -24,7 +39,9 @@ async def async_setup_entry(
async_add_entities([IAlarmXRPanel(coordinator)]) async_add_entities([IAlarmXRPanel(coordinator)])
class IAlarmXRPanel(CoordinatorEntity, AlarmControlPanelEntity): class IAlarmXRPanel(
CoordinatorEntity[IAlarmXRDataUpdateCoordinator], AlarmControlPanelEntity
):
"""Representation of an iAlarmXR device.""" """Representation of an iAlarmXR device."""
_attr_supported_features = ( _attr_supported_features = (
@ -37,7 +54,6 @@ class IAlarmXRPanel(CoordinatorEntity, AlarmControlPanelEntity):
def __init__(self, coordinator: IAlarmXRDataUpdateCoordinator) -> None: def __init__(self, coordinator: IAlarmXRDataUpdateCoordinator) -> None:
"""Initialize the alarm panel.""" """Initialize the alarm panel."""
super().__init__(coordinator) super().__init__(coordinator)
self.coordinator: IAlarmXRDataUpdateCoordinator = coordinator
self._attr_unique_id = coordinator.mac self._attr_unique_id = coordinator.mac
self._attr_device_info = DeviceInfo( self._attr_device_info = DeviceInfo(
manufacturer="Antifurto365 - Meian", manufacturer="Antifurto365 - Meian",
@ -48,7 +64,7 @@ class IAlarmXRPanel(CoordinatorEntity, AlarmControlPanelEntity):
@property @property
def state(self) -> str | None: def state(self) -> str | None:
"""Return the state of the device.""" """Return the state of the device."""
return self.coordinator.state return IALARMXR_TO_HASS.get(self.coordinator.state)
def alarm_disarm(self, code: str | None = None) -> None: def alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command.""" """Send disarm command."""

View File

@ -72,13 +72,13 @@ class IAlarmConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"IAlarmXRGenericException with message: [ %s ]", "IAlarmXRGenericException with message: [ %s ]",
ialarmxr_exception.message, ialarmxr_exception.message,
) )
errors["base"] = "unknown" errors["base"] = "cannot_connect"
except IAlarmXRSocketTimeoutException as ialarmxr_socket_timeout_exception: except IAlarmXRSocketTimeoutException as ialarmxr_socket_timeout_exception:
_LOGGER.debug( _LOGGER.debug(
"IAlarmXRSocketTimeoutException with message: [ %s ]", "IAlarmXRSocketTimeoutException with message: [ %s ]",
ialarmxr_socket_timeout_exception.message, ialarmxr_socket_timeout_exception.message,
) )
errors["base"] = "unknown" errors["base"] = "timeout"
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception") _LOGGER.exception("Unexpected exception")
errors["base"] = "unknown" errors["base"] = "unknown"

View File

@ -1,18 +1,3 @@
"""Constants for the iAlarmXR integration.""" """Constants for the iAlarmXR integration."""
from pyialarmxr import IAlarmXR
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
DOMAIN = "ialarm_xr" DOMAIN = "ialarm_xr"
IALARMXR_TO_HASS = {
IAlarmXR.ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
IAlarmXR.ARMED_STAY: STATE_ALARM_ARMED_HOME,
IAlarmXR.DISARMED: STATE_ALARM_DISARMED,
IAlarmXR.TRIGGERED: STATE_ALARM_TRIGGERED,
}

View File

@ -1,8 +1,8 @@
{ {
"domain": "ialarm_xr", "domain": "ialarm_xr",
"name": "Antifurto365 iAlarmXR", "name": "Antifurto365 iAlarmXR",
"documentation": "https://www.home-assistant.io/integrations/ialarmxr", "documentation": "https://www.home-assistant.io/integrations/ialarm_xr",
"requirements": ["pyialarmxr==1.0.13"], "requirements": ["pyialarmxr==1.0.18"],
"codeowners": ["@bigmoby"], "codeowners": ["@bigmoby"],
"config_flow": true, "config_flow": true,
"iot_class": "cloud_polling", "iot_class": "cloud_polling",

View File

@ -12,6 +12,7 @@
}, },
"error": { "error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"timeout": "[%key:common::config_flow::error::timeout_connect%]",
"unknown": "[%key:common::config_flow::error::unknown%]" "unknown": "[%key:common::config_flow::error::unknown%]"
}, },
"abort": { "abort": {

View File

@ -5,6 +5,7 @@
}, },
"error": { "error": {
"cannot_connect": "Failed to connect", "cannot_connect": "Failed to connect",
"timeout": "Timeout establishing connection",
"unknown": "Unexpected error" "unknown": "Unexpected error"
}, },
"step": { "step": {

View File

@ -1550,7 +1550,7 @@ pyhomeworks==0.0.6
pyialarm==1.9.0 pyialarm==1.9.0
# homeassistant.components.ialarm_xr # homeassistant.components.ialarm_xr
pyialarmxr==1.0.13 pyialarmxr==1.0.18
# homeassistant.components.icloud # homeassistant.components.icloud
pyicloud==1.0.0 pyicloud==1.0.0

View File

@ -1038,7 +1038,7 @@ pyhomematic==0.1.77
pyialarm==1.9.0 pyialarm==1.9.0
# homeassistant.components.ialarm_xr # homeassistant.components.ialarm_xr
pyialarmxr==1.0.13 pyialarmxr==1.0.18
# homeassistant.components.icloud # homeassistant.components.icloud
pyicloud==1.0.0 pyicloud==1.0.0

View File

@ -56,24 +56,6 @@ async def test_form(hass):
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
async def test_form_cannot_connect(hass):
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.ialarm_xr.config_flow.IAlarmXR.get_mac",
side_effect=ConnectionError,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], TEST_DATA
)
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result2["errors"] == {"base": "cannot_connect"}
async def test_form_exception(hass): async def test_form_exception(hass):
"""Test we handle unknown exception.""" """Test we handle unknown exception."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -125,7 +107,7 @@ async def test_form_cannot_connect_throwing_socket_timeout_exception(hass):
) )
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result2["errors"] == {"base": "unknown"} assert result2["errors"] == {"base": "timeout"}
async def test_form_cannot_connect_throwing_generic_exception(hass): async def test_form_cannot_connect_throwing_generic_exception(hass):
@ -143,7 +125,7 @@ async def test_form_cannot_connect_throwing_generic_exception(hass):
) )
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result2["errors"] == {"base": "unknown"} assert result2["errors"] == {"base": "cannot_connect"}
async def test_form_already_exists(hass): async def test_form_already_exists(hass):

View File

@ -48,16 +48,6 @@ async def test_setup_entry(hass, ialarmxr_api, mock_config_entry):
assert mock_config_entry.state is ConfigEntryState.LOADED assert mock_config_entry.state is ConfigEntryState.LOADED
async def test_setup_not_ready(hass, ialarmxr_api, mock_config_entry):
"""Test setup failed because we can't connect to the alarm system."""
ialarmxr_api.return_value.get_mac = Mock(side_effect=ConnectionError)
mock_config_entry.add_to_hass(hass)
assert not await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY
async def test_unload_entry(hass, ialarmxr_api, mock_config_entry): async def test_unload_entry(hass, ialarmxr_api, mock_config_entry):
"""Test being able to unload an entry.""" """Test being able to unload an entry."""
ialarmxr_api.return_value.get_mac = Mock(return_value="00:00:54:12:34:56") ialarmxr_api.return_value.get_mac = Mock(return_value="00:00:54:12:34:56")