Exemple #1
0
 def test_receive_encapsulated_command(self, rx, tx):
     rx('MULTI_CMD_ENCAP', commands=[
         make_object(command=[0x72, 0x04]),
         make_object(command=[0x5E, 0x01])
     ])
     tx('MULTI_CMD_ENCAP', commands=[
         make_object(command=[0x72, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03]),
         make_object(command=[0x5E, 0x02, 0x01, 0x02, 0x03, 0x00, 0x04, 0x00, 0x05])
     ])
 def test_version_get(self, rx, tx):
     rx('VERSION_GET')
     tx('VERSION_REPORT',
        protocol_library_type=0x06,
        protocol_version=make_object(major=1, minor=2),
        application_version=make_object(major=3, minor=4),
        hardware_version=5,
        firmware_versions=[
            make_object(major=6, minor=7),
            make_object(major=8, minor=9)
        ])
Exemple #3
0
    async def test_handle_long_command(self, rx_encrypted, tx_encrypted,
                                       bootstrap):
        await bootstrap()

        rx_encrypted('MULTI_CMD_ENCAP',
                     Version1.class_id,
                     commands=[make_object(command=[0x86, 0x13, 0x98])] * 8)
        await tx_encrypted(
            'MULTI_CMD_ENCAP',
            MultiCmd1.class_id,
            commands=[make_object(command=[0x86, 0x14, 0x98, 0x01])] * 8)
Exemple #4
0
    def test_set(self, rx, tx, tx_client, assert_observed, channel, lifeline, association_group_2):
        rx('MULTI_CHANNEL_ASSOCIATION_SET',
           group_id=1,
           node_ids=[4, 5],
           multi_channel_destinations=[
               make_object(node_id=3, bit_address=False, endpoint=4),
               make_object(node_id=5, bit_address=True, endpoint=0b00000101)
           ])
        assert_observed(channel)

        assert lifeline.targets == {1: {0, 1}, 3: {1, 2, 4}, 4: {0, 3}, 5: {0, 1, 3}}
        assert association_group_2.targets == {3: {0, 1}, 4: {1, 2}, 5: {8}}
Exemple #5
0
 def test_get(self, rx, tx, lifeline, association_group_2):
     rx('MULTI_CHANNEL_ASSOCIATION_GET', group_id=2)
     tx('MULTI_CHANNEL_ASSOCIATION_REPORT',
        group_id=2,
        max_nodes_supported=255,
        reports_to_follow=0,
        node_ids=[3],
        multi_channel_destinations=[
            make_object(node_id=3, endpoint=0b00000001, bit_address=True),
            make_object(node_id=4, endpoint=0b00000011, bit_address=True),
            make_object(node_id=5, endpoint=8, bit_address=False)
        ])
Exemple #6
0
    async def test_send_long_response(self, rx_encrypted, tx_encrypted,
                                      bootstrap):
        await bootstrap()

        rx_encrypted('MULTI_CMD_ENCAP',
                     MultiCmd1.class_id,
                     commands=[make_object(command=[0x72, 0x04])] * 3)
        await tx_encrypted(
            'MULTI_CMD_ENCAP',
            MultiCmd1.class_id,
            commands=[
                make_object(
                    command=[0x72, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03])
            ] * 3)
    def send_encapsulated_command(self, context: Context, command: List[int]):
        if len(command) <= MAX_SECURITY_FRAME_LENGTH:
            payload = make_object(sequenced=False,
                                  second=False,
                                  sequence_counter=0,
                                  command=command)

            async def flow():
                try:
                    self.send_nonce_get(context)
                    nonce = await self.external_nonce_table[context.node_id
                                                            ].get()

                    await self.encrypt_and_send(context, payload, nonce)
                except asyncio.TimeoutError:
                    pass

            asyncio.create_task(flow())
        else:
            assert len(command) <= MAX_SECURITY_FRAME_LENGTH * 2

            sequence = next(self.sequence_counter)
            first_command = command[:MAX_SECURITY_FRAME_LENGTH]
            first_payload = make_object(sequenced=True,
                                        second=False,
                                        sequence_counter=sequence,
                                        command=first_command)
            second_command = command[MAX_SECURITY_FRAME_LENGTH:]
            second_payload = make_object(sequenced=True,
                                         second=True,
                                         sequence_counter=sequence,
                                         command=second_command)

            async def flow():
                try:
                    self.send_nonce_get(context)
                    nonce = await self.external_nonce_table[context.node_id
                                                            ].get()

                    await self.encrypt_and_send(context, first_payload, nonce)
                    nonce = await self.external_nonce_table[context.node_id
                                                            ].get()

                    await self.encrypt_and_send(context, second_payload, nonce)
                except asyncio.TimeoutError:
                    pass

            asyncio.create_task(flow())
    async def start(self):
        yield AddNodeStatus.LEARN_READY, 0, None
        self.network_controller.broadcast_message('ADD_NODE_STARTED', {})

        try:
            old_home_id, old_node_id, node_info = await self.node_info
            yield AddNodeStatus.NODE_FOUND, 0, None

            if old_home_id == self.network_controller.home_id:
                yield AddNodeStatus.FAILED, 0, None
                return

            self.new_node_id = self.generate_node_id()
            self.network_controller.node_infos.add(
                self.new_node_id,
                make_object(
                    basic=node_info.basic,
                    generic=node_info.generic,
                    specific=node_info.specific,
                    # Controller doesn't store command classes, but this field is still required for serialization
                    command_class_ids=[]))
            yield AddNodeStatus.ADDING_SLAVE, self.new_node_id, node_info

            self.network_controller.send_message(
                old_home_id, old_node_id, 'ADD_TO_NETWORK',
                {'newNodeId': self.new_node_id})
            yield AddNodeStatus.PROTOCOL_DONE, self.new_node_id, None
        except CancelledError:
            pass
