Browse Source

Mid-process commit now that the fire refactor works correctly.

pyserial_fix
Scott Petersen 8 years ago
parent
commit
bdd99facbb
5 changed files with 98 additions and 19 deletions
  1. +63
    -9
      alarmdecoder/decoder.py
  2. +2
    -1
      alarmdecoder/messages/lrr/events.py
  3. +7
    -1
      alarmdecoder/messages/lrr/message.py
  4. +22
    -8
      alarmdecoder/messages/lrr/system.py
  5. +4
    -0
      alarmdecoder/states.py

+ 63
- 9
alarmdecoder/decoder.py View File

@@ -21,6 +21,7 @@ from .messages import Message, ExpanderMessage, RFMessage, LRRMessage
from .messages.lrr import LRRSystem from .messages.lrr import LRRSystem
from .zonetracking import Zonetracker from .zonetracking import Zonetracker
from .panels import PANEL_TYPES, ADEMCO, DSC from .panels import PANEL_TYPES, ADEMCO, DSC
from .states import FireState




class AlarmDecoder(object): class AlarmDecoder(object):
@@ -100,6 +101,10 @@ class AlarmDecoder(object):
version_flags = "" version_flags = ""
"""Device flags enabled""" """Device flags enabled"""


FIRE_STATE_NONE = 0
FIRE_STATE_FIRE = 1
FIRE_STATE_ACKNOWLEDGED = 2

def __init__(self, device, ignore_message_states=False): def __init__(self, device, ignore_message_states=False):
""" """
Constructor Constructor
@@ -121,6 +126,9 @@ class AlarmDecoder(object):
self._armed_status = None self._armed_status = None
self._armed_stay = False self._armed_stay = False
self._fire_status = (False, 0) self._fire_status = (False, 0)
self._fire_alarming = False
self._fire_alarming_changed = 0
self._fire_state = FireState.NONE
self._battery_status = (False, 0) self._battery_status = (False, 0)
self._panic_status = False self._panic_status = False
self._relay_status = {} self._relay_status = {}
@@ -411,6 +419,8 @@ class AlarmDecoder(object):
if self._internal_address_mask & msg.mask > 0: if self._internal_address_mask & msg.mask > 0:
if not self._ignore_message_states: if not self._ignore_message_states:
self._update_internal_states(msg) self._update_internal_states(msg)
else:
self._update_fire_status(status=None)


self.on_message(message=msg) self.on_message(message=msg)


@@ -678,22 +688,66 @@ class AlarmDecoder(object):


:returns: boolean indicating the new status :returns: boolean indicating the new status
""" """
is_lrr = status is not None
fire_status = status fire_status = status
if isinstance(message, Message): if isinstance(message, Message):
fire_status = message.fire_alarm fire_status = message.fire_alarm


if fire_status is None:
return

last_status, last_update = self._fire_status last_status, last_update = self._fire_status
if fire_status == last_status:
self._fire_status = (last_status, time.time())
else:
if fire_status is True or time.time() > last_update + self._fire_timeout:
print("_update_fire_status: fire_status={fire_status} last_status={last_status} last_update={last_update}".format(fire_status=fire_status, last_status=last_status, last_update=last_update))


if self._fire_state == FireState.NONE:
# Always move to a FIRE state if detected
if fire_status == True:
print("FIRE STATE: NONE -> ALARM")
self._fire_state = FireState.ALARM
self._fire_status = (fire_status, time.time())

self.on_fire(status=FireState.ALARM)

elif self._fire_state == FireState.ALARM:
# If we've received an LRR CANCEL message, move to ACKNOWLEDGED
if is_lrr and fire_status == False:
print("FIRE STATE: ALARM -> ACKNOWLEDGED")
self._fire_state = FireState.ACKNOWLEDGED
self._fire_status = (fire_status, time.time())
self.on_fire(status=FireState.ACKNOWLEDGED)
else:
# Handle bouncing status changes and timeout in order to revert back to NONE.
if last_status != fire_status or fire_status == True:
self._fire_status = (fire_status, time.time())
if fire_status == False and time.time() > last_update + self._fire_timeout:
print("FIRE STATE: ALARM -> NONE")
self._fire_state = FireState.NONE
self.on_fire(status=FireState.NONE)

elif self._fire_state == FireState.ACKNOWLEDGED:
# If we've received a second LRR FIRE message after a CANCEL, revert back to FIRE and trigger another event.
if is_lrr and fire_status == True:
print("FIRE STATE: ACKNOWLEDGED -> ALARM")
self._fire_state = FireState.ALARM
self._fire_status = (fire_status, time.time()) self._fire_status = (fire_status, time.time())
self.on_fire(status=fire_status)


return self._fire_status[0]
self.on_fire(status=FireState.ALARM)
else:
# Handle bouncing status changes and timeout in order to revert back to NONE.
if last_status != fire_status or fire_status == True:
self._fire_status = (fire_status, time.time())

# Handle timeout to revert back to NONE.
if fire_status != True and time.time() > last_update + self._fire_timeout:
print("FIRE STATE: ACKNOWLEDGED -> NONE")
self._fire_state = FireState.NONE
self.on_fire(status=FireState.NONE)

else:
print("INVALID FIRE STATE={}".format(self._fire_state))


