예제 #1
0
def test_userdata_basic():
    """Test insteonplm User Data type class."""
    userdata = {
        'd1': 0x11,
        'd2': 0x22,
        'd3': 0x33,
        'd4': 0x44,
        'd5': 0x55,
        'd6': 0x66,
        'd7': 0x77,
        'd8': 0x88,
        'd9': 0x99,
        'd10': 0xaa,
        'd11': 0xbb,
        'd12': 0xcc,
        'd13': 0xdd,
        'd14': 0xee
    }

    ud = Userdata(userdata)
    chk = Userdata.create_pattern(userdata)
    chk2 = Userdata.create_pattern({'d1': 0x11})
    assert chk == ud
    assert ud.matches_pattern(chk2)
    assert chk2.matches_pattern(ud)
def test_message_callback_extended():
    """Test message callback extended."""
    callbacks = MessageCallback()
    callbacktest = "test callback"
    address = '1a2b3c'
    target = '4d5e6f'

    template_ext_on = ExtendedReceive.template(
        commandtuple=COMMAND_LIGHT_ON_0X11_NONE,
        userdata=Userdata({'d1': 0x02}))
    callbacks.add(template_ext_on, callbacktest)
    msg1 = ExtendedReceive(address,
                           target,
                           COMMAND_LIGHT_ON_0X11_NONE,
                           Userdata({'d1': 0x02}),
                           cmd2=0xff)
    msg2 = ExtendedReceive(address,
                           target,
                           COMMAND_LIGHT_ON_0X11_NONE,
                           Userdata({
                               'd1': 0x03,
                               'd2': 0x02
                           }),
                           cmd2=0xff)

    callback1 = callbacks.get_callbacks_from_message(msg1)
    callback2 = callbacks.get_callbacks_from_message(msg2)

    assert callback1[0] == callbacktest
    assert not callback2
예제 #3
0
    def _register_messages(self):
        mode_status_msg = StandardReceive.template(
            commandtuple=COMMAND_THERMOSTAT_MODE_STATUS_0X70_NONE,
            address=self._address,
            flags=MessageFlags.template(MESSAGE_TYPE_DIRECT_MESSAGE, None),
        )
        mode_change_fan_on_ack = StandardReceive.template(
            commandtuple=COMMAND_THERMOSTAT_CONTROL_ON_FAN_0X6B_0X07,
            address=self._address,
            flags=MessageFlags.template(MESSAGE_TYPE_DIRECT_MESSAGE_ACK),
        )
        mode_change_fan_auto_ack = StandardReceive.template(
            commandtuple=COMMAND_THERMOSTAT_CONTROL_OFF_FAN_0X6B_0X08,
            address=self._address,
            flags=MessageFlags.template(MESSAGE_TYPE_DIRECT_MESSAGE_ACK),
        )
        mode_change_off_ack = StandardReceive.template(
            commandtuple=COMMAND_THERMOSTAT_CONTROL_OFF_ALL_0X6B_0X09,
            address=self._address,
            flags=MessageFlags.template(MESSAGE_TYPE_DIRECT_MESSAGE_ACK),
        )
        ext_status_recd = ExtendedReceive.template(
            commandtuple=COMMAND_EXTENDED_GET_SET_0X2E_0X00,
            cmd2=0x02,
            userdata=Userdata.template({"d1": 0x01}),
        )

        self._message_callbacks.add(mode_status_msg, self._status_received)
        self._message_callbacks.add(mode_change_fan_on_ack,
                                    self._mode_change_ack)
        self._message_callbacks.add(mode_change_fan_auto_ack,
                                    self._mode_change_ack)
        self._message_callbacks.add(mode_change_off_ack, self._mode_change_ack)
        self._message_callbacks.add(ext_status_recd, self._ext_status_received)
예제 #4
0
    def _create_set_property_msg(self, prop, cmd, val):
        """Create an extended message to set a property.

        Create an extended message with:
            cmd1: 0x2e
            cmd2: 0x00
            flags: Direct Extended
            d1: group
            d2: cmd
            d3: val
            d4 - d14: 0x00

        Parameters:
            prop: Property name to update
            cmd: Command value
                0x02: on mask
                0x03: off mask
                0x04: x10 house code
                0x05: ramp rate
                0x06: on level
                0x07: LED brightness
                0x08: Non-Toggle mask
                0x09: LED bit mask (Do not use in this class. Use LED class)
                0x0a: X10 All bit mask
                0x0c: Trigger group bit mask
            val: New property value

        """
        user_data = Userdata({'d1': self.group, 'd2': cmd, 'd3': val})
        msg = ExtendedSend(self._address, COMMAND_EXTENDED_GET_SET_0X2E_0X00,
                           user_data)
        msg.set_checksum()
        self._set_sent_property(prop, val)
        return msg
