Skip to content

Device discovery

BUSY Bars announce themselves over mDNS, so an address doesn't have to be hardcoded.

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 device name and its Wi-Fi address. Empty output means no bars were discovered, not that the library failed; use 10.0.4.20 for a USB-connected bar in that case.

Note

Shipped firmware doesn't advertise the _busybar._tcp service yet, so discover() can legitimately return an empty list. A USB-connected bar is still reachable at its well-known static address, 10.0.4.20.

busylib.devices

BUSYBAR_SERVICE module-attribute

BUSYBAR_SERVICE = '_busybar._tcp.local.'

BUSYBAR_USB_SUBNET module-attribute

BUSYBAR_USB_SUBNET = '10.0.4.'

BUSYBAR_DEFAULT_NAME module-attribute

BUSYBAR_DEFAULT_NAME = b'BUSY Bar'

TIMEOUT module-attribute

TIMEOUT = 1.5

RESOLVE_TIMEOUT_MS module-attribute

RESOLVE_TIMEOUT_MS = 1500.0

BusyBarAddressAffinity

Bases: Enum

OVER_USB class-attribute instance-attribute

OVER_USB = 'over_usb'

OVER_WIFI class-attribute instance-attribute

OVER_WIFI = 'over_wifi'

BusyBarAddress dataclass

BusyBarAddress(ip_address: str, affinity: BusyBarAddressAffinity)

ip_address instance-attribute

ip_address: str

affinity instance-attribute

affinity: BusyBarAddressAffinity

BusyBarDevice dataclass

BusyBarDevice(name: str, device_id: str, addresses: set[BusyBarAddress])

name instance-attribute

name: str

device_id instance-attribute

device_id: str

addresses instance-attribute

addresses: set[BusyBarAddress]

get_address

get_address(affinity: Literal['over_usb'] | Literal['over_wifi'] | None = None) -> str | None

to_sync_client

to_sync_client(affinity: Literal['over_usb'] | Literal['over_wifi'] | None = None, **kwargs) -> BusyBar | None

to_async_client

to_async_client(affinity: Literal['over_usb'] | Literal['over_wifi'] | None = None, **kwargs) -> AsyncBusyBar | None

BusyBarDeviceDiscoverer

BusyBarDeviceDiscoverer(zeroconf: Zeroconf | None)

Bases: _DeviceCollector

Blocking mDNS discovery.

Owns the Zeroconf instance it creates and closes it when done. One supplied by the caller is left exactly as it was found: not reconfigured, and not closed, because they may still be using it.

sync_teardown

sync_teardown() -> None

Close the Zeroconf instance, if this discoverer created it.

sync_collect

sync_collect(timeout: float) -> list[BusyBarDevice]

AsyncBusyBarDeviceDiscoverer

AsyncBusyBarDeviceDiscoverer(zeroconf: AsyncZeroconf | None)

Bases: _DeviceCollector

Non-blocking mDNS discovery, on zeroconf's own async API.

Nothing here reaches for a worker thread: AsyncZeroconf closes with async_close, the browser cancels with async_cancel, and records are resolved with AsyncServiceInfo.async_request instead of the blocking get_service_info.

async_teardown async

async_teardown() -> None

Close the AsyncZeroconf instance, if this discoverer created it.

async_collect async

async_collect(timeout: float) -> list[BusyBarDevice]

BusyBarDevices

async_discover async staticmethod

async_discover(timeout: float = TIMEOUT, zeroconf: AsyncZeroconf | None = None) -> list[BusyBarDevice]

Discover bars without blocking the event loop.

Takes an AsyncZeroconf, not a Zeroconf, mirroring zeroconf's own split between the two APIs. Wrap an existing instance with AsyncZeroconf(zc=my_zeroconf) if you already have one.

discover staticmethod

discover(timeout: float = TIMEOUT, zeroconf: Zeroconf | None = None) -> list[BusyBarDevice]