diff --git a/ALARM_STATUS.md b/ALARM_STATUS.md index d7c4266..77f8136 100644 --- a/ALARM_STATUS.md +++ b/ALARM_STATUS.md @@ -28,14 +28,34 @@ Code | Status ## ZoneStatus ZoneStatus is reported per Zone. +Status code we have seen are in the table below: + Code | Status ------------ | ------------- 0 | Normal 1 | Bypassed 2 | Fault -8 | Tamper +8 | Trouble/Tampered +10 | Fault + Trouble 64 | Low Battery -72 | Trouble (low battery) +65 | Low Battery + Bypassed +72 | Trouble + Low Battery 256 | Alarm/Triggered Fault is only returned when "Sensor Events" are enabled for a specific zone in Total Connect, otherwise Normal is returned. + +The returned ZoneStatus code appears to be an integer that contains a number of individual bit flags. + +Bit | Integer | Status +------------ | ------------- | ------------- +1 | 1 | Bypassed +2 | 2 | Fault +3 | 4 | ??? +4 | 8 | Tamper/Trouble +5 | 16 | ??? +6 | 32 | ??? +7 | 64 | Low Battery +8 | 128 | ??? +9 | 256 | Triggered + +So a status code of 10 ( = 2 + 8) is both faulted and troubled. Bypassed and low battery is 65 (1 + 64). Troubled and low battery is 72 (8 + 64). diff --git a/tests/test_total_connect_zone.py b/tests/test_total_connect_zone.py index 57c4370..f24b3ff 100644 --- a/tests/test_total_connect_zone.py +++ b/tests/test_total_connect_zone.py @@ -34,7 +34,7 @@ "PartitionId": "1", "ZoneTypeId": TotalConnectClient.ZONE_TYPE_SECURITY, "CanBeBypassed": 1, - "ZoneStatus": TotalConnectClient.ZONE_STATUS_TAMPER, + "ZoneStatus": TotalConnectClient.ZONE_STATUS_TROUBLE, } ZONE_LOW_BATTERY = { @@ -50,7 +50,7 @@ "PartitionId": "1", "ZoneTypeId": TotalConnectClient.ZONE_TYPE_SECURITY, "CanBeBypassed": 1, - "ZoneStatus": TotalConnectClient.ZONE_STATUS_BYPASSED_LOW_BATTERY, + "ZoneStatus": 65, } ZONE_TROUBLE_LOW_BATTERY = { @@ -58,7 +58,7 @@ "PartitionId": "1", "ZoneTypeId": TotalConnectClient.ZONE_TYPE_SECURITY, "CanBeBypassed": 1, - "ZoneStatus": TotalConnectClient.ZONE_STATUS_TROUBLE_LOW_BATTERY, + "ZoneStatus": 72, } ZONE_TRIGGERED = { @@ -157,7 +157,7 @@ def tests_tampered(self): self.assertFalse(self.zone_tampered.is_faulted()) self.assertTrue(self.zone_tampered.is_tampered()) self.assertFalse(self.zone_tampered.is_low_battery()) - self.assertFalse(self.zone_tampered.is_troubled()) + self.assertTrue(self.zone_tampered.is_troubled()) self.assertFalse(self.zone_tampered.is_triggered()) def tests_low_battery(self): @@ -182,7 +182,7 @@ def tests_trouble_low_battery(self): """Zone with low battery and trouble.""" self.assertFalse(self.zone_trouble_low_battery.is_bypassed()) self.assertFalse(self.zone_trouble_low_battery.is_faulted()) - self.assertFalse(self.zone_trouble_low_battery.is_tampered()) + self.assertTrue(self.zone_trouble_low_battery.is_tampered()) self.assertTrue(self.zone_trouble_low_battery.is_low_battery()) self.assertTrue(self.zone_trouble_low_battery.is_troubled()) self.assertFalse(self.zone_trouble_low_battery.is_triggered()) diff --git a/total_connect_client/TotalConnectClient.py b/total_connect_client/TotalConnectClient.py index ddbfb41..cee2910 100644 --- a/total_connect_client/TotalConnectClient.py +++ b/total_connect_client/TotalConnectClient.py @@ -5,7 +5,6 @@ import zeep - ARM_TYPE_AWAY = 0 ARM_TYPE_STAY = 1 ARM_TYPE_STAY_INSTANT = 2 @@ -15,10 +14,8 @@ ZONE_STATUS_NORMAL = 0 ZONE_STATUS_BYPASSED = 1 ZONE_STATUS_FAULT = 2 -ZONE_STATUS_TAMPER = 8 +ZONE_STATUS_TROUBLE = 8 # is also Tampered ZONE_STATUS_LOW_BATTERY = 64 -ZONE_STATUS_BYPASSED_LOW_BATTERY = 65 -ZONE_STATUS_TROUBLE_LOW_BATTERY = 72 ZONE_STATUS_TRIGGERED = 256 ZONE_TYPE_SECURITY = 0 @@ -80,7 +77,7 @@ def request(self, request, attempts=0): attempts += 1 response = eval(self.soap_base + request) - if response.ResultCode in (self.SUCCESS, self.FEATURE_NOT_SUPPORTED,): + if response.ResultCode in (self.SUCCESS, self.FEATURE_NOT_SUPPORTED): return zeep.helpers.serialize_object(response) if response.ResultCode == self.INVALID_SESSION: logging.debug( @@ -246,20 +243,12 @@ def arm(self, arm_type, location_id): def arm_custom(self, arm_type, location_id): """Arm custom the system. Return true if successul.""" - ZONE_INFO = { - "ZoneID": "12", - "ByPass": False, - "ZoneStatus": ZONE_STATUS_NORMAL, - } + ZONE_INFO = {"ZoneID": "12", "ByPass": False, "ZoneStatus": ZONE_STATUS_NORMAL} ZONES_LIST = {} ZONES_LIST[0] = ZONE_INFO - CUSTOM_ARM_SETTINGS = { - "ArmMode": "1", - "ArmDelay": "5", - "ZonesList": ZONES_LIST, - } + CUSTOM_ARM_SETTINGS = {"ArmMode": "1", "ArmDelay": "5", "ZonesList": ZONES_LIST} result = self.request( f"CustomArmSecuritySystem(self.token, " @@ -643,7 +632,7 @@ def __str__(self): def is_bypassed(self): """Return true if the zone is bypassed.""" - return self.status in (ZONE_STATUS_BYPASSED, ZONE_STATUS_BYPASSED_LOW_BATTERY) + return self.status & ZONE_STATUS_BYPASSED > 0 def bypass(self): """Set is_bypassed status.""" @@ -651,27 +640,23 @@ def bypass(self): def is_faulted(self): """Return true if the zone is faulted.""" - return self.status == ZONE_STATUS_FAULT + return self.status & ZONE_STATUS_FAULT > 0 def is_tampered(self): """Return true if zone is tampered.""" - return self.status == ZONE_STATUS_TAMPER + return self.status & ZONE_STATUS_TROUBLE > 0 def is_low_battery(self): """Return true if low battery.""" - return self.status in ( - ZONE_STATUS_LOW_BATTERY, - ZONE_STATUS_BYPASSED_LOW_BATTERY, - ZONE_STATUS_TROUBLE_LOW_BATTERY, - ) + return self.status & ZONE_STATUS_LOW_BATTERY > 0 def is_troubled(self): """Return true if zone is troubled.""" - return self.status == ZONE_STATUS_TROUBLE_LOW_BATTERY + return self.status & ZONE_STATUS_TROUBLE > 0 def is_triggered(self): """Return true if zone is triggered.""" - return self.status == ZONE_STATUS_TRIGGERED + return self.status & ZONE_STATUS_TRIGGERED > 0 def is_type_button(self): """Return true if zone is a button."""