Updated May 2025
coreMQTT Demo (without TLS)
coreMQTT is an MIT licensed open source MQTT C library for microcontroller and small microprocessor based IoT devices.
- On this Page
Notice: We recommend using mutual authentication in any Internet of Things (IoT) application. The demo on this page is only meant for educational purposes as it demonstrates MQTT communication prior to introducing encryption and authentication. It is not intended to be suitable for production use.
Single Threaded Vs Multi Threaded
There are two coreMQTT usage models, single threaded and multithreaded (multitasking). Using the MQTT library solely from one thread within an otherwise multi-threaded application, as the demo documented on this page does, is equivalent to the single threaded use case. Single threaded use cases require the application writer to make repeated explicit calls into the MQTT library. Multithreaded use cases can instead execute the MQTT protocol in the background within an agent (or daemon) task. Executing the MQTT protocol in an agent task removes the need for the application writer to explicitly manage any MQTT state or call the
MQTT_ProcessLoop()
Demo Introduction
This example project is one of three that introduce the concepts described on the "TLS Introduction" page one at a time. The first example (this page) demonstrates unencrypted MQTT communication. The second example builds on the first to introduce server authentication (where the IoT client authenticates the MQTT server it connects to). The third example builds on the second to introduce strong mutual authentication (where the MQTT server also authenticates the IoT client connecting to it).
This first project in the series only demonstrated the basic MQTT use cases of how to connect to a MQTT broker and the subscribe-publish workflow of MQTT at the QoS 0 level. After it subscribes to a single topic filter, it publishes to that topic, then waits to receive that same message back from the server. This cycle of publishing to the broker and receiving the same message back from the broker is repeated indefinitely. As it uses QoS 0 it does not implement any retransmission mechanism for publish messages.
This demo does not create a secure connection and is therefore not suitable for production use - do not send any confidential information on an unencrypted network connection. The demo does demonstrate how to connect with an exponential backoff time (including timing jitter) in the event of a connection failure. Exponentially increasing the time between connection attempts and including some random timing jitter is best practice for large IoT device fleets as it prevents all the IoT devices attempting to reconnect at the same time should they all become disconnected at the same time.
This basic MQTT demo project uses
the FreeRTOS Windows port, enabling it
to be built and evaluated with the free Community version of Visual Studio
on Windows, so without the need for any particular MCU hardware.
Source Code Organization
The demo project is called mqtt_plain_text_demo.sln and can be found in the FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text directory of the main FreeRTOS download (and in Github, linked from the download page).
Configuring the Demo Project
The demo uses the FreeRTOS-Plus-TCP TCP/IP stack, so follow the instructions provided for the TCP/IP starter project to ensure you:
- Have the pre-requisite components installed (such as WinPCap).
- Optionally set a static or dynamic IP address, gateway address and netmask.
- Optionally set a MAC address.
- Select an Ethernet network interface on your host machine.
- …and importantly test your network connection before attempting to run the MQTT demo.
Each demo project has its own configuration settings. When you are following the network configuration instructions, make sure to apply the settings in the MQTT demo project, rather than the TCP/IP starter project. By default the TCP/IP stack is configured to use a dynamic IP address.
Configuring the MQTT Broker Connection
Option 1: Using the publicly hosted Mosquitto MQTT broker (web hosted)
The demo project can communicate with Mosquitto's publicly hosted message broker at “test.mosquitto.org”. This should
work if the demo connects to a network that has a DHCP service and Internet access. Note that the FreeRTOS Windows
port only works with a wired Ethernet network adapter, which can be a virtual Ethernet adapter. You should use a
separate MQTT client, such as MQTT.fx, to test the MQTT connection from your host machine
to the public MQTT broker. To use the hosted Mosquitto server:
- Open your local copy of /FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/demo_config.h
- Add the following lines:
- #define democonfigMQTT_BROKER_ENDPOINT "test.mosquitto.org"
- #define democonfigMQTT_BROKER_PORT ( 1883 )
Note: Mosquitto is an open source MQTT message broker that supports MQTT versions 5.0, 3.1.1, and 3.1.
It is part of the Eclipse foundation and is an Eclipse IoT project. The
test.mosquitto.org MQTT broker is not affiliated with or maintained by FreeRTOS and may be unavailable
at any time.
Option 2: Using a locally hosted Mosquitto MQTT message broker (host machine)
The Mosquitto broker can also run locally, either on your host machine (the machine used to build the demo application), or another machine on your local network. To do this:
- Follow the instructions on https://mosquitto.org/download/
to download and install Mosquitto locally.
- Open “mosquitto.conf”, which is located in the Mosquitto install directory, and set the “bind_address” to the network
on which Mosquitto will listen for connection on your system.
- NOTE: Starting from Mosquitto Version 2.0.0, when the Mosquitto broker is run without configuring any listener
it will now bind to the loopback interfaces
and/or127.0.0.1, limiting the inbound connections to only from the local host. Also, all listeners now default to::1allow_anonymousfalse, preventing the clients from connecting without providing a username. As a result, both
andlistenerneed to be specified explicitly in theallow_anonymousconfiguration file:mosquitto.conf1listener 18832allow_anonymous true - To start Mosquitto with a custom configuration file use: mosquitto -v -c <path/to/config/file>
- NOTE: Starting from Mosquitto Version 2.0.0, when the Mosquitto broker is run without configuring any
- Find the IP address of your host machine (run the command on Windows, oripconfigon Linux or MAC OS). Note that the FreeRTOS Windows port only works with a wired Ethernet network adapter, which can be a virtual Ethernet adapter.ifconfig
- Open .FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/demo_config.h
- Add the following lines to set democonfigMQTT_BROKER_ENDPOINT to the IP address of the machine on which Mosquitto is
running, which must be a machine on the same subnet as the network to which the demo is connected:
- #define democonfigMQTT_BROKER_ENDPOINT "w.x.y.z"
- #define democonfigMQTT_BROKER_PORT ( 1883 )
You should use a separate MQTT client, such as MQTT.fx, to test the MQTT connection from your
host machine to the installed MQTT broker.
Note: Port number 1883 is the default port number for unencrypted MQTT. If you cannot use that port (for example if it is blocked by your IT security policy) then change the port used by Mosquitto to a high port number (for example something in the 50000 to 55000 range), and set
mqttexampleMQTT_BROKER_PORT
Option 3: Any other unencrypted MQTT broker of your choosing:
Any MQTT broker that supports unencrypted TCP/IP communication can also be used with this demo. To do this:
- Open your local copy of /FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/demo_config.h
- Add the following lines with settings specific to your chosen broker:
- #define democonfigMQTT_BROKER_ENDPOINT "your-desired-endpoint"
- #define democonfigMQTT_BROKER_PORT ( 1883 )
Building the Demo Project
The demo project uses the free community edition of Visual Studio.
To build the demo:
- Open the Visual Studio solution file from within the Visual Studio IDE/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/mqt_plain_text_demo.sln
- Select ‘build solution’ from the IDE’s ‘build’ menu
Functionality
The demo creates a single application task that loops through a set of examples that demonstrate how to connect to the broker, subscribe to a topic on the broker, publish to a topic on the broker, and disconnect from the broker again. The demo application both subscribes to and publishes to the same topic, as a result of which each time the demo publishes a message to the MQTT broker the broker sends the same message back to the demo application. The structure of the demo is shown below:
1static void prvMQTTDemoTask( void * pvParameters )2{34 uint32_t ulPublishCount = 0U, ulTopicCount = 0U;5 const uint32_t ulMaxPublishCount = 5UL;6 NetworkContext_t xNetworkContext = { 0 };7 MQTTContext_t xMQTTContext;8 MQTTStatus_t xMQTTStatus;9 PlaintextTransportStatus_t xNetworkStatus;1011 /***12 * For readability, error handling in this function is restricted to13 * the use of asserts().14 ***/1516 for( ; ; )17 {18 /*************************** Connect. *********************************/1920 /* Attempt to connect to the MQTT broker. The socket is returned in21 * the network context structure. */22 xNetworkStatus = prvConnectToServerWithBackoffRetries( &xNetworkContext );23 configASSERT( xNetworkStatus == PLAINTEXT_TRANSPORT_SUCCESS );2425 /* Connect to the MQTT broker using the already connected TCP socket. */26 prvCreateMQTTConnectionWithBroker( &xMQTTContext, &xNetworkContext );2728 /**************************** Subscribe. ******************************/2930 /* Subscribe to the test topic. */31 prvMQTTSubscribeWithBackoffRetries( &xMQTTContext );3233 /******************* Publish and Keep Alive Loop. *********************/3435 /* Publish messages with QoS0, then send and process Keep Alive36 * messages. */37 for( ulPublishCount = 0; ulPublishCount < ulMaxPublishCount; ulPublishCount++ )38 {39 prvMQTTPublishToTopic( &xMQTTContext );4041 /* Process the incoming publish echo. Since the application subscribed42 * to the same topic, the broker will send the same publish message43 * back to the application. Note there is a separate demo that44 * shows how to use coreMQTT in a thread safe way - in which case the45 * MQTT protocol runs in the background and this call is not46 * required. */47 xMQTTStatus = MQTT_ProcessLoop( &xMQTTContext, mqttexamplePROCESS_LOOP_TIMEOUT_MS );48 configASSERT( xMQTTStatus == MQTTSuccess );4950 /* Leave the connection idle for some time. */51 vTaskDelay( mqttexampleDELAY_BETWEEN_PUBLISHES );52 }5354 /******************** Unsubscribe from the topic. *********************/5556 prvMQTTUnsubscribeFromTopic( &xMQTTContext );5758 /* Process the incoming packet from the broker. Note there is a separate59 * demo that shows how to use coreMQTT in a thread safe way - in which case60 * the MQTT protocol runs in the background and this call is not required. */61 xMQTTStatus = MQTT_ProcessLoop( &xMQTTContext, mqttexamplePROCESS_LOOP_TIMEOUT_MS );62 configASSERT( xMQTTStatus == MQTTSuccess );6364 /**************************** Disconnect. *****************************/6566 xMQTTStatus = MQTT_Disconnect( &xMQTTContext );6768 /* Close the network connection. */69 xNetworkStatus = Plaintext_FreeRTOS_Disconnect( &xNetworkContext );70 configASSERT( xNetworkStatus == PLAINTEXT_TRANSPORT_SUCCESS );7172 /* Wait for some time between two iterations to ensure that we do not73 * bombard the MQTT broker. */74 vTaskDelay( mqttexampleDELAY_BETWEEN_DEMO_ITERATIONS );75 }76}
Connecting to the MQTT Broker
In the function above,
prvConnectToServerWithBackoffRetries()
The function
prvCreateMQTTConnectionWithBroker()
FreeRTOS-Plus/Source/Application-Protocols/platform/freertos/transport/src/plaintext_freertos.c
prvCreateMQTTConnectionWithBroker()
xConnectInfo
The function below shows how FreeRTOS-Plus-TCP transport interface and time function are set in MQTT Context using MQTT_Init(). It also shows how event callback function pointer (
prvEventCallback
1static void prvCreateMQTTConnectionWithBroker( MQTTContext_t * pxMQTTContext, NetworkContext_t * pxNetworkContext )2{3 MQTTStatus_t xResult;4 MQTTConnectInfo_t xConnectInfo;5 bool xSessionPresent;6 TransportInterface_t xTransport;78 /***9 * For readability, error handling in this function is restricted to10 * the use of asserts().11 ***/1213 /* Fill in [Transport Interface](/Documentation/03-Libraries/03-FreeRTOS-core/06-Transport-Interface/01-Transport-interface) send and receive function pointers. */14 xTransport.pNetworkContext = pxNetworkContext;15 xTransport.send = Plaintext_FreeRTOS_send;16 xTransport.recv = Plaintext_FreeRTOS_recv;1718 /* Initialize MQTT library. */19 xResult = MQTT_Init(20 pxMQTTContext,21 &xTransport,22 prvGetTimeMs,23 prvEventCallback,24 &xBuffer );25 configASSERT( xResult == MQTTSuccess );2627 /* Many fields not used in this demo so start with everything at 0. */28 ( void ) memset( ( void * ) &xConnectInfo, 0x00, sizeof( xConnectInfo ) );2930 /* Start with a clean session i.e. direct the MQTT broker to discard any31 * previous session data. Also, establishing a connection with clean32 * session will ensure that the broker does not store any data when this33 * client gets disconnected. */34 xConnectInfo.cleanSession = true;3536 /* The client identifier is used to uniquely identify this MQTT client to37 * the MQTT broker. In a production device the identifier can be something38 * unique, such as a device serial number. */39 xConnectInfo.pClientIdentifier = democonfigCLIENT_IDENTIFIER;40 xConnectInfo.clientIdentifierLength = ( uint16_t ) strlen( democonfigCLIENT_IDENTIFIER );4142 /* Set MQTT keep-alive period. It is the responsibility of the application43 * to ensure that the interval between Control Packets being sent does not44 * exceed the Keep Alive value. In the absence of sending any other45 * Control Packets, the Client MUST send a PINGREQ Packet. */46 xConnectInfo.keepAliveSeconds = mqttexampleKEEP_ALIVE_TIMEOUT_SECONDS;4748 /* Send MQTT CONNECT packet to broker. LWT is not used in this demo, so it49 * is passed as NULL. */50 xResult = MQTT_Connect(51 pxMQTTContext,52 &xConnectInfo,53 NULL,54 mqttexampleCONNACK_RECV_TIMEOUT_MS,55 &xSessionPresent );56 configASSERT( xResult == MQTTSuccess );57}58
Subscribing to a MQTT Topic
The function
prvMQTTSubscribeWithBackoffRetries()
1static const char *const pcExampleTopic = "/example/topic";23static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext )4{5 MQTTStatus_t xResult = MQTTSuccess;6 RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess;7 RetryUtilsParams_t xRetryParams;8 MQTTSubscribeInfo_t xMQTTSubscription[ mqttexampleTOPIC_COUNT ];9 bool xFailedSubscribeToTopic = false;1011 /***12 * For readability, error handling in this function is restricted to13 * the use of asserts().14 ***/1516 /* Some fields not used by this demo so start with everything at 0. */17 ( void ) memset( ( void * ) &xMQTTSubscription, 0x00, sizeof( xMQTTSubscription ) );1819 /* Each packet requires a unique ID. */20 usSubscribePacketIdentifier = MQTT\_GetPacketId( pxMQTTContext );2122 /* Subscribe to the pcExampleTopic topic filter. This example subscribes23 * to only one topic and uses QoS0. */24 xMQTTSubscription[ 0 ].qos = MQTTQoS0;25 xMQTTSubscription[ 0 ].pTopicFilter = pcExampleTopic;26 xMQTTSubscription[ 0 ].topicFilterLength = strlen( pcExampleTopic );2728 /* Initialize retry attempts and interval. */29 RetryUtils_ParamsReset( &xRetryParams );30 xRetryParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS;3132 do33 {3435 /* The client is already connected to the broker. Subscribe to the topic36 * as specified in pcExampleTopic by sending a subscribe packet then37 * waiting for a subscribe acknowledgment (SUBACK). */38 xResult = MQTT_Subscribe(39 pxMQTTContext,40 xMQTTSubscription,41 1, /* Only subscribing to one topic. */42 usSubscribePacketIdentifier );43 configASSERT( xResult == MQTTSuccess );4445 /* Process incoming packet from the broker. After sending the46 * subscribe, the client may receive a publish before it receives a47 * subscribe ack. Therefore, call generic incoming packet processing48 * function. Since this demo is subscribing to the topic to which no49 * one is publishing, probability of receiving Publish message before50 * subscribe ack is zero; but application must be ready to receive any51 * packet. This demo uses the generic packet processing function52 * everywhere to highlight this fact. Note there is a separate demo that53 * shows how to use coreMQTT in a thread safe way – in which case the54 * MQTT protocol runs in the background and this call is not required. */55 xResult = MQTT_ProcessLoop( pxMQTTContext, mqttexamplePROCESS_LOOP_TIMEOUT_MS );56 configASSERT( xResult == MQTTSuccess );5758 /* Reset flag before checking suback responses. */59 xFailedSubscribeToTopic = false;6061 /* Check if recent subscription request has been rejected.62 * #xTopicFilterContext is updated in the event callback (shown in a63 * code block below) to reflect the status of the SUBACK sent by the64 * broker. It represents either the QoS level granted by the server upon65 * subscription, or acknowledgment of server rejection of the66 * subscription request. */67 if( xTopicFilterContext.xSubAckStatus == MQTTSubAckFailure )68 {69 xFailedSubscribeToTopic = true;70 xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xRetryParams );71 break;72 }73 configASSERT( xRetryUtilsStatus != RetryUtilsRetriesExhausted );74 }75 while( ( xFailedSubscribeToTopic == true ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) );76}
Publishing to a Topic
The function
prvMQTTPublishToTopic()
1static const char *const pcExampleTopic = "/example/topic";23static void prvMQTTPublishToTopic( MQTTContext_t * pxMQTTContext )4{5 MQTTStatus_t xResult;6 MQTTPublishInfo_t xMQTTPublishInfo;78 /***9 * For readability, error handling in this function is restricted to the10 * use of asserts().11 ***/1213 /* Some fields are not used by this demo so start with everything at 0. */14 ( void ) memset( ( void * ) &xMQTTPublishInfo, 0x00, sizeof( xMQTTPublishInfo ) );1516 /* This demo uses QoS0. */17 xMQTTPublishInfo.qos = MQTTQoS0;18 xMQTTPublishInfo.retain = false;19 xMQTTPublishInfo.pTopicName = pcExampleTopic;20 xMQTTPublishInfo.topicNameLength = ( uint16_t ) strlen( pcExampleTopic );21 xMQTTPublishInfo.pPayload = mqttexampleMESSAGE;22 xMQTTPublishInfo.payloadLength = strlen( mqttexampleMESSAGE );2324 /* Send PUBLISH packet. Packet ID is not used for a QoS0 publish. */25 xResult = MQTT_Publish(26 pxMQTTContext,27 &xMQTTPublishInfo,28 0U );29 configASSERT( xResult == MQTTSuccess );3031}
Receiving incoming messages
The application registers an event callback function before connecting to the broker as described earlier. The function
prvMQTTDemoTask()
MQTT_ProcessLoop()
prvEventCallback()
prvMQTTProcessIncomingPublish()
prvMQTTProcessResponse()
1static void prvEventCallback( MQTTContext_t * pxMQTTContext, MQTTPacketInfo_t * pxPacketInfo, MQTTDeserializedInfo_t * pxDeserializedInfo )2{3 /* The MQTT context is not used for this demo. */4 ( void ) pxMQTTContext;56 if( ( pxPacketInfo->type & 0xF0U ) == MQTT_PACKET_TYPE_PUBLISH )7 {8 prvMQTTProcessIncomingPublish( pxDeserializedInfo->pPublishInfo );9 }10 else11 {12 prvMQTTProcessResponse( pxPacketInfo, pxDeserializedInfo->packetIdentifier );13 }14}
Processing Incoming MQTT Publish Packets
The function
prvMQTTProcessIncomingPublish()
prvMQTTProcessResonse()
1static const char *const pcExampleTopic = "/example/topic";23static void prvMQTTProcessIncomingPublish( MQTTPublishInfo_t * pxPublishInfo )4{5 /* Verify the received publish is for the we have subscribed to. */6 if( ( pxPublishInfo->topicNameLength == strlen( pcExampleTopic ) ) &&7 ( 0 == strcmp( pcExampleTopic, pxPublishInfo->pTopicName ) ) )8 {9 LogInfo( ( "Incoming Publish Topic Name: %.*s matches subscribed topic.\r\n"10 "Incoming Publish Message : %.*s",11 pxPublishInfo->topicNameLength,12 pxPublishInfo->pTopicName,13 pxPublishInfo->payloadLength,14 pxPublishInfo->pPayload ) );15 }1617 else18 {19 LogInfo( ( "Incoming Publish Topic Name: %.*s does not match subscribed topic.",20 pxPublishInfo->topicNameLength,21 pxPublishInfo->pTopicName ) );22 }23}2425static void prvMQTTProcessResponse( MQTTPacketInfo_t * pxIncomingPacket, uint16_t usPacketId )26{27 MQTTStatus_t xResult = MQTTSuccess;28 uint8_t * pucPayload = NULL;29 size_t ulSize = 0;3031 switch( pxIncomingPacket->type )32 {33 case MQTT_PACKET_TYPE_SUBACK:34 /* A SUBACK from the broker, containing the server response to our35 * subscription request, has been received. It contains the status36 * code indicating server approval/rejection for the subscription to37 * the single topic requested. The SUBACK will be parsed to obtain38 * the status code, and this status code will be stored in39 * #xTopicFilterContext. */40 xResult = MQTT_GetSubAckStatusCodes( pxIncomingPacket, &pucPayload, &ulSize );4142 /* MQTT\_GetSubAckStatusCodes always returns success if called with43 * packet info from the event callback and non-NULL parameters. */44 configASSERT( xResult == MQTTSuccess );4546 /* This should be the QOS leve, 0 in this case. */47 xTopicFilterContext.xSubAckStatus = *pucPayload;4849 /* Make sure ACK packet identifier matches with Request packet50 * identifier. */51 configASSERT( usSubscribePacketIdentifier == usPacketId );52 break;5354 case MQTT_PACKET_TYPE_UNSUBACK:55 LogInfo( ( "Unsubscribed from the topic %s.", mqttexampleTOPIC ) );5657 /* Make sure ACK packet identifier matches with Request packet58 * identifier. */59 configASSERT( usUnsubscribePacketIdentifier == usPacketId );60 break;6162 case MQTT_PACKET_TYPE_PINGRESP:6364 /* Nothing to be done from application as library handles65 * PINGRESP with the use of MQTT\_ProcessLoop API function. */66 LogWarn( ( "PINGRESP should not be handled by the application "67 "callback when using MQTT_ProcessLoop.\n" ) );68 break;6970 /* Any other packet type is invalid. */71 default:72 LogWarn( ( "prvMQTTProcessResponse() called with unknown packet type:(%02X).", pxIncomingPacket->type ) );73 }74}
Unsubscribing from a Topic
The last step in the workflow is to unsubscribe from the topic so that the broker will no longer send any publishes from
pcExampleTopic
1static const char *const pcExampleTopic = "/example/topic";23static void prvMQTTUnsubscribeFromTopic( MQTTContext_t * pxMQTTContext )4{5 MQTTStatus_t xResult;6 MQTTSubscribeInfo_t xMQTTSubscription[ mqttexampleTOPIC_COUNT ];78 /* Some fields not used by this demo so start with everything at 0. */9 ( void ) memset( ( void * ) &xMQTTSubscription, 0x00, sizeof( xMQTTSubscription ) );1011 /* Subscribe to the pcExampleTopic topic filter. This example subscribes12 * to only one topic and uses QoS0. */13 xMQTTSubscription[ 0 ].qos = MQTTQoS0;14 xMQTTSubscription[ 0 ].pTopicFilter = pcExampleTopic;15 xMQTTSubscription[ 0 ].topicFilterLength = ( uint16_t ) strlen( pcExampleTopic);1617 /* Each packet requires a unique ID. */18 usUnsubscribePacketIdentifier = MQTT_GetPacketId( pxMQTTContext );1920 /* Send UNSUBSCRIBE packet. */21 xResult = MQTT_Unsubscribe(22 pxMQTTContext,23 xMQTTSubscription,24 sizeof( xMQTTSubscription ) / sizeof( MQTTSubscribeInfo_t ),25 usUnsubscribePacketIdentifier );26 configASSERT( xResult == MQTTSuccess );27}