Skip to content

Clients

BusyBar is the synchronous client and AsyncBusyBar is its async/await counterpart. Both compose the same set of endpoint mixins, so the method surface is identical apart from the coroutines.

from busylib import AsyncBusyBar, BusyBar

bb = BusyBar("10.0.4.20")

async_bb = AsyncBusyBar(addr="10.0.4.20", token="my-access-key")

Creating either client has no terminal output and does not contact the device. The first endpoint call performs the connection; see the quick start for its expected output.

busylib.client.BusyBar

BusyBar(addr: str | None = None, *, token: str | None = None, timeout: float | Timeout | None = None, max_retries: int = 2, backoff: float = DEFAULT_BACKOFF, transport: BaseTransport | None = None, api_version: str | None = None, compatibility_mode: CompatibilityMode = 'warn', is_cloud: bool | None = None)

Bases: AccessMixin, AccountMixin, BusyMixin, TimeMixin, UpdaterMixin, FirmwareMixin, StorageMixin, AssetsMixin, DisplayMixin, AudioMixin, WifiMixin, InputMixin, SmartHomeMixin, StateStreamMixin, BleMixin, SyncClientBase

HTTPX-based client for the BUSY Bar API.

Build a client for one bar.

addr is a device address; leaving it out with a token reaches the bar through the cloud, at the host BUSYLIB_CLOUD_URL names. Pass is_cloud=True only to name a cloud host per client, which is what stops an address like api.dev.busy.app being taken for a device.

usb property

usb: UsbController

Lazy-loaded USB controller.

is_usb_connected property

is_usb_connected: bool

Returns True if a USB device was found and connected.

connection_type class-attribute instance-attribute

connection_type: Literal['local', 'cloud', 'network'] = 'network'

max_retries instance-attribute

max_retries = max(0, int(max_retries))

backoff instance-attribute

backoff = backoff

api_version instance-attribute

api_version = api_version or versioning.API_VERSION

compatibility_mode instance-attribute

compatibility_mode: CompatibilityMode = compatibility_mode

client instance-attribute

client = httpx2.Client(base_url=self.base_url, headers=headers or None, timeout=_as_timeout(timeout), transport=transport)

is_cloud property

is_cloud: bool

Check whether connection uses cloud mode.

Returns True for cloud connection_type.

is_local property

is_local: bool

Check whether connection uses local mode.

Returns True for local connection_type.

usb_reboot

usb_reboot(*, raise_on_error: bool = False) -> bool

Attempt to reboot the device via USB.

Returns True on success and False on failure by default. If raise_on_error is True, re-raises BusyBarUsbError.

usb_reset

usb_reset(*, raise_on_error: bool = False) -> bool

Alias for usb_reboot().

Provided for callers that prefer "reset" naming.

method_compatibility

method_compatibility(method_name: str) -> versioning.MethodCompatibility | None

Return declarative OpenAPI compatibility metadata for a client method.

is_local_available

is_local_available() -> bool

Check local API reachability on base_url.

Returns True when /api/version responds without network errors.

close

close() -> None

api_request

api_request(method: str, path: str, *, params: dict[str, Any] | None = None, headers: dict[str, str] | None = None, session_id: str | None = None, application_name: str | None = None, json_payload: JsonType | None = None, data: bytes | Iterable[bytes] | None = None, expect_bytes: bool = False, allow_text: bool = False, timeout: float | Timeout | None = None) -> JsonType | bytes | str

Execute a raw API request through the current client session.

Advanced callers can control path, params, headers, body, and request context without creating a separate HTTP client.

prepare_request

prepare_request(method: str, path: str, *, params: dict[str, Any] | None = None, headers: dict[str, str] | None = None, session_id: str | None = None, application_name: str | None = None, json_payload: JsonType | None = None, data: bytes | Iterable[bytes] | None = None, expect_bytes: bool = False, allow_text: bool = False, timeout: float | Timeout | None = None) -> PreparedRequest

Build a prepared request without executing network I/O.

External integrations can inspect the prepared payload, route it to custom transports, or execute later via execute_prepared_request.

execute_prepared_request

execute_prepared_request(prepared: PreparedRequest, *, client: Client | None = None) -> JsonType | bytes | str

Execute a previously prepared request.

By default the current httpx2.Client is used. Callers may inject a custom client while preserving error mapping. Prepared streaming content is single-use and should be regenerated for repeated executions.

