Browse Source

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

pyserial_fix
Scott Petersen 7 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 .zonetracking import Zonetracker
from .panels import PANEL_TYPES, ADEMCO, DSC
from .states import FireState


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

FIRE_STATE_NONE = 0
FIRE_STATE_FIRE = 1
FIRE_STATE_ACKNOWLEDGED = 2

def __init__(self, device, ignore_message_states=False):
"""
Constructor
@@ -121,6 +126,9 @@ class AlarmDecoder(object):
self._armed_status = None
self._armed_stay = False
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._panic_status = False
self._relay_status = {}
@@ -411,6 +419,8 @@ class AlarmDecoder(object):
if self._internal_address_mask & msg.mask > 0:
if not self._ignore_message_states:
self._update_internal_states(msg)
else:
self._update_fire_status(status=None)

self.on_message(message=msg)

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

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

if fire_status is None:
return

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.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):
"""


+ 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_PULL_STATION,
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 = [


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

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

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

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

self.skip_report_override = skip_report_override

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

@@ -80,6 +82,10 @@ class LRRMessage(BaseMessage):
self.event_source = _get_event_source(self.event_prefix)
self.event_status = int(event_type_data[1][0])
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)

except ValueError:


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

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

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

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

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)
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)
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)
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)
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:
status = False

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.
status_stay = (message.event_status == LRR_EVENT_STATUS.RESTORE \
and message.event_code in LRR_STAY_EVENTS)
self._alarmdecoder._update_armed_status(status=not status, status_stay=status_stay)
else:
handled = False
handled = True

return handled



+ 4
- 0
alarmdecoder/states.py View File

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

Loading…
Cancel
Save