예제 #5
0
    def __init__(self,
                 address,
                 target,
                 commandtuple,
                 userdata,
                 cmd2=None,
                 flags=0x10):
        """Initialize the ExtendedRecieve message class."""
        if commandtuple.get('cmd1', None) is not None:
            cmd1 = commandtuple['cmd1']
            cmd2out = commandtuple['cmd2']
        else:
            raise ValueError

        if cmd2 is not None:
            cmd2out = cmd2

        if cmd2out is None:
            raise ValueError

        self._address = Address(address)
        self._target = Address(target)
        self._messageFlags = MessageFlags(flags)
        # self._messageFlags.extended = 1
        self._cmd1 = cmd1
        self._cmd2 = cmd2out
        self._userdata = Userdata(userdata)
예제 #6
0
    def template(
        cls,
        address=None,
        target=None,
        commandtuple=None,
        userdata=None,
        cmd2=-1,
        flags=None,
    ):
        """Create message template for callbacks."""
        msgraw = bytearray([0x02, cls._code])
        msgraw.extend(bytes(cls._receivedSize))
        msg = ExtendedReceive.from_raw_message(msgraw)

        if commandtuple:
            cmd1 = commandtuple.get("cmd1")
            cmd2out = commandtuple.get("cmd2")
        else:
            cmd1 = None
            cmd2out = None

        if cmd2 is not -1:
            cmd2out = cmd2

        msg._address = Address(address)
        msg._target = Address(target)
        msg._messageFlags = MessageFlags(flags)
        msg._cmd1 = cmd1
        msg._cmd2 = cmd2out
        msg._userdata = Userdata.create_pattern(userdata)
        return msg
예제 #7
0
    def __init__(self,
                 address,
                 commandtuple,
                 userdata,
                 cmd2=None,
                 flags=0x10,
                 acknak=None):
        """Init the ExtendedSend message class."""
        if commandtuple.get("cmd1", None) is not None:
            cmd1 = commandtuple["cmd1"]
            cmd2out = commandtuple["cmd2"]
        else:
            raise ValueError

        if cmd2 is not None:
            cmd2out = cmd2

        if cmd2out is None:
            raise ValueError

        self._address = Address(address)
        self._messageFlags = MessageFlags(flags)
        self._messageFlags.extended = 1
        self._cmd1 = cmd1
        self._cmd2 = cmd2out
        self._userdata = Userdata(userdata)
        self._acknak = self._setacknak(acknak)
예제 #8
0
    def template(
        cls,
        address=None,
        commandtuple=None,
        userdata=None,
        cmd2=-1,
        flags=None,
        acknak=None,
    ):
        """Create a message template used for callbacks."""
        msgraw = bytearray([0x02, cls._code])
        msgraw.extend(bytes(cls._receivedSize))
        msg = ExtendedSend.from_raw_message(msgraw)

        if commandtuple:
            cmd1 = commandtuple.get("cmd1")
            cmd2out = commandtuple.get("cmd2")
        else:
            cmd1 = None
            cmd2out = None

        if cmd2 is not -1:
            cmd2out = cmd2

        msg._address = Address(address)
        msg._messageFlags = MessageFlags(flags)
        msg._messageFlags.extended = 1
        msg._cmd1 = cmd1
        msg._cmd2 = cmd2out
        msg._userdata = Userdata.template(userdata)
        msg._acknak = acknak
        return msg
예제 #9
0
    def set(self, mode):
        """Set the thermostat mode.

        Mode optons:
            OFF = 0x00,
            HEAT = 0x01,
            COOL = 0x02,
            AUTO = 0x03,
            FAN_AUTO = 0x04,
            FAN_ALWAYS_ON = 0x8
        """
        new_mode = None
        if mode == ThermostatMode.OFF:
            new_mode = COMMAND_THERMOSTAT_CONTROL_OFF_ALL_0X6B_0X09
        elif mode == ThermostatMode.HEAT:
            new_mode = COMMAND_THERMOSTAT_CONTROL_ON_HEAT_0X6B_0X04
        elif mode == ThermostatMode.COOL:
            new_mode = COMMAND_THERMOSTAT_CONTROL_ON_COOL_0X6B_0X05
        elif mode == ThermostatMode.AUTO:
            new_mode = COMMAND_THERMOSTAT_CONTROL_ON_AUTO_0X6B_0X06
        if new_mode:
            msg = ExtendedSend(address=self._address,
                               commandtuple=new_mode,
                               userdata=Userdata())
            msg.set_checksum()
            self._send_method(msg, self._mode_change_ack)