return self._fire_state == FireState.ALARM



def _update_panic_status(self, status=None): def _update_panic_status(self, status=None):
""" """


+ 2
- 1
alarmdecoder/messages/lrr/events.py View File

@@ -677,7 +677,8 @@ LRR_FIRE_EVENTS = [
LRR_CID_EVENT.FIRE_HEAT, LRR_CID_EVENT.FIRE_HEAT,
LRR_CID_EVENT.FIRE_PULL_STATION, LRR_CID_EVENT.FIRE_PULL_STATION,
LRR_CID_EVENT.FIRE_DUCT, LRR_CID_EVENT.FIRE_DUCT,
LRR_CID_EVENT.FIRE_FLAME
LRR_CID_EVENT.FIRE_FLAME,
LRR_CID_EVENT.OPENCLOSE_CANCEL_BY_USER
] ]


LRR_POWER_EVENTS = [ LRR_POWER_EVENTS = [


+ 7
- 1
alarmdecoder/messages/lrr/message.py View File

@@ -42,7 +42,7 @@ class LRRMessage(BaseMessage):
event_description = '' event_description = ''
"""Human-readable description of LRR event.""" """Human-readable description of LRR event."""


def __init__(self, data=None):
def __init__(self, data=None, skip_report_override=False):
""" """
Constructor Constructor


@@ -51,6 +51,8 @@ class LRRMessage(BaseMessage):
""" """
BaseMessage.__init__(self) BaseMessage.__init__(self)


self.skip_report_override = skip_report_override

if data is not None: if data is not None:
self._parse_message(data) self._parse_message(data)


@@ -80,6 +82,10 @@ class LRRMessage(BaseMessage):
self.event_source = _get_event_source(self.event_prefix) self.event_source = _get_event_source(self.event_prefix)
self.event_status = int(event_type_data[1][0]) self.event_status = int(event_type_data[1][0])
self.event_code = int(event_type_data[1][1:], 16) self.event_code = int(event_type_data[1][1:], 16)

# replace last 2 digits of event_code with report_code, if applicable.
if not self.skip_report_override and self.report_code not in ['00', 'ff']:
self.event_code = int(event_type_data[1][1] + self.report_code, 16)
self.event_description = get_event_description(self.event_source, self.event_code) self.event_description = get_event_description(self.event_source, self.event_code)


except ValueError: except ValueError:


+ 22
- 8
alarmdecoder/messages/lrr/system.py View File

@@ -40,7 +40,7 @@ class LRRSystem(object):
return handled return handled


def _handle_cid_message(self, message): def _handle_cid_message(self, message):
handled = True
handled = False


status = self._get_event_status(message) status = self._get_event_status(message)
if status is None: if status is None:
@@ -48,25 +48,39 @@ class LRRSystem(object):
return return


if message.event_code in LRR_FIRE_EVENTS: if message.event_code in LRR_FIRE_EVENTS:
if message.event_code == LRR_CID_EVENT.OPENCLOSE_CANCEL_BY_USER:
status = False

print("FIRE, status={}".format(status))
self._alarmdecoder._update_fire_status(status=status) self._alarmdecoder._update_fire_status(status=status)
elif message.event_code in LRR_POWER_EVENTS:
handled = True
if message.event_code in LRR_POWER_EVENTS:
self._alarmdecoder._update_power_status(status=status) self._alarmdecoder._update_power_status(status=status)
elif message.event_code in LRR_BYPASS_EVENTS:
handled = True

if message.event_code in LRR_BYPASS_EVENTS:
self._alarmdecoder._update_zone_bypass_status(status=status) self._alarmdecoder._update_zone_bypass_status(status=status)
elif message.event_code in LRR_BATTERY_EVENTS:
handled = True

if message.event_code in LRR_BATTERY_EVENTS:
self._alarmdecoder._update_battery_status(status=status) self._alarmdecoder._update_battery_status(status=status)
elif message.event_code in LRR_PANIC_EVENTS:
handled = True

if message.event_code in LRR_PANIC_EVENTS:
if message.event_code == LRR_CID_EVENT.OPENCLOSE_CANCEL_BY_USER: if message.event_code == LRR_CID_EVENT.OPENCLOSE_CANCEL_BY_USER:
status = False status = False


self._alarmdecoder._update_panic_status(status=status) self._alarmdecoder._update_panic_status(status=status)
elif message.event_code in LRR_ARM_EVENTS:
handled = True

if message.event_code in LRR_ARM_EVENTS:
# NOTE: status on OPENCLOSE messages is backwards. # NOTE: status on OPENCLOSE messages is backwards.
status_stay = (message.event_status == LRR_EVENT_STATUS.RESTORE \ status_stay = (message.event_status == LRR_EVENT_STATUS.RESTORE \
and message.event_code in LRR_STAY_EVENTS) and message.event_code in LRR_STAY_EVENTS)
self._alarmdecoder._update_armed_status(status=not status, status_stay=status_stay) self._alarmdecoder._update_armed_status(status=not status, status_stay=status_stay)
else:
handled = False
handled = True


return handled return handled




+ 4
- 0
alarmdecoder/states.py View File

@@ -0,0 +1,4 @@
class FireState:
NONE = 0
ALARM = 1
ACKNOWLEDGED = 2

Loading…
Cancel
Save