# Supported devices and catalog

Canonical page: https://docs.ovok.com/native-sdk/guide/modules/bt-device

The device catalog joins display metadata with the Bluetooth declarations the SDK can use. Import it from `@ovok/native/bt-device`:

For the complete current model list, see [all supported Bluetooth devices](/native-sdk/guide/supported-devices).

~~~tsx
import {
  SUPPORTED_DEVICES,
  SUPPORTED_ACCEPTED_DEVICES,
  Devices,
} from "@ovok/native/bt-device";
~~~

## Pick a connectable entry [#pick-a-connectable-entry]

`SUPPORTED_DEVICES` is the app-facing catalog. Each row contains `id`, `name`, `manufacturer`, image and attribution data, measurement types, an optional manual URL, and an `acceptedDevices` array for `BTProvider`.

~~~tsx
const selected = SUPPORTED_DEVICES.find(
  (device) => device.id === selectedId,
);
const acceptedDevices = selected?.acceptedDevices ?? [];

if (acceptedDevices.length > 0) {
  // Use this declaration list as BTProvider.acceptedDevices.
}
~~~

Some rows are useful for display but have no accepted declaration. An empty array means the current SDK catalog does not provide a decoder for that row. Do not offer a connect action for it.

`SUPPORTED_ACCEPTED_DEVICES` is a de-duplicated union of the declaration arrays in the catalog. Use it only when the feature intentionally accepts every catalog declaration; most apps should provide the narrower set that matches their product.

Catalog IDs are generated from each entry's name. Use the exported `id` as the selection key rather than constructing it from a display name.

## What each device is [#what-each-device-is]

Every row also says what the product is, so an app needs no table of its own:

| Field | Meaning |
| --- | --- |
| `kind` | What it is for: `blood-pressure-monitor`, `weight-scale`, `pulse-oximeter`, `thermometer`, `glucose-meter`, `ecg-recorder`, `heart-rate-monitor`, `activity-tracker`, `urine-analyzer`, `lipid-analyzer`, `respiratory-therapy`, `sleep-monitor`, or `multi-parameter-monitor` (three or more kinds of reading, such as the Checkme or the Lepod). |
| `primaryMeasurement` | The reading it is for. Heart rate comes along with most readings, so it is the main one only on a device that measures nothing else. |
| `delivery` | `spot`: one reading per measurement. `live`: values every second or so while connected (live oximeters, heart-rate straps, the Lepod). |
| `keys` | The keys BTManager reports its devices under (`deviceData.name`). |
| `shared` | Its parser also serves other products (rebadged models, a Bluetooth SIG profile), so a connected device may be any of them; `deviceData.variant` names the one it is when its advertised name says. |
| `imageCredit` | `creditsForImage` as `{ label, url? }`. |

## Find and filter devices [#find-and-filter-devices]

~~~tsx
import { MeasurementTypeKey } from "@ovok/core/next";
import {
  filterSupportedDevices,
  findSupportedDevice,
  useSupportedDevices,
} from "@ovok/native/bt-device";

const scales = useSupportedDevices({ kind: "weight-scale" });
const hartmann = filterSupportedDevices({ manufacturer: "HARTMANN", kind: "blood-pressure-monitor" });
const recorders = filterSupportedDevices({ measures: MeasurementTypeKey.ecg, delivery: "spot" });
const product = findSupportedDevice(device.deviceData); // a connected device's catalog product
~~~

Every field of a filter has to match, and a list matches any one of its values. Text matches in any case, or pass a `RegExp` (`{ manufacturer: /yonker/i }`). `where` covers anything else. A string passed to `findSupportedDevice` is a catalog id, else a product name, else a reported key; pass a connected device's `deviceData` to get the product it is.

