Ejemplo n.º 1
0
    async def start(self, skip_initial_messages=False):
        """Connect to device and listen to incoming messages."""
        if self.connection.connected:
            return

        await self.connection.connect()

        # In case credentials have been given externally (i.e. not by pairing
        # with a device), then use that client id
        if self.service.credentials:
            self.srp.pairing_id = Credentials.parse(
                self.service.credentials).client_id

        # The first message must always be DEVICE_INFORMATION, otherwise the
        # device will not respond with anything
        msg = messages.device_information('pyatv',
                                          self.srp.pairing_id.decode())

        await self.send_and_receive(msg)
        self._initial_message_sent = True

        # This is a hack to support re-use of a protocol object in
        # proxy (will be removed/refactored later)
        if skip_initial_messages:
            return

        await self._connect_and_encrypt()

        # This should be the first message sent after encryption has
        # been enabled
        await self.send(messages.set_connection_state())

        # Subscribe to updates at this stage
        await self.send(messages.client_updates_config())
        await self.send_and_receive(messages.get_keyboard_session())
Ejemplo n.º 2
0
    def handle_send_hid_event(self, message, inner):
        # These corresponds to the bytes mapping to pressed key (see
        # send_hid_event in pyatv/mrp/messages.py)
        start = inner.hidEventData[43:49]
        use_page, usage, down_press = struct.unpack('>HHH', start)

        if down_press == 1:
            self.outstanding_keypresses.add((use_page, usage))
            self.send(messages.create(0, identifier=message.identifier))
        elif down_press == 0:
            if (use_page, usage) in self.outstanding_keypresses:
                if (
                    _convert_key_press(use_page, usage) == 'select'
                    and self.last_button_pressed == 'home'
                   ):
                    msg = messages.device_information(
                        'pyatv', message.identifier, 0)
                    self.send(msg)
                self.last_button_pressed = _convert_key_press(use_page, usage)
                self.outstanding_keypresses.remove((use_page, usage))
                _LOGGER.debug('Pressed button: %s', self.last_button_pressed)
                self.send(messages.create(0, identifier=message.identifier))
            else:
                _LOGGER.error('Missing key down for %d,%d', use_page, usage)
        else:
            _LOGGER.error('Invalid key press state: %d', down_press)
Ejemplo n.º 3
0
    async def start(self, skip_initial_messages=False):
        """Connect to device and listen to incoming messages."""
        if self._state != ProtocolState.NOT_CONNECTED:
            raise exceptions.InvalidStateError(self._state.name)

        self._state = ProtocolState.CONNECTING

        try:
            await self.connection.connect()

            self._state = ProtocolState.CONNECTED

            # In case credentials have been given externally (i.e. not by pairing
            # with a device), then use that client id
            if self.service.credentials:
                self.srp.pairing_id = HapCredentials.parse(
                    self.service.credentials).client_id

            # The first message must always be DEVICE_INFORMATION, otherwise the
            # device will not respond with anything
            msg = messages.device_information("pyatv",
                                              self.srp.pairing_id.decode())

            self.device_info = await self.send_and_receive(msg)

            # This is a hack to support re-use of a protocol object in
            # proxy (will be removed/refactored later)
            if skip_initial_messages:
                return

            await self._enable_encryption()

            # This should be the first message sent after encryption has
            # been enabled
            await self.send(messages.set_connection_state())

            # Subscribe to updates at this stage
            await self.send_and_receive(messages.client_updates_config())
            await self.send_and_receive(messages.get_keyboard_session())

            self._heartbeat_task = asyncio.ensure_future(heartbeat_loop(self))
        except Exception:
            # Something went wrong, let's do cleanup
            self.stop()
            raise
        else:
            # We're now ready
            self._state = ProtocolState.READY
Ejemplo n.º 4
0
    async def start(self):
        """Connect to device and listen to incoming messages."""
        if self.connection.connected:
            return

        await self.connection.connect()

        # In case credentials have been given externally (i.e. not by pairing
        # with a device), then use that client id
        if self.service.device_credentials:
            self.srp.pairing_id = Credentials.parse(
                self.service.device_credentials).client_id

        # The first message must always be DEVICE_INFORMATION, otherwise the
        # device will not respond with anything
        msg = messages.device_information(
            'pyatv', self.srp.pairing_id.decode())
        await self.send_and_receive(msg)
        self._initial_message_sent = True

        # This should be the first message sent after encryption has
        # been enabled
        await self.send(messages.set_ready_state())

        async def _wait_for_updates(_, semaphore):
            # Use a counter here whenever more than one message is expected
            semaphore.release()

        # Wait for some stuff to arrive before returning
        semaphore = asyncio.Semaphore(value=0, loop=self.loop)
        self.add_listener(_wait_for_updates,
                          protobuf.SET_STATE_MESSAGE,
                          data=semaphore,
                          one_shot=True)

        # Subscribe to updates at this stage
        await self.send(messages.client_updates_config())
        await self.send(messages.wake_device())

        try:
            await asyncio.wait_for(
                semaphore.acquire(), 1, loop=self.loop)
        except asyncio.TimeoutError:
            # This is not an issue itself, but I should do something better.
            # Basically this gives the device about one second to respond with
            # some metadata before continuing.
            pass
Ejemplo n.º 5
0
 def _send_device_info(self, identifier=None, update=False):
     resp = messages.device_information(DEVICE_NAME, "1234", update=update)
     if identifier:
         resp.identifier = identifier
     resp.inner().logicalDeviceCount = 1 if self.state.powered_on else 0
     self.send(resp)
Ejemplo n.º 6
0
    def handle_device_info(self, message):
        _LOGGER.debug('Received device info message')

        resp = messages.device_information('Fake MRP ATV', '1234')
        resp.identifier = message.identifier
        self._send(resp)
Ejemplo n.º 7
0
 def handle_wake_device(self, message, inner):
     msg = messages.device_information('pyatv', message.identifier, 1)
     self.send(msg)
     self.send(messages.command_result(message.identifier))
Ejemplo n.º 8
0
 def handle_device_info(self, message, inner):
     resp = messages.device_information(DEVICE_NAME, '1234')
     resp.identifier = message.identifier
     self.send(resp)