Aktualizacje OTA przez MQTT: Jak przesyłać firmware na urządzeniach IoT z ograniczonymi zasobami

Author: Łukasz Moskała, 11 lipca, 2025

W świecie Internetu Rzeczy (IoT) regularne aktualizacje firmware są kluczowe dla bezpieczeństwa, stabilności i dodawania nowych funkcji. Jednak w urządzeniach o ograniczonych zasobach, takich jak te działające na modemach 2G i mikrokontrolerach RP2350, proces aktualizacji Over-The-Air (OTA) staje się wyzwaniem. W tym wpisie podzielę się doświadczeniami z projektu, w którym wykorzystaliśmy protokół MQTT do bezpiecznego i efektywnego przesyłania aktualizacji firmware. Przyjrzymy się wybranemu rozwiązaniu, jego zaletom i problemom, z jakimi się zmierzyliśmy.

W trakcie prac nad projektem IoT natknąłem się na problem, jak przesyłać aktualizacje firmware bezprzewodowo na urządzenie. Urządzenia te, wyposażone w modem 2G i mikrokontroler RP2350, musiały działać z ograniczonymi zasobami, co narzucało pewne niedogodności wynikające z wybranej platformy.Standardowy proces aktualizacji wygląda mniej więcej tak:
  1. Rozpoczęcie procesu aktualizacji. Aplikacja na tym etapie wie tylko jaki rozmiar ma aktualizacja.
  2. Aplikacja odbiera dane i zapisuje w pamięci flash w wyznaczonym miejscu.
  3. Poprzedni krok powtarza się dopóki aplikacja nie odbierze wszystkich danych.
  4. Aplikacja ustawia flagę informującą bootloader o tym, że jest aktualizacja do zainstalowania.
  5. Aplikacja restartuje procesor.
  6. Bootloader wykrywa flagę informującą o konieczności aktualizacji.
  7. Bootloader przepisuje dane z pamięci flash w miejsce gdzie znajduje się wykonywalny kod aplikacji.
  8. Bootloader czyści flagę i uruchamia aplikacje.
Grafika przedstawiająca koncept IoT

Dlaczego MQTT?

MQTT jest protokołem do przesyłania “wiadomości” (gdzie wiadomością jest zwykle tekst lub inne dane) na podstawie publikacji i subskrybcji. W protokole MQTT wyróżniamy broker (czyli serwer mqtt) oraz klientów (na przykład program komputerowy lub jakieś urządzenie IoT). Klienci łączą się do serwera i proszą o subskrybcję na danym kanale (lub kanałach). W takiej sytuacji, broker po otrzymaniu na tym kanale wiadomości, przesyła ją do wszystkich klientów, którzy ten kanał subskrybują. Klienci również mogą publikować wiadomości na kanałach. Dodatkowo, budowa protokołu MQTT zapewnia dobrą niezawodność w wypadku niestabilnych połączeń sieciowych.

Dodatkowo protokół MQTT można zabezpieczyć, wykorzystując między innymi szyfrowanie TLS lub mutual TLS oraz listy kontroli dostępu (ACL). Szyfrowanie oczywiście zapewnia nam poufność i autentyczność przesyłanych danych, natomiast listy kontroli dostępu mówią kto może subskrybować i publikować na danych kanałach. Pozwala to na przykład uniemożliwić komunikacje urządzeń IoT między sobą, ale zezwolić na komunikację urządzeń IoT z systemem zarządzającym.

Jak widać, protokół MQTT ma wiele zalet w zakresie projektów IoT. Dlaczego więc zdecydowaliśmy się na implementacje aktualizacji przez protokół MQTT?

  1. MQTT i tak musiałoby być ze względu na inne założenia projektu
  2. Użycie mutual TLS zapewnia dwustronną weryfikację – broker wie jakie urządzenie się do niego łączy, natomiast urządzenie ma pewność, że nikt pod serwer się nie podszywa.
  3. Implementacja innego protokołu (np HTTPS), który wykorzystywany byłby wyłącznie do aktualizacji, niepotrzebnie zwiększyłaby skomplikowanie całej infrastruktury. Wymagałoby to implementacji klienta HTTPS na urządzeniu oraz postawienia i utrzymywania serwera HTTPS.

