MQTT dla STM32 -- zestaw dla opornych

Język C dla mikrokontrolerów ARM
ODPOWIEDZ
Awatar użytkownika
SunRiver
Użytkownik
Posty: 1338
Rejestracja: 08 paź 2017, 11:27
Lokalizacja: Festung Oppeln
Kontakt:

MQTT dla STM32 -- zestaw dla opornych

Post autor: SunRiver »

W tym miejscu chcę przedstawić prostą bazową implementację MQTT dla mikrokontrolera STM32 który będzie korzystał
przy komunikacji z ESP8266 który zapewni stos TCP/IP , a z którym STM32 będzie się komunikował przy pomocy najprostszego mozliwego sposobu
czyli połączenia UART i komend AT czyli z firmware np od AIthinkera

Co to jest MQTT?
MQTT (Message Queuing Telemetry Transport) to lekki protokół komunikacyjny opracowany z myślą o systemach o ograniczonych zasobach oraz komunikacji M2M (Machine-to-Machine). Jego główne cechy to:

Model publikuj-subskrybuj:

Publikujący (publisher) wysyła wiadomości do tematów (topics).
Subskrybenci (subscribers) odbierają wiadomości, subskrybując konkretne tematy.
Pośrednikiem między nimi jest broker MQTT.

Efektywność:

Protokół działa na TCP/IP, ale jest zoptymalizowany pod kątem małych ilości przesyłanych danych.
Stosuje mechanizm QoS (Quality of Service), który pozwala na kontrolę niezawodności przesyłanych wiadomości.

Zastosowanie:

IoT (Internet of Things), urządzenia smart home, przemysłowe systemy SCADA, monitorowanie zdrowia, itd.

Dlaczego MQTT dla STM32?
STM32 to rodzina mikrokontrolerów firmy STMicroelectronics, często stosowanych w projektach IoT. Dzięki niskim wymaganiom sprzętowym MQTT, jest on idealnym wyborem dla mikrokontrolerów takich jak STM32. Dzięki czemu możemy liczyć na szereg korzyści implementacji MQTT na STM32:

-- Minimalne wykorzystanie pamięci.
-- Niskie zużycie energii.
-- Możliwość łatwej komunikacji z usługami chmurowymi (np. AWS IoT, Azure IoT).

Podstawy implementacji MQTT w języku C
Wymagania sprzętowe i programowe
Sprzęt:

Mikrokontroler STM32 (np.STM32F1, STM32F4, STM32F7, STM32H7).
Moduł Wi-Fi (np. ESP8266/ESP32) lub Ethernet (np. moduł W5500).

Oprogramowanie:

IDE: STM32CubeIDE lub Keil uVision.
Stos TCP/IP (np. LwIP).
Biblioteka MQTT (np. Paho MQTT, umqtt, lub własna implemetacja protokołu).

Kroki implementacji MQTT

1. Konfiguracja środowiska

STM32CubeMX:

Wybierz odpowiedni mikrokontroler STM32.
Skonfiguruj zegary systemowe, GPIO oraz interfejsy komunikacyjne (UART, SPI, Ethernet).
Jeśli korzystasz z modułu Ethernet, dodaj stos LwIP i skonfiguruj DHCP lub statyczny adres IP.

Dodanie biblioteki MQTT:

Wybierz bibliotekę dostosowaną do STM32. Popularnym wyborem jest Paho Embedded C.
lub własną implementację czyli funkcje CONNECT, PUBLISH, SUBSCRIBE

2. Integracja stosu TCP/IP

W przypadku Ethernet:
Użyj LwIP do zarządzania połączeniami TCP/IP.
Skonfiguruj stos LwIP w STM32CubeMX.

W przypadku Wi-Fi:
Skonfiguruj komunikację UART lub SPI z modułem Wi-Fi (np. ESP8266).
Użyj poleceń AT lub dedykowanych bibliotek do zarządzania połączeniami Wi-Fi.

3. Połączenie z brokerem MQTT
Inicjalizacja protokołu MQTT:

Zainicjalizuj strukturę klienta MQTT (np. w Paho: MQTTClient).
Ustaw wymagane parametry, takie jak adres brokera, port (domyślnie 1883), oraz dane logowania, jeśli wymagane.
  1.  
  2. MQTTClient client;
  3. Network network;
  4. MQTTClientInit(&client, &network, 1000, sendBuffer, sizeof(sendBuffer), readBuffer, sizeof(readBuffer));
  5.  
