| @@ -93,6 +93,8 @@ class AlarmDecoder(object): | |||||
| BATTERY_TIMEOUT = 30 | BATTERY_TIMEOUT = 30 | ||||
| """Default timeout (in seconds) before the battery status reverts.""" | """Default timeout (in seconds) before the battery status reverts.""" | ||||
| FIRE_TIMEOUT = 30 | |||||
| """Default tTimeout (in seconds) before the fire status reverts.""" | |||||
| # Attributes | # Attributes | ||||
| address = 18 | address = 18 | ||||
| @@ -141,6 +143,7 @@ class AlarmDecoder(object): | |||||
| self._ignore_message_states = ignore_message_states | self._ignore_message_states = ignore_message_states | ||||
| self._ignore_lrr_states = ignore_lrr_states | self._ignore_lrr_states = ignore_lrr_states | ||||
| self._battery_timeout = AlarmDecoder.BATTERY_TIMEOUT | self._battery_timeout = AlarmDecoder.BATTERY_TIMEOUT | ||||
| self._fire_timeout = AlarmDecoder.FIRE_TIMEOUT | |||||
| self._power_status = None | self._power_status = None | ||||
| self._chime_status = None | self._chime_status = None | ||||
| self._ready_status = None | self._ready_status = None | ||||
| @@ -152,6 +155,7 @@ class AlarmDecoder(object): | |||||
| self._armed_stay = False | self._armed_stay = False | ||||
| self._exit = False | self._exit = False | ||||
| self._fire_status = False | self._fire_status = False | ||||
| self._fire_status_timeout = 0 | |||||
| self._battery_status = (False, 0) | self._battery_status = (False, 0) | ||||
| self._panic_status = False | self._panic_status = False | ||||
| self._relay_status = {} | self._relay_status = {} | ||||
| @@ -216,6 +220,25 @@ class AlarmDecoder(object): | |||||
| """ | """ | ||||
| self._battery_timeout = value | 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 | @property | ||||
| def internal_address_mask(self): | def internal_address_mask(self): | ||||
| """ | """ | ||||
| @@ -893,21 +916,38 @@ class AlarmDecoder(object): | |||||
| fire_status = status | fire_status = status | ||||
| last_status = self._fire_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 | # Quirk in Ademco panels. Fire bit goes on/off if other alarms are on or a system fault | ||||
| if isinstance(message, Message): | if isinstance(message, Message): | ||||
| if self.mode == ADEMCO: | 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 | 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: | else: | ||||
| fire_status = message.fire_alarm | fire_status = message.fire_alarm | ||||
| @@ -915,6 +955,7 @@ class AlarmDecoder(object): | |||||
| if fire_status != self._fire_status: | if fire_status != self._fire_status: | ||||
| if fire_status is not None: | if fire_status is not None: | ||||
| self._fire_status = fire_status | self._fire_status = fire_status | ||||
| self._fire_status_timeout = time.time() | |||||
| self.on_fire(status=fire_status) | self.on_fire(status=fire_status) | ||||
| return self._fire_status | return self._fire_status | ||||