def from_bytes(cls, _bytes: bytes): # There is weird decoding here since it is mixed X-ADS and BER.... data = bytearray(_bytes) apdu_tag = data.pop(0) if apdu_tag != 0x01: raise ValueError( f"Data is not a InitiateReques APDU, got apdu tag {apdu_tag}") decoder = a_xdr.AXdrDecoder(cls.ENCODING_CONF) object_dict = decoder.decode(data) # Since the initiate request mixes a-xdr and ber encoding we make some pragmatic # one-off handling of that case. rest = bytearray(object_dict.pop("rest").value) # rest contains ber endoced propesed conformance and max reciec pdu conformance_tag = rest[:2] if conformance_tag != b"\x5f\x1f": raise ValueError( f"Didnt receive conformance tag correcly, got {conformance_tag!r}" ) conformance = xdlms.Conformance.from_bytes(data[-5:-2]) max_pdu_size = int.from_bytes(data[-2:], "big") dedicated_key_obj = object_dict.pop("dedicated_key") if dedicated_key_obj: dedicated_key = bytes(dedicated_key_obj.value) else: dedicated_key = None return cls( **object_dict, dedicated_key=dedicated_key, proposed_conformance=conformance, client_max_receive_pdu_size=max_pdu_size, )
def parse_bytes(profile_bytes: bytes): """ Profile generic are sent as a sequence of A-XDR encoded DlmsData. """ data_decoder = a_xdr.AXdrDecoder(encoding_conf=a_xdr.EncodingConf( attributes=[a_xdr.Sequence(attribute_name="data")])) entries: List[List[Any]] = data_decoder.decode(profile_bytes)["data"] return AssociationObjectListParser.parse_entries(entries)
def from_bytes(cls, source_bytes: bytes): data = bytearray(source_bytes) tag = data.pop(0) if tag != cls.TAG: raise ValueError( f"Tag not as expected. Expected: {cls.TAG} but got {tag}") decoder = a_xdr.AXdrDecoder(encoding_conf=cls.ENCODING_CONF) in_dict = decoder.decode(data) system_title = in_dict["system_title"].value ciphered_content = in_dict["ciphered_content"].value security_control = SecurityControlField.from_bytes( ciphered_content.pop(0).to_bytes(1, "big")) invocation_counter = int.from_bytes(ciphered_content[:4], "big") ciphered_text = bytes(ciphered_content[4:]) return cls(system_title, security_control, invocation_counter, ciphered_text)
encryption_key=encryption_key, authentication_key=authentication_key, ) with public_client(host=host, port=port).session() as client: response_data = client.get( cosem.CosemAttribute( interface=enumerations.CosemInterface.DATA, instance=cosem.Obis(0, 0, 0x2B, 1, 0), attribute=2, ) ) data_decoder = a_xdr.AXdrDecoder( encoding_conf=a_xdr.EncodingConf( attributes=[a_xdr.Sequence(attribute_name="data")] ) ) invocation_counter = data_decoder.decode(response_data)["data"] print(f"meter_initial_invocation_counter = {invocation_counter}") # we are not reusing the socket as of now. We just need to give the meter some time to # close the connection on its side sleep(1) with management_client( host=host, port=port, client_initial_invocation_counter=invocation_counter + 1 ).session() as client: profile = client.get( cosem.CosemAttribute(
def parse_as_dlms_data(data: bytes): data_decoder = a_xdr.AXdrDecoder(encoding_conf=a_xdr.EncodingConf( attributes=[a_xdr.Sequence(attribute_name="data")])) return data_decoder.decode(data)["data"]