Реализация OTA-обновления прошивки IoT-устройств через мобильное приложение
OTA (Over-The-Air) обновление прошивки — критически важная функция для любого IoT-продукта. Баги в прошивке, новые протоколы, патчи безопасности — всё это нужно доставлять на устройства без физического доступа к ним. Мобильное приложение здесь либо инициирует обновление, либо служит транспортом для передачи прошивки напрямую через BLE.
Два сценария OTA
Cloud OTA: устройство само скачивает прошивку с сервера, когда оказывается в Wi-Fi. Мобильное приложение только уведомляет пользователя о доступном обновлении и показывает прогресс. Логика обновления — на стороне прошивки (ESP-IDF OTA, Mender, Hawkbit).
BLE OTA: прошивка скачивается на телефон, телефон передаёт её на устройство через BLE. Используется когда устройство не имеет прямого выхода в интернет или когда нужен жёсткий контроль над процессом обновления.
BLE OTA: DFU для Nordic nRF
Для устройств на nRF51/nRF52 — Nordic DFU (Device Firmware Update). Официальная библиотека от Nordic Semiconductor:
// build.gradle
implementation 'no.nordicsemi.android:dfu:2.3.0'
// Запуск DFU
val starter = DfuServiceInitiator(deviceAddress)
.setDeviceName(deviceName)
.setKeepBond(true)
.setForceDfu(false)
.setPacketsReceiptNotificationsEnabled(true)
.setNumberOfPackets(12) // PRN - баланс скорости и надёжности
.setZip(firmwareUri) // .zip с прошивкой и init packet
val controller = starter.start(context, DfuService::class.java)
setPacketsReceiptNotificationsEnabled(true) + setNumberOfPackets(12) — устройство подтверждает каждые 12 пакетов. Без PRN при потере пакета всё приходится начинать заново. С PRN — возобновление с последней подтверждённой позиции.
DFU-библиотека запускает DfuService как foreground service — пользователь может свернуть приложение, обновление продолжится. Прогресс через DfuProgressListenerHelper:
DfuProgressListenerHelper.registerProgressListener(this, object : DfuProgressListener {
override fun onDfuProgressChanged(deviceAddress: String, percent: Int,
speed: Float, avgSpeed: Float,
currentPart: Int, partsTotal: Int) {
updateProgress(percent)
}
override fun onDfuCompleted(deviceAddress: String) { onUpdateSuccess() }
override fun onError(deviceAddress: String, error: Int, errorType: Int, message: String) {
onUpdateFailed(message)
}
})
Типичная скорость DFU: 50–80 кб/с для nRF52840. Прошивка 200 кб — около 3 минут.
ESP32 OTA через BLE
Для ESP32 — esp_ota_ops на стороне прошивки + кастомный BLE-сервис для приёма данных. Espressif не предоставляет готовый BLE DFU SDK (в отличие от Nordic), поэтому протокол нужно реализовывать самостоятельно или использовать библиотеку esp-idf-ble-ota.
Базовая схема: телефон отправляет прошивку чанками по MTU-3 байта. Устройство собирает прошивку в OTA-буфер (esp_ota_begin, esp_ota_write, esp_ota_end), затем перезагружается с новым образом. При ошибке — rollback на предыдущую версию через esp_ota_mark_app_invalid_rollback_and_reboot().
// Разбивка прошивки на чанки и отправка
val chunkSize = mtu - 3
val chunks = firmware.toList().chunked(chunkSize)
chunks.forEachIndexed { index, chunk ->
writeCharacteristic(firmwareDataCharacteristic, chunk.toByteArray())
// Ждать ACK от устройства перед следующим чанком
awaitAck()
updateProgress((index + 1) * 100 / chunks.size)
}
Важно: никогда не начинать OTA при заряде телефона ниже 20% и слабом BLE-сигнале. Обрыв в середине прошивки — потенциально кирпич, если на устройстве нет механизма rollback.
Cloud OTA: роль мобильного приложения
При cloud OTA телефон — только UI. Пользователь видит уведомление «Доступно обновление 2.1.0», жмёт «Обновить», следит за прогрессом.
Прогресс обновления устройство отправляет через MQTT или WebSocket. Статусы: idle → downloading (с процентом) → applying → rebooting → updated / failed.
Не показывать бесконечный спиннер. Обновление может занять 5–15 минут (скачивание + запись flash). Нужен конкретный прогресс с этапами. После перезагрузки устройство появится в сети с новой версией прошивки — это нужно отразить в UI немедленно.
Безопасность OTA
Прошивка должна быть подписана — устройство верифицирует подпись перед применением. RSA-2048 или ECDSA-256. При cloud OTA — HTTPS с certificate pinning для защиты от MITM. Для BLE OTA — init packet Nordic DFU уже содержит hash и подпись прошивки.
Без верификации подписи любой злоумышленник с доступом к BLE может залить вредоносную прошивку.
Реализация BLE OTA с Nordic DFU: 2–3 недели. Cloud OTA UI с прогресс-мониторингом: 1–2 недели. Кастомный ESP32 BLE OTA протокол: 3–5 недель.







