Skip to content

Connecting to a bar

Addresses

A bar plugged in over USB comes up as a network device at the well-known address 10.0.4.20, with no Wi-Fi configuration needed. Once it joins a network it also gets a normal address on that network, and either works:

from busylib import BusyBar

bb = BusyBar("10.0.4.20")  # over USB
bb = BusyBar("192.168.1.20")  # over Wi-Fi

Constructing a client produces no output and does not make a network request. Call version() or another method to verify that the selected address works.

Run the first check

Run terminal commands in PowerShell on Windows, or Terminal on macOS and Linux. Put Python examples in a .py file in your editor and run that file; do not paste git, py, or uv commands into a Python file or >>> prompt.

The quick start has copyable Windows and macOS/Linux installation commands, a complete check_busybar.py file, and the expected successful output. The bar's /docs page documents its raw HTTP API; it does not execute Python examples from this documentation.

Access keys

On current firmware the access key is enforced only on connections arriving over Wi-Fi — USB and localhost traffic skips the check — so a bar reached at 10.0.4.20 usually needs no token whatever access mode it is in. Treat that as an observation about the firmware in front of you rather than a guarantee, and handle a 403 on the USB path too.

Over Wi-Fi, if the access mode is set to key, every request needs that token and unauthenticated calls come back as 403 Forbidden. The key is a 4–10 digit PIN:

bb = BusyBar("10.0.4.20", token="your-access-key")

The current mode is readable without authentication, which is what the setup and remote examples use to decide whether to ask for a key:

info = bb.access()
print(info.mode, info.key_valid)  # 'key' True

Example output:

key True

This means the bar has access-key mode enabled. key_valid describes the device configuration, not whether the token supplied by this client is valid.

Note

key_valid reports whether the device has a key configured, not whether the token you supplied is the right one. Don't use it to decide that no token is needed.

Discovery

Rather than hardcoding an address:

from busylib import BusyBarDevices

for device in BusyBarDevices.discover():
    print(device.name, device.get_address("over_wifi"))

Example output when a bar advertises itself:

Front desk 192.168.1.20

Each line is the advertised device name and Wi-Fi address. No output is normal on firmware that does not advertise the service; a USB-connected bar remains available at 10.0.4.20.

Discovery browses for the _busybar._tcp mDNS service and classifies each address it finds: anything in 10.0.4.* is treated as the USB link, everything else as Wi-Fi.

Warning

Shipped firmware does not advertise _busybar._tcp yet, so discover() can legitimately return an empty list. The remote and setup examples fall back to 10.0.4.20 in that case.

Closing the client

Both clients hold an HTTP connection pool. Use them as context managers, or close them explicitly:

with BusyBar("10.0.4.20") as bb:
    ...

async with AsyncBusyBar("10.0.4.20") as bb:
    ...

Timeouts and retries

Requests carry a default timeout and are retried a few times on transport errors. Override per call where it matters — uploads, for instance, accept a longer timeout:

bb.assets_upload("my-app", "big.png", data, timeout=60.0)

Expected result: the call returns SuccessResponse(result="OK") without printing anything. A timeout applies only to this upload, not to future client requests.

Helpers for endpoints that no longer exist

A few helpers target device endpoints that current firmware doesn't serve at all. They fail immediately with BusyBarRemovedEndpointError and name their replacement, rather than letting an opaque 404 come back:

Helper Use instead
account_profile(), account_profile_set() account_backend(), account_backend_set()
wifi_enable(), wifi_disable() wifi_connect(), wifi_disconnect()

These did exist once — wifi/enable and wifi/disable up to firmware 0.2.0, account/profile from 0.6.0-rc to 0.8.1 — but every firmware since serves none of them, and the library targets a far newer API than those bars run. To talk to firmware that old, pin a busylib version from the same era, as the versioning policy describes; api_request() remains the escape hatch.

This is deliberately distinct from BusyBarAPIVersionError: updating the firmware won't help, because the endpoint was withdrawn rather than added later. method_compatibility() reports the same information:

bb.method_compatibility("account_profile")
# {'path': '/api/account/profile', 'method': 'GET',
#  'status': 'removed', 'replacement': 'account_backend()'}

The result is local compatibility metadata: it explains that the helper must not be called and names its replacement; no request reaches the device.