From 0b15f3aa989b5d05526928d224ec254b7ef9686a Mon Sep 17 00:00:00 2001
From: Franck Nijhof <git@frenck.dev>
Date: Fri, 28 May 2021 08:29:01 +0200
Subject: [PATCH] Define alarm_control_panel entity attributes as class
 variables (#51120)

* Define alarm_control_panel entity attributes as class variables

* Example Verisure

* Remove redundant AttributeError
---
 .../alarm_control_panel/__init__.py           | 14 ++++++++-----
 .../verisure/alarm_control_panel.py           | 20 +++----------------
 2 files changed, 12 insertions(+), 22 deletions(-)

diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py
index 2d6d1f4d5b1..c8da648fec6 100644
--- a/homeassistant/components/alarm_control_panel/__init__.py
+++ b/homeassistant/components/alarm_control_panel/__init__.py
@@ -1,7 +1,6 @@
 """Component to interface with an alarm control panel."""
 from __future__ import annotations
 
-from abc import abstractmethod
 from datetime import timedelta
 import logging
 from typing import Any, Final, final
@@ -113,20 +112,25 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
 class AlarmControlPanelEntity(Entity):
     """An abstract class for alarm control entities."""
 
+    _attr_changed_by: str | None = None
+    _attr_code_arm_required: bool = True
+    _attr_code_format: str | None = None
+    _attr_supported_features: int
+
     @property
     def code_format(self) -> str | None:
         """Regex for code format or None if no code is required."""
-        return None
+        return self._attr_code_format
 
     @property
     def changed_by(self) -> str | None:
         """Last change triggered by."""
-        return None
+        return self._attr_changed_by
 
     @property
     def code_arm_required(self) -> bool:
         """Whether the code is required for arm actions."""
-        return True
+        return self._attr_code_arm_required
 
     def alarm_disarm(self, code: str | None = None) -> None:
         """Send disarm command."""
@@ -177,9 +181,9 @@ class AlarmControlPanelEntity(Entity):
         await self.hass.async_add_executor_job(self.alarm_arm_custom_bypass, code)
 
     @property
-    @abstractmethod
     def supported_features(self) -> int:
         """Return the list of supported features."""
+        return self._attr_supported_features
 
     @final
     @property
diff --git a/homeassistant/components/verisure/alarm_control_panel.py b/homeassistant/components/verisure/alarm_control_panel.py
index 4def470ac5e..176ca9444c1 100644
--- a/homeassistant/components/verisure/alarm_control_panel.py
+++ b/homeassistant/components/verisure/alarm_control_panel.py
@@ -35,8 +35,9 @@ class VerisureAlarm(CoordinatorEntity, AlarmControlPanelEntity):
 
     coordinator: VerisureDataUpdateCoordinator
 
+    _attr_code_format = FORMAT_NUMBER
     _attr_name = "Verisure Alarm"
-    _changed_by: str | None = None
+    _attr_supported_features = SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
 
     @property
     def device_info(self) -> DeviceInfo:
@@ -48,26 +49,11 @@ class VerisureAlarm(CoordinatorEntity, AlarmControlPanelEntity):
             "identifiers": {(DOMAIN, self.coordinator.entry.data[CONF_GIID])},
         }
 
-    @property
-    def supported_features(self) -> int:
-        """Return the list of supported features."""
-        return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
-
     @property
     def unique_id(self) -> str:
         """Return the unique ID for this entity."""
         return self.coordinator.entry.data[CONF_GIID]
 
-    @property
-    def code_format(self) -> str:
-        """Return one or more digits/characters."""
-        return FORMAT_NUMBER
-
-    @property
-    def changed_by(self) -> str | None:
-        """Return the last change triggered by."""
-        return self._changed_by
-
     async def _async_set_arm_state(self, state: str, code: str | None = None) -> None:
         """Send set arm state command."""
         arm_state = await self.hass.async_add_executor_job(
@@ -102,7 +88,7 @@ class VerisureAlarm(CoordinatorEntity, AlarmControlPanelEntity):
         self._attr_state = ALARM_STATE_TO_HA.get(
             self.coordinator.data["alarm"]["statusType"]
         )
-        self._changed_by = self.coordinator.data["alarm"].get("name")
+        self._attr_changed_by = self.coordinator.data["alarm"].get("name")
         super()._handle_coordinator_update()
 
     async def async_added_to_hass(self) -> None: