async def write_encoded(self, data: bytes):
        if not self.connected:
            raise exceptions.NotConnected(f'{self} not connected')

        LOGGER.debug(f'{self} writing: {data}')
        self._writer.write(data + b'\n')
        await self._writer.drain()
예제 #2
0
    async def write(self, msg: Union[str, bytes]):
        if isinstance(msg, str):
            msg = msg.encode()

        if not self.connected:
            raise exceptions.NotConnected(f'{self} not connected')

        LOGGER.debug(f'{self} writing: {msg}')
        self._writer.write(msg + b'\n')
        await self._writer.drain()
    async def flash(self) -> dict:  # pragma: no cover
        sender = ymodem.FileSender(self._notify)
        cmder = commander.fget(self.app)
        address = service_status.desc(self.app).device_address

        self._notify(
            f'Started updating {self.name}@{address} to version {self.version} ({self.date})'
        )

        try:
            if not service_status.desc(self.app).is_connected:
                self._notify('Controller is not connected. Aborting update.')
                raise exceptions.NotConnected()

            if self.simulation:
                raise NotImplementedError(
                    'Firmware updates not available for simulation controllers'
                )

            self._notify('Sending update command to controller')
            service_status.set_updating(self.app)
            await asyncio.sleep(FLUSH_PERIOD_S
                                )  # Wait for in-progress commands to finish
            await cmder.execute(commands.FirmwareUpdateCommand.from_args())

            self._notify('Shutting down normal communication')
            await cmder.shutdown(self.app)

            self._notify('Waiting for normal connection to close')
            await asyncio.wait_for(service_status.wait_disconnected(self.app),
                                   STATE_TIMEOUT_S)

            self._notify(f'Connecting to {address}')
            conn = await self._connect(address)

            with conn.autoclose():
                await asyncio.wait_for(sender.transfer(conn),
                                       TRANSFER_TIMEOUT_S)

        except Exception as ex:
            self._notify(f'Failed to update firmware: {strex(ex)}')
            raise exceptions.FirmwareUpdateFailed(strex(ex))

        finally:
            self._notify('Scheduling service reboot')
            await shutdown_soon(self.app, UPDATE_SHUTDOWN_DELAY_S)

        self._notify('Firmware updated!')
        return {'address': address, 'version': self.version}
예제 #4
0
    async def flash(self) -> dict:  # pragma: no cover
        ota = ymodem.OtaClient(self._notify)
        cmder = commander.fget(self.app)
        status_desc = service_status.desc(self.app)
        address = status_desc.device_address
        platform = status_desc.device_info.platform

        self._notify(
            f'Started updating {self.name}@{address} to version {self.version} ({self.date})'
        )

        try:
            if not status_desc.is_connected:
                self._notify('Controller is not connected. Aborting update.')
                raise exceptions.NotConnected()

            if self.simulation:
                raise NotImplementedError(
                    'Firmware updates not available for simulation controllers'
                )

            self._notify('Preparing update')
            service_status.set_updating(self.app)
            await asyncio.sleep(FLUSH_PERIOD_S
                                )  # Wait for in-progress commands to finish

            if platform != 'esp32':  # pragma: no cover
                self._notify('Sending update command to controller')
                await cmder.execute(commands.FirmwareUpdateCommand.from_args())

            self._notify('Waiting for normal connection to close')
            await cmder.shutdown(self.app)
            await asyncio.wait_for(service_status.wait_disconnected(self.app),
                                   STATE_TIMEOUT_S)

            if platform == 'esp32':  # pragma: no cover
                # ESP connections will always be a TCP address
                host, _ = address.split(':')
                self._notify(f'Sending update prompt to {host}')
                self._notify(
                    'The Spark will now download and apply the new firmware')
                self._notify('The update is done when the service reconnects')
                fw_url = ESP_URL_FMT.format(**self.app['ini'])
                await http.session(self.app
                                   ).post(f'http://{host}:80/firmware_update',
                                          data=fw_url)

            else:
                self._notify(f'Connecting to {address}')
                conn = await ymodem.connect(address)

                with conn.autoclose():
                    await asyncio.wait_for(
                        ota.send(conn, f'firmware/brewblox-{platform}.bin'),
                        TRANSFER_TIMEOUT_S)
                    self._notify('Update done!')

        except Exception as ex:
            self._notify(f'Failed to update firmware: {strex(ex)}')
            raise exceptions.FirmwareUpdateFailed(strex(ex))

        finally:
            self._notify('Restarting service...')
            await shutdown_soon(self.app, UPDATE_SHUTDOWN_DELAY_S)

        return {'address': address, 'version': self.version}