import logging from pyenvisalink import HoneywellClient from pyenvisalink import DSCClient from pyenvisalink import AlarmState _LOGGER = logging.getLogger(__name__) COMMAND_ERR = "Cannot run this command while disconnected. Please run start() first." class EnvisalinkAlarmPanel: """This class represents an envisalink-based alarm panel.""" def __init__(self, host, port=4025, panelType='HONEYWELL', envisalinkVersion=3, userName='user', password='user', zoneTimerInterval=20, keepAliveInterval=30, eventLoop=None, connectionTimeout=10, zoneBypassEnabled=False): self._host = host self._port = port self._connectionTimeout = connectionTimeout self._panelType = panelType self._evlVersion = envisalinkVersion self._username = userName self._password = password self._keepAliveInterval = keepAliveInterval self._zoneTimerInterval = zoneTimerInterval self._maxPartitions = 8 if envisalinkVersion < 4: self._maxZones = 64 else: self._maxZones = 128 self._alarmState = AlarmState.get_initial_alarm_state(self._maxZones, self._maxPartitions) self._client = None self._eventLoop = eventLoop self._zoneBypassEnabled = zoneBypassEnabled self._loginSuccessCallback = self._defaultCallback self._loginFailureCallback = self._defaultCallback self._loginTimeoutCallback = self._defaultCallback self._commandResponseCallback = self._defaultCallback self._pollResponseCallback = self._defaultCallback self._keypadUpdateCallback = self._defaultCallback self._zoneStateChangeCallback = self._defaultCallback self._partitionStateChangeCallback = self._defaultCallback self._cidEventCallback = self._defaultCallback self._zoneTimerCallback = self._defaultCallback @property def host(self): return self._host @ property def port(self): return self._port @ property def connection_timeout(self): return self._connectionTimeout @property def user_name(self): return self._username @property def password(self): return self._password @property def panel_type(self): return self._panelType @property def envisalink_version(self): return self._evlVersion @property def keepalive_interval(self): return self._keepAliveInterval @property def zone_timer_interval(self): return self._zoneTimerInterval @property def alarm_state(self): return self._alarmState @property def callback_login(self): return self._defaultCallback @property def callback_login_success(self): return self._loginSuccessCallback @callback_login_success.setter def callback_login_success(self, value): self._loginSuccessCallback = value @property def callback_login_failure(self): return self._loginFailureCallback @callback_login_failure.setter def callback_login_failure(self, value): self._loginFailureCallback = value @property def callback_login_timeout(self): return self._loginTimeoutCallback @callback_login_timeout.setter def callback_login_timeout(self, value): self._loginTimeoutCallback = value @property def callback_poll_response(self): return self._pollResponseCallback @callback_poll_response.setter def callback_poll_response(self, value): self._pollResponseCallback = value @property def callback_command_response(self): return self._commandResponseCallback @callback_command_response.setter def callback_command_response(self, value): self._commandResponseCallback = value @property def callback_keypad_update(self): return self._keypadUpdateCallback @callback_keypad_update.setter def callback_keypad_update(self, value): self._keypadUpdateCallback = value @property def callback_zone_state_change(self): return self._zoneStateChangeCallback @callback_zone_state_change.setter def callback_zone_state_change(self, value): self._zoneStateChangeCallback = value @property def callback_partition_state_change(self): return self._partitionStateChangeCallback @callback_partition_state_change.setter def callback_partition_state_change(self, value): self._partitionStateChangeCallback = value @property def callback_realtime_cid_event(self): return self._cidEventCallback @callback_realtime_cid_event.setter def callback_realtime_cid_event(self, value): self._cidEventCallback = value @property def callback_zone_timer_dump(self): return self._zoneTimerCallback @callback_zone_timer_dump.setter def callback_zone_timer_dump(self, value): self._zoneTimerCallback = value def _defaultCallback(self, data): """This is the callback that occurs when the client doesn't subscribe.""" _LOGGER.debug("Callback has not been set by client.") def start(self): """Connect to the envisalink, and listen for events to occur.""" logging.info(str.format("Connecting to envisalink on host: {0}, port: {1}", self._host, self._port)) if self._panelType == 'HONEYWELL': self._client = HoneywellClient(self, self._eventLoop) self._client.start() elif self._panelType == 'DSC': self._client = DSCClient(self, self._eventLoop) self._client.start() else: _LOGGER.error("Unexpected panel type.") def stop(self): """Shut down and close our connection to the envisalink.""" if self._client: _LOGGER.info("Disconnecting from the envisalink...") self._client.stop() else: _LOGGER.error(COMMAND_ERR) def dump_zone_timers(self): """Request a zone timer dump from the envisalink.""" if self._client: self._client.dump_zone_timers() else: _LOGGER.error(COMMAND_ERR) def change_partition(self, partitionNumber): """Request that the default partition be changed.""" if self._client: self._client.change_partition(partitionNumber) else: _LOGGER.error(COMMAND_ERR) def keypresses_to_default_partition(self, keypresses): """Send a key to the current partition.""" if self._client: self._client.keypresses_to_default_partition(keypresses) else: _LOGGER.error(COMMAND_ERR) def keypresses_to_partition(self, partitionNumber, keypresses): """Send a key to a partition other than the current one.""" if self._client: self._client.keypresses_to_partition(partitionNumber, keypresses) else: _LOGGER.error(COMMAND_ERR) def arm_stay_partition(self, code, partitionNumber): """Public method to arm/stay a partition.""" if self._client: self._client.arm_stay_partition(code, partitionNumber) else: _LOGGER.error(COMMAND_ERR) def arm_away_partition(self, code, partitionNumber): """Public method to arm/away a partition.""" if self._client: self._client.arm_away_partition(code, partitionNumber) else: _LOGGER.error(COMMAND_ERR) def arm_max_partition(self, code, partitionNumber): """Public method to arm/max a partition.""" if self._client: self._client.arm_max_partition(code, partitionNumber) else: _LOGGER.error(COMMAND_ERR) def arm_night_partition(self, code, partitionNumber): """Public method to arm/night a partition.""" if self._client: self._client.arm_night_partition(code, partitionNumber) else: _LOGGER.error(COMMAND_ERR) def disarm_partition(self, code, partitionNumber): """Public method to disarm a partition.""" if self._client: self._client.disarm_partition(code, partitionNumber) else: _LOGGER.error(COMMAND_ERR) def panic_alarm(self, panic_type): """Public method to raise a panic alarm.""" if self._client: self._client.panic_alarm(panic_type) else: _LOGGER.error(COMMAND_ERR) def toggle_zone_bypass(self, zone): """Public method to toggle a zone's bypass state.""" if not self._zoneBypassEnabled: _LOGGER.error(COMMAND_ERR) elif self._client: self._client.toggle_zone_bypass(zone) else: _LOGGER.error(COMMAND_ERR) def command_output(self, code, partitionNumber, outputNumber): """Public method to activate an output""" if self._client: self._client.command_output(code, partitionNumber, outputNumber) else: _LOGGER.error(COMMAND_ERR)