Nawiązanie połączenia TCP:

Połącz się z brokerem za pomocą gniazda TCP/IP.
  1. int rc = NetworkConnect(&network, "mqtt.example.com", 1883);
  2. if (rc != 0) {
  3.     printf("Failed to connect to broker.\n");
  4.     return rc;
  5. }
  6.  
Subskrypcja tematu:

Subskrybuj temat, aby odbierać wiadomości
  1.  
  2. MQTTSubscribe(&client, "sensor/temperature", QOS1, messageArrived);
  3.  
Publikowanie wiadomości:

Wysyłaj dane do brokera.
  1.  
  2. MQTTMessage message;
  3. message.qos = QOS1;
  4. message.retained = 0;
  5. message.payload = "Hello, MQTT!";
  6. message.payloadlen = strlen("Hello, MQTT!");
  7. MQTTPublish(&client, "sensor/temperature", &message);
  8.  
Obsługa zdarzeń i pętla główna

MQTT wymaga ciągłego przetwarzania wiadomości. W pętli głównej programu należy wywoływać funkcję obsługującą komunikację z brokerem.
  1.  
  2. while (1) {
  3.     MQTTYield(&client, 1000);  // Przetwarza przychodzące wiadomości.
  4. }
  5.  
Oczywiście klient może też łaczyć się tylko by wysłać wiadomość np. Gdy zmienią się jakieś parametry , jak temperatura czy np nastąpi otwarcie drzwi itd... Ale w takim wypadku urządzenie nie może odbierać komunikatów z brokera gdyż mogą one dotrzeć gdy urzadzenie jest połaczone
inaczej mówiąc wtedy robimy urządzenie typu Client-Publish -- działa tak więklszość urzadzeń IoT np Czujniki temperatury , które łaczą się z brokerem tylko wtedy gdy wysyłają komunikaty o zmianach parametrów, co pozwala na zminimalizowanie ilości pobieranej energii. wiec mogą działać długi czas na bateriach.

Przykładowy kod programu
Oto uproszczony przykład komunikacji MQTT na STM32 z użyciem biblioteki Paho MQTT, która zwalnia nas z karkołomnego implementowania
funkcji CONNECT , PUBLISH, SUBSCRIBE
  1.  
  2. #include "MQTTClient.h"
  3. #include "lwip/sockets.h"
  4.  
  5. void messageArrived(MessageData* data) {
  6.     printf("Message received: %.*s\n", data->message->payloadlen, (char*)data->message->payload);
  7. }
  8.  
  9. int main() {
  10.     Network network;
  11.     MQTTClient client;
  12.     unsigned char sendbuf[80], readbuf[80];
  13.  
  14.     NetworkInit(&network);
  15.     MQTTClientInit(&client, &network, 1000, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf));
  16.  
  17.     if (NetworkConnect(&network, "mqtt.example.com", 1883) != 0) {
  18.         printf("Failed to connect to MQTT broker\n");
  19.         return -1;
  20.     }
  21.  
  22.     MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
  23.     connectData.MQTTVersion = 3;
  24.     connectData.clientID.cstring = "STM32Client";
  25.  
  26.     if (MQTTConnect(&client, &connectData) != 0) {
  27.         printf("MQTT connection failed\n");
  28.         return -1;
  29.     }
  30.  
  31.     MQTTSubscribe(&client, "sensor/temperature", QOS1, messageArrived);
  32.  
  33.     while (1) {
  34.         MQTTYield(&client, 1000);  // Keep connection alive and process messages.
  35.     }
  36.  
  37.     return 0;
  38. }
  39.  
Wskazówki i najlepsze praktyki

Monitorowanie pamięci:
STM32 ma ograniczone zasoby, więc należy śledzić zużycie pamięci RAM i FLASH.

Optymalizacja QoS:
Używaj poziomu QoS 0, jeśli szybkość i niskie opóźnienia są ważniejsze od niezawodności.
Wybierz QoS 1 lub 2 dla krytycznych danych.

Zabezpieczenia:
W miarę mozliwości korzystaj z połączeń TLS/SSL, jeśli broker obsługuje port 8883.
Dodaj autoryzację za pomocą nazw użytkowników i haseł.

Testowanie:
Kod możecie przetestować z popularnymi brokerami MQTT, np. HiveMQ, Mosquitto.

Własna Implementacja protokołu:

Tymczasem własna implementacja protokołu jest również prosta i wygodna z czego sam chętnie korzystam by nie używać opasłych bibliotek
gdy nie jest to konieczne a urządzenie niema za wiele procy i ograniczone zasoby jak np STM32F100. W tym przypadku całość polega
na manualnym tworzeniu ramek protokołu MQTT i wysyłaniu ich przez gniazdo TCP.
Założenia sprzętowe zostawmy wiec jak wyżej czyli STM32 komunikuje się przez Ethernet lub moduł Wi-Fi.
Korzystamy z surowego stosu TCP/IP (np. LwIP) do obsługi połączeń TCP.
będziemy implementować protokół MQTT w wersji 3.1.1.

Struktura MQTT
W protokole MQTT ramki są kodowane w formacie binarnym przez co musimy ręcznie zadbać o właściwe kodowanie i format:

Funkcja Connect:
Zawierać musi Nagłówek MQTT i polecenia dotyczące połączenia.
  1.  
  2. // Parametry połączenia
  3. #define MQTT_KEEPALIVE 60  // Czas keep-alive w sekundach
  4.  
  5. int MQTT_Connect(int socket, const char *client_id) {
  6.     uint8_t buffer[128];
  7.     uint16_t offset = 0;
  8.  
  9.     // Nagłówek zmienny MQTT (protocol name, level, flags, keepalive)
  10.     buffer[offset++] = 0x10;  // CONNECT fixed header
  11.     buffer[offset++] = 0;     // Placeholder for remaining length
  12.  
  13.     // Payload MQTT: Protocol Name "MQTT"
  14.     buffer[offset++] = 0x00;
  15.     buffer[offset++] = 0x04;
  16.     memcpy(&buffer[offset], "MQTT", 4);
  17.     offset += 4;
  18.  
  19.     buffer[offset++] = 0x04;  // MQTT Protocol Level (4 = MQTT 3.1.1)
  20.     buffer[offset++] = 0x02;  // Connect Flags: Clean Session = 1
  21.     buffer[offset++] = (MQTT_KEEPALIVE >> 8) & 0xFF;  // Keep-Alive MSB
  22.     buffer[offset++] = MQTT_KEEPALIVE & 0xFF;         // Keep-Alive LSB
  23.  
  24.     // Payload: Client ID
  25.     uint16_t client_id_len = strlen(client_id);
  26.     buffer[offset++] = (client_id_len >> 8) & 0xFF;
  27.     buffer[offset++] = client_id_len & 0xFF;
  28.     memcpy(&buffer[offset], client_id, client_id_len);
  29.     offset += client_id_len;
  30.  
  31.     // Ustawienie długości całkowitej (remaining length)
  32.     buffer[1] = offset - 2;
  33.  
  34.     // Wyślij ramkę
  35.     int sent_bytes = send(socket, buffer, offset, 0);
  36.     if (sent_bytes < 0) {
  37.         return -1;  // Błąd wysyłania
  38.     }
  39.  
  40.     // Odbierz odpowiedź (CONNACK)
  41.     uint8_t response[4];
  42.     int received_bytes = recv(socket, response, sizeof(response), 0);
  43.     if (received_bytes != 4 || response[0] != 0x20 || response[1] != 0x02) {
  44.         return -1;  // Błąd w odpowiedzi brokera
  45.     }
  46.  
  47.     if (response[3] != 0x00) {
  48.         return -1;  // Kod powrotu inny niż sukces
  49.     }
  50.  
  51.     return 0;  // Sukces
  52. }
  53.  
  54.  
Publish:
Musi zawierać Nagłówek i payload wiadomości (temat + dane).
  1.  
  2. int MQTT_Publish(int socket, const char *topic, const char *message) {
  3.     uint8_t buffer[256];
  4.     uint16_t offset = 0;
  5.  
  6.     // Nagłówek stały (Fixed Header)
  7.     buffer[offset++] = 0x30;  // PUBLISH, QoS 0, DUP 0, Retain 0
  8.     buffer[offset++] = 0;     // Placeholder for remaining length
  9.  
  10.     // Temat wiadomości (Topic Name)
  11.     uint16_t topic_len = strlen(topic);
  12.     buffer[offset++] = (topic_len >> 8) & 0xFF;
  13.     buffer[offset++] = topic_len & 0xFF;
  14.     memcpy(&buffer[offset], topic, topic_len);
  15.     offset += topic_len;
  16.  
  17.     // Payload wiadomości
  18.     uint16_t message_len = strlen(message);
  19.     memcpy(&buffer[offset], message, message_len);
  20.     offset += message_len;
  21.  
  22.     // Ustawienie długości całkowitej (remaining length)
  23.     buffer[1] = offset - 2;
  24.  
  25.     // Wyślij ramkę
  26.     int sent_bytes = send(socket, buffer, offset, 0);
  27.     if (sent_bytes < 0) {
  28.         return -1;  // Błąd wysyłania
  29.     }
  30.  
  31.     return 0;  // Sukces
  32. }
  33.  