Live devices send a reading every second or so. To keep the whole stream, pass `resultPoliciesFor(devices)` as `resultPolicies`: it gives live devices `LIVE_RESULT_POLICY`, which records their values as [series](/native-sdk/guide/modules/bt-management#streams-as-series) and still reports each blood pressure, glucose reading and ECG recording they take.

## Follow connected devices by what they are [#follow-connected-devices-by-what-they-are]

`useBTDevice` and `useBTDevices` from `@ovok/native/bt-management` take the same filter, plus the connection `status` and a `where(device, product)`:

~~~tsx
import { DeviceStatus, useBTDevice, useBTDevices } from "@ovok/native/bt-management";

const { device, connect } = useBTDevice({ kind: "blood-pressure-monitor", manufacturer: "HARTMANN" });
const connectedScales = useBTDevices({ kind: "weight-scale", status: DeviceStatus.CONNECTED });
~~~

A model key works as before: `useBTDevice(IntegratedDevices.BP2)`. A failed measurement's `BluetoothError.translationKey` is one of `MeasurementFeedbackKey` (`STUCK`, `CORRUPT_FRAME`, `LOOSE_SLEEVE`, …); compare against those rather than the strings.

## Choose the right catalog UI [#choose-the-right-catalog-ui]

| Component | Data and behavior |
| --- | --- |
| [SupportedDevicesCatalogList](/native-sdk/guide/components/ui/supported-devices-catalog-list) | Uses `SUPPORTED_DEVICES` by default. Shows artwork, name, manufacturer, measurement types, image credit, and an optional manual. `onSelect` returns metadata; it does not connect. |
| [SupportedDeviceList](/native-sdk/guide/components/bt-device/supported-device-list/) | Uses the simpler `Devices` array and renders the static name, manufacturer, image, and image credit. |
| [BTDeviceList](/native-sdk/guide/components/bt-device/bt-device-list/) | Shows the separate status-list context; it is not the supported catalog. |
| [BTDeviceInstruction](/native-sdk/guide/components/bt-device/bt-device-instruction/) | Resolves an integrated device's manual from the SDK instruction mapping. |

The richer catalog list displays the raw `name` and `manufacturer` strings. The simpler `SupportedDeviceList` uses `nameKey` and `manufacturerKey` with the catalog strings as fallback values. Add locale resources when your app wants translated catalog labels; measurement keys should also be mapped to app-facing copy.

Image URLs, bundled assets, and their `creditsForImage` values are part of the exported data. The catalog UI displays credit by default. If you replace the photo or credit slot, keep the attribution visible in your app's catalog experience.

## Device match and result identity [#device-match-and-result-identity]

A catalog declaration describes the device names or services the SDK can match and the protocol used to decode its frames. A product family can contain several models or firmware versions; verify the exact device variant your app offers. For standard GATT profiles, the service layout alone does not make every device with that service a match.

### Rebadged devices [#rebadged-devices]

Some manufacturers sell the same device under several brands. `DEVICE_VARIANTS` lists each brand and model next to the built-in parser it shares: Transtek and Bioland glucose meters sold by American Health Gate, LinkSun and Pursonic; Jamr blood-pressure monitors sold as Jamr, Sinocare, ProMedica, Ease Healthcare, Gamma, GLOWY and Nebucor; AOJ thermometers; TaiDoc and FORA multi-parameter meters (TD-4279, TD-4289, TD-4206, FORA 6 Connect, FORA 6 Duo, Test N'GO Advance) on the GlucoCheck parser, which reports only their glucose records and drops ketone, cholesterol and control-solution results; and the Vive Precision ECG on the PM10 parser. When an advertised name matches a variant, the connected device reports the parser in `deviceData.name` and the product in `deviceData.variant`:

```ts
device.deviceData.name; // "Bioland-BGM", the parser
device.deviceData.variant; // { manufacturer: "American Health Gate", model: "AHG-427B" }
```

`deviceTitle` shows the variant's model. Accepting the parser in `acceptedDevices` accepts every variant of it. `variant` is unset for a parser that serves a single product.

Transtek's own "command" protocol (generations A2 and A3) is built in too, as `Transtek BPM`, `Transtek Scale`, `Transtek Scale 1525` and `Transtek Tracker`: 180 white-label and rebadged products, including Transtek's Smart BP Monitor and Smart Weight Scale lines and products sold by Zewa, Medicare Lifesense, iProven, Kinetik Wellbeing, Welch Allyn and others. These devices pair with a password, so give the SDK somewhere to keep it (see [Keep device pairing secrets](/native-sdk/guide/modules/bt-management#keep-device-pairing-secrets)). Scales report a weight only once they mark it complete, so the values shown while someone steps on are not readings, and a scale set to pounds is converted to kilograms. The tracker reports its live running total for the day; its stored points and end-of-day statistics are earlier totals of the same steps and are not reported again. Records dated more than a day ahead of the phone are dropped as an unset device clock.

These vendors have built-in classes too:

- **Famidoc** (`Famidoc BPM`, `Famidoc IR Thermometer`, `Famidoc Contact Thermometer`): FDBP blood-pressure monitors, FDIR infrared and FDTH contact thermometers, and rebrands such as Trister and BYDOC. Records are acknowledged one by one and the session ends after a minute without a record. No pairing secret is involved.
- **AOJ Medical** (`AOJ BPM`, `AOJ BPM FFF0`, `AOJ-70B`): the AOJ-30/33 blood-pressure monitors and rebrands (CliniCare, Oxiline, Oxmedi, B.Well, Sinocare), the Cazon BSX530B (`AOJ BPM FFF0`, which only pushes readings), and the AOJ-70A/70B pulse oximeter. The SDK sets the monitor's clock, downloads its stored records and leaves them on the device. The oximeter reports one spot reading, the last valid saturation and pulse, once valid values stop for three seconds.
- **Jumper Medical** (`Jumper Oximeter`, `Jumper BPM`, `Jumper Thermometer`): the JPD-500D/500G pulse oximeters and rebrands (Zewa, AndesFit, Arystone, Kinetik, Tenovi, Qardio, Medicare Lifesense, LifeSyne), the HA120 blood-pressure monitor and rebrands (Oxiline, Alphamed, Medicare Lifesense), and the FR302/FR409 thermometers and rebrands (Zewa, iProven, Kinetik). All three only push live readings, so the phone's clock times them. The oximeter reports one spot reading once valid values stop for three seconds. A thermometer's repeated transmission of the same temperature within 30 seconds is dropped.
- **Joytech (Sejoy)** (`Joytech BPM`, `Joytech Thermometer`): DBP blood-pressure monitors, including the Controly AFIB Connect, and DET thermometers. The SDK sets the clock, asks a monitor for its history and acknowledges every record. Blood-pressure readings carry `irregularHeartbeat` and `atrialFibrillation`. Thermometer readings from the object/surface mode are skipped.
- **A&D Medical** (`A&D BPM`, `A&D BPM CTS`, `A&D Scale`): the UA-651BLE, UA-911BT-C and UA-656BLE blood-pressure monitors, the UA-1200BLE and UB-1100BLE (`A&D BPM CTS`, clock on Current Time), and the UC-352BLE scale. The SDK sets the clock on every connection: a monitor gets the SIG Date Time a second after connecting, then sends its readings over the SIG Blood Pressure profile with the device timestamp, `irregularHeartbeat` and the user as `memorySlot`; an exact repeat in one connection is reported once. The scale takes the A&D set-time command and reports kilograms, converting a scale set to pounds. All of them need an OS bond; the SDK has no explicit bonding step, so pairing relies on the platform's prompt when the device asks for encryption.
- **Yonker** (`Yonker Oximeter`, `Yonker BPM`, `Yonker Thermometer`, `Yonker Scale`, `Yonker 80B`): the YK-81C pulse oximeter and rebrands (Balans Plus, Incoterm), the YK-BPA/YK-IBPA blood-pressure monitors and rebrands (Metiko, OxiPro), the YK-IRT4 thermometer and the Balans Plus BPTI 24, the AiLink weight scale and the Balans Plus BPBI 24, and the YK-80B oximeter (Orluminis YK-83B). The SDK sets a monitor's clock and keeps the time each record carries; the monitor pushes its records by itself. The oximeters report one spot reading once valid values stop for three seconds. Thermometer readings in Fahrenheit are converted to Celsius, and a repeated transmission of the same temperature within 30 seconds is dropped. The scale is set to kilograms and reports the weight when it signals the measurement complete; body composition is not read.
- **Cofoe** (`Cofoe BPM`, `Cofoe BPM History`, `Cofoe Glucometer`, `Cofoe Glucometer CGH25`, `Cofoe Thermometer`): KF-65/KF-66EP blood-pressure monitors (`Cofoe BPM`, a live reading timed by the phone) and the KF-66EP+, KF-65BY/W/BW/G/DPLUS, KF-66DP, KF-67C/BP and Carditek Smart (`Cofoe BPM History`, stored records that keep the monitor's own time); the KF-B06, CGH200 and Novocont Comfort glucometers; the CGH25 and CGH30 glucometers; and the KF-HW-081A thermometer. The SDK sets each device's clock where the protocol has one, acknowledges every record, and never deletes a glucometer's memory. Blood-pressure readings carry `irregularHeartbeat`; glucose arrives in mmol/L and is reported in mg/dL. Every frame's checksum is verified and a frame that fails it is dropped.
- **Transtek A6 scales** (`GBS-2012-B`, `RPM_SCALE`): the GBS-2012-B and other A6-generation body-composition scales - GBF-2008-BF/BF1, LS212-B (also sold as Rossmax WF262), SFX61, Kinetik BTS200, Zewa 21300 v2, Pic BodyStation Easy, EZFAST GBF-2108-B, Prosper PW-100, Dovant BIANOVA 300 and the Dynamics SMART/FIT scales. Weight only; body composition isn't decoded. The separate **Transtek A6 blood-pressure** decoder (`A610`, `TRANSTEK_A6_BPM`) supports 94 catalogue models, including TMB-2079/2088 and listed rebrands. It reports systolic, diastolic, mean pressure, pulse, the record's UTC time, memory user and irregular-heartbeat status. The A6 BP layout and workflow follow Transtek Health 2.0.5's APK: authenticate, set the BP time with `0x1102`, then sync records with `0x4901` and decode `0x4902`. The app's A610 path omits the scale-only init exchange, ignores the optional local-time bytes and exposes no AFib flag. The A6_1970 time-base and AFIBWithoutIHB variants remain outside the catalogue because the APK does not establish their timestamp or AFib semantics. The A6 scale stays on `RPM_SCALE`; Mambo 2/6 activity bands remain unsupported while the Mambo class decodes A5 oxygen records.
- **TaiDoc (FORA)** (`TaiDoc Multi`, `TaiDoc BPM`, `TaiDoc Thermometer`, `TaiDoc Oximeter`, `TaiDoc Scale`): FORA and TaiDoc 2-in-1 meters, glucose meters and blood-pressure monitors on the 0x51 command protocol (FORA D40, MD, Premium V10, Test N'GO Voice, Diamond MINI, TD-3128, TD-3223, TD-3261, TD-4266, TD-4277, Pic Solution GoGlic/BeGlic, GlucoMaxx Connect), the Diamond Cuff/P20b monitors, TD-12xx and FORA IR42 thermometers, TD-8255/8201, Test N'GO SpO2 and PO200 pulse oximeters, and the TD-2555 and Test N'GO Scale 550. The SDK sets the clock, downloads every device user's stored records with the meter's own timestamps and the user in `memorySlot`, then powers the meter off; it never clears the memory. `TaiDoc Multi` reports blood pressure or glucose by each record's type, and only patient glucose (no control-solution or other-analyte records). Blood-pressure readings carry `irregularHeartbeat`. Thermometer object-mode records are skipped, and the scale reports weight only. The TaiDoc TD1035 is a standard Health Thermometer.

`DEVICE_VARIANTS` also lists products that implement a Bluetooth SIG profile (blood pressure, glucose, thermometer, weight scale, heart rate, spot-check pulse oximetry): Omron, Beurer, A&D, Accu-Chek, Contour, Medisana, Polar, Wahoo and many more. These are found by service, so any compliant device works whether or not it is listed; a listed product additionally gets its brand and model in `deviceData.variant` when its advertised name identifies it. A few products share one advertised name with others (for example several Contour meters advertise `Contour…`), so they are listed without a name pattern and connect under the profile's generic name. Each catalog entry's image is the manufacturer's or a retailer's photo, credited with its page, or a generic illustration that names the page the product was identified from.

A Bluetooth SIG device is read from its frames as the specification lays them out:

- A frame that carries the device's own timestamp dates the reading (`recordedAt`): blood pressure, thermometer, weight scale and spot-check oximeter. Blood pressure in kPa is converted to whole mmHg, and a weight of `0xFFFF`, which a scale sends when the measurement failed, is dropped.
- A multi-user monitor or scale reports its user as `memorySlot`: the device's user index plus one, left out when the device does not know the user. A thermometer reports where it measured as `temperatureType` (`armpit`, `body`, `ear`, `finger`, `gastrointestinal-tract`, `mouth`, `rectum`, `toe` or `tympanum`), and a heart-rate strap its RR intervals as `rrIntervals`, in milliseconds. A strap kept as a [series](/native-sdk/guide/modules/bt-management#streams-as-series) records only its heart rate.
- To report only the readings of the people a device is paired to, list their slots in `acceptedMemorySlots` of that device's `resultPolicies` entry. The SDK does not register users on a multi-user scale through the User Data Service, so a person's slot is the one the device assigns.

Bluetooth result IDs are stable for repeated delivery when the device identity and measurement payload are unchanged. The identity uses the device serial number when available, then manufacturer data, model, device name, and finally the platform peripheral ID. The final fallback is the platform peripheral ID, so a changed peripheral ID produces a different result identity.

The result's `id` is enumerable and non-writable at runtime. It is included in object spreads and JSON serialization. Use it as an idempotency key when the app retries persistence or uploads.

See [Bluetooth](/native-sdk/guide/modules/bt-management), [supported-device definitions](/native-sdk/guide/components/bt-management/supported-devices/), and [custom devices](/native-sdk/guide/components/bt-management/custom-devices/).

## API reference [#api-reference]

Every export of `@ovok/native/bt-device`, with signatures, props and types, is in the [`bt-device` API reference](/native-sdk/reference/bt-device).
