diff --git a/dc09_spt/dc09_spt.py b/dc09_spt/dc09_spt.py index 7a22bb2..b017e83 100644 --- a/dc09_spt/dc09_spt.py +++ b/dc09_spt/dc09_spt.py @@ -236,6 +236,7 @@ def send_msg(self, mtype, mparam): current implemented is : 'SIA' or 'SIA-DCS' for sending a message with a SIA-DC03 payload 'CID' or 'ADM-CID' for sending a message with a SIA-DC05 payload + 'CONTACT-ID' for sending a message with a SIA-DC05 payload mparam a map of key value pairs defining the message content. for a description of possible values see the documentation of the payload @@ -257,6 +258,9 @@ def send_msg(self, mtype, mparam): if mtype == 'CID' or mtype == 'ADM-CID': msg = dc05_msg.dc05event(self.account, mparam) dc09type = 'ADM-CID' + if mtype == 'CONTACT-ID': + msg = dc05_msg.conactid2dc05(self.account, mparam) + dc09type = 'ADM-CID' extra = dc09_msg.dc09_extra(mparam) if extra is not None: msg = msg + extra diff --git a/dc09_spt/msg/dc05_msg.py b/dc09_spt/msg/dc05_msg.py index 436adbe..720a53a 100644 --- a/dc09_spt/msg/dc05_msg.py +++ b/dc09_spt/msg/dc05_msg.py @@ -82,7 +82,7 @@ def dc05event(spt_account, params={}): if len(code) != 3: raise Exception('Code should be 3 positions') q = param.numpar(params, 'q', '1') - if q != '1' and q != '3' and q != '3': + if q not in ['1', '3', '6']: raise Exception('Qualifier q should be 1 or 3 or 6') area = param.numpar(params, 'area', '00') if len(area) != 2: @@ -96,3 +96,60 @@ def dc05event(spt_account, params={}): zone = ('000' + zone)[-3:] msg += q + code + ' ' + area + ' ' + zone + ']' return msg + + @staticmethod + def conactid2dc05(spt_account, params={}): + """ + Construct a DC05 message, also called Ademco Contact ID + Parameters + spt_account + the account of the alarm transceiver. + in most situations this will be used in the alarm message too, but for situations like + a cloud based receiver, the account in the map will be different. + params + a map with key-value pairs. + at this moment only the more commonly used fields are used. + the currently handled keys are: + account + the account number. + most receivers expect 4 to 8 numeric digits + area + the area number in which the event happened + (area is a part of an installation that can arm and disarm independently) + zone + the alarm zone. + code + the event code in 3 numbers according to the DC05 standard. + q + the qualifier defining the state of the alarm. + 1 means new alarm + 3 means new restore + 6 means old alarm + """ + account = param.strpar(params, 'account', spt_account) + zone = param.numpar(params, 'zone', '000') + area = param.numpar(params, 'area', '00') + qualifier = param.numpar(params, 'q', '1') + event_code = param.numpar(params, 'code', '602') + + if len(event_code) != 3: + raise ValueError("Event code should be 3 digits") + + if qualifier not in ['1', '3', '6']: + raise ValueError("Qualifier should be 1 (new event) or 3 (restore) or 6 (old event)") + + qualifier_code = qualifier + event_code + + parts = [account, '18', qualifier_code, area, zone] + + # Calculate checksum + total = sum(int(digit) if digit != '0' else 10 for part in parts for digit in part) + next_multiple = ((total // 15) + 1) * 15 + checksum = next_multiple - total + checksum = checksum if checksum != 0 else 'F' + + # Complete message with checksum + complete_message = ' '.join(parts) + ' ' + str(checksum) + ']' + return complete_message + + diff --git a/setup.py b/setup.py index 6cd6f0b..35e6d23 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ], python_requires='>=3.6', install_requires=[ - 'cryptograpy>=3.1' + 'cryptography>=3.1' ] )