Nasz kod w głównym programie więc może przedstawiać się następująco:
  1.  
  2. #include "lwip/sockets.h"
  3. #include <stdio.h>
  4.  
  5. #define BROKER_IP "192.168.1.100"
  6. #define BROKER_PORT 1883
  7.  
  8. int main() {
  9.     int socket_fd;
  10.     struct sockaddr_in broker_addr;
  11.  
  12.     // Utwórz gniazdo TCP
  13.     socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  14.     if (socket_fd < 0) {
  15.         printf("Error creating socket\n");
  16.         return -1;
  17.     }
  18.  
  19.     // Konfiguracja adresu brokera
  20.     broker_addr.sin_family = AF_INET;
  21.     broker_addr.sin_port = htons(BROKER_PORT);
  22.     broker_addr.sin_addr.s_addr = inet_addr(BROKER_IP);
  23.  
  24.     // Połącz z brokerem
  25.     if (connect(socket_fd, (struct sockaddr *)&broker_addr, sizeof(broker_addr)) < 0) {
  26.         printf("Error connecting to broker\n");
  27.         return -1;
  28.     }
  29.  
  30.     // Nawiąż połączenie MQTT
  31.     if (MQTT_Connect(socket_fd, "STM32Client") != 0) {
  32.         printf("MQTT Connect failed\n");
  33.         close(socket_fd);
  34.         return -1;
  35.     }
  36.     printf("MQTT Connected successfully\n");
  37.  
  38.     // Publikuj wiadomość
  39.     if (MQTT_Publish(socket_fd, "sensor/temperature", "23.5") != 0) {
  40.         printf("MQTT Publish failed\n");
  41.     } else {
  42.         printf("Message published successfully\n");
  43.     }
  44.  
  45.     // Zamknij połączenie
  46.     close(socket_fd);
  47.     return 0;
  48. }
  49.  
  50.  
  51.  
