From cbf3bfa3cbb28ac08d34ee61c1dd37731617bbad Mon Sep 17 00:00:00 2001 From: sdmorris1950 Date: Sun, 3 Nov 2024 18:41:23 +0200 Subject: [PATCH 1/3] extended current functionality 1) include all CONTACT types 2) give all devices the user's names instead of sensor IDs, which appears in the entity ID 3) report whether CURTAIN and MOTION sensors are on or off, depending on whether DISARM, HOME or AWAY 4) added icons to show state of sensors 4) give alarm panel unique_id --- .../visonicalarm/alarm_control_panel.py | 33 ++++--- custom_components/visonicalarm/sensor.py | 87 +++++++++++++++---- 2 files changed, 89 insertions(+), 31 deletions(-) diff --git a/custom_components/visonicalarm/alarm_control_panel.py b/custom_components/visonicalarm/alarm_control_panel.py index 1e26865..774902a 100644 --- a/custom_components/visonicalarm/alarm_control_panel.py +++ b/custom_components/visonicalarm/alarm_control_panel.py @@ -1,25 +1,29 @@ """ Interfaces with the Visonic Alarm control panel. """ + import logging from time import sleep from datetime import timedelta import homeassistant.components.alarm_control_panel as alarm +from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature import homeassistant.components.persistent_notification as pn -from homeassistant.const import (STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, - STATE_ALARM_DISARMED, STATE_UNKNOWN, - STATE_ALARM_ARMING, STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED ) -from homeassistant.const import (EVENT_STATE_CHANGED) -from homeassistant.const import (ATTR_CODE_FORMAT) -from homeassistant.components.alarm_control_panel.const import ( - SUPPORT_ALARM_ARM_AWAY, - SUPPORT_ALARM_ARM_HOME +from homeassistant.const import ( + ATTR_CODE_FORMAT, + EVENT_STATE_CHANGED, + STATE_ALARM_ARMED_AWAY, + STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMING, + STATE_ALARM_DISARMED, + STATE_ALARM_PENDING, + STATE_ALARM_TRIGGERED, + STATE_UNKNOWN, ) -from . import HUB as hub -from . import (CONF_USER_CODE, CONF_EVENT_HOUR_OFFSET, CONF_NO_PIN_REQUIRED) -SUPPORT_VISONIC = (SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY) +from . import CONF_EVENT_HOUR_OFFSET, CONF_NO_PIN_REQUIRED, CONF_USER_CODE, HUB as hub + +SUPPORT_VISONIC = AlarmControlPanelEntityFeature.ARM_HOME | AlarmControlPanelEntityFeature.ARM_AWAY _LOGGER = logging.getLogger(__name__) @@ -29,7 +33,6 @@ ATTR_SYSTEM_CONNECTED = 'connected' ATTR_SYSTEM_SESSION_TOKEN = 'session_token' ATTR_SYSTEM_LAST_UPDATE = 'last_update' -ATTR_CODE_FORMAT = 'code_format' ATTR_CHANGED_BY = 'changed_by' ATTR_CHANGED_TIMESTAMP = 'changed_timestamp' ATTR_ALARMS = 'alarm' @@ -79,12 +82,18 @@ def __init__(self, hass): self._changed_by = None self._changed_timestamp = None self._event_hour_offset = hub.config.get(CONF_EVENT_HOUR_OFFSET) + self._id = hub.alarm.serial_number @property def name(self): """ Return the name of the device. """ return 'Visonic Alarm' + @property + def unique_id(self): + """Return a unique id.""" + return self._id + @property def state_attributes(self): """ Return the state attributes of the alarm system. """ diff --git a/custom_components/visonicalarm/sensor.py b/custom_components/visonicalarm/sensor.py index 736b576..6e49adc 100644 --- a/custom_components/visonicalarm/sensor.py +++ b/custom_components/visonicalarm/sensor.py @@ -4,12 +4,18 @@ import logging from datetime import timedelta -from . import HUB as hub -from homeassistant.const import (STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME) -from homeassistant.const import (STATE_ALARM_DISARMED, STATE_UNKNOWN, - STATE_OPEN, STATE_CLOSED) + +from homeassistant.const import ( + STATE_CLOSED, + STATE_OFF, + STATE_ON, + STATE_OPEN, + STATE_UNKNOWN, +) from homeassistant.helpers.entity import Entity +from . import HUB as hub + _LOGGER = logging.getLogger(__name__) STATE_ALARM_ARMING_EXIT_DELAY_HOME = 'arming_exit_delay_home' @@ -38,16 +44,26 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device in hub.alarm.devices: if device is not None: if device.subtype is not None: - if 'CONTACT' in device.subtype or device.subtype == 'MOTION_CAMERA' or device.subtype == 'MOTION' or device.subtype == 'MOTION_DUAL' or device.subtype == 'MOTION_V_ANTIMASK' or device.subtype == 'CURTAIN': - _LOGGER.debug("New device found [Type:" + str(device.subtype) + "] [ID:" + str(device.id) + "]") + if ( + "CONTACT" in device.subtype + or "MOTION" in device.subtype + or "CURTAIN" in device.subtype + ): + _LOGGER.debug( + "New device found [Type:" + + str(device.subtype) + + "] [ID:" + + str(device.id) + + "]" + ) add_devices([VisonicAlarmContact(hub.alarm, device.id)], True) class VisonicAlarmContact(Entity): - """ Implementation of a Visonic Alarm Contact sensor. """ + """Implementation of a Visonic Alarm Contact sensor.""" def __init__(self, alarm, contact_id): - """ Initialize the sensor """ + """Initialize the sensor.""" self._state = STATE_UNKNOWN self._alarm = alarm self._id = contact_id @@ -58,11 +74,12 @@ def __init__(self, alarm, contact_id): @property def name(self): - """ Return the name of the sensor """ - return 'Visonic Alarm ' + str(self._id) + """Return the name of the sensor.""" + return str(self._name) @property def unique_id(self): + """Return a unique id.""" return self._id @property @@ -77,21 +94,30 @@ def state_attributes(self): @property def icon(self): - """ Return icon """ + """Return icon.""" icon = None - if self._state == STATE_CLOSED: - icon = 'mdi:door-closed' + if "24H" in self._zone: + if self._state == STATE_CLOSED: + icon = "mdi:hours-24" + elif self._state == STATE_OPEN: + icon = "mdi:alarm-light" + elif self._state == STATE_CLOSED: + icon = "mdi:door-closed" elif self._state == STATE_OPEN: - icon = 'mdi:door-open' + icon = "mdi:door-open" + elif self._state == STATE_OFF: + icon = "mdi:motion-sensor-off" + elif self._state == STATE_ON: + icon = "mdi:motion-sensor" return icon @property def state(self): - """ Return the state of the sensor. """ + """Return the state of the sensor.""" return self._state def update(self): - """ Get the latest data """ + """Get the latest data.""" try: hub.update() @@ -100,16 +126,39 @@ def update(self): status = device.state if status is None: - _LOGGER.warning("Device could not be found: %s.", self._id) + _LOGGER.warning("Device could not be found: %s", self._id) return - if status == 'opened': + if status == "opened": self._state = STATE_OPEN - elif status == 'closed': + elif status == "closed": self._state = STATE_CLOSED + elif "CURTAIN" in device.subtype or "MOTION" in device.subtype: + alarm_state = self._alarm.state + alarm_zone = device.zone + + if alarm_state in ("DISARM", "ARMING"): + if "24H" in alarm_zone: + self._state = STATE_ON + else: + self._state = STATE_OFF + elif alarm_state == "HOME": + if "INTERIOR" in alarm_zone: + self._state = STATE_OFF + else: + self._state = STATE_ON + elif alarm_state in ("AWAY", "DISARMING"): + self._state = STATE_ON + else: + self._state = STATE_UNKNOWN else: self._state = STATE_UNKNOWN + # orig_level = _LOGGER.level + # _LOGGER.setLevel(logging.DEBUG) + # _LOGGER.debug("alarm.state %s", self._alarm.state) + # _LOGGER.setLevel(orig_level) + self._zone = device.zone self._name = device.name self._device_type = device.device_type From 6cb08d1fb0f446e16dd6940a025a5a58e72ac00f Mon Sep 17 00:00:00 2001 From: sdmorris1950 Date: Thu, 2 Jan 2025 15:45:15 +0200 Subject: [PATCH 2/3] Update __init__.py require visonicalarm2==3.2.0 --- custom_components/visonicalarm/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/visonicalarm/__init__.py b/custom_components/visonicalarm/__init__.py index 9237aa7..64f030a 100644 --- a/custom_components/visonicalarm/__init__.py +++ b/custom_components/visonicalarm/__init__.py @@ -15,7 +15,7 @@ from homeassistant.util import Throttle import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['visonicalarm2==3.1.3', 'python-dateutil==2.7.3'] +REQUIREMENTS = ['visonicalarm2==3.2.0', 'python-dateutil==2.7.3'] _LOGGER = logging.getLogger(__name__) From 72333fca5e02b85c801be1ef0e6a44c4de81f88d Mon Sep 17 00:00:00 2001 From: sdmorris1950 Date: Thu, 2 Jan 2025 15:49:01 +0200 Subject: [PATCH 3/3] Update manifest.json advance version and require visonicalarm2==3.2.0 --- custom_components/visonicalarm/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/visonicalarm/manifest.json b/custom_components/visonicalarm/manifest.json index 1d649cf..bd2435c 100644 --- a/custom_components/visonicalarm/manifest.json +++ b/custom_components/visonicalarm/manifest.json @@ -2,9 +2,9 @@ "domain": "visonicalarm", "name": "Visonic/Bentel/Tyco Alarm System", "documentation": "https://github.com/And3rsL/VisonicAlarm-for-Hassio", - "version": "v3.0.6", + "version": "v3.1.0", "requirements": [ - "visonicalarm2==3.1.3", + "visonicalarm2==3.2.0", "python-dateutil==2.7.3" ], "dependencies": [],