Przebieg procesu aktualizacji OTA, który zrealizowałem
Po decyzji o wykorzystaniu MQTT, zaimplementowałem następujący proces aktualizacji firmware:

  1. System zarządzający przesyła na kanale SecretDevice/SerialNumber/ota/start payload zawierający długość (rozmiar, w bajtach) aktualizacji.
  2. Urządzenie przygotowuje się do rozpoczęcia aktualizacji
  3. Urządzenie przesyła na kanale SecretDevice/SerialNumber/ota/feedback payload start.
  4. System zarządzający przesyła na kanale SecretDevice/SerialNumber/ota/bytes pierwszą paczkę danych (o długości 768 bajtów – wyjaśnienie rozmiaru za chwile).
  5. Urządzenie zapisuje otrzymane dane do pamięci flash (jako plik w systemie plików)
  6. Urządzenie przesyła na kanale SecretDevice/SerialNumber/ota/feedback payload bytes.
  7. Poprzednie 3 kroki powtarzane są, aż zostaną przesłane wszystkie dane.
  8. System zarządzający wysyła na kanale SecretDevice/SerialNumber/ota/end pusty payload
  9. Urządzenie kończy proces aktualizacji. W tym momencie zostaje ustawiona flaga, która mówi bootloaderowi, że przy następnym uruchomieniu trzeba wykonać aktualizację.
  10. Urządzenie przesyła na kanale SecretDevice/SerialNumber/ota/feedback payload end.
  11. W tym momencie z punktu widzenia systemu zarządzającego, proces aktualizacji jest zakończony.
  12. Urządzenie ustawia timer na 2000 milisekund, po którym nastąpi restart do bootloadera
  13. Bootloader przepisuje nowy kod aplikacji z systemu plików do części pamięci flash, z której może być wykonywany kod i czyści ustawioną wcześniej flagę
  14. Bootloader uruchamia nowo załadowany kod z pamięci flash

W tym projekcie nie zostały wykorzystane mechanizmy zapewniające integralność danych takie jak weryfikacja podpisu cyfrowego przesłanego kodu oraz secureboot, ponieważ korzyści z tych konkretnie funkcji nie zostały uznane za warte wysiłku wymaganego do ich wdrożenia. MQTT wykorzystuje mutual TLS z pełną weryfikacją certyfikatów zarówno po stronie brokera jak i urządzenia, natomiast listy ACL brokera zapewniają, że tylko system zarządzający jest w stanie przesyłać aktualizacje. Nie uważam jednak, że podpisy cyfrowe aktualizacji oraz secureboot są niepotrzebne – zapewne wiele projektów będzie takich zabezpieczeń wymagać, tutaj jednak zostały uznane za zbędne.

Przesyłając aktualizację w ten sposób przez połączenie 2G, byłem w stanie uzyskać prędkości na poziomie 1.8kB/s. Nie jest to jakoś bardzo dużo, jednak to ograniczenie wynika przede wszystkim z przepustowości wykorzystanego modemu 2G. Nie stanowi to również dużego problemu, ponieważ skompilowany kod aplikacji zajmuje mniej niż 200kB. Dodatkowo, podczas przeprowadzania aktualizacji, aplikacja cały czas funkcjonuje.

Dane przesyłane są w paczkach po 768 bajtów, ponieważ wykorzystana biblioteka do MQTT statycznie alokuje bufory na przychodzące i wychodzące wiadomości. Rozmiar bufora ustawiony jest na 1024 bajty, z czego 768 to przesyłane dane, a reszta zostaje do wykorzystania przez nazwę kanału i inne informacje o przychodzącej wiadomości. Warto w tym momencie wspomnieć, że zgodnie ze specyfikacją protokołu MQTT, maksymalna długość wiadomości to 256 MiB, jednak tak duża wiadomość nie ma szans zmieścić się w pamięci RAM mikrokontrolera.

Inne problemy na które natknąłem się przy realizacji tego projektu, niekoniecznie związane z samymi aktualizacjami, to ograniczony rozmiar buforów wykorzystanej biblioteki do TLS. Zmniejszony rozmiar buforów pozwalał na komunikację w jedną stronę. Nie stanowiłoby to problemu w wypadku komunikacji HTTPS, gdzie w większości wypadków komunikacja faktycznie odbywa się tylko w jednym kierunku na raz. Jednak przy połączeniach MQTT, broker może przesłać do klienta dane w dowolnym momencie. Rozwiązanie tego problemu wymagało zmiany opcji w wykorzystanej bibliotece do połączeń TLS.

Podsumowując, mimo, że przesyłanie aktualizacji OTA przez protokół MQTT nie jest szczególnie często spotykaną opcją, w niektórych sytuacjach może okazać się najprostszą z punktu widzenia złożoności infrastruktury oraz ograniczenia wykorzystywanych zasobów. Dodatkowo, istniejące już zabezpieczenia infrastruktury zapewniają odpowiedni dla tego projektu poziom bezpieczeństwa przesyłanych aktualizacji.

Mam nadzieję, że ten wpis przybliżył Wam wyzwania związane z aktualizacją firmware urządzeń IoT o ograniczonych zasobach. Wykorzystanie protokołu MQTT okazało się skutecznym rozwiązaniem, ale wymagało uwzględnienia specyficznych ograniczeń i znalezienia kreatywnych rozwiązań.

Devology
Polityka prywatności

Ta strona korzysta z ciasteczek oraz skryptów analitycznych, aby zapewnić Ci najlepszą możliwą obsługę. Informacje o ciasteczkach są przechowywane w przeglądarce i wykonują funkcje takie jak rozpoznawanie Cię po powrocie na naszą stronę internetową i pomaganie naszemu zespołowi w zrozumieniu, które sekcje witryny są dla Ciebie najbardziej interesujące i przydatne. Aby zapoznać się z naszą polityką prywatności, kliknij tutaj.