ble_enable

ble_enable() -> types.SuccessResponse

ble_disable

ble_disable() -> types.SuccessResponse

ble_status

ble_status() -> types.BleStatus

ble_pairing_forget

ble_pairing_forget() -> types.SuccessResponse

stream_status_ws

stream_status_ws() -> None

Stream device status updates via WebSocket /api/status/ws.

Sync iteration is not supported because websocket lifecycle and frame handling are asynchronous in this client implementation.

smart_home_pairing

smart_home_pairing() -> types.SmartHomePairingInfo

Fetch smart home pairing status via GET /api/smart_home/pairing.

smart_home_pairing_start

smart_home_pairing_start() -> types.SmartHomePairingPayload

Start smart home pairing via POST /api/smart_home/pairing.

smart_home_pairing_stop

smart_home_pairing_stop() -> types.SuccessResponse

Stop smart home pairing via DELETE /api/smart_home/pairing.

smart_home_switch

smart_home_switch() -> types.SmartHomeSwitchState

Fetch smart home switch state via GET /api/smart_home/switch.

smart_home_switch_set

smart_home_switch_set(state: bool, *, startup: Literal['off', 'on', 'toggle', 'last'] | None = None) -> types.SuccessResponse

Set smart home switch state via POST /api/smart_home/switch.

input

input(key: InputKey) -> types.SuccessResponse

wifi_enable

wifi_enable() -> types.SuccessResponse

Removed from the device API.

No supported firmware serves POST /api/wifi/enable, so calling this raises BusyBarRemovedEndpointError. Use wifi_connect() / wifi_disconnect() instead.

wifi_disable

wifi_disable() -> types.SuccessResponse

Removed from the device API.

No supported firmware serves POST /api/wifi/disable, so calling this raises BusyBarRemovedEndpointError. Use wifi_connect() / wifi_disconnect() instead.

wifi_status

wifi_status() -> types.StatusResponse

wifi_connect

wifi_connect(config: ConnectRequestConfig | dict[str, Any]) -> types.SuccessResponse

wifi_disconnect

wifi_disconnect() -> types.SuccessResponse

wifi_networks

wifi_networks() -> types.NetworkResponse

Scan for nearby networks via GET /api/wifi/networks.

The device cannot scan while it is associated: doing so returns 400 "Scan not possible when connected" as a BusyBarAPIError. Disconnect first with wifi_disconnect(), or skip the scan and pass the SSID to wifi_connect() directly.

audio_play

audio_play(*, path: str | None = None, stock_path: str | None = None, payload: AudioPlayRequest | dict[str, Any] | None = None, **request_kwargs: Unpack[RequestKwargs]) -> types.SuccessResponse

Play audio through POST /api/audio/play.

The endpoint payload may reference either an uploaded asset path or a stock path. Explicit path and stock_path keyword arguments override the same keys provided in payload. Request context such as application_name and session_id is accepted through request kwargs; use api_request for fully custom bodies.

audio_stop

audio_stop() -> types.SuccessResponse

Stop audio through DELETE /api/audio/play.

Uses API-like naming for callers that mirror firmware endpoints.

audio_volume

audio_volume() -> types.AudioVolumeInfo

audio_volume_set

audio_volume_set(volume: float) -> types.SuccessResponse

display_draw

display_draw(display_data: DisplayElements | dict[str, Any], *, clear_before_draw: bool = False, sanitize_text: bool = False, **request_kwargs: Unpack[RequestKwargs]) -> types.SuccessResponse

display

display(display_data: DisplayElements | dict[str, Any], *, clear_before_draw: bool = False, sanitize_text: bool = False, audio_payload: AudioPlayRequest | dict[str, Any] | None = None, **request_kwargs: Unpack[RequestKwargs]) -> types.SuccessResponse

Render display content and optionally play audio after draw.

Operations are sequential, not atomic: clear may succeed before draw fails, and audio failure may occur after display content is visible. Exceptions include the failed endpoint path for diagnostics.

display_clear

display_clear(**request_kwargs: Unpack[RequestKwargs]) -> types.SuccessResponse

Clear display content through DELETE /api/display/draw.

Uses API-like naming for callers that mirror firmware endpoints.

display_brightness

display_brightness() -> types.DisplayBrightnessInfo