Exemple #9
0
def included_node(nif, node_info_repository):
    node_info = make_object(basic=0x04,
                            generic=nif.generic,
                            specific=nif.specific,
                            command_class_ids=[])
    node_info_repository.add(2, node_info)
    yield node_info
    def inner(command: List[int]):
        rx('SECURITY_NONCE_GET')
        tx('SECURITY_NONCE_REPORT', nonce=get_last_nonce())

        rx_payload(
            'SECURITY_MESSAGE_ENCAPSULATION_NONCE_GET',
            make_object(sequenced=True,
                        second=False,
                        sequence_counter=0,
                        command=command[:26]))
        tx('SECURITY_NONCE_REPORT', nonce=get_last_nonce())

        rx_payload(
            'SECURITY_MESSAGE_ENCAPSULATION',
            make_object(sequenced=True,
                        second=True,
                        sequence_counter=0,
                        command=command[26:]))
Exemple #11
0
    def get_destinations(self, group_id: int) -> Tuple[List[int], List[Object]]:
        node_ids = []
        multi_channel_destinations = []
        for node_id, endpoints in self.channel.associations.get_destinations(group_id):
            # Note: endpoints are sorted
            it = RangeIterator(endpoints)

            # If there's a 0 endpoint, add to node_ids
            for _ in it.takewhile(lambda channel: channel == 0, peek_last=True):
                node_ids.append(node_id)

            # Add endpoints 1 to 7 into a single destination via bitmask
            if (mask := create_mask(it.takewhile(lambda channel: channel <= 7, peek_last=True), start=1)) != 0:
                multi_channel_destinations.append(make_object(node_id=node_id, endpoint=mask, bit_address=True))

            # Add the rest of endpoints as separate destinations
            multi_channel_destinations.extend(make_object(node_id=node_id, endpoint=endpoint, bit_address=False)
                                              for endpoint in it)
Exemple #12
0
 def get_node_info(self) -> Object:
     return make_object(
         generic=self.root_channel.generic,
         specific=self.root_channel.specific,
         command_class_ids=[
             cc.class_id
             for cc in self.root_channel.command_classes.values()
             if cc.advertise_in_nif and cc.supported_non_securely
         ])
Exemple #13
0
def test_list_of_composites_field(from_bytes_converter, to_bytes_converter):
    schema = Schema("", [
        NumberOfField(field_name="commands"),
        ListField(name="commands",
                  element_type=Schema("_", [
                      LengthOfField(field_name="command"),
                      ListField(name="command")
                  ]))
    ])
    data = [0x03, 0x01, 0x0A, 0x03, 0x0A, 0x0B, 0x0C, 0x02, 0x0A, 0x0B]

    packet = from_bytes_converter.convert(schema, data)
    assert packet.commands == [
        make_object(command=[0x0A]),
        make_object(command=[0x0A, 0x0B, 0x0C]),
        make_object(command=[0x0A, 0x0B]),
    ]

    assert to_bytes_converter.convert(schema, packet) == data
