Skip to content

Commit

Permalink
Merge pull request #47 from hostcc/feat/hass-2024-11
Browse files Browse the repository at this point in the history
feat: Update for Home Assistant 2024.11
  • Loading branch information
hostcc authored Nov 19, 2024
2 parents 51b81f4 + e15ec59 commit 305212c
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 39 deletions.
33 changes: 9 additions & 24 deletions custom_components/gs_alarm/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,7 @@
)
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.components.alarm_control_panel.const import (
AlarmControlPanelEntityFeature
)

from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
STATE_UNKNOWN,
AlarmControlPanelEntityFeature, AlarmControlPanelState,
)

from pyg90alarm import (
Expand All @@ -36,10 +28,10 @@

# Mapping between `pyg90alarm` states for the panel and ones for HomeAssitant
STATE_MAPPING = {
G90ArmDisarmTypes.ARM_AWAY: STATE_ALARM_ARMED_AWAY,
G90ArmDisarmTypes.ARM_HOME: STATE_ALARM_ARMED_HOME,
G90ArmDisarmTypes.DISARM: STATE_ALARM_DISARMED,
G90ArmDisarmTypes.ALARMED: STATE_ALARM_TRIGGERED,
G90ArmDisarmTypes.ARM_AWAY: AlarmControlPanelState.ARMED_AWAY,
G90ArmDisarmTypes.ARM_HOME: AlarmControlPanelState.ARMED_HOME,
G90ArmDisarmTypes.DISARM: AlarmControlPanelState.DISARMED,
G90ArmDisarmTypes.ALARMED: AlarmControlPanelState.TRIGGERED,
}


Expand All @@ -66,7 +58,7 @@ def __init__(self, hass_data: GsAlarmData) -> None:
self._attr_name = hass_data.guid
self._attr_device_info = hass_data.device
self._attr_changed_by = None
self._state = STATE_UNKNOWN
self._attr_alarm_state = None
self._hass_data = hass_data
self._hass_data.client.armdisarm_callback = self.armdisarm_callback
self._hass_data.client.alarm_callback = self.alarm_callback
Expand All @@ -87,7 +79,7 @@ def armdisarm_callback(self, state: G90ArmDisarmTypes) -> None:
Invoked by `G90Alarm` when panel is armed or disarmed.
"""
_LOGGER.debug('Received arm/disarm callback: %s', state)
self._state = STATE_MAPPING[state]
self._attr_alarm_state = STATE_MAPPING[state]
# Reset `changed_by` attribute so the value it possibly has (name of
# sensor caused last alarm) isn't carried on indefinitely which might
# be confusing
Expand Down Expand Up @@ -119,7 +111,7 @@ def alarm_callback(
# in `extra_data`
if extra_data:
self._attr_changed_by = extra_data
self._state = STATE_ALARM_TRIGGERED
self._attr_alarm_state = AlarmControlPanelState.TRIGGERED
# Update HA entity since the panel state has changed
self.async_write_ha_state()

Expand All @@ -132,7 +124,7 @@ async def async_update(self) -> None:
try:
host_status = await self._hass_data.client.get_host_status()
host_state = host_status.host_status
self._state = STATE_MAPPING[host_state]
self._attr_alarm_state = STATE_MAPPING[host_state]
# Store alarm panel information (GSM/WiFi status/signal level etc.)
# so a sensor could use the data w/o duplicate access to
# `host_info` property of `G90Alarm`, which issues a device call
Expand All @@ -150,13 +142,6 @@ async def async_update(self) -> None:
repr(exc)
)

@property
def state(self) -> str:
"""
Returns the platform state.
"""
return self._state

async def async_alarm_disarm(self, _code: str | None = None) -> None:
"""Send disarm command."""
try:
Expand Down
14 changes: 13 additions & 1 deletion custom_components/gs_alarm/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from __future__ import annotations
import logging

from typing import Any, cast
from typing import Any, cast, Self

import voluptuous as vol

Expand Down Expand Up @@ -118,6 +118,18 @@ def async_get_options_flow(
"""
return OptionsFlowHandler(config_entry)

def is_matching(self, other_flow: Self) -> bool:
"""
Determine if there is another flow for the same entity running already.
Not currently implemented, and only used to prevent `pylint` from
erroring out stating the method is abstract in the base class:
W0223: Method 'is_matching' is abstract in class 'ConfigFlow' but
is not overridden in child class 'G90ConfigFlow' (abstract-method)
"""
raise NotImplementedError


# pylint:disable=too-few-public-methods
class OptionsFlowHandler(OptionsFlow):
Expand Down
2 changes: 1 addition & 1 deletion requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
flake8==7.0.0
pylint==3.0.3
coverage==7.6.1
pytest-homeassistant-custom-component==0.13.174
pytest-homeassistant-custom-component==0.13.183
pytest==8.3.3
pytest-cov==5.0.0
pytest-unordered==0.6.1
Expand Down
18 changes: 10 additions & 8 deletions tests/test_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
MockConfigEntry,
)
from homeassistant.core import HomeAssistant
from homeassistant.const import (
STATE_ALARM_DISARMED,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_TRIGGERED,
from homeassistant.components.alarm_control_panel.const import (
AlarmControlPanelState,
)

from pyg90alarm import G90ArmDisarmTypes
Expand Down Expand Up @@ -45,8 +43,11 @@ async def test_alarm_callback(
# Verify panel state and attributes reflect that
panel_state = hass.states.get('alarm_control_panel.dummy_guid')
assert panel_state is not None
assert panel_state.state == STATE_ALARM_TRIGGERED
assert panel_state.attributes.get('changed_by') == 'binary_sensor.dummy_1'
assert panel_state.state == AlarmControlPanelState.TRIGGERED
assert panel_state.attributes is not None
assert panel_state.attributes.get('changed_by') == (
'binary_sensor.dummy_1'
)

# Simulate the arm callback is triggered
mock_g90alarm.return_value.armdisarm_callback(
Expand All @@ -55,6 +56,7 @@ async def test_alarm_callback(
# Verify `changed_by` attribute has been reset
panel_state = hass.states.get('alarm_control_panel.dummy_guid')
assert panel_state is not None
assert panel_state.attributes is not None
assert panel_state.attributes.get('changed_by') is None


Expand Down Expand Up @@ -86,7 +88,7 @@ async def test_arm_callback(
# Verify panel state reflects that
panel_state = hass.states.get('alarm_control_panel.dummy_guid')
assert panel_state is not None
assert panel_state.state == STATE_ALARM_ARMED_AWAY
assert panel_state.state == AlarmControlPanelState.ARMED_AWAY


@pytest.mark.g90host_status(
Expand Down Expand Up @@ -118,7 +120,7 @@ async def test_disarm_callback(
# Verify panel state reflects that
panel_state = hass.states.get('alarm_control_panel.dummy_guid')
assert panel_state is not None
assert panel_state.state == STATE_ALARM_DISARMED
assert panel_state.state == AlarmControlPanelState.DISARMED


async def test_low_battery_callback(
Expand Down
7 changes: 3 additions & 4 deletions tests/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@
SERVICE_ALARM_DISARM,
SERVICE_TURN_ON,
SERVICE_TURN_OFF,
STATE_ALARM_DISARMED,
STATE_OFF,
)
from homeassistant.components.alarm_control_panel.const import (
DOMAIN as ALARM_DOMAIN
DOMAIN as ALARM_DOMAIN, AlarmControlPanelState,
)
from homeassistant.components.switch.const import (
DOMAIN as SWITCH_DOMAIN
Expand Down Expand Up @@ -112,7 +111,7 @@ async def test_alarm_panel_state_update_exception(
# Verify the panel's state is unknown
panel_state = hass.states.get('alarm_control_panel.dummy_guid')
assert panel_state is not None
assert panel_state.state == STATE_ALARM_DISARMED
assert panel_state.state == AlarmControlPanelState.DISARMED


@pytest.mark.parametrize("failed_service,failed_g90_method", [
Expand Down Expand Up @@ -158,7 +157,7 @@ async def test_alarm_panel_service_exception(

# Verify the panel's state is left unchanged - `mock_g90alarm` simulates
# the panel is disarmed during initial setup
assert entity.state == STATE_ALARM_DISARMED
assert entity.state == AlarmControlPanelState.DISARMED


@pytest.mark.parametrize("failed_service,failed_g90_method", [
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ setenv =

commands =
flake8 --tee --output-file=flake8.txt custom_components/ tests/
pylint --output-format=parseable:pylint.txt custom_components/ tests/
pylint --output-format=text,parseable:pylint.txt custom_components/ tests/
mypy --strict --cobertura-xml-report=mypy/ custom_components/ tests/
# Ensure only traces for in-repository module is processed, not for one
# installed by `tox` (see above for more details)
Expand Down

0 comments on commit 305212c

Please sign in to comment.