display_brightness_set

display_brightness_set(value: BrightnessValue) -> types.SuccessResponse

screen

screen(display_id: DisplaySpecLike) -> bytes

Fetch a single display frame via GET /api/screen.

Returns RGB bytes, three per pixel: 3456 for the front display (72x16) and 38400 for the back (160x80, sent L4-packed and expanded to grey triples here). The device sends colour as BGR and it is swapped on the way out.

The response body is base64-encoded, uncompressed framebuffer bytes (the Content-Type: image/bmp header is misleading, there is no real BMP header).

frame

frame(display_id: DisplaySpecLike) -> Frame

Fetch a display frame as a Frame via GET /api/screen.

The same bytes as screen(), with the geometry and the display attached, so callers can read pixels, rows or a PNG without tracking the layout themselves.

assets_upload

assets_upload(application_name: str, filename: str, data: bytes, *, timeout: float | Timeout | None = ASSET_UPLOAD_TIMEOUT) -> types.SuccessResponse

Upload an asset file for the given application.

Uses a longer default timeout to tolerate large payload uploads.

assets_delete

assets_delete(application_name: str) -> types.SuccessResponse

storage_write

storage_write(path: str, data: bytes, *, timeout: float | None = 60.0, progress_callback: Callable[[int, int], None] | None = None, chunk_size: int = 64 * 1024) -> types.SuccessResponse

storage_read

storage_read(path: str) -> bytes

storage_list

storage_list(path: str) -> types.StorageList

storage_remove

storage_remove(path: str) -> types.SuccessResponse

storage_mkdir

storage_mkdir(path: str) -> types.SuccessResponse

Create a storage directory via POST /api/storage/mkdir.

storage_rename

storage_rename(old_path: str, new_path: str) -> types.SuccessResponse

Rename a storage entry via POST /api/storage/rename.

storage_status

storage_status() -> types.StorageStatus

version

version() -> types.VersionInfo

Fetch API version info and validate compatibility.

transport

transport() -> types.NetworkInterfaceInfo

Fetch active network transport via GET /api/transport.

status

status() -> types.Status

Fetch full device status via GET /api/status.

status_device

status_device() -> types.StatusDevice

Fetch device manufacturing status via GET /api/status/device.

status_firmware

status_firmware() -> types.StatusFirmware

Fetch firmware status via GET /api/status/firmware.

status_system

status_system() -> types.StatusSystem

Fetch runtime status via GET /api/status/system.

status_power

status_power() -> types.StatusPower

Fetch power status via GET /api/status/power.

log_dump

log_dump(filename: str | None = None) -> types.LogDumpResponse

Dump the in-memory device log buffer to a storage file.

filename is a bare name without a path or extension, matching ^[a-zA-Z0-9_-]+$ on firmware OpenAPI 25.0.0+; the device appends its own extension and storage path. When omitted, the device picks a default file.

Breaking change: prior to 25.0.0 this method accepted path= (a full device-side path). That parameter has been removed rather than aliased, since the two contracts are not translatable (a full path never matches the new filename pattern). Callers targeting firmware older than 25.0.0 should pin an older busylib release instead of adapting call sites.

name

name() -> types.DeviceNameResponse

Fetch device name via GET /api/name.

name_set

name_set(name: str) -> types.SuccessResponse

Set device name via POST /api/name.

time

time() -> types.DeviceTimeResponse

Fetch device time via GET /api/time.

update

update(firmware_data: bytes) -> types.SuccessResponse

Upload firmware update TAR and initiate update.

update_check

update_check() -> types.SuccessResponse

Start asynchronous firmware update check.

update_status

update_status() -> types.UpdateStatus

Get firmware update status with progress information.

update_changelog

update_changelog(version: str) -> types.UpdateChangelogResponse

Fetch update changelog for a specific version.

update_install

update_install(version: str) -> types.SuccessResponse

Start firmware update installation by version.

update_abort_download

update_abort_download() -> types.SuccessResponse

Abort an ongoing firmware download.

update_autoupdate

update_autoupdate() -> types.AutoupdateSettings

Fetch autoupdate settings via GET /api/update/autoupdate.

update_autoupdate_set

update_autoupdate_set(settings: AutoupdateSettings | dict[str, object]) -> types.SuccessResponse

Set autoupdate settings via POST /api/update/autoupdate.

time_timezone_info

