├── new MQTT protocol V5 compatible libraries ├── library.properties ├── keywords.txt ├── src │ ├── mqtt_v5.h │ └── mqtt_v5.cpp └── examples │ ├── ATsim900mqtt_v5_subscribe.ino │ ├── ATsim900mqtt_v5_htu.ino │ ├── Full_loop_testing_mqtt_v5.ino │ ├── SIM800_FULL_LOOP_tst_MQTT_V5.ino │ └── SIM800_FULL_LOOP_tst_MQTT_V5_JSON.ino ├── mqtt.h ├── mqtt.cpp ├── MQTTSIM900Update24 ├── ATsim900mqtt_HTU_HWserial.ino └── ATsim900mqtt_HTU_v1.ino ├── MQTTSIM900 └── ATSIM900MQTT_HTU │ └── ATSIM900MQTT_HTU.ino └── README.md /new MQTT protocol V5 compatible libraries/library.properties: -------------------------------------------------------------------------------- 1 | name=UARTMqttV5 2 | version=1.0.0 3 | author=Edwin Kestler 4 | maintainer=Edwin Kestler 5 | sentence=An MQTT library with support for MQTT 5.0 protocol features. 6 | paragraph=This library allows Arduino-based devices to communicate with MQTT brokers using the MQTT 5.0 protocol via UART SIM800 boards. It includes support for features like properties, subscription handling, and more. 7 | category=Communication 8 | url=https://github.com/EdwinKestler/SIM800_MQTT 9 | architectures=avr, arm 10 | depends= 11 | -------------------------------------------------------------------------------- /new MQTT protocol V5 compatible libraries/keywords.txt: -------------------------------------------------------------------------------- 1 | # Syntax Coloring Map 2 | # KEYWORD1 (functions and methods) 3 | # KEYWORD2 (user-defined types) 4 | # KEYWORD3 (constants and macros) 5 | # LITERAL1 (keywords or predefined variables) 6 | 7 | mqtt_v5_connect_message KEYWORD1 8 | mqtt_v5_publish_message KEYWORD1 9 | mqtt_v5_subscribe_message KEYWORD1 10 | mqtt_v5_parse_suback_message KEYWORD1 11 | mqtt_v5_disconnect_message KEYWORD1 12 | 13 | mqtt_property KEYWORD2 14 | 15 | MQTT_CONNECT KEYWORD3 16 | MQTT_PUBLISH KEYWORD3 17 | MQTT_SUBSCRIBE KEYWORD3 18 | MQTT_SUBACK KEYWORD3 19 | MQTT_DISCONNECT KEYWORD3 20 | MQTT_PROTOCOL_VERSION_5 KEYWORD3 21 | MQTT_BUFFER_SIZE KEYWORD3 22 | -------------------------------------------------------------------------------- /new MQTT protocol V5 compatible libraries/src/mqtt_v5.h: -------------------------------------------------------------------------------- 1 | // mqtt_v5.h 2 | /****************************************** 3 | * MQTT v5.0 Library Header File 4 | * This file introduces MQTT 5.0 compatibility features including properties and protocol versioning. 5 | * Extended for SUBSCRIBE and SUBACK support. 6 | ******************************************/ 7 | 8 | #ifndef MQTT_V5_H_INCLUDED 9 | #define MQTT_V5_H_INCLUDED 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | // Define constants for MQTT message types 16 | #define MQTT_CONNECT 0x10 17 | #define MQTT_PUBLISH 0x30 18 | #define MQTT_SUBSCRIBE 0x82 19 | #define MQTT_SUBACK 0x90 20 | #define MQTT_DISCONNECT 0xE0 21 | #define MQTT_PROTOCOL_VERSION_5 0x05 22 | #define MQTT_BUFFER_SIZE 256 23 | #define MQTT_MAX_PROPERTIES 10 24 | 25 | // MQTT Property structure 26 | typedef struct { 27 | uint8_t property_id; 28 | uint16_t length; 29 | uint8_t *value; 30 | } mqtt_property; 31 | 32 | // Function prototypes 33 | int mqtt_v5_connect_message(uint8_t *, const char *, mqtt_property *, uint8_t); 34 | int mqtt_v5_publish_message(uint8_t *, const char *, const char *, mqtt_property *, uint8_t); 35 | int mqtt_v5_subscribe_message(uint8_t *, const char *, uint8_t, mqtt_property *, uint8_t); 36 | int mqtt_v5_parse_suback_message(const uint8_t *, uint8_t *, uint8_t *); 37 | int mqtt_v5_disconnect_message(uint8_t *); 38 | 39 | #endif // MQTT_V5_H_INCLUDED 40 | -------------------------------------------------------------------------------- /mqtt.h: -------------------------------------------------------------------------------- 1 | /****************************************** 2 | * this code was last updatesd by Edwin Kestler on 7/1/2024 3 | * this code is a header file for mqtt.cpp 4 | * updates include adding the mqtt_disconnect_message function 5 | * Key updates: 6 | * - Added static buffer for memory reuse in mqtt.cpp 7 | * - Defined constants for protocol and message types 8 | * #define MQTT_BUFFER_SIZE 256 to define the buffer size 9 | * #define MQTT_CONNECT 0x10 to define the connect message type 10 | * #define MQTT_PUBLISH 0x30 to define the publish message type 11 | * #define MQTT_DISCONNECT 0xE0 to define the disconnect message type 12 | * #define MQTT_PROTOCOL_VERSION 3 to define the protocol version 13 | ***************************************** 14 | */ 15 | 16 | #ifndef MQTT_H_INCLUDED 17 | #define MQTT_H_INCLUDED 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | // Define constants for MQTT message types and lengths 24 | #define MQTT_CONNECT 0x10 25 | #define MQTT_PUBLISH 0x30 26 | #define MQTT_DISCONNECT 0xE0 27 | #define MQTT_PROTOCOL_VERSION 3 28 | #define MQTT_BUFFER_SIZE 256 29 | 30 | // Preallocated buffer to reduce memory fragmentation 31 | extern uint8_t preallocated_mqtt_buffer[MQTT_BUFFER_SIZE]; 32 | 33 | // Function prototypes 34 | int mqtt_connect_message(uint8_t *, const char *); 35 | int mqtt_publish_message(uint8_t *, const char *, const char *); 36 | int mqtt_disconnect_message(uint8_t *); 37 | 38 | #endif // MQTT_H_INCLUDED 39 | -------------------------------------------------------------------------------- /new MQTT protocol V5 compatible libraries/examples/ATsim900mqtt_v5_subscribe.ino: -------------------------------------------------------------------------------- 1 | // ATSIM900MQTT_HTU.ino 2 | // description: This example demonstrates how to use the MQTT library with the SIM900 module to subscribe to an MQTT topic using the MQTT 5.0 protocol. 3 | 4 | 5 | #include 6 | #include 7 | 8 | #define SIM_TX 10 9 | #define SIM_RX 11 10 | 11 | SoftwareSerial SIM900(SIM_TX, SIM_RX); 12 | 13 | extern uint8_t preallocated_mqtt_buffer[]; 14 | 15 | const char *topic_to_subscribe = "sensor/data"; 16 | 17 | void setup() { 18 | Serial.begin(9600); 19 | SIM900.begin(9600); 20 | 21 | // Connect to MQTT broker 22 | mqtt_property connect_properties[1]; 23 | uint8_t session_expiry[4] = {0, 0, 0, 60}; 24 | connect_properties[0].property_id = 0x11; 25 | connect_properties[0].length = 4; 26 | connect_properties[0].value = session_expiry; 27 | mqtt_v5_connect_message(preallocated_mqtt_buffer, "arduino_client", connect_properties, 1); 28 | send_message(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 29 | 30 | // Subscribe to a topic 31 | mqtt_property subscribe_properties[1]; 32 | uint8_t subscription_identifier[2] = {0x00, 0x01}; // Subscription Identifier 33 | subscribe_properties[0].property_id = 0x0B; 34 | subscribe_properties[0].length = 2; 35 | subscribe_properties[0].value = subscription_identifier; 36 | mqtt_v5_subscribe_message(preallocated_mqtt_buffer, topic_to_subscribe, 1, subscribe_properties, 1); 37 | send_message(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 38 | } 39 | 40 | void loop() { 41 | // Handle incoming SUBACK response 42 | if (SIM900.available()) { 43 | uint8_t incoming_message[MQTT_BUFFER_SIZE]; 44 | int len = SIM900.readBytes(incoming_message, MQTT_BUFFER_SIZE); 45 | 46 | uint8_t packet_id; 47 | uint8_t return_code; 48 | if (mqtt_v5_parse_suback_message(incoming_message, &packet_id, &return_code) == 0) { 49 | Serial.print("SUBACK received. Packet ID: "); 50 | Serial.print(packet_id); 51 | Serial.print(", Return Code: "); 52 | Serial.println(return_code); 53 | } 54 | } 55 | } 56 | 57 | void send_message(const uint8_t *message, uint16_t length) { 58 | SIM900.write(message, length); 59 | } 60 | -------------------------------------------------------------------------------- /new MQTT protocol V5 compatible libraries/examples/ATsim900mqtt_v5_htu.ino: -------------------------------------------------------------------------------- 1 | 2 | // ATSIM900MQTT_HTU.ino 3 | // description: This example demonstrates how to use the MQTT library with the SIM900 module to publish sensor data to an MQTT broker. 4 | 5 | 6 | #include // Include the updated MQTT 5.0 library 7 | #include // For communication with SIM900 8 | 9 | #define SIM_TX 10 10 | #define SIM_RX 11 11 | 12 | SoftwareSerial SIM900(SIM_TX, SIM_RX); 13 | 14 | extern uint8_t preallocated_mqtt_buffer[]; 15 | 16 | const char *client_id = "arduino_client"; 17 | const char *topic = "sensor/data"; 18 | 19 | void setup() { 20 | Serial.begin(9600); 21 | SIM900.begin(9600); 22 | 23 | // Wait for initialization 24 | delay(3000); 25 | 26 | mqtt_property properties[1]; 27 | uint8_t session_expiry_value[4] = {0, 0, 0, 60}; 28 | properties[0].property_id = 0x11; 29 | properties[0].length = 4; 30 | properties[0].value = session_expiry_value; 31 | 32 | mqtt_v5_connect_message(preallocated_mqtt_buffer, client_id, properties, 1); 33 | send_message(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 34 | } 35 | 36 | void loop() { 37 | // Publish dummy sensor data periodically 38 | static unsigned long last_publish_time = 0; // Track last publish time 39 | if (millis() - last_publish_time > 5000) { // Publish every 5 seconds 40 | const char *sensor_data = "{\"temperature\":25,\"humidity\":60}"; 41 | 42 | // Define optional properties for MQTT 5.0 43 | mqtt_property properties[1]; 44 | uint8_t content_type_value[] = "application/json"; 45 | properties[0].property_id = 0x03; // Content Type identifier 46 | properties[0].length = strlen((char *)content_type_value); 47 | properties[0].value = content_type_value; 48 | 49 | // Construct the MQTT PUBLISH message 50 | int result = mqtt_v5_publish_message(preallocated_mqtt_buffer, topic, sensor_data, properties, 1); 51 | if (result != 0) { 52 | Serial.println("Error constructing MQTT PUBLISH message."); 53 | return; 54 | } 55 | 56 | // Send the PUBLISH message to the SIM900 module 57 | send_message(preallocated_mqtt_buffer, 2 + strlen(topic) + strlen(sensor_data)); 58 | Serial.println("MQTT PUBLISH message sent."); 59 | 60 | last_publish_time = millis(); // Update last publish time 61 | } 62 | } 63 | 64 | 65 | void send_message(const uint8_t *message, uint16_t length) { 66 | SIM900.write(message, length); 67 | } 68 | -------------------------------------------------------------------------------- /mqtt.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * this code was last updatesd by Edwin Kestler on 7/1/2024 4 | * this code is mqtt.cpp 5 | * 6 | * Key Updates: 7 | Buffer size validation: 8 | 9 | Checked if the constructed message exceeds MQTT_BUFFER_SIZE. 10 | Return error codes for buffer overflow or NULL parameters. 11 | Constants for magic numbers: 12 | 13 | Replaced magic numbers (e.g., 0x10, 0x30) with named constants like MQTT_CONNECT and MQTT_PUBLISH. 14 | Error logging and codes: 15 | 16 | Added error messages via fprintf(stderr, ...). 17 | Return distinct error codes for different failure cases (-1 for NULL parameters, -2 for buffer overflow). 18 | * Optimized for performance: memory reuse, use of memcpy, reduced fragmentation 19 | */ 20 | 21 | #include "mqtt.h" 22 | 23 | // Preallocated buffer to minimize temporary allocations 24 | static uint8_t preallocated_mqtt_buffer[MQTT_BUFFER_SIZE]; 25 | 26 | int mqtt_connect_message(uint8_t *mqtt_message, const char *client_id) { 27 | if (!mqtt_message || !client_id) { 28 | fprintf(stderr, "Error: NULL parameter provided.\n"); 29 | return -1; // Error code for NULL parameter 30 | } 31 | 32 | uint8_t client_id_length = strlen(client_id); 33 | if (14 + client_id_length > MQTT_BUFFER_SIZE) { 34 | fprintf(stderr, "Error: Buffer size exceeded in mqtt_connect_message.\n"); 35 | return -2; // Error code for buffer overflow 36 | } 37 | 38 | mqtt_message[0] = MQTT_CONNECT; 39 | mqtt_message[1] = 14 + client_id_length; 40 | 41 | mqtt_message[2] = 0; 42 | mqtt_message[3] = 6; 43 | memcpy(&mqtt_message[4], "MQIsdp", 6); 44 | mqtt_message[10] = MQTT_PROTOCOL_VERSION; 45 | mqtt_message[11] = 2; // Connection flags 46 | mqtt_message[12] = 0; 47 | mqtt_message[13] = 15; // Keep-alive 48 | 49 | mqtt_message[14] = 0; 50 | mqtt_message[15] = client_id_length; 51 | 52 | memcpy(&mqtt_message[16], client_id, client_id_length); 53 | 54 | return 0; // Success 55 | } 56 | 57 | int mqtt_publish_message(uint8_t *mqtt_message, const char *topic, const char *message) { 58 | if (!mqtt_message || !topic || !message) { 59 | fprintf(stderr, "Error: NULL parameter provided.\n"); 60 | return -1; // Error code for NULL parameter 61 | } 62 | 63 | uint8_t topic_length = strlen(topic); 64 | uint8_t message_length = strlen(message); 65 | if (2 + topic_length + message_length > MQTT_BUFFER_SIZE) { 66 | fprintf(stderr, "Error: Buffer size exceeded in mqtt_publish_message.\n"); 67 | return -2; // Error code for buffer overflow 68 | } 69 | 70 | mqtt_message[0] = MQTT_PUBLISH; 71 | mqtt_message[1] = 2 + topic_length + message_length; 72 | 73 | mqtt_message[2] = 0; 74 | mqtt_message[3] = topic_length; 75 | 76 | memcpy(&mqtt_message[4], topic, topic_length); 77 | memcpy(&mqtt_message[4 + topic_length], message, message_length); 78 | 79 | return 0; // Success 80 | } 81 | 82 | int mqtt_disconnect_message(uint8_t *mqtt_message) { 83 | if (!mqtt_message) { 84 | fprintf(stderr, "Error: NULL parameter provided.\n"); 85 | return -1; // Error code for NULL parameter 86 | } 87 | 88 | mqtt_message[0] = MQTT_DISCONNECT; 89 | mqtt_message[1] = 0; 90 | 91 | return 0; // Success 92 | } -------------------------------------------------------------------------------- /MQTTSIM900Update24/ATsim900mqtt_HTU_HWserial.ino: -------------------------------------------------------------------------------- 1 | // ATSIM900MQTT_HTU.ino 2 | // Updated to use hardware serial for communication with SIM900 3 | 4 | #include // Include custom MQTT library 5 | 6 | // Use the default hardware serial port for SIM900 communication 7 | #define SIM900 Serial1 8 | 9 | extern uint8_t preallocated_mqtt_buffer[]; // Use the preallocated MQTT buffer from mqtt.cpp 10 | 11 | const char *client_id = "arduino_client"; // MQTT client identifier 12 | const char *topic = "sensor/data"; // MQTT topic to publish 13 | const char *broker_ip = "192.168.1.100"; // MQTT broker IP address 14 | const int broker_port = 1883; // MQTT broker port 15 | 16 | void setup() { 17 | Serial.begin(9600); // Initialize Serial for debugging 18 | SIM900.begin(9600); // Initialize hardware Serial for SIM900 communication 19 | 20 | // Wait for the SIM900 to initialize 21 | Serial.println("Initializing SIM900..."); 22 | unsigned long start_time = millis(); 23 | while (millis() - start_time < 5000) { // Non-blocking delay for 5 seconds 24 | if (SIM900.available()) { 25 | // Check for any response from SIM900 during initialization 26 | Serial.write(SIM900.read()); 27 | } 28 | } 29 | 30 | // Connect to the broker 31 | Serial.println("Connecting to MQTT broker..."); 32 | mqtt_connect(); 33 | } 34 | 35 | void loop() { 36 | // Publish dummy sensor data periodically 37 | static unsigned long last_publish_time = 0; // Track last publish time 38 | if (millis() - last_publish_time > 5000) { // Publish every 5 seconds 39 | publish_sensor_data(); 40 | last_publish_time = millis(); // Update last publish time 41 | } 42 | } 43 | 44 | void mqtt_connect() { 45 | // Prepare and send MQTT CONNECT message 46 | int result = mqtt_connect_message(preallocated_mqtt_buffer, client_id); 47 | if (result != 0) { 48 | Serial.println("Error constructing MQTT CONNECT message."); 49 | return; 50 | } 51 | 52 | send_message_to_sim(preallocated_mqtt_buffer, 16 + strlen(client_id)); 53 | Serial.println("MQTT CONNECT message sent."); 54 | } 55 | 56 | void publish_sensor_data() { 57 | // Prepare dummy sensor data 58 | const char *sensor_data = "{\"temperature\":25,\"humidity\":60}"; 59 | 60 | // Prepare and send MQTT PUBLISH message 61 | int result = mqtt_publish_message(preallocated_mqtt_buffer, topic, sensor_data); 62 | if (result != 0) { 63 | Serial.println("Error constructing MQTT PUBLISH message."); 64 | return; 65 | } 66 | 67 | send_message_to_sim(preallocated_mqtt_buffer, 2 + strlen(topic) + strlen(sensor_data)); 68 | Serial.println("MQTT PUBLISH message sent."); 69 | } 70 | 71 | void send_message_to_sim(const uint8_t *message, uint16_t length) { 72 | // Function to send MQTT message via SIM900 73 | if (message == nullptr || length == 0) { 74 | Serial.println("Error: Message is null or length is zero."); 75 | return; 76 | } 77 | 78 | int bytes_sent = SIM900.write(message, length); // Send message to SIM module 79 | if (bytes_sent != length) { 80 | Serial.println("Error: Message not fully sent to SIM900 module."); 81 | return; 82 | } 83 | 84 | Serial.print("Message sent to SIM900: "); 85 | for (uint16_t i = 0; i < length; i++) { 86 | Serial.print(message[i], HEX); // Print message in HEX format 87 | Serial.print(" "); 88 | } 89 | Serial.println(); 90 | } 91 | -------------------------------------------------------------------------------- /MQTTSIM900Update24/ATsim900mqtt_HTU_v1.ino: -------------------------------------------------------------------------------- 1 | // ATSIM900MQTT_HTU.ino 2 | // Updated to use preallocated buffer and align with optimizations in mqtt.cpp 3 | 4 | #include // Include custom MQTT library 5 | #include // Include SoftwareSerial for communication with SIM module 6 | 7 | #define SIM_TX 10 // Define SIM module TX pin 8 | #define SIM_RX 11 // Define SIM module RX pin 9 | 10 | SoftwareSerial SIM900(SIM_TX, SIM_RX); // Initialize SoftwareSerial for SIM module communication 11 | 12 | // Use the preallocated MQTT buffer defined in mqtt.cpp 13 | extern uint8_t preallocated_mqtt_buffer[]; 14 | 15 | const char *client_id = "arduino_client"; // MQTT client identifier 16 | const char *topic = "sensor/data"; // MQTT topic to publish 17 | const char *broker_ip = "192.168.1.100"; // MQTT broker IP address 18 | const int broker_port = 1883; // MQTT broker port 19 | 20 | void setup() { 21 | Serial.begin(9600); // Initialize Serial for debugging 22 | SIM900.begin(9600); // Initialize SIM module communication 23 | 24 | // Wait for the SIM900 to initialize 25 | Serial.println("Initializing SIM900..."); 26 | unsigned long start_time = millis(); 27 | while (millis() - start_time < 5000) { // Non-blocking delay for 5 seconds 28 | if (SIM900.available()) { 29 | // Check for any response from SIM900 during initialization 30 | Serial.write(SIM900.read()); 31 | } 32 | } 33 | 34 | // Connect to the broker 35 | Serial.println("Connecting to MQTT broker..."); 36 | mqtt_connect(); 37 | } 38 | 39 | void loop() { 40 | // Publish dummy sensor data periodically 41 | static unsigned long last_publish_time = 0; // Track last publish time 42 | if (millis() - last_publish_time > 5000) { // Publish every 5 seconds 43 | publish_sensor_data(); 44 | last_publish_time = millis(); // Update last publish time 45 | } 46 | } 47 | 48 | void mqtt_connect() { 49 | // Prepare and send MQTT CONNECT message 50 | int result = mqtt_connect_message(preallocated_mqtt_buffer, client_id); 51 | if (result != 0) { 52 | Serial.println("Error constructing MQTT CONNECT message."); 53 | return; 54 | } 55 | 56 | send_message_to_sim(preallocated_mqtt_buffer, 16 + strlen(client_id)); 57 | Serial.println("MQTT CONNECT message sent."); 58 | } 59 | 60 | void publish_sensor_data() { 61 | // Prepare dummy sensor data 62 | const char *sensor_data = "{\"temperature\":25,\"humidity\":60}"; 63 | 64 | // Prepare and send MQTT PUBLISH message 65 | int result = mqtt_publish_message(preallocated_mqtt_buffer, topic, sensor_data); 66 | if (result != 0) { 67 | Serial.println("Error constructing MQTT PUBLISH message."); 68 | return; 69 | } 70 | 71 | send_message_to_sim(preallocated_mqtt_buffer, 2 + strlen(topic) + strlen(sensor_data)); 72 | Serial.println("MQTT PUBLISH message sent."); 73 | } 74 | 75 | void send_message_to_sim(const uint8_t *message, uint16_t length) { 76 | // Function to send MQTT message via SIM900 77 | if (message == nullptr || length == 0) { 78 | Serial.println("Error: Message is null or length is zero."); 79 | return; 80 | } 81 | 82 | int bytes_sent = SIM900.write(message, length); // Send message to SIM module 83 | if (bytes_sent != length) { 84 | Serial.println("Error: Message not fully sent to SIM900 module."); 85 | return; 86 | } 87 | 88 | Serial.print("Message sent to SIM900: "); 89 | for (uint16_t i = 0; i < length; i++) { 90 | Serial.print(message[i], HEX); // Print message in HEX format 91 | Serial.print(" "); 92 | } 93 | Serial.println(); 94 | } 95 | -------------------------------------------------------------------------------- /new MQTT protocol V5 compatible libraries/examples/Full_loop_testing_mqtt_v5.ino: -------------------------------------------------------------------------------- 1 | // Full_loop_testing_mqtt_v5.ino 2 | // Description: This example demonstrates a full loop testing scenario using the MQTT 5.0 protocol with the SIM900 module. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | #define SIM_TX 10 9 | #define SIM_RX 11 10 | 11 | SoftwareSerial SIM800(SIM_TX, SIM_RX); 12 | 13 | #define MAX_MESSAGE_SIZE 128 // Maximum expected MQTT message size 14 | char inputBuffer[MAX_MESSAGE_SIZE]; // Buffer to store incoming data 15 | volatile uint16_t bufferIndex = 0; // Index to track position in the buffer 16 | 17 | #define CHUNK_SIZE 32 // Read in chunks to avoid buffer overflow 18 | 19 | void readSerialChunks() { 20 | while (SIM800.available()) { 21 | char chunk[CHUNK_SIZE + 1] = {0}; // Temporary buffer 22 | int len = SIM800.readBytes(chunk, CHUNK_SIZE); 23 | chunk[len] = '\0'; // Null-terminate 24 | 25 | // Append to the main buffer 26 | if (bufferIndex + len < MAX_MESSAGE_SIZE) { 27 | strcat(inputBuffer, chunk); 28 | bufferIndex += len; 29 | } else { 30 | Serial.println("Error: Buffer Overflow in readSerialChunks"); 31 | } 32 | } 33 | } 34 | 35 | extern uint8_t preallocated_mqtt_buffer[]; 36 | 37 | // MQTT broker details 38 | const char *topic = "test/topic"; 39 | const char *payload = "{\"message\": \"Hello, MQTT V5!\"}"; 40 | 41 | void setup() { 42 | Serial.begin(9600); 43 | SIM800.begin(9600); 44 | 45 | Serial.println("Initializing SIM800..."); 46 | delay(3000); 47 | 48 | connectToMQTTBroker(); 49 | subscribeToTopic(); 50 | } 51 | 52 | void loop() { 53 | publishMessage(); 54 | readSerialChunks(); // Check and read serial chunks 55 | processMQTTMessages(); // Process buffered messages 56 | delay(5000); 57 | } 58 | 59 | void connectToMQTTBroker() { 60 | Serial.println("Connecting to MQTT broker..."); 61 | mqtt_property connect_properties[1]; 62 | uint8_t session_expiry[4] = {0, 0, 0, 60}; // Session Expiry Interval: 60 seconds 63 | connect_properties[0].property_id = 0x11; 64 | connect_properties[0].length = 4; 65 | connect_properties[0].value = session_expiry; 66 | 67 | int result = mqtt_v5_connect_message(preallocated_mqtt_buffer, "arduino_client", connect_properties, 1); 68 | if (result != 0) { 69 | Serial.println("Error constructing CONNECT message."); 70 | return; 71 | } 72 | 73 | sendMQTTMessage(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 74 | Serial.println("CONNECT message sent."); 75 | } 76 | 77 | void subscribeToTopic() { 78 | Serial.print("Subscribing to topic: "); 79 | Serial.println(topic); 80 | 81 | mqtt_property subscribe_properties[1]; 82 | uint8_t subscription_identifier[2] = {0x00, 0x01}; // Subscription Identifier 83 | subscribe_properties[0].property_id = 0x0B; 84 | subscribe_properties[0].length = 2; 85 | subscribe_properties[0].value = subscription_identifier; 86 | 87 | int result = mqtt_v5_subscribe_message(preallocated_mqtt_buffer, topic, 1, subscribe_properties, 1); 88 | if (result != 0) { 89 | Serial.println("Error constructing SUBSCRIBE message."); 90 | return; 91 | } 92 | 93 | sendMQTTMessage(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 94 | Serial.println("SUBSCRIBE message sent."); 95 | } 96 | 97 | void publishMessage() { 98 | Serial.print("Publishing message to topic: "); 99 | Serial.println(topic); 100 | 101 | mqtt_property publish_properties[1]; 102 | uint8_t content_type[] = "application/json"; // Content type property 103 | publish_properties[0].property_id = 0x03; 104 | publish_properties[0].length = strlen((char *)content_type); 105 | publish_properties[0].value = content_type; 106 | 107 | int result = mqtt_v5_publish_message(preallocated_mqtt_buffer, topic, payload, publish_properties, 1); 108 | if (result != 0) { 109 | Serial.println("Error constructing PUBLISH message."); 110 | return; 111 | } 112 | 113 | sendMQTTMessage(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 114 | Serial.println("PUBLISH message sent."); 115 | } 116 | 117 | void sendMQTTMessage(const uint8_t *message, uint16_t length) { 118 | SIM800.println("AT+CIPSEND"); 119 | delay(500); 120 | SIM800.write(message, length); 121 | SIM800.write((char)26); // End of message (Ctrl+Z) 122 | } 123 | 124 | void processMQTTMessages() { 125 | if (bufferIndex > 0) { 126 | Serial.print("Processing MQTT Message: "); 127 | Serial.println(inputBuffer); 128 | 129 | // Reset the buffer after processing 130 | memset(inputBuffer, 0, MAX_MESSAGE_SIZE); 131 | bufferIndex = 0; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /MQTTSIM900/ATSIM900MQTT_HTU/ATSIM900MQTT_HTU.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | SoftwareSerial GPRS(2, 3); //RX, TX 5 | 6 | //but is more 'smooth' 7 | #define NUMSAMPLES 5 8 | 9 | int samplesT [NUMSAMPLES]; 10 | int samplesH [NUMSAMPLES]; 11 | int HTU_Temp=0; 12 | int HTU_Hum=0; 13 | String gprsStr = ""; 14 | int index = 0; 15 | byte data1; 16 | char atCommand[50]; 17 | byte mqttMessage[127]; 18 | int mqttMessageLength = 0; 19 | 20 | 21 | //bolean flags 22 | boolean smsReady = false; 23 | boolean smsSent = false; 24 | boolean gprsReady = false; 25 | boolean mqttSent = false; 26 | 27 | void setup(){ 28 | Serial.begin (9600); //debug 29 | GPRS.begin(9600); //GPRS 30 | 31 | Serial.println("HTU21D-F test"); 32 | 33 | } 34 | 35 | void loop (){ 36 | delay (15000); //Time to get GPRS Satable 37 | 38 | get_HTU(); 39 | 40 | Serial.println("Checking if GPRS is READy?"); 41 | GPRS.println("AT"); 42 | delay(1000); 43 | 44 | gprsReady= isGPRSReady(); 45 | if(gprsReady == true){ 46 | Serial.println("GPRS READY!"); 47 | String json= buildJson(); 48 | char jsonStr[300]; 49 | json.toCharArray(jsonStr,300); 50 | Serial.println(json); 51 | 52 | //*arguments in function are: 53 | //clientID, IP, Port, Topic, Message 54 | 55 | sendMQTTMessage("NodeHTU", "flatbox.io", "1883", "prueba/", jsonStr); 56 | } 57 | delay (15000); 58 | } 59 | 60 | boolean isGPRSReady(){ 61 | GPRS.println("AT"); 62 | GPRS.println("AT"); 63 | GPRS.println("AT+CGATT?"); 64 | index = 0; 65 | while (GPRS.available()){ 66 | data1 = (char)GPRS.read(); 67 | Serial.write(data1); 68 | gprsStr[index++] = data1; 69 | } 70 | Serial.println("Check OK"); 71 | Serial.print("gprs str = "); 72 | Serial.println(data1); 73 | if (data1 > -1){ 74 | Serial.println("GPRS OK"); 75 | return true; 76 | } 77 | else { 78 | Serial.println("GPRS NOT OK"); 79 | return false; 80 | } 81 | } 82 | 83 | void sendMQTTMessage(char* clientId, char* brokerUrl, char* brokerPort, char* topic, char* message){ 84 | GPRS.println("AT"); // Sends AT command to wake up cell phone 85 | Serial.println("send AT to wake up GPRS"); 86 | delay(1000); // Wait a second 87 | // digitalWrite(13, HIGH); 88 | GPRS.println("AT+CSTT=\"broadband.tigo.gt\",\"\",\"\""); // Puts phone into GPRS mode 89 | Serial.println("AT+CSTT=\"broadband.tigo.gt\",\"\",\"\""); 90 | delay(2000); // Wait a second 91 | GPRS.println("AT+CIICR"); 92 | Serial.println("AT+CIICR"); 93 | delay(2000); 94 | GPRS.println("AT+CIFSR"); 95 | Serial.println("AT+CIFSR"); 96 | delay(2000); 97 | strcpy(atCommand, "AT+CIPSTART=\"TCP\",\""); 98 | strcat(atCommand, brokerUrl); 99 | strcat(atCommand, "\",\""); 100 | strcat(atCommand, brokerPort); 101 | strcat(atCommand, "\""); 102 | GPRS.println(atCommand); 103 | Serial.println(atCommand); 104 | // Serial.println("AT+CIPSTART=\"TCP\",\"mqttdashboard.com\",\"1883\""); 105 | delay(2000); 106 | GPRS.println("AT+CIPSEND"); 107 | Serial.println("AT+CIPSEND"); 108 | delay(2000); 109 | mqttMessageLength = 16 + strlen(clientId); 110 | Serial.println(mqttMessageLength); 111 | mqtt_connect_message(mqttMessage, clientId); 112 | for (int j = 0; j < mqttMessageLength; j++) { 113 | GPRS.write(mqttMessage[j]); // Message contents 114 | Serial.write(mqttMessage[j]); // Message contents 115 | Serial.println(""); 116 | } 117 | GPRS.write(byte(26)); // (signals end of message) 118 | Serial.println("Sent"); 119 | delay(10000); 120 | GPRS.println("AT+CIPSEND"); 121 | Serial.println("AT+CIPSEND"); 122 | delay(2000); 123 | mqttMessageLength = 4 + strlen(topic) + strlen(message); 124 | Serial.println(mqttMessageLength); 125 | mqtt_publish_message(mqttMessage, topic, message); 126 | for (int k = 0; k < mqttMessageLength; k++) { 127 | GPRS.write(mqttMessage[k]); 128 | Serial.write((byte)mqttMessage[k]); 129 | } 130 | GPRS.write(byte(26)); // (signals end of message) 131 | Serial.println("-------------Sent-------------"); // Message contents 132 | delay(5000); 133 | GPRS.println("AT+CIPCLOSE"); 134 | Serial.println("AT+CIPCLOSE"); 135 | delay(2000); 136 | } 137 | 138 | void get_HTU(){ 139 | uint8_t i; 140 | float averageT; 141 | float averageH; 142 | 143 | // take N samples in a row, with a slight delay 144 | for (i=0; i< NUMSAMPLES; i++) { 145 | samplesT[i] = 25; 146 | samplesH[i] = 45; 147 | delay(100); 148 | } 149 | 150 | // average all the samples out 151 | averageT = 0; 152 | averageH = 0; 153 | 154 | for (i=0; i< NUMSAMPLES; i++) { 155 | averageT += samplesT[i]; 156 | averageH += samplesH[i]; 157 | } 158 | averageT /= NUMSAMPLES; 159 | averageH /= NUMSAMPLES; 160 | 161 | Serial.print("Average reading "); 162 | Serial.println(averageT); 163 | Serial.println(averageT); 164 | 165 | HTU_Temp= averageT; 166 | HTU_Hum= averageH; 167 | 168 | Serial.print("Temperature "); 169 | Serial.print(HTU_Temp); 170 | Serial.println(" *C"); 171 | 172 | Serial.print("Humidity "); 173 | Serial.print(HTU_Hum); 174 | Serial.println(" %"); 175 | 176 | } 177 | 178 | String buildJson() { 179 | String data = "{"; 180 | data+="\n"; 181 | data+= "\"d\": {"; 182 | data+="\n"; 183 | data+="\"ID\": \"HTU_Node_01\","; 184 | data+="\n"; 185 | data+="\"HTU_T\": "; 186 | data+=(int)HTU_Temp; 187 | data+="\n"; 188 | data+="\"HTU_H\": "; 189 | data+=(int)HTU_Hum; 190 | data+="\n"; 191 | data+="}"; 192 | data+="\n"; 193 | data+="}"; 194 | return data; 195 | } 196 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SIM800 MQTT Library 2 | 3 | ## Description 4 | 5 | This Arduino library enables communication with MQTT brokers via a SIM800/SIM900 GPRS module. It provides functionality for sending MQTT CONNECT, PUBLISH, and DISCONNECT messages, tailored for lightweight embedded systems such as Arduino boards. 6 | 7 | ## Features 8 | 9 | - **MQTT Protocol Support**: Send CONNECT, PUBLISH, and DISCONNECT messages. 10 | - **Hardware Serial Support**: Uses hardware UART (`Serial1`) for efficient communication on boards with multiple serial ports. 11 | - **Buffer Optimizations**: Preallocated MQTT message buffer for efficient memory management. 12 | - **Error Handling**: Returns error codes for invalid parameters or buffer overflows, and logs messages for debugging. 13 | 14 | ## Recent Updates 15 | 16 | 1. **Performance Optimizations**: 17 | - Replaced manual loops with `memcpy` for copying data into buffers. 18 | - Introduced a preallocated static buffer to minimize memory fragmentation and improve performance. 19 | - Reduced temporary allocations by reusing a single buffer across all MQTT operations. 20 | 2. **Support for Hardware Serial**: 21 | - Dedicated `Serial1` for SIM900 communication on boards with multiple UARTs. 22 | - Compatibility maintained with single UART boards by allowing configurable serial handling. 23 | 3. **Enhanced Documentation**: 24 | - Added detailed usage instructions and examples. 25 | - Expanded troubleshooting and best practices sections. 26 | 4. **MQTT V5 Protocol Support**: 27 | - Introduced separate files for MQTT V5-compatible operations. 28 | - Added support for properties in CONNECT and PUBLISH messages. 29 | - Improved compatibility with brokers supporting MQTT V5. 30 | 31 | ## Installation 32 | 33 | 1. Download the library and add it to your Arduino IDE: 34 | - Navigate to `Sketch` -> `Include Library` -> `Add .ZIP Library...` 35 | 2. Include the library in your sketch: 36 | 37 | ```cpp 38 | 39 | #include 40 | 41 | ``` 42 | 43 | ### For MQTT V5 Support 44 | 45 | - The files for MQTT V5-compatible operations are located in the folder "new MQTT protocol V5 compatible libraries". 46 | Include the V5 header file in your sketch: 47 | 48 | ```cpp 49 | #include 50 | ``` 51 | 52 | ## Usage 53 | 54 | ## Basic Setup (MQTT 3.1.1) 55 | 56 | ```cpp 57 | #include 58 | 59 | #define SIM900 Serial1 // Use Serial1 for SIM900 communication 60 | 61 | extern uint8_t preallocated_mqtt_buffer[]; 62 | 63 | void setup() { 64 | Serial.begin(9600); // Debugging 65 | SIM900.begin(9600); // Initialize SIM900 communication 66 | 67 | // Connect to MQTT broker 68 | mqtt_connect_message(preallocated_mqtt_buffer, "arduino_client"); 69 | send_message_to_sim(preallocated_mqtt_buffer, 16 + strlen("arduino_client")); 70 | } 71 | 72 | void loop() { 73 | // Publish messages periodically 74 | mqtt_publish_message(preallocated_mqtt_buffer, "sensor/data", "{\"temperature\":25,\"humidity\":60}"); 75 | send_message_to_sim(preallocated_mqtt_buffer, 2 + strlen("sensor/data") + strlen("{\"temperature\":25,\"humidity\":60}")); 76 | delay(5000); 77 | } 78 | 79 | void send_message_to_sim(const uint8_t *message, uint16_t length) { 80 | SIM900.write(message, length); 81 | } 82 | ``` 83 | 84 | ## MQTT V5 Example 85 | 86 | ```cpp 87 | #include 88 | 89 | extern uint8_t preallocated_mqtt_buffer[]; 90 | 91 | void setup() { 92 | Serial.begin(9600); 93 | SIM900.begin(9600); 94 | 95 | mqtt_property properties[1]; 96 | uint8_t session_expiry_value[4] = {0, 0, 0, 60}; 97 | properties[0].property_id = 0x11; // Session Expiry Interval 98 | properties[0].length = 4; 99 | properties[0].value = session_expiry_value; 100 | 101 | mqtt_v5_connect_message(preallocated_mqtt_buffer, "arduino_client", properties, 1); 102 | send_message_to_sim(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 103 | } 104 | 105 | void loop() { 106 | // Example PUBLISH logic with MQTT V5 107 | } 108 | 109 | ``` 110 | 111 | ## Supported Boards 112 | 113 | **Single UART Boards**: 114 | 115 | - Arduino Uno, Nano (requires SoftwareSerial for SIM900 communication). 116 | 117 | **Multi-UART Boards**: 118 | 119 | - Arduino Mega, Leonardo, Due (recommended for better performance with Serial1). 120 | 121 | ## Best Practices 122 | 123 | **Use Hardware UART**: 124 | - For boards with multiple UARTs, dedicate a hardware serial port to the SIM900 module for optimal performance. 125 | 126 | **Manage Shared Serial Ports**: 127 | 128 | - For single UART boards, disconnect the SIM900 module while uploading code or debugging via USB. 129 | 130 | **Test with Public MQTT Brokers**: 131 | - Use brokers like test.mosquitto.org for initial testing. 132 | 133 | ## Troubleshooting 134 | 135 | **SIM900 Not Responding**: 136 | - Ensure proper wiring and power supply to the module. 137 | - Use AT commands to test module responsiveness before running the sketch. 138 | 139 | **MQTT Connection Issues**: 140 | - Verify the broker IP, port, and network connectivity. 141 | - Ensure the SIM card has an active data plan. 142 | 143 | **Future Enhancements**: 144 | - QoS Support: Add quality of service levels to MQTT PUBLISH messages. 145 | - TLS Security: Integrate SSL/TLS for secure MQTT communication. 146 | - SUBSCRIBE Support: Enable parsing and handling of incoming MQTT messages. 147 | 148 | ## License 149 | 150 | - This library is open-source and licensed under the MIT License. Feel free to modify and use it in your projects. 151 | 152 | ## Acknowledgments 153 | 154 | - Special thanks to Edwin Kestler for recent contributions and optimizations to improve performance and usability. 155 | 156 | --- 157 | 158 | ### Key Updates in README 159 | 160 | 1. **Added Section for MQTT V5**: 161 | - Highlighted the new folder **"new MQTT protocol V5 compatible libraries"**. 162 | - Documented usage of the new files `mqtt_v5.h` and `mqtt_v5.cpp`. 163 | 164 | 2. **Detailed MQTT V5 Example**: 165 | - Included a practical example for setting up and publishing using MQTT V5 features. 166 | 167 | 3. **Best Practices and Future Enhancements**: 168 | - Retained existing recommendations while maintaining backward compatibility. 169 | -------------------------------------------------------------------------------- /new MQTT protocol V5 compatible libraries/src/mqtt_v5.cpp: -------------------------------------------------------------------------------- 1 | /****************************************** 2 | * mqtt_v5.cpp 3 | * This source file implements MQTT 5.0 compatibility. 4 | ******************************************/ 5 | 6 | #include "mqtt_v5.h" 7 | 8 | // MQTT SUBSCRIBE message construction 9 | int mqtt_v5_subscribe_message(uint8_t *mqtt_message, const char *topic, uint8_t qos, mqtt_property *properties, uint8_t property_count) { 10 | if (!mqtt_message || !topic) { 11 | fprintf(stderr, "Error: NULL parameter provided.\n"); 12 | return -1; 13 | } 14 | 15 | uint8_t topic_length = strlen(topic); 16 | uint16_t remaining_length = 2 + topic_length + 1; // Topic length (2) + topic + QoS 17 | 18 | // Calculate properties length 19 | uint16_t properties_length = 0; 20 | for (uint8_t i = 0; i < property_count; i++) { 21 | properties_length += 1 + 2 + properties[i].length; // ID + Length + Value 22 | } 23 | remaining_length += 2 + properties_length; // Add property length field 24 | 25 | if (remaining_length > MQTT_BUFFER_SIZE) { 26 | fprintf(stderr, "Error: Buffer size exceeded in mqtt_v5_subscribe_message.\n"); 27 | return -2; 28 | } 29 | 30 | mqtt_message[0] = MQTT_SUBSCRIBE; 31 | mqtt_message[1] = remaining_length; 32 | 33 | mqtt_message[2] = 0; // Packet Identifier MSB 34 | mqtt_message[3] = 1; // Packet Identifier LSB (Static ID for simplicity) 35 | 36 | mqtt_message[4] = properties_length >> 8; 37 | mqtt_message[5] = properties_length & 0xFF; 38 | 39 | uint16_t index = 6; 40 | for (uint8_t i = 0; i < property_count; i++) { 41 | mqtt_message[index++] = properties[i].property_id; 42 | mqtt_message[index++] = (properties[i].length >> 8) & 0xFF; 43 | mqtt_message[index++] = properties[i].length & 0xFF; 44 | memcpy(&mqtt_message[index], properties[i].value, properties[i].length); 45 | index += properties[i].length; 46 | } 47 | 48 | mqtt_message[index++] = 0; // Topic length MSB 49 | mqtt_message[index++] = topic_length; // Topic length LSB 50 | 51 | memcpy(&mqtt_message[index], topic, topic_length); 52 | index += topic_length; 53 | 54 | mqtt_message[index++] = qos; // QoS level 55 | 56 | return 0; // Success 57 | } 58 | 59 | // Parse SUBACK message 60 | int mqtt_v5_parse_suback_message(const uint8_t *mqtt_message, uint8_t *packet_id, uint8_t *return_code) { 61 | if (!mqtt_message || !packet_id || !return_code) { 62 | fprintf(stderr, "Error: NULL parameter provided.\n"); 63 | return -1; 64 | } 65 | 66 | if (mqtt_message[0] != MQTT_SUBACK) { 67 | fprintf(stderr, "Error: Not a SUBACK message.\n"); 68 | return -2; 69 | } 70 | 71 | *packet_id = mqtt_message[2]; // Packet Identifier (Static ID assumed as 1) 72 | *return_code = mqtt_message[4]; // Return Code (e.g., Success or Failure) 73 | 74 | return 0; // Success 75 | } 76 | 77 | // MQTT CONNECT message construction 78 | int mqtt_v5_connect_message(uint8_t *mqtt_message, const char *client_id, mqtt_property *properties, uint8_t property_count) { 79 | if (!mqtt_message || !client_id) { 80 | fprintf(stderr, "Error: NULL parameter provided.\n"); 81 | return -1; 82 | } 83 | 84 | uint8_t client_id_length = strlen(client_id); 85 | uint16_t remaining_length = 14 + client_id_length; 86 | 87 | // Calculate properties length 88 | uint16_t properties_length = 0; 89 | for (uint8_t i = 0; i < property_count; i++) { 90 | properties_length += 1 + 2 + properties[i].length; // ID + Length + Value 91 | } 92 | remaining_length += 2 + properties_length; // Properties length field 93 | 94 | if (remaining_length > MQTT_BUFFER_SIZE) { 95 | fprintf(stderr, "Error: Buffer size exceeded in mqtt_v5_connect_message.\n"); 96 | return -2; 97 | } 98 | 99 | mqtt_message[0] = MQTT_CONNECT; 100 | mqtt_message[1] = remaining_length; 101 | 102 | mqtt_message[2] = 0; 103 | mqtt_message[3] = 4; // Protocol name length 104 | memcpy(&mqtt_message[4], "MQTT", 4); 105 | mqtt_message[8] = MQTT_PROTOCOL_VERSION_5; 106 | mqtt_message[9] = 2; // Connection flags 107 | mqtt_message[10] = 0; 108 | mqtt_message[11] = 15; // Keep-alive 109 | 110 | mqtt_message[12] = properties_length >> 8; 111 | mqtt_message[13] = properties_length & 0xFF; 112 | 113 | uint16_t index = 14; 114 | for (uint8_t i = 0; i < property_count; i++) { 115 | mqtt_message[index++] = properties[i].property_id; 116 | mqtt_message[index++] = (properties[i].length >> 8) & 0xFF; 117 | mqtt_message[index++] = properties[i].length & 0xFF; 118 | memcpy(&mqtt_message[index], properties[i].value, properties[i].length); 119 | index += properties[i].length; 120 | } 121 | 122 | mqtt_message[index++] = 0; 123 | mqtt_message[index++] = client_id_length; 124 | 125 | memcpy(&mqtt_message[index], client_id, client_id_length); 126 | return 0; 127 | } 128 | 129 | // MQTT PUBLISH message construction 130 | int mqtt_v5_publish_message(uint8_t *mqtt_message, const char *topic, const char *message, mqtt_property *properties, uint8_t property_count) { 131 | if (!mqtt_message || !topic || !message) { 132 | fprintf(stderr, "Error: NULL parameter provided.\n"); 133 | return -1; 134 | } 135 | 136 | uint8_t topic_length = strlen(topic); 137 | uint8_t message_length = strlen(message); 138 | uint16_t remaining_length = 2 + topic_length + message_length; 139 | 140 | // Calculate properties length 141 | uint16_t properties_length = 0; 142 | for (uint8_t i = 0; i < property_count; i++) { 143 | properties_length += 1 + 2 + properties[i].length; // ID + Length + Value 144 | } 145 | remaining_length += 2 + properties_length; // Properties length field 146 | 147 | if (remaining_length > MQTT_BUFFER_SIZE) { 148 | fprintf(stderr, "Error: Buffer size exceeded in mqtt_v5_publish_message.\n"); 149 | return -2; 150 | } 151 | 152 | mqtt_message[0] = MQTT_PUBLISH; 153 | mqtt_message[1] = remaining_length; 154 | 155 | mqtt_message[2] = 0; 156 | mqtt_message[3] = topic_length; 157 | 158 | memcpy(&mqtt_message[4], topic, topic_length); 159 | memcpy(&mqtt_message[4 + topic_length], message, message_length); 160 | 161 | return 0; 162 | } 163 | 164 | // MQTT DISCONNECT message construction 165 | int mqtt_v5_disconnect_message(uint8_t *mqtt_message) { 166 | if (!mqtt_message) { 167 | fprintf(stderr, "Error: NULL parameter provided.\n"); 168 | return -1; 169 | } 170 | 171 | mqtt_message[0] = MQTT_DISCONNECT; 172 | mqtt_message[1] = 0; 173 | 174 | return 0; 175 | } 176 | -------------------------------------------------------------------------------- /new MQTT protocol V5 compatible libraries/examples/SIM800_FULL_LOOP_tst_MQTT_V5.ino: -------------------------------------------------------------------------------- 1 | /* 2 | *complete this description: 3 | *This example demonstrates how to use the MQTT library with the SIM800 module to publish and subscribe to messages on an MQTT broker. 4 | *The example initializes the SIM800 module and establishes a GPRS connection for MQTT communication. 5 | *It then connects to an MQTT broker, subscribes to a topic, and publishes a test message. 6 | *The example also periodically publishes a message and checks for incoming messages from the broker. 7 | *key Updates: 8 | *readSerialChunks() Function: 9 | * 10 | *Reads incoming data in smaller chunks to avoid overflowing the inputBuffer. 11 | *Appends chunks to inputBuffer if space allows. 12 | *Integration in loop(): 13 | * 14 | *Continuously reads incoming data using readSerialChunks() and processes complete MQTT messages using processMQTTMessages(). 15 | *Buffer Management: 16 | * 17 | *The inputBuffer is reset after processing to ensure no old data is retained. 18 | *This updated example handles large incoming MQTT messages efficiently and prevents buffer overflows. 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | #define SIM_TX 10 25 | #define SIM_RX 11 26 | 27 | SoftwareSerial SIM800(SIM_TX, SIM_RX); 28 | 29 | #define MAX_MESSAGE_SIZE 128 // Maximum expected MQTT message size 30 | char inputBuffer[MAX_MESSAGE_SIZE]; // Buffer to store incoming data 31 | volatile uint16_t bufferIndex = 0; // Index to track position in the buffer 32 | 33 | #define CHUNK_SIZE 32 // Read in chunks to avoid buffer overflow 34 | 35 | void readSerialChunks() { 36 | while (SIM800.available()) { 37 | char chunk[CHUNK_SIZE + 1] = {0}; // Temporary buffer 38 | int len = SIM800.readBytes(chunk, CHUNK_SIZE); 39 | chunk[len] = '\0'; // Null-terminate 40 | 41 | // Append to the main buffer 42 | if (bufferIndex + len < MAX_MESSAGE_SIZE) { 43 | strcat(inputBuffer, chunk); 44 | bufferIndex += len; 45 | } else { 46 | Serial.println("Error: Buffer Overflow in readSerialChunks"); 47 | } 48 | } 49 | } 50 | 51 | extern uint8_t preallocated_mqtt_buffer[]; 52 | 53 | // Configuration for GPRS and MQTT 54 | const char *apn = "your-apn"; // Replace with your APN 55 | const char *mqtt_broker = "mqtt.example.com"; // Replace with your MQTT broker 56 | const int mqtt_port = 1883; 57 | const char *client_id = "arduino_client"; 58 | const char *topic_publish = "test/publish"; 59 | const char *topic_subscribe = "test/subscribe"; 60 | 61 | // Payload to publish 62 | const char *payload = "{\"message\": \"Hello, MQTT V5!\"}"; 63 | 64 | // Flags 65 | bool gprsReady = false; 66 | 67 | void setup() { 68 | Serial.begin(9600); // Debugging interface 69 | SIM800.begin(9600); // SIM800 communication 70 | 71 | Serial.println("Initializing SIM800..."); 72 | 73 | // Ensure SIM800 communication 74 | sendATCommand("AT"); 75 | sendATCommand("AT+CSQ"); // Check signal strength 76 | 77 | // Configure GPRS 78 | gprsReady = configureGPRS(); 79 | if (!gprsReady) { 80 | Serial.println("GPRS configuration failed. Restarting..."); 81 | while (1); 82 | } 83 | 84 | // Connect to the MQTT broker 85 | connectToMQTTBroker(); 86 | 87 | // Subscribe to a topic 88 | subscribeToTopic(topic_subscribe); 89 | 90 | // Publish a test message 91 | publishMessage(topic_publish, payload); 92 | } 93 | 94 | void loop() { 95 | // Publish periodically 96 | static unsigned long lastPublishTime = 0; 97 | if (millis() - lastPublishTime > 5000) { 98 | publishMessage(topic_publish, "{\"message\": \"Periodic Hello, MQTT V5!\"}"); 99 | lastPublishTime = millis(); 100 | } 101 | 102 | // Read incoming serial chunks 103 | readSerialChunks(); 104 | 105 | // Process buffered MQTT messages 106 | processMQTTMessages(); 107 | } 108 | 109 | void sendATCommand(const char *command, const char *expectedResponse = "OK", unsigned long timeout = 2000) { 110 | Serial.print("Sending: "); 111 | Serial.println(command); 112 | 113 | SIM800.println(command); 114 | unsigned long start = millis(); 115 | while (millis() - start < timeout) { 116 | if (SIM800.available()) { 117 | String response = SIM800.readString(); 118 | Serial.println("Response: " + response); 119 | if (response.indexOf(expectedResponse) != -1) { 120 | return; // Command executed successfully 121 | } 122 | } 123 | } 124 | Serial.println("Command timeout or failed."); 125 | } 126 | 127 | bool configureGPRS() { 128 | Serial.println("Configuring GPRS..."); 129 | 130 | // Set APN 131 | String command = String("AT+CGDCONT=1,\"IP\",\"") + apn + "\""; 132 | sendATCommand(command.c_str()); 133 | 134 | // Activate PDP context 135 | sendATCommand("AT+CGACT=1,1"); 136 | 137 | // Check GPRS registration 138 | sendATCommand("AT+CGREG?"); 139 | return true; 140 | } 141 | 142 | void connectToMQTTBroker() { 143 | Serial.println("Connecting to MQTT broker..."); 144 | 145 | // Setup MQTT configuration 146 | mqtt_property connect_properties[1]; 147 | uint8_t session_expiry[4] = {0, 0, 0, 60}; // Session expiry: 60 seconds 148 | connect_properties[0].property_id = 0x11; 149 | connect_properties[0].length = 4; 150 | connect_properties[0].value = session_expiry; 151 | 152 | int result = mqtt_v5_connect_message(preallocated_mqtt_buffer, client_id, connect_properties, 1); 153 | if (result != 0) { 154 | Serial.println("Error constructing CONNECT message."); 155 | return; 156 | } 157 | 158 | sendMQTTMessage(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 159 | Serial.println("CONNECT message sent."); 160 | } 161 | 162 | void subscribeToTopic(const char *topic) { 163 | Serial.print("Subscribing to topic: "); 164 | Serial.println(topic); 165 | 166 | mqtt_property subscribe_properties[1]; 167 | uint8_t subscription_identifier[2] = {0x00, 0x01}; // Subscription identifier 168 | subscribe_properties[0].property_id = 0x0B; 169 | subscribe_properties[0].length = 2; 170 | subscribe_properties[0].value = subscription_identifier; 171 | 172 | int result = mqtt_v5_subscribe_message(preallocated_mqtt_buffer, topic, 1, subscribe_properties, 1); 173 | if (result != 0) { 174 | Serial.println("Error constructing SUBSCRIBE message."); 175 | return; 176 | } 177 | 178 | sendMQTTMessage(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 179 | Serial.println("SUBSCRIBE message sent."); 180 | } 181 | 182 | void publishMessage(const char *topic, const char *message) { 183 | Serial.print("Publishing message to topic: "); 184 | Serial.println(topic); 185 | 186 | mqtt_property publish_properties[1]; 187 | uint8_t content_type[] = "application/json"; // Content type property 188 | publish_properties[0].property_id = 0x03; 189 | publish_properties[0].length = strlen((char *)content_type); 190 | publish_properties[0].value = content_type; 191 | 192 | int result = mqtt_v5_publish_message(preallocated_mqtt_buffer, topic, message, publish_properties, 1); 193 | if (result != 0) { 194 | Serial.println("Error constructing PUBLISH message."); 195 | return; 196 | } 197 | 198 | sendMQTTMessage(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 199 | Serial.println("PUBLISH message sent."); 200 | } 201 | 202 | void sendMQTTMessage(const uint8_t *message, uint16_t length) { 203 | SIM800.println("AT+CIPSEND"); 204 | delay(500); 205 | SIM800.write(message, length); 206 | SIM800.write((char)26); // End of message (Ctrl+Z) 207 | } 208 | 209 | void processMQTTMessages() { 210 | if (bufferIndex > 0) { 211 | Serial.print("Processing MQTT Message: "); 212 | Serial.println(inputBuffer); 213 | 214 | // Reset the buffer after processing 215 | memset(inputBuffer, 0, MAX_MESSAGE_SIZE); 216 | bufferIndex = 0; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /new MQTT protocol V5 compatible libraries/examples/SIM800_FULL_LOOP_tst_MQTT_V5_JSON.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * complete description: This example demonstrates how to use the MQTT library with the SIM800 module to publish and subscribe to messages on an MQTT broker. 3 | * The example initializes the SIM800 module and establishes a GPRS connection for MQTT communication. 4 | * It then connects to an MQTT broker, subscribes to a topic, and publishes a test message. 5 | * The example also periodically publishes a message and checks for incoming messages from the broker. 6 | * key Updates: 7 | * readSerialChunks() Function: 8 | * JSON Parsing: 9 | * The example uses the ArduinoJson library to parse incoming JSON messages. 10 | * The JSON message is parsed and the topic and payload are extracted for further processing. 11 | * Integration in loop(): 12 | * Continuously reads incoming data using readSerialChunks() and processes complete MQTT messages using processMQTTMessages(). 13 | * Buffer Management: 14 | * The inputBuffer is reset after processing to ensure no old data is retained. 15 | * This updated example handles large incoming MQTT messages efficiently and prevents buffer overflows. 16 | * 17 | */ 18 | #include 19 | #include 20 | #include 21 | 22 | #define SIM_TX 10 23 | #define SIM_RX 11 24 | 25 | SoftwareSerial SIM800(SIM_TX, SIM_RX); 26 | 27 | #define MAX_MESSAGE_SIZE 128 // Maximum expected MQTT message size 28 | char inputBuffer[MAX_MESSAGE_SIZE]; // Buffer to store incoming data 29 | volatile uint16_t bufferIndex = 0; // Index to track position in the buffer 30 | 31 | #define CHUNK_SIZE 32 // Read in chunks to avoid buffer overflow 32 | 33 | void readSerialChunks() { 34 | // Continuously read incoming data in fixed-size chunks 35 | while (SIM800.available()) { 36 | // Temporary buffer to hold one chunk of incoming data. 37 | char chunk[CHUNK_SIZE + 1] = {0}; 38 | int len = simSerial->readBytes(chunk, CHUNK_SIZE); 39 | chunk[len] = '\0'; // Ensure the chunk is null-terminated. 40 | 41 | // Check if there is enough space remaining in inputBuffer. 42 | if (bufferIndex + len < MAX_MESSAGE_SIZE) { 43 | // Copy the chunk directly into inputBuffer at the current bufferIndex. 44 | memcpy(inputBuffer + bufferIndex, chunk, len); 45 | bufferIndex += len; 46 | // Ensure the overall inputBuffer is null-terminated after appending. 47 | inputBuffer[bufferIndex] = '\0'; 48 | } else { 49 | Serial.println("Error: Buffer Overflow in readSerialChunks"); 50 | // Optionally, handle overflow here (e.g., discard incoming data or reset the buffer) 51 | memset(inputBuffer, 0, MAX_MESSAGE_SIZE); 52 | bufferIndex = 0; 53 | break; // Exit the loop, or you might continue depending on your error handling strategy. 54 | } 55 | } 56 | } 57 | 58 | extern uint8_t preallocated_mqtt_buffer[]; 59 | 60 | // Configuration for GPRS and MQTT 61 | const char *apn = "your-apn"; // Replace with your APN 62 | const char *mqtt_broker = "mqtt.example.com"; // Replace with your MQTT broker 63 | const int mqtt_port = 1883; 64 | const char *client_id = "arduino_client"; 65 | const char *topic_publish = "test/publish"; 66 | const char *topic_subscribe = "test/subscribe"; 67 | 68 | // Payload to publish 69 | const char *payload = "{\"temperature\": 25, \"humidity\": 60}"; 70 | 71 | void setup() { 72 | Serial.begin(9600); // Debugging interface 73 | SIM800.begin(9600); // SIM800 communication 74 | 75 | Serial.println("Initializing SIM800..."); 76 | 77 | // Ensure SIM800 communication 78 | sendATCommand("AT"); 79 | sendATCommand("AT+CSQ"); // Check signal strength 80 | 81 | // Configure GPRS 82 | configureGPRS(); 83 | 84 | // Connect to the MQTT broker 85 | connectToMQTTBroker(); 86 | 87 | // Subscribe to a topic 88 | subscribeToTopic(topic_subscribe); 89 | 90 | // Publish a test message 91 | publishMessage(topic_publish, payload); 92 | } 93 | 94 | void loop() { 95 | // Publish periodically 96 | static unsigned long lastPublishTime = 0; 97 | if (millis() - lastPublishTime > 10000) { // Publish every 10 seconds 98 | publishMessage(topic_publish, "{\"temperature\": 26, \"humidity\": 65}"); 99 | lastPublishTime = millis(); 100 | } 101 | 102 | // Read incoming serial chunks 103 | readSerialChunks(); 104 | 105 | // Process buffered MQTT messages 106 | processMQTTMessages(); 107 | } 108 | 109 | void sendATCommand(const char *command, const char *expectedResponse = "OK", unsigned long timeout = 2000) { 110 | Serial.print("Sending: "); 111 | Serial.println(command); 112 | 113 | SIM800.println(command); 114 | unsigned long start = millis(); 115 | while (millis() - start < timeout) { 116 | if (SIM800.available()) { 117 | String response = SIM800.readString(); 118 | Serial.println("Response: " + response); 119 | if (response.indexOf(expectedResponse) != -1) { 120 | return; // Command executed successfully 121 | } 122 | } 123 | } 124 | Serial.println("Command timeout or failed."); 125 | } 126 | 127 | void configureGPRS() { 128 | Serial.println("Configuring GPRS..."); 129 | String command = String("AT+CGDCONT=1,\"IP\",\"") + apn + "\""; 130 | sendATCommand(command.c_str()); 131 | sendATCommand("AT+CGACT=1,1"); 132 | sendATCommand("AT+CGREG?"); 133 | } 134 | 135 | void connectToMQTTBroker() { 136 | Serial.println("Connecting to MQTT broker..."); 137 | mqtt_property connect_properties[1]; 138 | uint8_t session_expiry[4] = {0, 0, 0, 60}; // Session expiry: 60 seconds 139 | connect_properties[0].property_id = 0x11; 140 | connect_properties[0].length = 4; 141 | connect_properties[0].value = session_expiry; 142 | 143 | int result = mqtt_v5_connect_message(preallocated_mqtt_buffer, client_id, connect_properties, 1); 144 | if (result != 0) { 145 | Serial.println("Error constructing CONNECT message."); 146 | return; 147 | } 148 | 149 | sendMQTTMessage(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 150 | Serial.println("CONNECT message sent."); 151 | } 152 | 153 | void subscribeToTopic(const char *topic) { 154 | Serial.print("Subscribing to topic: "); 155 | Serial.println(topic); 156 | 157 | mqtt_property subscribe_properties[1]; 158 | uint8_t subscription_identifier[2] = {0x00, 0x01}; // Subscription identifier 159 | subscribe_properties[0].property_id = 0x0B; 160 | subscribe_properties[0].length = 2; 161 | subscribe_properties[0].value = subscription_identifier; 162 | 163 | int result = mqtt_v5_subscribe_message(preallocated_mqtt_buffer, topic, 1, subscribe_properties, 1); 164 | if (result != 0) { 165 | Serial.println("Error constructing SUBSCRIBE message."); 166 | return; 167 | } 168 | 169 | sendMQTTMessage(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 170 | Serial.println("SUBSCRIBE message sent."); 171 | } 172 | 173 | void publishMessage(const char *topic, const char *message) { 174 | Serial.print("Publishing message to topic: "); 175 | Serial.println(topic); 176 | 177 | mqtt_property publish_properties[1]; 178 | uint8_t content_type[] = "application/json"; // Content type property 179 | publish_properties[0].property_id = 0x03; 180 | publish_properties[0].length = strlen((char *)content_type); 181 | publish_properties[0].value = content_type; 182 | 183 | int result = mqtt_v5_publish_message(preallocated_mqtt_buffer, topic, message, publish_properties, 1); 184 | if (result != 0) { 185 | Serial.println("Error constructing PUBLISH message."); 186 | return; 187 | } 188 | 189 | sendMQTTMessage(preallocated_mqtt_buffer, strlen((char *)preallocated_mqtt_buffer)); 190 | Serial.println("PUBLISH message sent."); 191 | } 192 | 193 | void sendMQTTMessage(const uint8_t *message, uint16_t length) { 194 | SIM800.println("AT+CIPSEND"); 195 | delay(500); 196 | SIM800.write(message, length); 197 | SIM800.write((char)26); // End of message (Ctrl+Z) 198 | } 199 | 200 | void processMQTTMessages() { 201 | if (bufferIndex > 0) { 202 | Serial.print("Processing MQTT Message: "); 203 | Serial.println(inputBuffer); 204 | 205 | // Parse JSON response 206 | StaticJsonDocument<128> doc; 207 | DeserializationError error = deserializeJson(doc, inputBuffer); 208 | if (error) { 209 | Serial.print("JSON Parse Error: "); 210 | Serial.println(error.c_str()); 211 | } else { 212 | // Extract JSON fields 213 | const char *topic = doc["topic"]; 214 | const char *payload = doc["payload"]; 215 | 216 | Serial.print("Topic: "); 217 | Serial.println(topic); 218 | Serial.print("Payload: "); 219 | Serial.println(payload); 220 | } 221 | 222 | // Reset the buffer after processing 223 | memset(inputBuffer, 0, MAX_MESSAGE_SIZE); 224 | bufferIndex = 0; 225 | } 226 | } 227 | --------------------------------------------------------------------------------