Электросамокаты и электровелосипеды с контроллером — это не просто устройства с 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.
Оцените экономию времени: закажите разработку приложения под ключ и получите готовый продукт, протестированный на реальных устройствах. Пишите — мы поможем.