time_timezone_info() -> types.TimezoneInfo

Fetch current device timezone via GET /api/time/timezone.

time_timezone_list

time_timezone_list() -> types.TimezoneListResponse

Fetch supported device timezones via GET /api/time/tzlist.

time_timestamp

time_timestamp(timestamp: str) -> types.SuccessResponse

Set device time via POST /api/time/timestamp.

time_timezone

time_timezone(timezone: str) -> types.SuccessResponse

Set device timezone via POST /api/time/timezone.

busy_snapshot

busy_snapshot() -> types.BusySnapshot

Fetch busy snapshot via GET /api/busy/snapshot.

busy_snapshot_set

busy_snapshot_set(snapshot: BusySnapshot) -> types.SuccessResponse

Set busy snapshot via PUT /api/busy/snapshot.

busy_profile

busy_profile(slot: BusyProfileSlot) -> types.BusyProfile

Fetch a busy profile slot via GET /api/busy/profiles/{slot}.

busy_profile_set

busy_profile_set(slot: BusyProfileSlot, profile: BusyProfile | dict[str, object]) -> types.SuccessResponse

Set a busy profile slot via PUT /api/busy/profiles/{slot}.

account_unlink() -> types.SuccessResponse

Unlink the device from the account via DELETE /api/account.

account_link() -> types.AccountLink

Request an account link code via POST /api/account/link.

account_info

account_info() -> types.AccountInfo

Fetch linked account info via GET /api/account/info.

account_status

account_status() -> types.AccountState

Fetch MQTT status info via GET /api/account/status.

account_backend

account_backend() -> types.AccountBackend

Fetch MQTT backend settings via GET /api/account/backend.

account_backend_set

account_backend_set(backend: AccountBackend | dict[str, object]) -> types.SuccessResponse

Set MQTT backend settings via PUT /api/account/backend.

account_profile

account_profile() -> types.AccountProfile

Removed from the device API.

No supported firmware serves GET /api/account/profile, so calling this raises BusyBarRemovedEndpointError. Use account_backend() instead.

account_profile_set

account_profile_set(profile: AccountProfileName, custom_url: str | None = None) -> types.SuccessResponse

Removed from the device API.

No supported firmware serves POST /api/account/profile, so calling this raises BusyBarRemovedEndpointError. Use account_backend_set() instead.

access

access() -> types.HttpAccessInfo

Fetch HTTP access mode via GET /api/access.

access_set

access_set(mode: HttpAccessMode, key: str) -> types.SuccessResponse

Set HTTP access mode via POST /api/access.

access_tokens_list

access_tokens_list() -> types.AccessTokensInfo

List issued access tokens via GET /api/access/tokens.

The secret itself is returned only when a token is minted, so every token here has token set to None.

Experimental: needs firmware from busy-app/busybar-firmware#886, which is not released yet, so it answers 404 on every released firmware.

access_token_mint

access_token_mint(name: str) -> types.AccessToken

Issue a new access token via POST /api/access/tokens.

This is the only time the device discloses the secret; it cannot be read back afterwards.

Experimental: needs firmware from busy-app/busybar-firmware#886, which is not released yet, so it answers 404 on every released firmware.

access_tokens_delete_all

access_tokens_delete_all() -> types.SuccessResponse

Revoke every access token via DELETE /api/access/tokens.

Experimental: needs firmware from busy-app/busybar-firmware#886, which is not released yet, so it answers 404 on every released firmware.

access_tokens_revoke

access_tokens_revoke(short_id: str) -> types.SuccessResponse

Revoke one access token via DELETE /api/access/tokens/{short_id}.

Experimental: needs firmware from busy-app/busybar-firmware#886, which is not released yet, so it answers 404 on every released firmware.

busylib.client.AsyncBusyBar

AsyncBusyBar(addr: str | None = None, *, token: str | None = None, timeout: float | Timeout | None = None, max_retries: int = 2, backoff: float = DEFAULT_BACKOFF, transport: AsyncBaseTransport | None = None, api_version: str | None = None, compatibility_mode: CompatibilityMode = 'warn', is_cloud: bool | None = None)

