Skip to content

RedFeuer/Central-App-BLE

Repository files navigation

Custom Service BLE: Central + Peripheral (Android)

Данный проект — это собственная реализация нестандартного BLE-сервиса (Custom Service) и протокола обмена данными между:

  • Central (клиент) — Android-приложение, которое сканирует, подключается, инициирует сопряжение и обменивается данными;
  • Peripheral (сервер) — Android-приложение, которое поднимает GATT-сервер, запускает рекламу и обслуживает подключение Central.

1) Суть проекта

Цель работы: разработать комплекс из двух программ для связи по BLE между Android и любым другим устройством (Android/Windows/Linux), где:

  • на Android должно быть хост-приложение, к которому выполняется подключение по BLE;
  • на другой стороне имитируется BLE-устройство, которое подключается к хосту и осуществляет приём-передачу данных.

В рамках данного проекта реализовано:

  • Central-приложение под Android, которое:
    • сканирует устройства и находит Peripheral по UUID сервиса;
    • выполняет сопряжение;
    • подключается к GATT-серверу и инициализирует соединение;
    • умеет отправлять команды (например, Ping) и получать ответ (Pong) через уведомления;
    • умеет отправлять поток данных Central → Peripheral блоками фиксированного размера.
  • Peripheral-приложение под Android, которое:
    • запускает рекламу (Advertising) с UUID сервиса;
    • поднимает GATT-сервер с характеристиками команд и данных;
    • принимает команды и данные от Central;
    • отправляет уведомления Peripheral → Central (ответы на команды, а также поток данных).

При необходимости заменить Peripheral-часть на ПК (под Linux/Windows) — протокол и UUID уже выделены в shared модуль, их можно переиспользовать.


2) Что использовал

Язык и платформа

  • Kotlin
  • Android SDK Bluetooth (BLE) — встроенный API Android для работы с Bluetooth Low Energy:
    • Сканирование (Central): BluetoothAdapter, BluetoothLeScanner, ScanCallback, ScanFilter, ScanSettings, ScanResult
    • GATT-клиент (Central): BluetoothDevice, BluetoothGatt, BluetoothGattCallback, BluetoothGattCharacteristic, BluetoothGattDescriptor, BluetoothProfile
    • GATT-сервер (Peripheral): BluetoothManager, BluetoothGattServer, BluetoothGattServerCallback, BluetoothGattService, BluetoothGattCharacteristic, BluetoothGattDescriptor, BluetoothDevice
    • Advertising (Peripheral): BluetoothLeAdvertiser, AdvertiseSettings, AdvertiseData, AdvertiseCallback, ParcelUuid

Интерфейс, асинхронность и реактивность

  • Jetpack Compose (Material 3)
  • Coroutines + Flow
    • StateFlow — для состояния (подключение, работа сервера)
    • SharedFlow — для событий и логов

Архитектура

  • Clean Architecture: разделение на слои по смыслу (Presentation → Data → Domain)
  • MVVM: ViewModel + State + Events
  • внедрение зависимостей: Hilt
  • Assisted Factory для AndroidGattClientFactory, так как адрес устройства известен только во время работы

Общий модуль

Модуль shared содержит общие для обеих реализаций вещи:

  • UUID сервиса, характеристик (BleUuids)
  • параметры протокола (Protocol) - 160 байт каждые 60 мс
  • разрешения (BlePermissions)
  • шлюз разрешений (BlePermissionGate)
  • кодирование, декодирование команд (CommandCodec)

3) Как работает

3.1. Общая схема обмена

Peripheral (сервер):

  1. Проверяет поддержку рекламы BLE (наличие BluetoothLeAdvertiser).
  2. Запускает GATT-сервер и добавляет сервис BleUuids.SERVICE.
  3. Запускает рекламу с UUID сервиса (UUID в рекламных данных).
  4. При подключении Central ведёт счётчики:
    • сколько устройств подключено,
    • кто подписался на уведомления CMD_TX и DATA_TX.

Central (клиент):

  1. Сканирует BLE-устройства и фильтрует только те, у которых в рекламе есть BleUuids.SERVICE.
  2. После выбора устройства:
    • выполняет сопряжение (bonding),
    • подключается к GATT,
    • делает discoverServices(),
    • привязывается к характеристикам,
    • запрашивает MTU (чтобы гарантированно влезали блоки данных, заданные в Protocol),
    • включает уведомления на CMD_TX и DATA_TX.

3.2. Архитектура и потоки данных

Проект состоит из двух приложений:

  • Central (центральное устройство) — сканирует, подключается к Peripheral, отправляет команды и поток данных.
  • Peripheral (периферийное устройство) — рекламирует сервис, поднимает GATT-сервер, принимает записи от Central и отправляет уведомления.

Архитектура слоистая:

  • Интерфейс (Compose): показывает состояние и журнал, отправляет события в модель представления.
  • Модель представления (ViewModel): преобразует нажатия кнопок в вызовы сценариев, подписывается на потоки состояния и журнал.
  • Сценарии (UseCase): общая логика приложения, независимо от реализации Data слоя.
  • Репозиторий: единая точка доступа к BLE-операциям и потокам данных.
  • BLE-реализация (Android BLE API): сканер, GATT-клиент, GATT-сервер, реклама.

Потоки данных: Central

  • UI → ViewModel: UiEvent (нажатия кнопок).
  • ViewModel → UseCase → BleRepository: операции сканирования, подключения, пинг, отключения, передачи.
  • BleRepository → UI:
    • connectionState: StateFlow<ConnectionState> — текущее состояние соединения;
    • logs: Flow<String> — строки журнала;
    • notifications: Flow<BleNotification> — входящие уведомления от Peripheral.
