async def send_dev(self, destination: int, net_index: int, opcode: int, params: MessageDescription): """ Send a message using a device key. `destination` determines which device key is going to be used. For local destinations, the key is always known, but if `destination` is a remote node, the caller must first import its device key using :func:`~bluetooth_mesh.application.Application.import_remote_node`. Unlike application keys, device keys are bound to all subnets, so you need to explicitly provide `net_index`. See :py:func:`send_app` :param destination: Destination address :param net_index: Index of the network key :param opcode: Message opcode. :param params: Message parameters. """ remote = True data = AccessMessage.build(dict(opcode=opcode, params=params)) message = AccessMessage.parse(data) self.logger.debug( "Sending: %s -> %04x [remote %s, net_index %d] %r", self.element.path, destination, remote, net_index, message, ) await self._send_dev(destination, remote, net_index, data)
def dev_key_message_received(self, source: int, remote: bool, net_index: int, data: bytes): """ Called by :py:class:`bluetooth_mesh.interfaces.ElementInterface` when receiving a message encrypted with device key. The message is parsed using :py:class:`bluetooth_mesh.messages.AccessMessage` and (depending on the opcode) passed to relevant models' :py:func:`bluetooth_mesh.models.Model.dev_key_message_received`. """ try: message = AccessMessage.parse(data) except construct.ConstructError as ex: self.logger.warning( "Dev message parse error [source %04x, net_index %d, data %s]: %s", source, net_index, data.hex(), ex, ) return for model in self._models.values(): if message["opcode"] in model.OPCODES: model.dev_key_message_received(source, remote, net_index, message) return
def message_received(self, source: int, app_index: int, destination: Union[int, UUID], data: bytes): """ Called by :py:class:`bluetooth_mesh.interfaces.ElementInterface` when receiving a message encrypted with application key. The message is parsed using :py:class:`bluetooth_mesh.messages.AccessMessage` and (depending on the opcode) passed to relevant models' :func:`~bluetooth_mesh.models.Model.message_received`. """ try: message = AccessMessage.parse(data) except construct.ConstructError as ex: self.logger.warning( "App message parse error [source %04x, app_index %d, destination %04x, data %s]: %s", source, app_index, destination, data.hex(), ex, ) return for model in self._models.values(): if message["opcode"] in model.OPCODES: model.message_received(source, app_index, destination, message) return
async def send_app( self, destination: int, app_index: int, opcode: int, params: MessageDescription ): """ Send a message using an application key. :param destination: Destination address :param app_index: Index of the application key :param opcode: Message opcode. :param params: Message parameters. """ data = AccessMessage.build(dict(opcode=opcode, params=params)) message = AccessMessage.parse(data) self.logger.debug( "Sending: %s -> %04x [app_index %d] %s %r", self.element.path, destination, app_index, message["opcode"], message["params"], ) await self._send_app(destination, app_index, data)
def test_parse_capnproto(encoded, capnproto): logging.info("MESH[%i] %s", len(encoded), encoded.hex()) decoded = AccessMessage.parse(encoded) logging.info("CONSTRUCT %r", decoded) params = CaseConverter.to_camelcase(decoded) logging.info("CAPNP INPUT[%i] %s", len(json.dumps(params)), json.dumps(params)) message = capnproto.AccessMessage.new_message(**params) logging.info("CAPNP %r", message) packed = message.to_bytes_packed() logging.info("PACKED[%i] %s", len(packed), packed.hex()) unpacked = capnproto.AccessMessage.from_bytes_packed(packed) logging.info("UNPACKED %r", unpacked) params = CaseConverter.to_snakecase(unpacked.to_dict()) logging.info("CONSTRUCT INPUT %s", params) assert AccessMessage.build(params) == encoded
def test_dev_message_received(element, source, net_index, status_encoded): status_parsed = AccessMessage.parse(status_encoded) element.dev_key_message_received(source, True, net_index, status_encoded) MockModel.INSTANCES[0].dev_key_message_received.assert_called_once_with( source, True, net_index, status_parsed)
def test_message_received(element, source, app_index, status_encoded): status_parsed = AccessMessage.parse(status_encoded) element.message_received(source, app_index, False, status_encoded) MockModel.INSTANCES[0].message_received.assert_called_once_with( source, app_index, False, status_parsed)
def test_parse(encoded, decoded): result = AccessMessage.parse(data=encoded) # print(result) assert result == decoded