Bases: AsyncAccessMixin, AsyncAccountMixin, AsyncBusyMixin, AsyncTimeMixin, AsyncUpdaterMixin, AsyncFirmwareMixin, AsyncStorageMixin, AsyncAssetsMixin, AsyncDisplayMixin, AsyncAudioMixin, AsyncWifiMixin, AsyncInputMixin, AsyncSmartHomeMixin, AsyncStateStreamMixin, AsyncBleMixin, AsyncClientBase

Async HTTPX-based client for the BUSY Bar API.

Build a client for one bar.

addr is a device address; leaving it out with a token reaches the bar through the cloud, at the host BUSYLIB_CLOUD_URL names. Pass is_cloud=True only to name a cloud host per client, which is what stops an address like api.dev.busy.app being taken for a device.

usb property

usb: AsyncUsbController

Lazy-loaded USB controller.

is_usb_connected property

is_usb_connected: bool

Returns True if a USB device was found and connected.

connection_type class-attribute instance-attribute

connection_type: Literal['local', 'cloud', 'network'] = 'network'

max_retries instance-attribute

max_retries = max(0, int(max_retries))

backoff instance-attribute

backoff = backoff

api_version instance-attribute

api_version = api_version or versioning.API_VERSION

compatibility_mode instance-attribute

compatibility_mode: CompatibilityMode = compatibility_mode

client instance-attribute

client = httpx2.AsyncClient(base_url=self.base_url, headers=headers or None, timeout=_as_timeout(timeout), transport=transport)

is_cloud property

is_cloud: bool

Check whether connection uses cloud mode.

Returns True for cloud connection_type.

is_local property

is_local: bool

Check whether connection uses local mode.

Returns True for local connection_type.

usb_reboot async

usb_reboot(*, raise_on_error: bool = False) -> bool

Attempt to reboot the device via USB.

usb_reset async

usb_reset(*, raise_on_error: bool = False) -> bool

Alias for usb_reboot().

Provided for callers that prefer "reset" naming.

method_compatibility

method_compatibility(method_name: str) -> versioning.MethodCompatibility | None

Return declarative OpenAPI compatibility metadata for a client method.

is_local_available async

is_local_available() -> bool

Check local API reachability on base_url.

Returns True when /api/version responds without network errors.

aclose async

aclose() -> None

api_request async

api_request(method: str, path: str, *, params: dict[str, Any] | None = None, headers: dict[str, str] | None = None, session_id: str | None = None, application_name: str | None = None, json_payload: JsonType | None = None, data: bytes | AsyncIterable[bytes] | None = None, expect_bytes: bool = False, allow_text: bool = False, timeout: float | Timeout | None = None) -> JsonType | bytes | str

Execute a raw async API request through the current client session.

Advanced callers can control path, params, headers, body, and request context without creating a separate HTTP client.

prepare_request

prepare_request(method: str, path: str, *, params: dict[str, Any] | None = None, headers: dict[str, str] | None = None, session_id: str | None = None, application_name: str | None = None, json_payload: JsonType | None = None, data: bytes | AsyncIterable[bytes] | None = None, expect_bytes: bool = False, allow_text: bool = False, timeout: float | Timeout | None = None) -> PreparedRequest

Build a prepared async request without executing network I/O.

External integrations can inspect the prepared payload, route it to custom transports, or execute later via execute_prepared_request. Prepared request should be executed with an async executor.

execute_prepared_request async

execute_prepared_request(prepared: PreparedRequest, *, client: AsyncClient | None = None) -> JsonType | bytes | str

Execute a previously prepared async request.

By default the current httpx2.AsyncClient is used. Callers may inject a custom client while preserving error mapping. Prepared streaming content is single-use and should be regenerated for repeated executions.

ble_enable async

ble_enable() -> types.SuccessResponse

ble_disable async

ble_disable() -> types.SuccessResponse

ble_status async

ble_status() -> types.BleStatus

ble_pairing_forget async

ble_pairing_forget() -> types.SuccessResponse

stream_status_ws async

stream_status_ws(*, enable: bool = True, decode_protobuf: bool = True) -> AsyncIterator[dict[str, Any] | bytes | str]

Open /api/status/ws and yield status updates.

When decode_protobuf=True, binary frames are decoded using BSB_State.State protobuf schema from bsb-protobuf and converted into dictionaries with original proto field names.

smart_home_pairing async

smart_home_pairing() -> types.SmartHomePairingInfo

Fetch smart home pairing status via GET /api/smart_home/pairing.

smart_home_pairing_start async

