mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
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:
parent
75669dba6e
commit
6e355e1074
@ -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."""
|
||||||
|
@ -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."""
|
||||||
|
@ -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"
|
||||||
|
@ -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,
|
|
||||||
}
|
|
||||||
|
@ -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",
|
||||||
|
@ -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": {
|
||||||
|
@ -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": {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
@ -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")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user