# `Bluez.Advert`
[🔗](https://github.com/bbangert/bluez/blob/v0.1.0/lib/bluez/advert.ex#L1)

Reconstructs a BLE advertisement (the verbatim-ish AD byte structure plus
the fields an ESPHome-style scanner host needs) from BlueZ's *parsed* device
properties.

D-Bus / `org.bluez` does NOT expose the raw over-the-air AD bytes, only
parsed properties (`ManufacturerData`, `ServiceData`, `ServiceUUIDs`,
`Name`, `TxPower`, `RSSI`, `Address`). We re-serialize those back into AD
elements. This is **lossy** — it drops AD element order, the Flags (0x01)
element, unknown/proprietary AD types, and the adv/scan-response split —
but it is faithful for the manufacturer- and service-data elements that
Home Assistant's sensor decoders use (BTHome `0xFCD2`, Govee, Xiaomi).

This is how HA's own Linux/BlueZ adapters reconstruct adverts
(`bluetooth-data-tools`).

## Inputs

`reconstruct/1` takes a *props map* keyed by BlueZ property name with
values already unwrapped from their D-Bus variants by
`Bluez.Client`:

    %{
      "Address" => "AA:BB:CC:DD:EE:FF",
      "AddressType" => "public" | "random",
      "RSSI" => -60,                       # int16, may be absent
      "ManufacturerData" => %{0x004C => <<...>>},   # company_id => bytes
      "ServiceData" => %{"0000fcd2-..." => <<...>>},# uuid string => bytes
      "ServiceUUIDs" => ["0000fcd2-0000-1000-8000-00805f9b34fb", ...],
      "Name" => "Govee_...",
      "TxPower" => -4
    }

## Output

`{:ok, advert}` where `advert` is the map shape
`Bluez.Client`'s `on_advertisement:` fun consumes, or `:skip` when there
is no `Address` (can't address the advert) — RSSI/data may legitimately be
absent on a given update.

# `advert`

```elixir
@type advert() :: %{
  address: non_neg_integer(),
  rss: integer(),
  address_type: 0 | 1,
  raw_data: binary()
}
```

# `address_to_integer`

```elixir
@spec address_to_integer(String.t()) :: non_neg_integer()
```

Parse `"AA:BB:CC:DD:EE:FF"` into the MSB-first integer Home Assistant
expects (`0xAABBCCDDEEFF`). Matches what blue_heron forwarded (validated on
rpi3 against HA — no byte swap).

# `reconstruct`

```elixir
@spec reconstruct(map()) :: {:ok, advert()} | :skip
```

Build the `on_advertisement/1` map from unwrapped BlueZ props, or `:skip`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