smart_home_pairing_start() -> types.SmartHomePairingPayload

Start smart home pairing via POST /api/smart_home/pairing.

smart_home_pairing_stop async

smart_home_pairing_stop() -> types.SuccessResponse

Stop smart home pairing via DELETE /api/smart_home/pairing.

smart_home_switch async

smart_home_switch() -> types.SmartHomeSwitchState

Fetch smart home switch state via GET /api/smart_home/switch.

smart_home_switch_set async

smart_home_switch_set(state: bool, *, startup: Literal['off', 'on', 'toggle', 'last'] | None = None) -> types.SuccessResponse

Set smart home switch state via POST /api/smart_home/switch.

input async

input(key: InputKey) -> types.SuccessResponse

wifi_enable async

wifi_enable() -> types.SuccessResponse

Removed from the device API.

No supported firmware serves POST /api/wifi/enable, so calling this raises BusyBarRemovedEndpointError. Use wifi_connect() / wifi_disconnect() instead.

wifi_disable async

wifi_disable() -> types.SuccessResponse

Removed from the device API.

No supported firmware serves POST /api/wifi/disable, so calling this raises BusyBarRemovedEndpointError. Use wifi_connect() / wifi_disconnect() instead.

wifi_status async

wifi_status() -> types.StatusResponse

wifi_connect async

wifi_connect(config: ConnectRequestConfig | dict[str, Any]) -> types.SuccessResponse

wifi_disconnect async

wifi_disconnect() -> types.SuccessResponse

wifi_networks async

wifi_networks() -> types.NetworkResponse

Scan for nearby networks via GET /api/wifi/networks.

The device cannot scan while it is associated: doing so returns 400 "Scan not possible when connected" as a BusyBarAPIError. Disconnect first with wifi_disconnect(), or skip the scan and pass the SSID to wifi_connect() directly.

audio_play async

audio_play(*, path: str | None = None, stock_path: str | None = None, payload: AudioPlayRequest | dict[str, Any] | None = None, **request_kwargs: Unpack[RequestKwargs]) -> types.SuccessResponse

Play audio through async POST /api/audio/play.

The endpoint payload may reference either an uploaded asset path or a stock path. Explicit path and stock_path keyword arguments override the same keys provided in payload. Request context such as application_name and session_id is accepted through request kwargs; use api_request for fully custom bodies.

audio_stop async

audio_stop() -> types.SuccessResponse

Stop audio through async DELETE /api/audio/play.

Uses API-like naming for callers that mirror firmware endpoints.

audio_volume async

audio_volume() -> types.AudioVolumeInfo

audio_volume_set async

audio_volume_set(volume: float) -> types.SuccessResponse

display_draw async

display_draw(display_data: DisplayElements | dict[str, Any], *, clear_before_draw: bool = False, sanitize_text: bool = False, **request_kwargs: Unpack[RequestKwargs]) -> types.SuccessResponse

display async

display(display_data: DisplayElements | dict[str, Any], *, clear_before_draw: bool = False, sanitize_text: bool = False, audio_payload: AudioPlayRequest | dict[str, Any] | None = None, **request_kwargs: Unpack[RequestKwargs]) -> types.SuccessResponse

Render display content and optionally play audio after draw.

Operations are sequential, not atomic: clear may succeed before draw fails, and audio failure may occur after display content is visible. Exceptions include the failed endpoint path for diagnostics.

display_clear async

display_clear(**request_kwargs: Unpack[RequestKwargs]) -> types.SuccessResponse

Clear display content through async DELETE /api/display/draw.

Uses API-like naming for callers that mirror firmware endpoints.

display_brightness async

display_brightness() -> types.DisplayBrightnessInfo

display_brightness_set async

display_brightness_set(value: BrightnessValue) -> types.SuccessResponse

screen async

screen(display_id: DisplaySpecLike) -> bytes

Fetch a single display frame via GET /api/screen.

Returns RGB bytes, three per pixel: 3456 for the front display (72x16) and 38400 for the back (160x80, sent L4-packed and expanded to grey triples here). The device sends colour as BGR and it is swapped on the way out.

The response body is base64-encoded, uncompressed framebuffer bytes (the Content-Type: image/bmp header is misleading, there is no real BMP header).

frame async

frame(display_id: DisplaySpecLike) -> Frame

Fetch a display frame as a Frame via GET /api/screen.