Exemple #14
0
    def test_remove_from_group(self, rx, tx, assert_observed, channel, lifeline, association_group_2):
        rx('MULTI_CHANNEL_ASSOCIATION_REMOVE',
           group_id=1,
           node_ids=[1],
           multi_channel_destinations=[
               make_object(node_id=4, endpoint=3, bit_address=False)
           ])
        assert_observed(channel)

        assert lifeline.targets == {1: {1}, 3: {1, 2}}
        assert association_group_2.targets == {3: {0, 1}, 4: {1, 2}, 5: {8}}
    def send_group_command_list_report(self, context: Context, group_id: int):
        group = self.channel.associations.get_group(group_id)
        commands = [
            make_object(class_id=class_id, command_id=command_id)
            for class_id, command_id in group.commands
        ]

        self.send_command(context,
                          'ASSOCIATION_GROUP_COMMAND_LIST_REPORT',
                          group_id=group_id,
                          commands=commands)
    async def inner(command: List[int]):
        await asyncio.sleep(0)

        tx('SECURITY_NONCE_GET')
        await rx_nonce('SECURITY_NONCE_REPORT')

        tx_payload(
            'SECURITY_MESSAGE_ENCAPSULATION_NONCE_GET',
            make_object(sequenced=True,
                        second=False,
                        sequence_counter=0,
                        command=command[:26]))

        await rx_nonce('SECURITY_NONCE_REPORT')

        tx_payload(
            'SECURITY_MESSAGE_ENCAPSULATION',
            make_object(sequenced=True,
                        second=True,
                        sequence_counter=0,
                        command=command[26:]))
 def test_software_get(self, rx, tx):
     rx('VERSION_ZWAVE_SOFTWARE_GET')
     tx('VERSION_ZWAVE_SOFTWARE_REPORT',
        sdk_version=make_object(major=1, minor=2, patch=3),
        zwave_application_framework=make_object(api_version=make_object(
            major=2, minor=3, patch=4),
                                                build_number=1),
        host_interface=make_object(api_version=make_object(major=3,
                                                           minor=4,
                                                           patch=5),
                                   build_number=2),
        zwave_protocol=make_object(api_version=make_object(major=4,
                                                           minor=5,
                                                           patch=6),
                                   build_number=3),
        application=make_object(api_version=make_object(major=5,
                                                        minor=6,
                                                        patch=7),
                                build_number=4))
Exemple #18
0
async def test_application_node_information(rx_network, tx_req):
    rx_network(
        'APPLICATION_NODE_INFORMATION', {
            'source': {
                'homeId': 0xC0000000,
                'nodeId': 2
            },
            'nodeInfo': {
                'generic': 0x10,
                'specific': 0x01,
                'commandClassIds': [0x72, 0x5E]
            }
        })
    await tx_req('APPLICATION_SLAVE_UPDATE',
                 status=UpdateStatus.NODE_INFO_RECEIVED,
                 node_id=2,
                 node_info=make_object(basic=0x04,
                                       generic=0x10,
                                       specific=0x01,
                                       command_class_ids=[0x72, 0x5E]))
Exemple #19
0
 def send_encapsulated_command(self, context: Context,
                               commands: List[List[int]]):
     self.send_command(
         context,
         'MULTI_CMD_ENCAP',
         commands=[make_object(command=command) for command in commands])
Exemple #20
0
def test_extra_field(to_bytes_converter):
    schema = Schema("", [IntField(name="hello")])
    data = [0x11]

    packet = make_object(hello=0x11, bye=0x22)
    assert to_bytes_converter.convert(schema, packet) == data
 def test_version_get(self, rx, tx):
     rx('VERSION_GET')
     tx('VERSION_REPORT',
        protocol_library_type=0x06,
        protocol_version=make_object(major=1, minor=2),
        application_version=make_object(major=3, minor=4))
 def to_major_minor_patch(cls, data: MajorMinorPatch) -> Object:
     return make_object(major=data[0], minor=data[1], patch=data[2])
 def to_major_minor(cls, data: MajorMinor) -> Object:
     return make_object(major=data[0], minor=data[1])
