Электросамокаты и электровелосипеды с контроллером — это не просто устройства с BLE-чипом. Типичный стек: контроллер BLDC-мотора (Sabvoton, Kelly, Votol) общается с дисплеем или BMS по протоколу UART/RS485 (часто проприетарный), BLE-модуль (Nordic nRF52840, ESP32) слушает шину и транслирует данные в мобильное приложение. Разработка приложения без понимания этой цепочки заканчивается тем, что приложение «подключилось», но не знает, что делать с потоком байт. Наша команда имеет 5+ лет опыта в этой нише и более 30 успешно запущенных проектов. Мы гарантируем стабильное BLE-соединение и корректную обработку данных с любых контроллеров.
Как мы решаем проблему отсутствия документации на контроллер?
Большинство производителей контроллеров (особенно китайских) не публикуют протоколы. Процесс: снять родной дисплей, подключить USB-UART анализатор (FTDI232, CP2102) параллельно шине и записать трафик в логи. Инструмент — PulseView + декодер UART, либо просто запись в файл через minicom/CoolTerm.
Типичный фрейм протокола Xiaomi M365 (как пример открытого):
[0x55][0xAA][len][addr][cmd][data...][crc_lo][crc_hi]
Фрейм начинается с 0x55 0xAA, затем длина полезной нагрузки, адрес получателя (0x20 — контроллер, 0x21 — BMS, 0x3E — дисплей), команда, данные, CRC16. Для менее популярных брендов CRC считается по-разному — XOR, Modbus CRC, иногда просто сумма байт с маской.
class ScooterFrameParser {
private val buffer = ByteArrayOutputStream()
fun feed(byte: Byte): ScooterFrame? {
buffer.write(byte.toInt())
val bytes = buffer.toByteArray()
// Ищем начало фрейма
val start = findStart(bytes) ?: return null
if (bytes.size - start < 4) return null
val len = bytes[start + 2].toInt() and 0xFF
val totalLen = len + 6 // header(2) + len(1) + addr(1) + cmd(1) + crc(2) - 1
if (bytes.size - start < totalLen) return null
val frame = bytes.copyOfRange(start, start + totalLen)
buffer.reset()
if (start + totalLen < bytes.size) {
buffer.write(bytes, start + totalLen, bytes.size - start - totalLen)
}
return if (verifyCRC(frame)) parseFrame(frame) else null
}
}
Почему стабильность BLE-соединения критична для поездок?
На Android BLE работает через BluetoothGatt. Главная боль — onConnectionStateChange с status = 133 (GATT_ERROR) при подключении, особенно на Android 12+ с включённым Bluetooth Permission. Лечение: retry с задержкой 500-1000 мс, максимум 3 попытки, после — показываем пользователю инструкцию переподключить Bluetooth.
class ScooterBLEManager(private val context: Context) {
private var gatt: BluetoothGatt? = null
private var retryCount = 0
fun connect(device: BluetoothDevice) {
gatt = device.connectGatt(context, false, object : BluetoothGattCallback() {
override fun onConnectionStateChange(g: BluetoothGatt, status: Int, newState: Int) {
when {
newState == BluetoothProfile.STATE_CONNECTED -> {
retryCount = 0
g.discoverServices()
}
status == 133 && retryCount < 3 -> {
retryCount++
g.close()
Handler(Looper.getMainLooper()).postDelayed({ connect(device) }, 800)
}
else -> notifyConnectionFailed()
}
}
override fun onCharacteristicChanged(g: BluetoothGatt,
characteristic: BluetoothGattCharacteristic, value: ByteArray) {
frameParser.feed(value)
}
}, BluetoothDevice.TRANSPORT_LE)
}
}
На iOS CBPeripheral стабильнее, но сессия CoreBluetooth не выживает после перезапуска приложения — сохраняем peripheral.identifier (UUID) в UserDefaults и восстанавливаем через retrievePeripherals(withIdentifiers:). Сравнение платформ показывает, что Android BLE требует больше retry-механизмов, что увеличивает время разработки на 10-15% относительно iOS.
| Характеристика | Android | iOS |
|---|---|---|
| Стабильность подключения | Ниже (status 133) | Высокая |
| Retry-логика | 3 попытки | Не требуется |
| Время разработки BLE-слоя | ~2 недели | ~1 неделя |
| Работа в фоне | Ограничена (Background limits) | Хорошая |
Дашборд: что показываем
Стандартный набор данных с контроллера самоката/велосипеда:
- Скорость (км/ч) — реальная, с датчика колеса или расчётная из RPM + длина окружности
- Заряд батареи (%) — из BMS, реже — расчётный по напряжению
- Напряжение/ток батареи — важно для мониторинга рекуперации
- Температура контроллера и мотора — критично для тяжёлых подъёмов
- Пробег — одометр, суммарный и за поездку
- Режим езды — Eco/Normal/Sport или D1-D5
- Состояние тормозов (если датчики подключены к контроллеру)
Выделим скорость, заряд батареи и температуру как ключевые показатели — их обновление должно быть максимально быстрым. Скоростной график за поездку — обязательный элемент. Renderим через MPAndroidChart (Android) или Swift Charts (iOS 16+). Данные пишем в Room/Core Data каждые 500 мс — поездка на 30 км при таком интервале = ~3600 точек, это не проблема.
Детали протоколов контроллеров
Помимо Xiaomi, встречаются протоколы с фреймом длиной 10-20 байт, где CRC считается как XOR всех байт, или Modbus RTU. Мы разбирали контроллеры Votol (EM-30, EM-100) — там фрейм начинается с 0xAA, команда 0xB1 для данных, CRC16 Modbus. Алгоритм парсинга универсален: ищем преамбулу, читаем длину, проверяем CRC.Управление режимами и настройки контроллера
Ряд контроллеров позволяет перепрограммировать параметры: максимальный ток, ограничение скорости, мощность рекуперации. Отправляем write-команду в Notify Characteristic. Важно: изменения параметров контроллера требуют предупреждения пользователя и подтверждения — неправильный ток может вывести мотор из строя или разрядить батарею за поездку.
Для шеринговых сервисов (флот самокатов) добавляется серверная часть: MQTT или WebSocket, история поездок на бэкенде, геофенсинг, удалённая блокировка. Это отдельный уровень сложности.
Процесс работы
- Анализ протокола контроллера и спецификации BLE-модуля (1-2 недели).
- Прототип подключения: приём и отправка команд, верификация (1 неделя).
- Разработка UI/UX: дашборд, экран поездки, настройки (2-3 недели).
- Реализация BLE-слоя, парсера, записи данных (2 недели).
- Тестирование на реальных поездках (1-2 недели).
- Публикация в App Store и Google Play, прохождение ревью (1 неделя).
Сроки: 6-8 недель на одну платформу, 3-4 месяца на кросс-платформенное решение (Flutter) с поддержкой нескольких протоколов. Стоимость рассчитывается индивидуально после анализа конкретной модели устройства и наличия документации на протокол. Свяжитесь с нами для оценки вашего проекта.
Что входит в работу
После завершения проекта вы получаете:
- Исходный код приложения (native или Flutter) с документацией.
- Инструкцию по сборке и деплою.
- Документацию протокола контроллера (если проводился реверс-инжиниринг).
- Доступ к репозиторию и средствам CI/CD.
- Поддержку при публикации в магазины приложений.
- Обучение администраторов флота (если проект шеринговый).
Мы даём гарантию на стабильную работу BLE-соединения и корректный парсинг данных. Постоянно обновляем приложение под новые версии iOS и Android.
Оцените экономию времени: закажите разработку приложения под ключ и получите готовый продукт, протестированный на реальных устройствах. Пишите — мы поможем.