The same bytes as screen(), with the geometry and the display attached, so callers can read pixels, rows or a PNG without tracking the layout themselves.

assets_upload async

assets_upload(application_name: str, filename: str, data: bytes, *, timeout: float | Timeout | None = ASSET_UPLOAD_TIMEOUT) -> types.SuccessResponse

Upload an asset file for the given application.

Uses a longer default timeout to tolerate large payload uploads.

assets_delete async

assets_delete(application_name: str) -> types.SuccessResponse

storage_write async

storage_write(path: str, data: bytes, *, timeout: float | None = 60.0, progress_callback: Callable[[int, int], None] | None = None, chunk_size: int = 64 * 1024) -> types.SuccessResponse

storage_read async

storage_read(path: str) -> bytes

storage_list async

storage_list(path: str) -> types.StorageList

storage_remove async

storage_remove(path: str) -> types.SuccessResponse

storage_mkdir async

storage_mkdir(path: str) -> types.SuccessResponse

Create a storage directory via POST /api/storage/mkdir.

storage_rename async

storage_rename(old_path: str, new_path: str) -> types.SuccessResponse

Rename a storage entry via POST /api/storage/rename.

storage_status async

storage_status() -> types.StorageStatus

version async

version() -> types.VersionInfo

Fetch API version info and validate compatibility.

transport async

transport() -> types.NetworkInterfaceInfo

Fetch active network transport via GET /api/transport.

status async

status() -> types.Status

Fetch full device status via GET /api/status.

status_device async

status_device() -> types.StatusDevice

Fetch device manufacturing status via GET /api/status/device.

status_firmware async

status_firmware() -> types.StatusFirmware

Fetch firmware status via GET /api/status/firmware.

status_system async

status_system() -> types.StatusSystem

Fetch runtime status via GET /api/status/system.

status_power async

status_power() -> types.StatusPower

Fetch power status via GET /api/status/power.

log_dump async

log_dump(filename: str | None = None) -> types.LogDumpResponse

Dump the in-memory device log buffer to a storage file.

filename is a bare name without a path or extension, matching ^[a-zA-Z0-9_-]+$ on firmware OpenAPI 25.0.0+; the device appends its own extension and storage path. When omitted, the device picks a default file.

Breaking change: prior to 25.0.0 this method accepted path= (a full device-side path). That parameter has been removed rather than aliased, since the two contracts are not translatable (a full path never matches the new filename pattern). Callers targeting firmware older than 25.0.0 should pin an older busylib release instead of adapting call sites.

name async

name() -> types.DeviceNameResponse

Fetch device name via GET /api/name.

name_set async

name_set(name: str) -> types.SuccessResponse

Set device name via POST /api/name.

time async

time() -> types.DeviceTimeResponse

Fetch device time via GET /api/time.

update async

update(firmware_data: bytes) -> types.SuccessResponse

Upload firmware update TAR and initiate update.

update_check async

update_check() -> types.SuccessResponse

Start asynchronous firmware update check.

update_status async

update_status() -> types.UpdateStatus

Get firmware update status with progress information.

update_changelog async

update_changelog(version: str) -> types.UpdateChangelogResponse

Fetch update changelog for a specific version.

update_install async

update_install(version: str) -> types.SuccessResponse

Start firmware update installation by version.

update_abort_download async

update_abort_download() -> types.SuccessResponse

Abort an ongoing firmware download.

update_autoupdate async

update_autoupdate() -> types.AutoupdateSettings

Fetch autoupdate settings via GET /api/update/autoupdate.

update_autoupdate_set async

update_autoupdate_set(settings: AutoupdateSettings | dict[str, object]) -> types.SuccessResponse

Set autoupdate settings via POST /api/update/autoupdate.

time_timezone_info async

time_timezone_info() -> types.TimezoneInfo

Fetch current device timezone via GET /api/time/timezone.

time_timezone_list async

time_timezone_list() -> types.TimezoneListResponse

Fetch supported device timezones via GET /api/time/tzlist.

time_timestamp async

time_timestamp(timestamp: str) -> types.SuccessResponse

Set device time via POST /api/time/timestamp.

time_timezone async

time_timezone(timezone: str) -> types.SuccessResponse

Set device timezone via POST /api/time/timezone.

busy_snapshot async

busy_snapshot() -> types.BusySnapshot

