Типичная ситуация: у вас есть BLE-устройство — пульсометр, умная лампа или промышленный датчик. Производитель даёт только мобильное приложение. Вы хотите, чтобы пользователи управляли устройством прямо с сайта, без установки софта. Web Bluetooth API решает эту задачу, но требует аккуратной работы с протоколом, переподключениями и обработкой ошибок. За 5 лет мы провели более 20 интеграций с BLE-устройствами: от фитнес-браслетов до медицинских мониторов. Экономия на разработке мобильного приложения может достигать 70%, а время выхода на рынок сокращается в 3 раза. Хотите подключить BLE-устройство к сайту? Оценим проект за один день — напишите нам.
Какие BLE-устройства можно подключить к сайту?
Подключаемся к пульсометрам, термометрам, лампам, контроллерам — любым устройствам с Bluetooth Low Energy. Пользователь открывает страницу, нажимает «Подключить», выбирает устройство из списка — и сайт начинает принимать показания датчика, менять яркость или включать мотор. Главное — разобраться с сервисами и характеристиками GATT. Если документация есть, интеграция занимает дни. Если нет — мы реверсим протокол через сниффер.
Почему Web Bluetooth API — альтернатива мобильному приложению?
Внедрение через браузер втрое быстрее нативной разработки и не требует публикации в магазинах. Пользователь не скачивает приложение — просто переходит по ссылке. Обновления применяются мгновенно на сервере, без версионирования. Для компании это снижает порог входа и экономит до 70% на поддержке двух платформ.
Как обеспечить стабильное подключение после разрыва?
Критично для устройств, требующих непрерывного потока данных. Мы реализуем автоматическое переподключение с экспоненциальной задержкой: первая попытка через 1 секунду, вторая через 2, третья через 4. После трёх неудач выводим уведомление. Ниже пример кода на TypeScript.
Подключение к устройству
interface BluetoothDevice { name: string gatt: BluetoothRemoteGATTServer } async function connectToDevice(serviceUUID: string): Promise<BluetoothRemoteGATTServer> { const device = await navigator.bluetooth.requestDevice({ filters: [{ services: [serviceUUID] }], }) console.log(`Подключаемся к: ${device.name}`) device.addEventListener('gattserverdisconnected', () => { console.log('Устройство отключилось') }) const server = await device.gatt!.connect() return server } Чтение данных: пульсометр
class HeartRateMonitor { private server: BluetoothRemoteGATTServer | null = null private characteristic: BluetoothRemoteGATTCharacteristic | null = null async connect() { this.server = await connectToDevice('heart_rate') const service = await this.server.getPrimaryService('heart_rate') this.characteristic = await service.getCharacteristic('heart_rate_measurement') await this.characteristic.startNotifications() this.characteristic.addEventListener( 'characteristicvaluechanged', this.handleHeartRateMeasurement.bind(this) ) } private handleHeartRateMeasurement(event: Event) { const value = (event.target as BluetoothRemoteGATTCharacteristic).value! const flags = value.getUint8(0) let heartRate: number if (flags & 0x01) { heartRate = value.getUint16(1, true) } else { heartRate = value.getUint8(1) } const rrIntervals: number[] = [] if (flags & 0x10) { for (let i = 2; i + 1 < value.byteLength; i += 2) { rrIntervals.push(value.getUint16(i, true) / 1024 * 1000) } } console.log(`ЧСС: ${heartRate} уд/мин, RR: [${rrIntervals.join(', ')}] мс`) } async disconnect() { await this.characteristic?.stopNotifications() this.server?.disconnect() } } Запись данных: управление умной лампой
class SmartLightController { private server: BluetoothRemoteGATTServer | null = null private controlChar: BluetoothRemoteGATTCharacteristic | null = null private readonly SERVICE_UUID = '00010203-0405-0607-0809-0a0b0c0d1910' private readonly CONTROL_UUID = '00010203-0405-0607-0809-0a0b0c0d2b11' async connect() { this.server = await connectToDevice(this.SERVICE_UUID) const service = await this.server.getPrimaryService(this.SERVICE_UUID) this.controlChar = await service.getCharacteristic(this.CONTROL_UUID) } async setColor(r: number, g: number, b: number) { const command = new Uint8Array([ 0x33, 0x05, 0x02, r, g, b, 0x00, 0x00, 0x00, r ^ g ^ b, ]) await this.controlChar!.writeValueWithResponse(command) } async setBrightness(level: number) { const command = new Uint8Array([ 0x33, 0x04, Math.round(level * 2.55), 0x00, ]) await this.controlChar!.writeValueWithoutResponse(command) } async readBatteryLevel(): Promise<number> { const service = await this.server!.getPrimaryService('battery_service') const char = await service.getCharacteristic('battery_level') const value = await char.readValue() return value.getUint8(0) } } React-хук для управления подключением
function useBluetooth() { const [device, setDevice] = useState<BluetoothRemoteGATTServer | null>(null) const [isConnected, setIsConnected] = useState(false) const [isSupported] = useState(() => 'bluetooth' in navigator) const [error, setError] = useState<string | null>(null) const connect = useCallback(async (serviceUUID: string) => { try { setError(null) const server = await connectToDevice(serviceUUID) setDevice(server) setIsConnected(true) } catch (err) { if ((err as Error).name === 'NotFoundError') { setError('Устройство не выбрано') } else { setError((err as Error).message) } } }, []) const disconnect = useCallback(() => { device?.disconnect() setDevice(null) setIsConnected(false) }, [device]) return { device, isConnected, isSupported, error, connect, disconnect } } Переподключение после разрыва
device.addEventListener('gattserverdisconnected', async () => { let retries = 0 while (retries < 3) { await new Promise((r) => setTimeout(r, 1000 * (retries + 1))) try { await device.gatt!.connect() await resubscribeCharacteristics() console.log('Переподключено') return } catch { retries++ } } console.error('Не удалось переподключиться') }) Сравнение: Web Bluetooth API vs нативное приложение
| Критерий | Web Bluetooth API | Нативное приложение |
|---|---|---|
| Время разработки | 1–2 недели | 2–3 месяца |
| Доставка | Ссылка | Магазины приложений |
| Обновления | Мгновенно | Ручные, через store |
| Платформы | Chrome/Edge | iOS, Android |
| Сложность | Средняя | Высокая |
| Стоимость | Индивидуально | Индивидуально |
Типичные ошибки при интеграции BLE
Устройство не отображается при сканировании. Убедитесь, что сайт открыт по HTTPS, запросите разрешение на использование Bluetooth. Причина часто в отсутствии optionalServices. Разрыв соединения при переходе фона. Используйте navigator.wakeLock или переподключайтесь автоматически. Некорректный парсинг данных. Проверяйте битовые флаги, порядок байтов (little-endian).
Какие браузеры поддерживают Web Bluetooth?
На сегодня Web Bluetooth API работает в Chrome 70+, Edge 79+ и Chrome Android. Firefox и Safari не поддерживают. Если ваша аудитория использует эти браузеры, можно предложить обходные пути: Native Messaging, PWA с Service Worker или гибридное приложение. Для большинства B2B-сценариев Chrome — стандартный выбор.
План работ: этапы интеграции
| Этап | Длительность |
|---|---|
| Анализ документации и реверс-инжиниринг | 1–3 дня |
| Проектирование архитектуры и UI | 1–2 дня |
| Реализация подключения и обработка ошибок | 2–4 дня |
| Тестирование на реальном устройстве | 1–2 дня |
| Деплой и мониторинг | 0.5–1 день |
Что входит в работу
- Полная документация по протоколу и коду интеграции.
- Доступ к репозиторию с исходным кодом и инструкцией по развёртыванию.
- Обучение вашей команды: как поддерживать и расширять интеграцию.
- Поддержка в течение 30 дней после запуска (исправление багов, консультации).
Как подключить BLE-устройство: пошаговая инструкция
- Проверьте поддержку браузера:
if ('bluetooth' in navigator). - Запросите устройство:
navigator.bluetooth.requestDevice({ filters: [...] }). - Подключитесь к GATT-серверу:
device.gatt.connect(). - Получите нужный сервис и характеристику.
- Начните читать или записывать данные.
- Обработайте отключение: подпишитесь на событие
gattserverdisconnected.
Что такое GATT-сервисы и характеристики?
GATT (Generic Attribute Profile) — протокол, определяющий структуру данных BLE-устройства. Сервис — это группа характеристик, например, сервис «Батарея». Характеристика — конкретный параметр, например, уровень заряда. Каждый сервис и характеристика имеют уникальный UUID.Сроки и стоимость
Срок интеграции с задокументированным устройством — от 3 до 5 дней. Для устройств без документации (реверс протокола) — от 7 до 12 дней. Стоимость рассчитывается индивидуально, исходя из сложности протокола и необходимости разработки UI. Оценим ваш проект в течение рабочего дня — просто напишите нам. Получите консультацию по интеграции BLE уже сегодня.
Подробнее о технологии: Web Bluetooth API и Bluetooth Low Energy.







