diff --git a/homeassistant/components/alarmdecoder/__init__.py b/homeassistant/components/alarmdecoder/__init__.py index aff7dd8c5ba..69870450869 100644 --- a/homeassistant/components/alarmdecoder/__init__.py +++ b/homeassistant/components/alarmdecoder/__init__.py @@ -129,7 +129,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a AlarmDecoder entry.""" hass.data[DOMAIN][entry.entry_id][DATA_RESTART] = False diff --git a/homeassistant/components/alarmdecoder/alarm_control_panel.py b/homeassistant/components/alarmdecoder/alarm_control_panel.py index 47da48de66f..3a0b3923231 100644 --- a/homeassistant/components/alarmdecoder/alarm_control_panel.py +++ b/homeassistant/components/alarmdecoder/alarm_control_panel.py @@ -77,24 +77,18 @@ async def async_setup_entry( class AlarmDecoderAlarmPanel(AlarmControlPanelEntity): """Representation of an AlarmDecoder-based alarm panel.""" + _attr_name = "Alarm Panel" + _attr_should_poll = False + _attr_code_format = FORMAT_NUMBER + _attr_supported_features = ( + SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_NIGHT + ) + def __init__(self, client, auto_bypass, code_arm_required, alt_night_mode): """Initialize the alarm panel.""" self._client = client - self._display = "" - self._name = "Alarm Panel" - self._state = None - self._ac_power = None - self._alarm_event_occurred = None - self._backlight_on = None - self._battery_low = None - self._check_zone = None - self._chime = None - self._entry_delay_off = None - self._programming_mode = None - self._ready = None - self._zone_bypassed = None self._auto_bypass = auto_bypass - self._code_arm_required = code_arm_required + self._attr_code_arm_required = code_arm_required self._alt_night_mode = alt_night_mode async def async_added_to_hass(self): @@ -108,75 +102,29 @@ class AlarmDecoderAlarmPanel(AlarmControlPanelEntity): def _message_callback(self, message): """Handle received messages.""" if message.alarm_sounding or message.fire_alarm: - self._state = STATE_ALARM_TRIGGERED + self._attr_state = STATE_ALARM_TRIGGERED elif message.armed_away: - self._state = STATE_ALARM_ARMED_AWAY + self._attr_state = STATE_ALARM_ARMED_AWAY elif message.armed_home and (message.entry_delay_off or message.perimeter_only): - self._state = STATE_ALARM_ARMED_NIGHT + self._attr_state = STATE_ALARM_ARMED_NIGHT elif message.armed_home: - self._state = STATE_ALARM_ARMED_HOME + self._attr_state = STATE_ALARM_ARMED_HOME else: - self._state = STATE_ALARM_DISARMED + self._attr_state = STATE_ALARM_DISARMED - self._ac_power = message.ac_power - self._alarm_event_occurred = message.alarm_event_occurred - self._backlight_on = message.backlight_on - self._battery_low = message.battery_low - self._check_zone = message.check_zone - self._chime = message.chime_on - self._entry_delay_off = message.entry_delay_off - self._programming_mode = message.programming_mode - self._ready = message.ready - self._zone_bypassed = message.zone_bypassed - - self.schedule_update_ha_state() - - @property - def name(self): - """Return the name of the device.""" - return self._name - - @property - def should_poll(self): - """Return the polling state.""" - return False - - @property - def code_format(self): - """Return one or more digits/characters.""" - return FORMAT_NUMBER - - @property - def state(self): - """Return the state of the device.""" - return self._state - - @property - def supported_features(self) -> int: - """Return the list of supported features.""" - return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_NIGHT - - @property - def code_arm_required(self): - """Whether the code is required for arm actions.""" - return self._code_arm_required - - @property - def extra_state_attributes(self): - """Return the state attributes.""" - return { - "ac_power": self._ac_power, - "alarm_event_occurred": self._alarm_event_occurred, - "backlight_on": self._backlight_on, - "battery_low": self._battery_low, - "check_zone": self._check_zone, - "chime": self._chime, - "entry_delay_off": self._entry_delay_off, - "programming_mode": self._programming_mode, - "ready": self._ready, - "zone_bypassed": self._zone_bypassed, - "code_arm_required": self._code_arm_required, + self._attr_extra_state_attributes = { + "ac_power": message.ac_power, + "alarm_event_occurred": message.alarm_event_occurred, + "backlight_on": message.backlight_on, + "battery_low": message.battery_low, + "check_zone": message.check_zone, + "chime": message.chime_on, + "entry_delay_off": message.entry_delay_off, + "programming_mode": message.programming_mode, + "ready": message.ready, + "zone_bypassed": message.zone_bypassed, } + self.schedule_update_ha_state() def alarm_disarm(self, code=None): """Send disarm command.""" @@ -187,7 +135,7 @@ class AlarmDecoderAlarmPanel(AlarmControlPanelEntity): """Send arm away command.""" self._client.arm_away( code=code, - code_arm_required=self._code_arm_required, + code_arm_required=self._attr_code_arm_required, auto_bypass=self._auto_bypass, ) @@ -195,7 +143,7 @@ class AlarmDecoderAlarmPanel(AlarmControlPanelEntity): """Send arm home command.""" self._client.arm_home( code=code, - code_arm_required=self._code_arm_required, + code_arm_required=self._attr_code_arm_required, auto_bypass=self._auto_bypass, ) @@ -203,7 +151,7 @@ class AlarmDecoderAlarmPanel(AlarmControlPanelEntity): """Send arm night command.""" self._client.arm_night( code=code, - code_arm_required=self._code_arm_required, + code_arm_required=self._attr_code_arm_required, alt_night_mode=self._alt_night_mode, auto_bypass=self._auto_bypass, ) diff --git a/homeassistant/components/alarmdecoder/binary_sensor.py b/homeassistant/components/alarmdecoder/binary_sensor.py index 71bcc399e08..397394e256b 100644 --- a/homeassistant/components/alarmdecoder/binary_sensor.py +++ b/homeassistant/components/alarmdecoder/binary_sensor.py @@ -60,6 +60,8 @@ async def async_setup_entry( class AlarmDecoderBinarySensor(BinarySensorEntity): """Representation of an AlarmDecoder binary sensor.""" + _attr_should_poll = False + def __init__( self, zone_number, @@ -73,13 +75,12 @@ class AlarmDecoderBinarySensor(BinarySensorEntity): """Initialize the binary_sensor.""" self._zone_number = int(zone_number) self._zone_type = zone_type - self._state = None - self._name = zone_name + self._attr_name = zone_name self._rfid = zone_rfid self._loop = zone_loop - self._rfstate = None self._relay_addr = relay_addr self._relay_chan = relay_chan + self._attr_device_class = zone_type async def async_added_to_hass(self): """Register callbacks.""" @@ -107,59 +108,35 @@ class AlarmDecoderBinarySensor(BinarySensorEntity): ) ) - @property - def name(self): - """Return the name of the entity.""" - return self._name - - @property - def should_poll(self): - """No polling needed.""" - return False - - @property - def extra_state_attributes(self): - """Return the state attributes.""" - attr = {CONF_ZONE_NUMBER: self._zone_number} - if self._rfid and self._rfstate is not None: - attr[ATTR_RF_BIT0] = bool(self._rfstate & 0x01) - attr[ATTR_RF_LOW_BAT] = bool(self._rfstate & 0x02) - attr[ATTR_RF_SUPERVISED] = bool(self._rfstate & 0x04) - attr[ATTR_RF_BIT3] = bool(self._rfstate & 0x08) - attr[ATTR_RF_LOOP3] = bool(self._rfstate & 0x10) - attr[ATTR_RF_LOOP2] = bool(self._rfstate & 0x20) - attr[ATTR_RF_LOOP4] = bool(self._rfstate & 0x40) - attr[ATTR_RF_LOOP1] = bool(self._rfstate & 0x80) - return attr - - @property - def is_on(self): - """Return true if sensor is on.""" - return self._state == 1 - - @property - def device_class(self): - """Return the class of this sensor, from DEVICE_CLASSES.""" - return self._zone_type - def _fault_callback(self, zone): """Update the zone's state, if needed.""" if zone is None or int(zone) == self._zone_number: - self._state = 1 + self._attr_state = 1 self.schedule_update_ha_state() def _restore_callback(self, zone): """Update the zone's state, if needed.""" if zone is None or (int(zone) == self._zone_number and not self._loop): - self._state = 0 + self._attr_state = 0 self.schedule_update_ha_state() def _rfx_message_callback(self, message): """Update RF state.""" if self._rfid and message and message.serial_number == self._rfid: - self._rfstate = message.value + rfstate = message.value if self._loop: - self._state = 1 if message.loop[self._loop - 1] else 0 + self._attr_state = 1 if message.loop[self._loop - 1] else 0 + attr = {CONF_ZONE_NUMBER: self._zone_number} + if self._rfid and rfstate is not None: + attr[ATTR_RF_BIT0] = bool(rfstate & 0x01) + attr[ATTR_RF_LOW_BAT] = bool(rfstate & 0x02) + attr[ATTR_RF_SUPERVISED] = bool(rfstate & 0x04) + attr[ATTR_RF_BIT3] = bool(rfstate & 0x08) + attr[ATTR_RF_LOOP3] = bool(rfstate & 0x10) + attr[ATTR_RF_LOOP2] = bool(rfstate & 0x20) + attr[ATTR_RF_LOOP4] = bool(rfstate & 0x40) + attr[ATTR_RF_LOOP1] = bool(rfstate & 0x80) + self._attr_extra_state_attributes = attr self.schedule_update_ha_state() def _rel_message_callback(self, message): @@ -173,5 +150,5 @@ class AlarmDecoderBinarySensor(BinarySensorEntity): message.channel, message.value, ) - self._state = message.value + self._attr_state = message.value self.schedule_update_ha_state() diff --git a/homeassistant/components/alarmdecoder/sensor.py b/homeassistant/components/alarmdecoder/sensor.py index e3c85cb5893..67b7ee4861a 100644 --- a/homeassistant/components/alarmdecoder/sensor.py +++ b/homeassistant/components/alarmdecoder/sensor.py @@ -8,7 +8,7 @@ from .const import SIGNAL_PANEL_MESSAGE async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities -): +) -> bool: """Set up for AlarmDecoder sensor.""" entity = AlarmDecoderSensor() @@ -19,12 +19,9 @@ async def async_setup_entry( class AlarmDecoderSensor(SensorEntity): """Representation of an AlarmDecoder keypad.""" - def __init__(self): - """Initialize the alarm panel.""" - self._display = "" - self._state = None - self._icon = "mdi:alarm-check" - self._name = "Alarm Panel Display" + _attr_icon = "mdi:alarm-check" + _attr_name = "Alarm Panel Display" + _attr_should_poll = False async def async_added_to_hass(self): """Register callbacks.""" @@ -35,26 +32,6 @@ class AlarmDecoderSensor(SensorEntity): ) def _message_callback(self, message): - if self._display != message.text: - self._display = message.text + if self._attr_state != message.text: + self._attr_state = message.text self.schedule_update_ha_state() - - @property - def icon(self): - """Return the icon if any.""" - return self._icon - - @property - def state(self): - """Return the overall state.""" - return self._display - - @property - def name(self): - """Return the name of the device.""" - return self._name - - @property - def should_poll(self): - """No polling needed.""" - return False diff --git a/tests/components/alarmdecoder/test_config_flow.py b/tests/components/alarmdecoder/test_config_flow.py index 2ab965023bd..8a2aae48f9b 100644 --- a/tests/components/alarmdecoder/test_config_flow.py +++ b/tests/components/alarmdecoder/test_config_flow.py @@ -126,6 +126,16 @@ async def test_setup_connection_error(hass: HomeAssistant): assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"] == {"base": "cannot_connect"} + with patch( + "homeassistant.components.alarmdecoder.config_flow.AdExt.open", + side_effect=Exception, + ), patch("homeassistant.components.alarmdecoder.config_flow.AdExt.close"): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], connection_settings + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["errors"] == {"base": "unknown"} + async def test_options_arm_flow(hass: HomeAssistant): """Test arm options flow."""