예제 #10
0
 def set(self, val):
     """Set the heat set point."""
     msg = ExtendedSend(
         address=self._address,
         commandtuple=COMMAND_THERMOSTAT_SET_HEAT_SETPOINT_0X6D_NONE,
         cmd2=int(val * 2),
         userdata=Userdata())
     msg.set_checksum()
     self._send_method(msg, self._set_heat_point_ack)
예제 #11
0
 def from_raw_message(cls, rawmessage):
     """Create a message from a raw byte stream."""
     userdata_dict = Userdata(rawmessage[8:22])
     return ExtendedSend(rawmessage[2:5],
                         {'cmd1': rawmessage[6],
                          'cmd2': rawmessage[7]},
                         userdata_dict,
                         flags=rawmessage[5],
                         acknak=rawmessage[22:23])
예제 #12
0
 def extended_status_request(self):
     """Send status request for group/button."""
     self._status_received = False
     user_data = Userdata({'d1': self.group, 'd2': 0x00})
     cmd = ExtendedSend(self._address,
                        COMMAND_EXTENDED_GET_SET_0X2E_0X00,
                        userdata=user_data)
     cmd.set_checksum()
     self._send_method(cmd, self._status_message_received, True)
예제 #13
0
 def from_raw_message(cls, rawmessage):
     """Create message from raw byte stream."""
     userdata = Userdata.from_raw_message(rawmessage[11:25])
     return ExtendedReceive(
         rawmessage[2:5],
         rawmessage[5:8],
         {"cmd1": rawmessage[9], "cmd2": rawmessage[10]},
         userdata,
         flags=rawmessage[8],
     )
예제 #14
0
    async def _send_led_on_off_request(self, group, val):
        _LOGGER.debug("OnOffKeypadLed._send_led_on_off_request was called")
        await self._send_led_change_lock
        self._new_value = set_bit(self._value, group, bool(val))

        user_data = Userdata({'d1': 0x01, 'd2': 0x09, 'd3': self._new_value})
        msg = ExtendedSend(self._address, COMMAND_EXTENDED_GET_SET_0X2E_0X00,
                           user_data)
        msg.set_checksum()
        self._send_method(msg, self._on_off_ack_received, True)
예제 #15
0
    def _register_messages(self):
        temp_msg = StandardReceive.template(
            commandtuple=COMMAND_THERMOSTAT_TEMPERATURE_STATUS_0X6E_NONE,
            address=self._address,
            flags=MessageFlags.template(MESSAGE_TYPE_DIRECT_MESSAGE, None))

        self._message_callbacks.add(temp_msg, self._temp_received)
        ext_status_recd = ExtendedReceive.template(
            commandtuple=COMMAND_EXTENDED_GET_SET_0X2E_0X00,
            cmd2=0x02,
            userdata=Userdata.template({"d1": 0x01}))
        self._message_callbacks.add(ext_status_recd, self._ext_status_received)
예제 #16
0
 def _register_messages(self):
     cool_set_point_status = StandardReceive.template(
         address=self._address,
         commandtuple=COMMAND_THERMOSTAT_COOL_SET_POINT_STATUS_0X71_NONE,
         flags=MessageFlags.template(MESSAGE_TYPE_DIRECT_MESSAGE, False))
     self._message_callbacks.add(cool_set_point_status,
                                 self._status_message_received)
     ext_status_recd = ExtendedReceive.template(
         commandtuple=COMMAND_EXTENDED_GET_SET_0X2E_0X00,
         cmd2=0x02,
         userdata=Userdata.template({"d1": 0x01}))
     self._message_callbacks.add(ext_status_recd, self._ext_status_received)
예제 #17
0
 def async_refresh_state(self):
     """Request each state to provide status update."""
     _LOGGER.debug('Setting up extended status')
     ext_status = ExtendedSend(
         address=self._address,
         commandtuple=COMMAND_EXTENDED_GET_SET_0X2E_0X00,
         cmd2=0x02,
         userdata=Userdata())
     ext_status.set_crc()
     _LOGGER.debug('Sending ext status: %s', ext_status)
     self._send_msg(ext_status)
     _LOGGER.debug('Sending temp status request')
     self.temperature.async_refresh_state()
