Fix ness alarm armed_home state appearing as disarmed/armed_away (#94351)
* Fix nessclient arm home appearing as arm away * patch arming mode enum and use dynamic access * Revert "patch arming mode enum and use dynamic access" This reverts commit b9cca8e92bcb382abe364381a8cb1674c32d1d2a. * Remove mock enums
This commit is contained in:
parent
cf8c9ad184
commit
2c48f0e416
6 changed files with 43 additions and 37 deletions
|
@ -3,7 +3,7 @@ from collections import namedtuple
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from nessclient import ArmingState, Client
|
from nessclient import ArmingMode, ArmingState, Client
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import (
|
from homeassistant.components.binary_sensor import (
|
||||||
|
@ -136,9 +136,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
hass, SIGNAL_ZONE_CHANGED, ZoneChangedData(zone_id=zone_id, state=state)
|
hass, SIGNAL_ZONE_CHANGED, ZoneChangedData(zone_id=zone_id, state=state)
|
||||||
)
|
)
|
||||||
|
|
||||||
def on_state_change(arming_state: ArmingState):
|
def on_state_change(arming_state: ArmingState, arming_mode: ArmingMode | None):
|
||||||
"""Receives and propagates arming state updates."""
|
"""Receives and propagates arming state updates."""
|
||||||
async_dispatcher_send(hass, SIGNAL_ARMING_STATE_CHANGED, arming_state)
|
async_dispatcher_send(
|
||||||
|
hass, SIGNAL_ARMING_STATE_CHANGED, arming_state, arming_mode
|
||||||
|
)
|
||||||
|
|
||||||
client.on_zone_change(on_zone_change)
|
client.on_zone_change(on_zone_change)
|
||||||
client.on_state_change(on_state_change)
|
client.on_state_change(on_state_change)
|
||||||
|
|
|
@ -3,12 +3,15 @@ from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from nessclient import ArmingState, Client
|
from nessclient import ArmingMode, ArmingState, Client
|
||||||
|
|
||||||
import homeassistant.components.alarm_control_panel as alarm
|
import homeassistant.components.alarm_control_panel as alarm
|
||||||
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
|
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_ALARM_ARMED_AWAY,
|
STATE_ALARM_ARMED_AWAY,
|
||||||
|
STATE_ALARM_ARMED_HOME,
|
||||||
|
STATE_ALARM_ARMED_NIGHT,
|
||||||
|
STATE_ALARM_ARMED_VACATION,
|
||||||
STATE_ALARM_ARMING,
|
STATE_ALARM_ARMING,
|
||||||
STATE_ALARM_DISARMED,
|
STATE_ALARM_DISARMED,
|
||||||
STATE_ALARM_PENDING,
|
STATE_ALARM_PENDING,
|
||||||
|
@ -23,6 +26,15 @@ from . import DATA_NESS, SIGNAL_ARMING_STATE_CHANGED
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ARMING_MODE_TO_STATE = {
|
||||||
|
ArmingMode.ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
|
||||||
|
ArmingMode.ARMED_HOME: STATE_ALARM_ARMED_HOME,
|
||||||
|
ArmingMode.ARMED_DAY: STATE_ALARM_ARMED_AWAY, # no applicable state, fallback to away
|
||||||
|
ArmingMode.ARMED_NIGHT: STATE_ALARM_ARMED_NIGHT,
|
||||||
|
ArmingMode.ARMED_VACATION: STATE_ALARM_ARMED_VACATION,
|
||||||
|
ArmingMode.ARMED_HIGHEST: STATE_ALARM_ARMED_AWAY, # no applicable state, fallback to away
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
async def async_setup_platform(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
@ -79,7 +91,9 @@ class NessAlarmPanel(alarm.AlarmControlPanelEntity):
|
||||||
await self._client.panic(code)
|
await self._client.panic(code)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _handle_arming_state_change(self, arming_state: ArmingState) -> None:
|
def _handle_arming_state_change(
|
||||||
|
self, arming_state: ArmingState, arming_mode: ArmingMode | None
|
||||||
|
) -> None:
|
||||||
"""Handle arming state update."""
|
"""Handle arming state update."""
|
||||||
|
|
||||||
if arming_state == ArmingState.UNKNOWN:
|
if arming_state == ArmingState.UNKNOWN:
|
||||||
|
@ -91,7 +105,9 @@ class NessAlarmPanel(alarm.AlarmControlPanelEntity):
|
||||||
elif arming_state == ArmingState.EXIT_DELAY:
|
elif arming_state == ArmingState.EXIT_DELAY:
|
||||||
self._attr_state = STATE_ALARM_ARMING
|
self._attr_state = STATE_ALARM_ARMING
|
||||||
elif arming_state == ArmingState.ARMED:
|
elif arming_state == ArmingState.ARMED:
|
||||||
self._attr_state = STATE_ALARM_ARMED_AWAY
|
self._attr_state = ARMING_MODE_TO_STATE.get(
|
||||||
|
arming_mode, STATE_ALARM_ARMED_AWAY
|
||||||
|
)
|
||||||
elif arming_state == ArmingState.ENTRY_DELAY:
|
elif arming_state == ArmingState.ENTRY_DELAY:
|
||||||
self._attr_state = STATE_ALARM_PENDING
|
self._attr_state = STATE_ALARM_PENDING
|
||||||
elif arming_state == ArmingState.TRIGGERED:
|
elif arming_state == ArmingState.TRIGGERED:
|
||||||
|
|
|
@ -5,5 +5,5 @@
|
||||||
"documentation": "https://www.home-assistant.io/integrations/ness_alarm",
|
"documentation": "https://www.home-assistant.io/integrations/ness_alarm",
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["nessclient"],
|
"loggers": ["nessclient"],
|
||||||
"requirements": ["nessclient==0.10.0"]
|
"requirements": ["nessclient==1.0.0"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1240,7 +1240,7 @@ nad-receiver==0.3.0
|
||||||
ndms2-client==0.1.2
|
ndms2-client==0.1.2
|
||||||
|
|
||||||
# homeassistant.components.ness_alarm
|
# homeassistant.components.ness_alarm
|
||||||
nessclient==0.10.0
|
nessclient==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.netdata
|
# homeassistant.components.netdata
|
||||||
netdata==1.1.0
|
netdata==1.1.0
|
||||||
|
|
|
@ -951,7 +951,7 @@ mutesync==0.0.1
|
||||||
ndms2-client==0.1.2
|
ndms2-client==0.1.2
|
||||||
|
|
||||||
# homeassistant.components.ness_alarm
|
# homeassistant.components.ness_alarm
|
||||||
nessclient==0.10.0
|
nessclient==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.nmap_tracker
|
# homeassistant.components.nmap_tracker
|
||||||
netmap==0.7.0.2
|
netmap==0.7.0.2
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Tests for the ness_alarm component."""
|
"""Tests for the ness_alarm component."""
|
||||||
from enum import Enum
|
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from nessclient import ArmingMode, ArmingState
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components import alarm_control_panel
|
from homeassistant.components import alarm_control_panel
|
||||||
|
@ -24,6 +24,8 @@ from homeassistant.const import (
|
||||||
SERVICE_ALARM_DISARM,
|
SERVICE_ALARM_DISARM,
|
||||||
SERVICE_ALARM_TRIGGER,
|
SERVICE_ALARM_TRIGGER,
|
||||||
STATE_ALARM_ARMED_AWAY,
|
STATE_ALARM_ARMED_AWAY,
|
||||||
|
STATE_ALARM_ARMED_HOME,
|
||||||
|
STATE_ALARM_ARMED_NIGHT,
|
||||||
STATE_ALARM_ARMING,
|
STATE_ALARM_ARMING,
|
||||||
STATE_ALARM_DISARMED,
|
STATE_ALARM_DISARMED,
|
||||||
STATE_ALARM_PENDING,
|
STATE_ALARM_PENDING,
|
||||||
|
@ -84,7 +86,7 @@ async def test_dispatch_state_change(hass: HomeAssistant, mock_nessclient) -> No
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
on_state_change = mock_nessclient.on_state_change.call_args[0][0]
|
on_state_change = mock_nessclient.on_state_change.call_args[0][0]
|
||||||
on_state_change(MockArmingState.ARMING)
|
on_state_change(ArmingState.ARMING, None)
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.is_state("alarm_control_panel.alarm_panel", STATE_ALARM_ARMING)
|
assert hass.states.is_state("alarm_control_panel.alarm_panel", STATE_ALARM_ARMING)
|
||||||
|
@ -174,13 +176,16 @@ async def test_dispatch_zone_change(hass: HomeAssistant, mock_nessclient) -> Non
|
||||||
async def test_arming_state_change(hass: HomeAssistant, mock_nessclient) -> None:
|
async def test_arming_state_change(hass: HomeAssistant, mock_nessclient) -> None:
|
||||||
"""Test arming state change handing."""
|
"""Test arming state change handing."""
|
||||||
states = [
|
states = [
|
||||||
(MockArmingState.UNKNOWN, STATE_UNKNOWN),
|
(ArmingState.UNKNOWN, None, STATE_UNKNOWN),
|
||||||
(MockArmingState.DISARMED, STATE_ALARM_DISARMED),
|
(ArmingState.DISARMED, None, STATE_ALARM_DISARMED),
|
||||||
(MockArmingState.ARMING, STATE_ALARM_ARMING),
|
(ArmingState.ARMING, None, STATE_ALARM_ARMING),
|
||||||
(MockArmingState.EXIT_DELAY, STATE_ALARM_ARMING),
|
(ArmingState.EXIT_DELAY, None, STATE_ALARM_ARMING),
|
||||||
(MockArmingState.ARMED, STATE_ALARM_ARMED_AWAY),
|
(ArmingState.ARMED, None, STATE_ALARM_ARMED_AWAY),
|
||||||
(MockArmingState.ENTRY_DELAY, STATE_ALARM_PENDING),
|
(ArmingState.ARMED, ArmingMode.ARMED_AWAY, STATE_ALARM_ARMED_AWAY),
|
||||||
(MockArmingState.TRIGGERED, STATE_ALARM_TRIGGERED),
|
(ArmingState.ARMED, ArmingMode.ARMED_HOME, STATE_ALARM_ARMED_HOME),
|
||||||
|
(ArmingState.ARMED, ArmingMode.ARMED_NIGHT, STATE_ALARM_ARMED_NIGHT),
|
||||||
|
(ArmingState.ENTRY_DELAY, None, STATE_ALARM_PENDING),
|
||||||
|
(ArmingState.TRIGGERED, None, STATE_ALARM_TRIGGERED),
|
||||||
]
|
]
|
||||||
|
|
||||||
await async_setup_component(hass, DOMAIN, VALID_CONFIG)
|
await async_setup_component(hass, DOMAIN, VALID_CONFIG)
|
||||||
|
@ -188,24 +193,12 @@ async def test_arming_state_change(hass: HomeAssistant, mock_nessclient) -> None
|
||||||
assert hass.states.is_state("alarm_control_panel.alarm_panel", STATE_UNKNOWN)
|
assert hass.states.is_state("alarm_control_panel.alarm_panel", STATE_UNKNOWN)
|
||||||
on_state_change = mock_nessclient.on_state_change.call_args[0][0]
|
on_state_change = mock_nessclient.on_state_change.call_args[0][0]
|
||||||
|
|
||||||
for arming_state, expected_state in states:
|
for arming_state, arming_mode, expected_state in states:
|
||||||
on_state_change(arming_state)
|
on_state_change(arming_state, arming_mode)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.is_state("alarm_control_panel.alarm_panel", expected_state)
|
assert hass.states.is_state("alarm_control_panel.alarm_panel", expected_state)
|
||||||
|
|
||||||
|
|
||||||
class MockArmingState(Enum):
|
|
||||||
"""Mock nessclient.ArmingState enum."""
|
|
||||||
|
|
||||||
UNKNOWN = "UNKNOWN"
|
|
||||||
DISARMED = "DISARMED"
|
|
||||||
ARMING = "ARMING"
|
|
||||||
EXIT_DELAY = "EXIT_DELAY"
|
|
||||||
ARMED = "ARMED"
|
|
||||||
ENTRY_DELAY = "ENTRY_DELAY"
|
|
||||||
TRIGGERED = "TRIGGERED"
|
|
||||||
|
|
||||||
|
|
||||||
class MockClient:
|
class MockClient:
|
||||||
"""Mock nessclient.Client stub."""
|
"""Mock nessclient.Client stub."""
|
||||||
|
|
||||||
|
@ -253,10 +246,5 @@ def mock_nessclient():
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.ness_alarm.Client", new=_mock_factory, create=True
|
"homeassistant.components.ness_alarm.Client", new=_mock_factory, create=True
|
||||||
), patch(
|
|
||||||
"homeassistant.components.ness_alarm.ArmingState", new=MockArmingState
|
|
||||||
), patch(
|
|
||||||
"homeassistant.components.ness_alarm.alarm_control_panel.ArmingState",
|
|
||||||
new=MockArmingState,
|
|
||||||
):
|
):
|
||||||
yield _mock_instance
|
yield _mock_instance
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue