# Usage

See Supported devices for the full list of recognised models and the transport (advertisement / poll / notify) each one uses.

`inkbird-ble` turns the BLE advertisements (and, for some models, GATT notifications/reads) emitted by INKBIRD devices into structured sensor values. It is built on top of `bluetooth-sensor-state-data` and is the parser used by the Home Assistant INKBIRD integration, but it can be used on its own.

The entry point is the `INKBIRDBluetoothDeviceData` class:

    from inkbird_ble import INKBIRDBluetoothDeviceData

## Passive devices (advertisement only)

Most INKBIRD sensors (the `IBS-TH`, `IBS-TH2`, `ITH-*-B`, `iBBQ-*` and `IAM-T2` families) broadcast their readings in the BLE advertisement, so no connection is required. Feed each advertisement to `update()` and you get a `SensorUpdate` back:

    from inkbird_ble import INKBIRDBluetoothDeviceData

    # `service_info` is a habluetooth `BluetoothServiceInfoBleak`. Inside Home
    # Assistant you receive one for every advertisement; standalone you can build
    # one from a Bleak scan (see below).
    data = INKBIRDBluetoothDeviceData()

    if data.supported(service_info):
        update = data.update(service_info)
        print(data.device_type)   # e.g. Model.IBS_TH
        print(update.entity_values)

`update()` returns a `SensorUpdate` whose `entity_values` maps each `DeviceKey` to a `SensorValue` (temperature in °C, humidity in %, battery in %, signal strength in dBm, …):

    for device_key, sensor_value in update.entity_values.items():
        print(device_key.key, sensor_value.native_value)
    # temperature 20.44
    # humidity 48.07
    # battery 86
    # signal_strength -60

### What is the integer key in `manufacturer_data`?

A `BluetoothServiceInfoBleak` exposes `manufacturer_data` as a `dict[int, bytes]`. The integer key is the Bluetooth SIG company identifier advertised by the device — it is not a temperature or a value you need to decode yourself. You never index into `manufacturer_data` manually; pass the whole `service_info` to `update()` and the parser selects the right model and payload for you.

If your device firmware also exposes the raw advertisement bytes, populate the `raw` field of the `BluetoothServiceInfoBleak` — when present, the parser prefers it over `manufacturer_data`, which avoids a class of misreads.

## Active devices (connect, read or subscribe)

A few models do not put everything in the advertisement and must be polled or subscribed to over a GATT connection. `inkbird-ble` handles the connection for you via Bleak; you only supply a `BLEDevice`.

If you know the model up front, pass it to the constructor (otherwise it is detected from the first advertisement):

    from inkbird_ble import INKBIRDBluetoothDeviceData

    data = INKBIRDBluetoothDeviceData("IBS-TH")
    data.supported(service_info)  # also sets the device type

### Polling models

For models that expose their data through a readable characteristic, check `poll_needed()` and call `async_poll()` with a `BLEDevice`:

    if data.poll_needed(service_info, last_poll=None):
        update = await data.async_poll(ble_device)
        print(update.entity_values)

`poll_needed()` rate-limits itself, so it is safe to call on every advertisement; it only returns `True` when a fresh read is actually due.

The `INT-11P-B` BBQ probe is a polling model that carries no readings in its advertisement at all — it is detected by name and read over GATT. A poll yields its probe and ambient temperatures (`temperature_probe`, `temperature_ambient`) and its probe and case battery levels (`probe_battery`, `case_battery`).

### Notify models

Some models (for example the `IAM-T1` and the `IHT-2PB` probe thermometer) push readings over GATT notifications. Start a notification session and receive updates through callbacks:

    def on_update(update):
        print(update.entity_values)

    def on_device_data_changed(device_data):
        # e.g. the device's temperature unit changed
        print(device_data)

    data = INKBIRDBluetoothDeviceData(
        "IAM-T1",
        update_callback=on_update,
        device_data_changed_callback=on_device_data_changed,
    )

    await data.async_start(service_info, ble_device)
    # ... receive callbacks while connected ...
    await data.async_stop()

Use the `uses_notify` property to tell the two active styles apart:

    if data.uses_notify:
        await data.async_start(service_info, ble_device)
    elif data.poll_needed(service_info, last_poll=None):
        await data.async_poll(ble_device)

## Building a `BluetoothServiceInfoBleak` outside Home Assistant

When you are not running inside Home Assistant you can construct the `service_info` yourself from a Bleak scan result:

    from habluetooth import BluetoothServiceInfoBleak

    service_info = BluetoothServiceInfoBleak(
        name=device.name,
        address=device.address,
        rssi=advertisement_data.rssi,
        manufacturer_data=advertisement_data.manufacturer_data,
        service_data=advertisement_data.service_data,
        service_uuids=advertisement_data.service_uuids,
        source="local",
        device=device,
        advertisement=advertisement_data,
        connectable=True,
        time=0,
        tx_power=advertisement_data.tx_power or 0,
        raw=None,
    )

`device` and `advertisement_data` are the `BLEDevice` and `AdvertisementData` objects yielded by `bleak.BleakScanner`.