예제 #18
0
 def to_userdata(self):
     """Return a Userdata dictionary."""
     userdata = Userdata({
         'd3': self.memhi,
         'd4': self.memlo,
         'd6': self.control_flags,
         'd7': self.group,
         'd8': self.address[2],
         'd9': self.address[1],
         'd10': self.address[0],
         'd11': self.data1,
         'd12': self.data2,
         'd13': self.data3
     })
     return userdata
예제 #19
0
 def _register_messages(self):
     _LOGGER.debug('Starting HeatSetPoint register_messages')
     heat_set_point_status = StandardReceive.template(
         address=self._address,
         commandtuple=COMMAND_THERMOSTAT_HEAT_SET_POINT_STATUS_0X72_NONE,
         flags=MessageFlags.template(MESSAGE_TYPE_DIRECT_MESSAGE, False))
     self._message_callbacks.add(heat_set_point_status,
                                 self._status_message_received)
     ext_status_recd = ExtendedReceive.template(
         commandtuple=COMMAND_EXTENDED_GET_SET_0X2E_0X00,
         cmd2=0x02,
         flags=MessageFlags.template(MESSAGE_TYPE_DIRECT_MESSAGE, True),
         userdata=Userdata.template({"d1": 0x01}))
     _LOGGER.debug('Reg Ext Status: %s', ext_status_recd)
     self._message_callbacks.add(ext_status_recd, self._ext_status_received)
예제 #20
0
 def write_record(self,
                  mem_addr: int,
                  mode: str,
                  group: int,
                  target,
                  data1=0x00,
                  data2=0x00,
                  data3=0x00):
     """Write an All-Link database record."""
     if not (self._have_first_record() and self._have_last_record()):
         self.log.error('Must load the ALDB before writing to it')
     else:
         self._prior_status = self._status
         self._status = ALDBStatus.LOADING
         mem_hi = mem_addr >> 8
         mem_lo = mem_addr & 0xff
         controller = True if mode == 'c' else False
         control_flag = ControlFlags(True, controller, True, False, False)
         addr = Address(target)
         addr_lo = addr.bytes[0]
         addr_mid = addr.bytes[1]
         addr_hi = addr.bytes[2]
         chksum = 0xff - (
             (0x2f + 0x02 + mem_hi + mem_lo + 0x08 + control_flag.byte +
              addr_lo + addr_mid + addr_hi + group + data1 + data2 + data3)
             & 0xff) + 1
         userdata = Userdata({
             'd1': 0,
             'd2': 0x02,
             'd3': mem_hi,
             'd4': mem_lo,
             'd5': 0x08,
             'd6': control_flag.byte,
             'd7': group,
             'd8': addr_lo,
             'd9': addr_mid,
             'd10': addr_hi,
             'd11': data1,
             'd12': data2,
             'd13': data3,
             'd14': chksum
         })
         msg = ExtendedSend(self._address,
                            COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00,
                            userdata=userdata)
         self.log.info('writing message %s', msg)
         self._send_method(msg, self._handle_write_aldb_ack, True)
         self._load_action = LoadAction(mem_addr, 1, 0)
예제 #21
0
 def scene_off(self):
     """Trigger group/scene to OFF level."""
     user_data = Userdata({
         'd1': self._group,
         'd2': 0x00,
         'd3': 0x00,
         'd4': 0x13,
         'd5': 0x00,
         'd6': 0x00
     })
     self._set_sent_property(DIMMABLE_KEYPAD_SCENE_ON_LEVEL, 0x00)
     cmd = ExtendedSend(self._address,
                        COMMAND_EXTENDED_TRIGGER_ALL_LINK_0X30_0X00,
                        user_data)
     cmd.set_checksum()
     self._send_method(cmd, self._received_scene_triggered)