Exemple #24
0
  make_command(0x59,
               'ASSOCIATION_GROUP_INFO_GET',
               refresh_cache=True,
               list_mode=False,
               group_id=0x02)),
 ([
     0x59, 0x04, 0x82, 0x02, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00,
     0x06, 0x07, 0x00, 0x00, 0x00
 ],
  make_command(0x59,
               'ASSOCIATION_GROUP_INFO_REPORT',
               list_mode=True,
               dynamic_info=False,
               groups=[
                   make_object(group_id=0x02,
                               profile=make_object(generic=0x03,
                                                   specific=0x04)),
                   make_object(group_id=0x05,
                               profile=make_object(generic=0x06,
                                                   specific=0x07))
               ])),
 ([0x59, 0x05, 0x80, 0x02],
  make_command(0x59,
               'ASSOCIATION_GROUP_COMMAND_LIST_GET',
               allow_cache=True,
               group_id=0x02)),
 ([0x59, 0x06, 0x01, 0x04, 0x03, 0x04, 0x05, 0x06],
  make_command(0x59,
               'ASSOCIATION_GROUP_COMMAND_LIST_REPORT',
               group_id=0x01,
               commands=[
 def to_software_info(cls, data: MajorMinorPatch,
                      build_number: int) -> Object:
     return make_object(api_version=cls.to_major_minor_patch(data),
                        build_number=build_number)
 ),
 (
     [0x13, 0x01, 0x02],
     make_packet('SEND_DATA', function_id=0x01, tx_status=0x02)
 ),
 (
     [0x42, 0x01],
     make_packet('SET_DEFAULT', function_id=0x01)
 ),
 (
     [0x49, 0x01, 0x02, 0x05, 0x04, 0x05, 0x06, 0x07, 0x08],
     make_packet('APPLICATION_SLAVE_UPDATE',
                 status=0x01,
                 node_id=0x02,
                 node_info=make_object(basic=0x04,
                                       generic=0x05,
                                       specific=0x06,
                                       command_class_ids=[0x07, 0x08]))
 ),
 (
     [0x4A, 0x00, 0x01, 0x02, 0x05, 0x04, 0x05, 0x06, 0x07, 0x08],
     make_packet('ADD_NODE_TO_NETWORK',
                 function_id=0x00,
                 status=0x01,
                 source=0x02,
                 node_info=make_object(basic=0x04,
                                       generic=0x05,
                                       specific=0x06,
                                       command_class_ids=[0x07, 0x08]))
 ),
 (
     [0x4B, 0x00, 0x01, 0x02, 0x05, 0x04, 0x05, 0x06, 0x07, 0x08],
Exemple #27
0
def nif():
    yield make_object(generic=2,
                      specific=3,
                      command_class_ids=[0x72, 0x5E, 0x20])
     make_command(0x60,
                  'MULTI_CHANNEL_CMD_ENCAP',
                  3,
                  source_endpoint=0x01,
                  bit_address=False,
                  destination=0x02,
                  command=[0x03, 0x04]))
]

COMMAND_CLASS_MULTI_CMD_1 = [
    ([0x8F, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x02, 0x04, 0x05],
     make_command(0x60,
                  'MULTI_CMD_ENCAP',
                  1,
                  commands=[
                      make_object(command=[0x01, 0x02, 0x03]),
                      make_object(command=[0x04, 0x05])
                  ]))
]

COMMAND_CLASS_SECURITY_1 = [
    ([0x98, 0x02], make_command(0x98, 'SECURITY_COMMANDS_SUPPORTED_GET', 1)),
    ([0x98, 0x03, 0x01, 0x02, 0x03],
     make_command(0x98,
                  'SECURITY_COMMANDS_SUPPORTED_REPORT',
                  1,
                  reports_to_follow=0x01,
                  command_class_ids=[0x02, 0x03])),
    ([0x98, 0x04, 0x01],
     make_command(0x98,
                  'SECURITY_SCHEME_GET',
 def visit_list_field(self, field: ListField, obj: Object):
     for value in getattr(obj, field.name):
         proxy = make_object(_=value)
         yield from self.visit(field.element_type, proxy)
 def get_group_info(self, group_id: int):
     group = self.channel.associations.get_group(group_id)
     return make_object(group_id=group_id,
                        profile=make_object(generic=group.profile[0],
                                            specific=group.profile[1]))