Oczywiście minimalnie modyfikując program dostosujemy go do STM32F100 który będzie przy pomocy ESP-01 łaczył się z siecią WIFI i wysyłał
temperaturę, W programie nie uwzględniłem obsługi żadnego czujnika - a temperatura jest wpisana na stałe i wysyłana via MQTT
do brokera , niemniej DS18B20 czy DHT lub inny każdy sobie może łatwo dodać do kodu. Kod ten może stanowić inspirację i ewentualną bazę
do innych zadań. W ESP-01 powinien być wgrany firmware obsługujący komendy AT i pracujący jako UART-WIFI.
  1. #include "stm32f1xx_hal.h"
  2. #include <string.h>
  3. #include <stdio.h>
  4.  
  5. // Parametry Wi-Fi i MQTT
  6. #define WIFI_SSID       "TwojaSiecWiFi"  // Nazwa sieci Wi-Fi
  7. #define WIFI_PASSWORD   "TwojeHaslo"    // Hasło Wi-Fi
  8. #define BROKER_IP       "192.168.1.100" // Adres IP brokera MQTT
  9. #define BROKER_PORT     1883            // Port MQTT
  10. #define CLIENT_ID       "STM32Client"   // Identyfikator klienta MQTT
  11. #define TOPIC           "sensor/temperature" // Temat publikacji
  12.  
  13. // Bufory do komunikacji z ESP-01
  14. #define UART_BUFFER_SIZE 512
  15. char uart_rx_buffer[UART_BUFFER_SIZE];
  16. char uart_tx_buffer[UART_BUFFER_SIZE];
  17.  
  18. // Deklaracja UART
  19. UART_HandleTypeDef huart1;
  20.  
  21. // Prototypy funkcji
  22. void SystemClock_Config(void);
  23. void Error_Handler(void);
  24. void ESP_SendCommand(const char *cmd, const char *expected_response, uint32_t timeout);
  25. void ESP_Init(void);
  26. void ESP_ConnectToWiFi(const char *ssid, const char *password);
  27. void ESP_ConnectToBroker(const char *broker_ip, uint16_t port);
  28. void ESP_Publish(const char *topic, const char *message);
  29.  
  30. int main(void) {
  31.     HAL_Init();
  32.     SystemClock_Config();
  33.  
  34.     // Inicjalizacja UART
  35.     __HAL_RCC_USART1_CLK_ENABLE();
  36.     __HAL_RCC_GPIOA_CLK_ENABLE();
  37.  
  38.     GPIO_InitTypeDef GPIO_InitStruct = {0};
  39.     GPIO_InitStruct.Pin = GPIO_PIN_9;  // USART1_TX
  40.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  41.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  42.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  43.  
  44.     GPIO_InitStruct.Pin = GPIO_PIN_10;  // USART1_RX
  45.     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  46.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  47.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  48.  
  49.     huart1.Instance = USART1;
  50.     huart1.Init.BaudRate = 115200;
  51.     huart1.Init.WordLength = UART_WORDLENGTH_8B;
  52.     huart1.Init.StopBits = UART_STOPBITS_1;
  53.     huart1.Init.Parity = UART_PARITY_NONE;
  54.     huart1.Init.Mode = UART_MODE_TX_RX;
  55.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  56.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  57.     if (HAL_UART_Init(&huart1) != HAL_OK) {
  58.         Error_Handler();
  59.     }
  60.  
  61.     // Inicjalizacja ESP-01
  62.     ESP_Init();
  63.     ESP_ConnectToWiFi(WIFI_SSID, WIFI_PASSWORD);
  64.     ESP_ConnectToBroker(BROKER_IP, BROKER_PORT);
  65.  
  66.     // Publikowanie wiadomości do tematu
  67.     const char *message = "23.5";  // Przykładowa temperatura
  68.     ESP_Publish(TOPIC, message);
  69.  
  70.     while (1) {
  71.         // Główna pętla
  72.     }
  73. }
  74.  
  75. // Funkcja wysyłania komendy AT
  76. void ESP_SendCommand(const char *cmd, const char *expected_response, uint32_t timeout) {
  77.     memset(uart_rx_buffer, 0, UART_BUFFER_SIZE);
  78.     HAL_UART_Transmit(&huart1, (uint8_t *)cmd, strlen(cmd), HAL_MAX_DELAY);
  79.     HAL_UART_Transmit(&huart1, (uint8_t *)"\r\n", 2, HAL_MAX_DELAY);
  80.  
  81.     uint32_t start_time = HAL_GetTick();
  82.     while ((HAL_GetTick() - start_time) < timeout) {
  83.         HAL_UART_Receive(&huart1, (uint8_t *)uart_rx_buffer, UART_BUFFER_SIZE, 100);
  84.         if (strstr(uart_rx_buffer, expected_response)) {
  85.             return;  // Oczekiwana odpowiedź została otrzymana
  86.         }
  87.     }
  88.  
  89.     printf("Error: No response or unexpected response for: %s\n", cmd);
  90.     Error_Handler();
  91. }
  92.  
  93. // Funkcja inicjalizacji ESP-01
  94. void ESP_Init(void) {
  95.     ESP_SendCommand("AT", "OK", 2000);                      // Test połączenia z ESP
  96.     ESP_SendCommand("AT+RST", "OK", 5000);                  // Reset modułu
  97.     ESP_SendCommand("AT+CWMODE=1", "OK", 2000);             // Ustawienie modułu w trybie klienta Wi-Fi
  98.     ESP_SendCommand("AT+CIPMUX=0", "OK", 2000);             // Tryb połączenia pojedynczego
  99. }
  100.  
  101. // Funkcja łączenia z Wi-Fi
  102. void ESP_ConnectToWiFi(const char *ssid, const char *password) {
  103.     sprintf(uart_tx_buffer, "AT+CWJAP=\"%s\",\"%s\"", ssid, password);
  104.     ESP_SendCommand(uart_tx_buffer, "OK", 10000);           // Połączenie z Wi-Fi
  105. }
  106.  
  107. // Funkcja łączenia z brokerem MQTT
  108. void ESP_ConnectToBroker(const char *broker_ip, uint16_t port) {
  109.     sprintf(uart_tx_buffer, "AT+CIPSTART=\"TCP\",\"%s\",%d", broker_ip, port);
  110.     ESP_SendCommand(uart_tx_buffer, "OK", 5000);            // Połączenie z brokerem
  111.  
  112.     // Budowanie ramki CONNECT
  113.     uint8_t buffer[128];
  114.     uint16_t offset = 0;
  115.  
  116.     buffer[offset++] = 0x10;  // CONNECT fixed header
  117.     buffer[offset++] = 0;     // Placeholder for remaining length
  118.  
  119.     buffer[offset++] = 0x00;
  120.     buffer[offset++] = 0x04;
  121.     memcpy(&buffer[offset], "MQTT", 4);
  122.     offset += 4;
  123.  
  124.     buffer[offset++] = 0x04;  // MQTT Protocol Level
  125.     buffer[offset++] = 0x02;  // Clean session
  126.     buffer[offset++] = 0x00;  // Keepalive MSB
  127.     buffer[offset++] = 0x3C;  // Keepalive LSB (60 sek)
  128.  
  129.     uint16_t client_id_len = strlen(CLIENT_ID);
  130.     buffer[offset++] = (client_id_len >> 8) & 0xFF;
  131.     buffer[offset++] = client_id_len & 0xFF;
  132.     memcpy(&buffer[offset], CLIENT_ID, client_id_len);
  133.     offset += client_id_len;
  134.  
  135.     buffer[1] = offset - 2;  // Obliczenie remaining length
  136.  
  137.     // Wysyłanie CONNECT
  138.     sprintf(uart_tx_buffer, "AT+CIPSEND=%d", offset);
  139.     ESP_SendCommand(uart_tx_buffer, ">", 2000);
  140.     HAL_UART_Transmit(&huart1, buffer, offset, HAL_MAX_DELAY);
  141.  
  142.     ESP_SendCommand("", "CONNACK", 5000);  // Oczekiwanie na odpowiedź
  143. }
  144.  
  145. // Funkcja publikowania wiadomości
  146. void ESP_Publish(const char *topic, const char *message) {
  147.     uint8_t buffer[256];
  148.     uint16_t offset = 0;
  149.  
  150.     buffer[offset++] = 0x30;  // PUBLISH fixed header
  151.     buffer[offset++] = 0;     // Placeholder for remaining length
  152.  
  153.     uint16_t topic_len = strlen(topic);
  154.     buffer[offset++] = (topic_len >> 8) & 0xFF;
  155.     buffer[offset++] = topic_len & 0xFF;
  156.     memcpy(&buffer[offset], topic, topic_len);
  157.     offset += topic_len;
  158.  
  159.     uint16_t message_len = strlen(message);
  160.     memcpy(&buffer[offset], message, message_len);
  161.     offset += message_len;
  162.  
  163.     buffer[1] = offset - 2;  // Obliczenie remaining length
  164.  
  165.     // Wysyłanie PUBLISH
  166.     sprintf(uart_tx_buffer, "AT+CIPSEND=%d", offset);
  167.     ESP_SendCommand(uart_tx_buffer, ">", 2000);
  168.     HAL_UART_Transmit(&huart1, buffer, offset, HAL_MAX_DELAY);
  169. }
  170.  
  171.  
Wyjaśnienie :

Komunikacja AT:
Komendy AT są wysyłane do ESP-01, który realizuje połączenie z Wi-Fi i brokerem MQTT.
Funkcja ESP_SendCommand weryfikuje odpowiedzi ESP-01.

Funkcje MQTT:
ESP_ConnectToBroker i ESP_Publish budują ramki MQTT ręcznie i wysyłają je przez ESP-01.

ESP-01 jest konfigurowany w trybie klienta Wi-Fi i pojedynczego połączenia TCP.
UART1 obsługuje komunikację z ESP-01.

Oczywiście to najprostsza opcja i nie jest doskonała należałoby jeszcze wprowadzić
Obsługę wyjątków: (np. ponowne łączenie w przypadku zerwania połączenia).
Subskrypcja: Implementacja funkcji SUBSCRIBE i odbioru wiadomości -- jeśli urządzenie ma odbierać informacje
TLS: Jeśli broker wymaga zabezpieczonego połączenia TLS/SSL

To by było na tyle , od teraz nikt nie będzie miał problemu z postawieniem klienta MQTT czy to ręcznie czy z użyciem bibliotek dedykowanych.
ODPOWIEDZ

Wróć do „C dla ARM”