예제 #22
0
 def _register_messages(self):
     ext_msg_aldb_record = ExtendedReceive.template(
         address=self._address,
         commandtuple=COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00,
         userdata=Userdata.template({'d2': 1}),
         flags=MessageFlags.template(
             messageType=MESSAGE_TYPE_DIRECT_MESSAGE, extended=1))
     std_msg_pre_nak = StandardReceive.template(flags=MessageFlags.template(
         messageType=MESSAGE_FLAG_DIRECT_MESSAGE_NAK_0XA0),
                                                cmd2=0xfc)
     ext_msg_pre_nak = ExtendedReceive.template(flags=MessageFlags.template(
         messageType=MESSAGE_FLAG_DIRECT_MESSAGE_NAK_0XA0),
                                                cmd2=0xfc)
     self._message_callbacks.add(ext_msg_aldb_record,
                                 self._handle_aldb_record_received)
     self._message_callbacks.add(std_msg_pre_nak, self._handle_pre_nak)
     self._message_callbacks.add(ext_msg_pre_nak, self._handle_pre_nak)
예제 #23
0
    def load(self, mem_addr=0x0000, rec_count=0, retry=0):
        """Read the device database and load."""
        if self._version == ALDBVersion.Null:
            self._status = ALDBStatus.LOADED
            self.log.debug('Device has no ALDB')
        else:
            self._status = ALDBStatus.LOADING
            self.log.debug('Tring to lock from load')
            yield from self._rec_mgr_lock
            self.log.debug('load yielded lock')

            mem_hi = mem_addr >> 8
            mem_lo = mem_addr & 0xff
            log_output = 'ALDB read'
            max_retries = 0
            if rec_count:
                max_retries = ALDB_RECORD_RETRIES
                if mem_addr == 0x0000:
                    log_output = '{:s} first record'.format(log_output)
                else:
                    log_output = '{:s} record {:04x}'.format(
                        log_output, mem_addr)
            else:
                max_retries = ALDB_ALL_RECORD_RETRIES
                log_output = '{:s} all records'.format(log_output)

            if retry:
                log_output = '{:s} retry {:d} of {:d}'.format(
                    log_output, retry, max_retries)
            self.log.info(log_output)
            chksum = 0xff - ((0x2f + mem_hi + mem_lo + 1) & 0xff) + 1
            userdata = Userdata({
                'd1': 0,
                'd2': 0,
                'd3': mem_hi,
                'd4': mem_lo,
                'd5': rec_count,
                'd14': chksum
            })
            msg = ExtendedSend(self._address,
                               COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00,
                               userdata=userdata)
            self._send_method(msg, self._handle_read_aldb_ack, True)

            if not self._load_action:
                self._set_load_action(mem_addr, rec_count, -1, False)
예제 #24
0
 def del_record(self, mem_addr: int):
     """Write an All-Link database record."""
     record = self._records.get(mem_addr)
     if not record:
         self.log.error('Must load the ALDB record before deleting it')
     else:
         self._prior_status = self._status
         self._status = ALDBStatus.LOADING
         mem_hi = mem_addr >> 8
         mem_lo = mem_addr & 0xff
         controller = record.control_flags.is_controller
         control_flag = ControlFlags(False, controller, True, False, False)
         addr = record.address
         addr_lo = addr.bytes[0]
         addr_mid = addr.bytes[1]
         addr_hi = addr.bytes[2]
         group = record.group
         data1 = record.data1
         data2 = record.data2
         data3 = record.data3
         chksum = 0xff - (
             (0x2f + 0x02 + mem_hi + mem_lo + 0x08 + control_flag.byte +
              addr_lo + addr_mid + addr_hi + group + data1 + data2 + data3)
             & 0xff) + 1
         userdata = Userdata({
             'd1': 0,
             'd2': 0x02,
             'd3': mem_hi,
             'd4': mem_lo,
             'd5': 0x08,
             'd6': control_flag.byte,
             'd7': group,
             'd8': addr_lo,
             'd9': addr_mid,
             'd10': addr_hi,
             'd11': data1,
             'd12': data2,
             'd13': data3,
             'd14': chksum
         })
         msg = ExtendedSend(self._address,
                            COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00,
                            userdata=userdata)
         self.log.info('writing message %s', msg)
         self._send_method(msg, self._handle_write_aldb_ack, True)
         self._load_action = LoadAction(mem_addr, 1, 0)
예제 #25
0
 def scene_on(self):
     """Trigger group/scene to ON level."""
     user_data = Userdata({
         "d1": self._group,
         "d2": 0x00,
         "d3": 0x00,
         "d4": 0x11,
         "d5": 0xFF,
         "d6": 0x00,
     })
     self._set_sent_property(DIMMABLE_KEYPAD_SCENE_ON_LEVEL, 0xFF)
     cmd = ExtendedSend(self._address,
                        COMMAND_EXTENDED_TRIGGER_ALL_LINK_0X30_0X00,
                        user_data)
     cmd.set_checksum()
     _LOGGER.debug("Calling scene_on and sending response to "
                   "_received_scene_triggered")
     self._send_method(cmd, self._received_scene_triggered)
