From 6218baa611fc2b4201527bb6f9e61aa92ea0b7d4 Mon Sep 17 00:00:00 2001 From: f34rdotcom Date: Sat, 3 Aug 2019 21:07:29 -0700 Subject: [PATCH 1/3] Ok. I sure hope that is the last quirk with Ademco system messages and alarms :( It was still cycling with fire on/off during a fire event restoring fire on system messages. Looked at my 20p and 50pul and both would show 3 on the system specific field so I am going to use it! --- alarmdecoder/decoder.py | 11 ++++++++--- setup.py | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/alarmdecoder/decoder.py b/alarmdecoder/decoder.py index 027028a..11e9d5a 100644 --- a/alarmdecoder/decoder.py +++ b/alarmdecoder/decoder.py @@ -782,7 +782,7 @@ class AlarmDecoder(object): if arm_status or stay_status: exit = False messageUp = message.text.upper() - + if self.mode == ADEMCO: # skip these messages if not messageUp.startswith("SYSTEM") and not messageUp.startswith("CHECK"): @@ -791,7 +791,7 @@ class AlarmDecoder(object): else: # preserve last state exit = self._exit - + if self.mode == DSC: if any(s in messageUp for s in ("QUICK EXIT", "EXIT DELAY")): exit = True @@ -922,7 +922,9 @@ class AlarmDecoder(object): if isinstance(message, Message): if self.mode == ADEMCO: # ignore sticky bit on these messages :( - if not message.text.startswith("SYSTEM") and not message.text.startswith("CHECK"): + if (not message.text.startswith("SYSTEM") and + not message.text.startswith("CHECK") and + message.system_fault != 3): # if we had an alarm and the sticky bit was cleared then clear the alarm if self._fire_status and not message.alarm_event_occurred: @@ -948,6 +950,9 @@ class AlarmDecoder(object): # if we timeout with an alarm set restore it if time.time() > last_update + self._fire_timeout: fire_status = False + else: + # Keep the current fire state do not update for SYSTEM messages. + fire_status = self._fire_status else: fire_status = message.fire_alarm diff --git a/setup.py b/setup.py index 190dbd1..90ed074 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ if sys.version_info < (3,): extra_requirements.append('future==0.14.3') setup(name='alarmdecoder', - version='1.13.7', + version='1.13.8', description='Python interface for the AlarmDecoder (AD2) family ' 'of alarm devices which includes the AD2USB, AD2SERIAL and AD2PI.', long_description=readme(), From 75947c726fec10284ebfd4147af6a42c1296e7c1 Mon Sep 17 00:00:00 2001 From: f34rdotcom Date: Sun, 4 Aug 2019 11:35:21 -0700 Subject: [PATCH 2/3] Remove fire timeout. Not needed now that fire is tracked correctly by removing system messages. In theory any normal message with no fire bit will clear the fire event so most of this was just workarrounds for other issues. --- alarmdecoder/decoder.py | 52 +++-------------------------------------- 1 file changed, 3 insertions(+), 49 deletions(-) diff --git a/alarmdecoder/decoder.py b/alarmdecoder/decoder.py index 11e9d5a..e280ad5 100644 --- a/alarmdecoder/decoder.py +++ b/alarmdecoder/decoder.py @@ -93,8 +93,6 @@ class AlarmDecoder(object): BATTERY_TIMEOUT = 30 """Default timeout (in seconds) before the battery status reverts.""" - FIRE_TIMEOUT = 30 - """Default tTimeout (in seconds) before the fire status reverts.""" # Attributes address = 18 @@ -143,7 +141,6 @@ class AlarmDecoder(object): self._ignore_message_states = ignore_message_states self._ignore_lrr_states = ignore_lrr_states self._battery_timeout = AlarmDecoder.BATTERY_TIMEOUT - self._fire_timeout = AlarmDecoder.FIRE_TIMEOUT self._power_status = None self._chime_status = None self._ready_status = None @@ -155,7 +152,6 @@ class AlarmDecoder(object): self._armed_stay = False self._exit = False self._fire_status = False - self._fire_status_timeout = 0 self._battery_status = (False, 0) self._panic_status = False self._relay_status = {} @@ -220,25 +216,6 @@ class AlarmDecoder(object): """ self._battery_timeout = value - @property - def fire_timeout(self): - """ - Retrieves the timeout for restoring the fire status, in seconds. - - :returns: fire status timeout - """ - return self._fire_timeout - - @fire_timeout.setter - def fire_timeout(self, value): - """ - Sets the timeout for restoring the fire status, in seconds. - - :param value: timeout in seconds - :type value: int - """ - self._fire_timeout = value - @property def internal_address_mask(self): """ @@ -916,7 +893,6 @@ class AlarmDecoder(object): fire_status = status last_status = self._fire_status - last_update = self._fire_status_timeout # Quirk in Ademco panels. Fire bit goes on/off if other alarms are on or a system fault if isinstance(message, Message): @@ -926,33 +902,12 @@ class AlarmDecoder(object): not message.text.startswith("CHECK") and message.system_fault != 3): - # if we had an alarm and the sticky bit was cleared then clear the alarm - if self._fire_status and not message.alarm_event_occurred: - # fire restore - fire_status = False - - # if we had a fire event and it went away and we still have a sticky alarm bit - # then it is not gone yet just restore it - if not message.fire_alarm and self._fire_status: - if message.alarm_event_occurred: - fire_status = self._fire_status - # if we did not have an alarm and we do now send event - if message.fire_alarm and message.fire_alarm != self._fire_status: - fire_status = message.fire_alarm - - # if we had an alarm already send and we get it again extend the timeout - if message.fire_alarm and message.fire_alarm == self._fire_status: - self._fire_status = message.fire_alarm - self._fire_status_timeout = time.time() + fire_status = message.fire_alarm else: - # if we timeout with an alarm set restore it - if time.time() > last_update + self._fire_timeout: - fire_status = False - else: - # Keep the current fire state do not update for SYSTEM messages. - fire_status = self._fire_status + # Keep the current fire state do not update for SYSTEM messages. + fire_status = self._fire_status else: fire_status = message.fire_alarm @@ -960,7 +915,6 @@ class AlarmDecoder(object): if fire_status != self._fire_status: if fire_status is not None: self._fire_status = fire_status - self._fire_status_timeout = time.time() self.on_fire(status=fire_status) return self._fire_status From cf9c94053d7084815841b67e4e634ea9ddeb635b Mon Sep 17 00:00:00 2001 From: f34rdotcom Date: Sun, 4 Aug 2019 16:53:51 -0700 Subject: [PATCH 3/3] Ok that did not work on some panels. Back to timers ;(. Sorry fire will take 30 seconds to clear. At least its not flopping back and forth anymore. --- alarmdecoder/decoder.py | 59 ++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/alarmdecoder/decoder.py b/alarmdecoder/decoder.py index e280ad5..c87e069 100644 --- a/alarmdecoder/decoder.py +++ b/alarmdecoder/decoder.py @@ -93,6 +93,8 @@ class AlarmDecoder(object): BATTERY_TIMEOUT = 30 """Default timeout (in seconds) before the battery status reverts.""" + FIRE_TIMEOUT = 30 + """Default tTimeout (in seconds) before the fire status reverts.""" # Attributes address = 18 @@ -141,6 +143,7 @@ class AlarmDecoder(object): self._ignore_message_states = ignore_message_states self._ignore_lrr_states = ignore_lrr_states self._battery_timeout = AlarmDecoder.BATTERY_TIMEOUT + self._fire_timeout = AlarmDecoder.FIRE_TIMEOUT self._power_status = None self._chime_status = None self._ready_status = None @@ -152,6 +155,7 @@ class AlarmDecoder(object): self._armed_stay = False self._exit = False self._fire_status = False + self._fire_status_timeout = 0 self._battery_status = (False, 0) self._panic_status = False self._relay_status = {} @@ -216,6 +220,25 @@ class AlarmDecoder(object): """ self._battery_timeout = value + @property + def fire_timeout(self): + """ + Retrieves the timeout for restoring the fire status, in seconds. + + :returns: fire status timeout + """ + return self._fire_timeout + + @fire_timeout.setter + def fire_timeout(self, value): + """ + Sets the timeout for restoring the fire status, in seconds. + + :param value: timeout in seconds + :type value: int + """ + self._fire_timeout = value + @property def internal_address_mask(self): """ @@ -893,21 +916,38 @@ class AlarmDecoder(object): fire_status = status last_status = self._fire_status + last_update = self._fire_status_timeout # Quirk in Ademco panels. Fire bit goes on/off if other alarms are on or a system fault if isinstance(message, Message): if self.mode == ADEMCO: - # ignore sticky bit on these messages :( - if (not message.text.startswith("SYSTEM") and - not message.text.startswith("CHECK") and - message.system_fault != 3): - - # if we did not have an alarm and we do now send event + # if we did not have an alarm and we do now send event + if message.fire_alarm and message.fire_alarm != self._fire_status: fire_status = message.fire_alarm - else: - # Keep the current fire state do not update for SYSTEM messages. - fire_status = self._fire_status + # if we had an alarm and the sticky bit was cleared then clear the alarm + ## ignore sticky bit on these messages :( + if (not message.text.startswith("SYSTEM") and + not message.text.startswith("CHECK")): + if self._fire_status and not message.alarm_event_occurred: + # fire restore + fire_status = False + + # if we had a fire event and it went away and we still have a sticky alarm bit + # then it is not gone yet just restore it + if not message.fire_alarm and self._fire_status: + if message.alarm_event_occurred: + fire_status = self._fire_status + + # if we had an alarm already and we get it again extend the timeout + if message.fire_alarm and message.fire_alarm == self._fire_status: + self._fire_status = message.fire_alarm + self._fire_status_timeout = time.time() + + # if we timeout with an alarm set restore it + if self._fire_status: + if time.time() > last_update + self._fire_timeout: + fire_status = False else: fire_status = message.fire_alarm @@ -915,6 +955,7 @@ class AlarmDecoder(object): if fire_status != self._fire_status: if fire_status is not None: self._fire_status = fire_status + self._fire_status_timeout = time.time() self.on_fire(status=fire_status) return self._fire_status