Fetch busy snapshot via GET /api/busy/snapshot.

busy_snapshot_set async

busy_snapshot_set(snapshot: BusySnapshot) -> types.SuccessResponse

Set busy snapshot via PUT /api/busy/snapshot.

busy_profile async

busy_profile(slot: BusyProfileSlot) -> types.BusyProfile

Fetch a busy profile slot via GET /api/busy/profiles/{slot}.

busy_profile_set async

busy_profile_set(slot: BusyProfileSlot, profile: BusyProfile | dict[str, object]) -> types.SuccessResponse

Set a busy profile slot via PUT /api/busy/profiles/{slot}.

account_unlink() -> types.SuccessResponse

Unlink the device from the account via DELETE /api/account.

account_link() -> types.AccountLink

Request an account link code via POST /api/account/link.

account_info async

account_info() -> types.AccountInfo

Fetch linked account info via GET /api/account/info.

account_status async

account_status() -> types.AccountState

Fetch MQTT status info via GET /api/account/status.

account_backend async

account_backend() -> types.AccountBackend

Fetch MQTT backend settings via GET /api/account/backend.

account_backend_set async

account_backend_set(backend: AccountBackend | dict[str, object]) -> types.SuccessResponse

Set MQTT backend settings via PUT /api/account/backend.

account_profile async

account_profile() -> types.AccountProfile

Removed from the device API.

No supported firmware serves GET /api/account/profile, so calling this raises BusyBarRemovedEndpointError. Use account_backend() instead.

account_profile_set async

account_profile_set(profile: AccountProfileName, custom_url: str | None = None) -> types.SuccessResponse

Removed from the device API.

No supported firmware serves POST /api/account/profile, so calling this raises BusyBarRemovedEndpointError. Use account_backend_set() instead.

access async

access() -> types.HttpAccessInfo

Fetch HTTP access mode via GET /api/access.

access_set async

access_set(mode: HttpAccessMode, key: str) -> types.SuccessResponse

Set HTTP access mode via POST /api/access.

access_tokens_list async

access_tokens_list() -> types.AccessTokensInfo

List issued access tokens via GET /api/access/tokens.

The secret itself is returned only when a token is minted, so every token here has token set to None.

Experimental: needs firmware from busy-app/busybar-firmware#886, which is not released yet, so it answers 404 on every released firmware.

access_token_mint async

access_token_mint(name: str) -> types.AccessToken

Issue a new access token via POST /api/access/tokens.

This is the only time the device discloses the secret; it cannot be read back afterwards.

Experimental: needs firmware from busy-app/busybar-firmware#886, which is not released yet, so it answers 404 on every released firmware.

access_tokens_delete_all async

access_tokens_delete_all() -> types.SuccessResponse

Revoke every access token via DELETE /api/access/tokens.

Experimental: needs firmware from busy-app/busybar-firmware#886, which is not released yet, so it answers 404 on every released firmware.

access_tokens_revoke async

access_tokens_revoke(short_id: str) -> types.SuccessResponse

Revoke one access token via DELETE /api/access/tokens/{short_id}.

Experimental: needs firmware from busy-app/busybar-firmware#886, which is not released yet, so it answers 404 on every released firmware.

Prepared requests

busylib.client.PreparedRequest

Bases: BaseModel

Prepared low-level request ready for execution by HTTP clients.

This object stores normalized request attributes after payload encoding. Callers can execute it with built-in client transport or pass fields to an external request executor. Serialization is not guaranteed because timeout and streaming content may contain runtime-only objects.

Streaming content based on iterables/generators is single-use and should not be reused across multiple executions.

method instance-attribute

method: str

path instance-attribute

path: str

params instance-attribute

params: dict[str, Any] | None

headers class-attribute instance-attribute

headers: dict[str, str] | None = Field(default=None, repr=False)

content class-attribute instance-attribute

content: bytes | Iterable[bytes] | AsyncIterable[bytes] | None = Field(default=None, repr=False)

expect_bytes instance-attribute

expect_bytes: bool

allow_text instance-attribute

allow_text: bool

timeout instance-attribute

timeout: Timeout

request_id instance-attribute

request_id: str

json_payload class-attribute instance-attribute

json_payload: JsonType | None = None

model_config class-attribute instance-attribute

model_config = ConfigDict(arbitrary_types_allowed=True)