예제 #26
0
 def scene_on(self):
     """Trigger group/scene to ON level."""
     user_data = Userdata({
         'd1': self._group,
         'd2': 0x00,
         'd3': 0x00,
         'd4': 0x11,
         'd5': 0xff,
         'd6': 0x00
     })
     self._set_sent_property(DIMMABLE_KEYPAD_SCENE_ON_LEVEL, 0xff)
     cmd = ExtendedSend(self._address,
                        COMMAND_EXTENDED_TRIGGER_ALL_LINK_0X30_0X00,
                        user_data)
     cmd.set_checksum()
     _LOGGER.debug('Calling scene_on and sending response to '
                   '_received_scene_triggered')
     self._send_method(cmd, self._received_scene_triggered)
예제 #27
0
 def scene_level(self, level):
     """Trigger group/scene to input level."""
     if level == 0:
         self.scene_off()
     else:
         user_data = Userdata({
             "d1": self._group,
             "d2": 0x00,
             "d3": 0x00,
             "d4": 0x11,
             "d5": level,
             "d6": 0x00,
         })
         self._set_sent_property(DIMMABLE_KEYPAD_SCENE_ON_LEVEL, level)
         cmd = ExtendedSend(self._address,
                            COMMAND_EXTENDED_TRIGGER_ALL_LINK_0X30_0X00,
                            user_data)
         cmd.set_checksum()
         self._send_method(cmd, self._received_scene_triggered)
예제 #28
0
    async def run_test(loop):
        mockPLM = MockPLM(loop)
        linkcode = 0x01
        group = 0x00
        address = '112233'
        cat = 0x02
        subcat = 0x39
        firmware = 0x44
        # Create OutletLinc
        device = insteonplm.devices.create(mockPLM, address, cat, subcat,
                                           firmware)

        # Start the process with an All-Link complete message with
        # the IM as a controller of Group 0x00
        msg = AllLinkComplete(linkcode, group, address, cat, subcat, firmware)
        device.receive_message(msg)
        await asyncio.sleep(.1, loop=loop)

        # The device should start linking based on the groups in
        # self.states
        assert mockPLM.sentmessage == StandardSend(
            device.address, COMMAND_ENTER_LINKING_MODE_0X09_NONE,
            cmd2=0x01).hex
        msg = StandardSend(device.address,
                           COMMAND_ENTER_LINKING_MODE_0X09_NONE,
                           cmd2=0x01,
                           acknak=MESSAGE_ACK)
        device.receive_message(msg)
        await asyncio.sleep(.1, loop=loop)
        # Confirm that the link attempt to group 0x01 completed
        msg = AllLinkComplete(0x00, 0x01, address, cat, subcat, firmware)
        device.receive_message(msg)
        await asyncio.sleep(.1, loop=loop)

        # The device should then start linking to group 0x02
        assert mockPLM.sentmessage == StandardSend(
            device.address, COMMAND_ENTER_LINKING_MODE_0X09_NONE,
            cmd2=0x02).hex
        await asyncio.sleep(1, loop=loop)
        # Confirm that the link attempt to group 0x02 completed
        msg = AllLinkComplete(0x00, 0x01, address, cat, subcat, firmware)
        device.receive_message(msg)
        await asyncio.sleep(.1, loop=loop)

        # The device will now attempt to read the ALDB
        msg = ExtendedSend(address,
                           COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00,
                           userdata=Userdata())
        msg.set_checksum()
        assert mockPLM.sentmessage == msg.hex
        # Send a dummy ALDB record as a high water mark to end the process
        msg = ExtendedReceive(
            address,
            '111111',
            commandtuple=COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00,
            userdata=Userdata({
                'd1': 0,
                'd2': 0x01,
                'd3': 0xff,
                'd4': 0x77,
                'd5': 0,
                'd6': 0,
                'd7': 0,
                'd8': 0,
                'd9': 0,
                'd10': 0,
                'd11': 0,
                'd12': 0,
                'd13': 0,
                'd14': 0x3b
            }))
        device.receive_message(msg)
        await asyncio.sleep(1, loop=loop)