Схема состояний ConnectionState
Idle
 ├─(Scan)──────────────► Scanning ──(found/timeout)──► Idle
 └─(Connect)───────────► Bonding ──(bond ok)─────────► Connecting
                           │
                           └─(bond fail)────────────► Error ─► Idle

Connecting ──(init ok)──► Ready
    │
    └─(init fail)──────► Error ─► Idle

Ready
 ├─(Disconnect)────────► Idle
 └─(remote disconnect)─► Disconnected ─► Idle

3.3. Каналы протокола (логика характеристик)

Сервис содержит 4 ключевые характеристики:

Команды

  • CMD_RX — куда Central пишет команду (write, с подтверждением)
  • CMD_TX — откуда Peripheral шлёт уведомления о командах или ответах (notify)

Пример:

  • Central пишет Ping в CMD_RX
  • Peripheral отвечает Pong через уведомление CMD_TX

Данные (поток)

  • DATA_RX — куда Central пишет блоки данных (write без подтверждения)
  • DATA_TX — откуда Peripheral шлёт уведомления с блоками данных (notify)

Размер блока и период задаются в Protocol:

  • STREAM_BLOCK_SIZE — размер блока (160 байт)
  • STREAM_PERIOD_MS — период отправки (60 мс)

3.4. Почему запись данных Central → Peripheral без подтверждения

Для потока данных важнее пропускная способность и стабильный период отправки, чем подтверждение каждого блока.

WRITE_TYPE_NO_RESPONSE:

  • уменьшает объем служебного обмена на уровне BLE;
  • снижает задержки из-за подтверждений;
  • лучше подходит для частых небольших пакетов (поток).

3.5. Состояние и логи

Central

  • состояние соединения публикуется как StateFlow<ConnectionState> для инициализации начальным состоянием и отображения актуального состояния
  • логи идут потоком строк (Flow<String>) и в UI собираются в список с ограничением до 2000 строк
  • разрыв соединения ловится через событие GattEvent.Disconnected, репозиторий закрывает GATT и переводит состояние в Disconnected/Idle

Peripheral

  • состояние сервера публикуется как StateFlow<PeripheralState>
  • логи публикуются через PeripheralLogBus (в Logcat + в UI потоком)

4) Какие версии и устройства тестировал

Роль Устройство Версия Android Результат
Central Google Pixel 6 Android 16 сканирование→сопряжение→подключение→ping→передача
Peripheral Xiaomi Redmi 7 Android 10 реклама→GATT→уведомления→передача

Примечания по совместимости:

  • На Android 12+ (API 31+) нужны отдельные runtime-разрешения Bluetooth (BLUETOOTH_*).
  • На Android 11 и ниже поведение по разрешениям другое (для сканирования часто требуется включенная геолокация на Central устройстве).
  • Запускал также в противоположных ролях - все также работает

5) Что решает (зачем этот проект)

Проект реализует рабочую основу для Custom Service BLE:

  • Полный цикл: реклама → сканирование → сопряжение → подключение → инициализация → обмен командами → поток данных → корректная обработка разрыва.
  • Единая обработка разрешений (шлюз BlePermissionGate + BlePermissions), чтобы действия не выполнялись без разрешений.
  • Реактивное состояние: UI всегда отображает актуальное состояние соединения.
  • Отладка: потоки логов из BLE-слоя показываются в интерфейсе и в Logcat.
  • Разделение ответственности: протокол и UUID вынесены в общий модуль и не прибиты гвоздями в приложениях.

6) Как запускать

Требования

  • Android Studio (AGP 9+)
  • два физических устройства Android 9+ (SDK 28+)
  • включённый Bluetooth на обоих устройствах. Также при работе Central устройства на SDK<31 (Android 12<) требуется включенная геолокация

Шаги запуска (Android ↔ Android)

1) Запустите Peripheral

  1. Соберите и установите модуль Peripheral-приложения на устройство-сервер.
  2. Выдайте разрешения (на Android 12+):
    • BLUETOOTH_ADVERTISE
    • BLUETOOTH_CONNECT
  3. Нажмите Start Server:
    • запустится реклама и GATT-сервер;
    • в логе появятся сообщения о старте.

2) Запустите Central

  1. Соберите и установите модуль Central-приложения на устройство-клиент.
  2. Выдайте разрешения (на Android 12+):
    • BLUETOOTH_SCAN
    • BLUETOOTH_CONNECT
    • На Android 11 и ниже может понадобиться ACCESS_FINE_LOCATION для сканирования - также включите геолокацию.
  3. Нажмите Scan (сканирование ограничено по времени - 5 секунд).
  4. Нажмите Connect и дождись INIT OK.
  5. Проверьте обмен командами:
    • Ping → в логе Peripheral должен быть приём, а Central должен получить Pong через уведомление.
  6. Проверьте поток данных:
    • Central: Stream start — отправка данных Central → Peripheral
    • Peripheral: Start TX — отправка данных Peripheral → Central. Также работает при отсуствии подписчика в лице Central устройства. При отключении и переподключении Central устройства Peripheral продолжает отправлять данные.

Частые проблемы

  • Peripheral/Advertising не поддерживается
    Устройство не умеет в рекламу BLE (нет BluetoothLeAdvertiser). Я простукивал оба устройства через BLE Scanner, когда каждое из них по очереди находилось с запущенным GATT-сервером в роли Peripheral. Может быть полезно в качестве проверки.
  • Bluetooth выключен
    Peripheral требует включённый Bluetooth перед запуском.
  • Нет разрешений на Android 12+
    Выдайте данные разрешения.
  • На Android 11 и ниже не видит устройства
    Для сканирования может требоваться ACCESS_FINE_LOCATION (и включённая геолокация на устройстве).

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages