Using Device Shadow library's API with MQTT Agent

Continuing the discussion from MQTT_ProcessLoop vs MQTTAgent_CommandLoop (or coreMQTT vs FreeRTOS-Plus-MQTT):

I want to manage my shadow connection using the Device Shadow library’s API in conjunction with the MQTT agent but I can’t figure out how I can get access to the MQTT context that the agent is created internally and use for the shadow APIs (like SubscribeToTopic for example that take the MQTT context pointer as its first parameter)

I assume you are talking about this function: https://github.com/FreeRTOS/FreeRTOS/blob/master/FreeRTOS-Plus/Demo/AWS/Mqtt_Demo_Helpers/mqtt_demo_helpers.h#L88

This function is part of demo and you will need to modify it to work with the MQTT Agent. The parameter should be MQTTContextHandle_t and not MQTTContext_t *. The implementation of the function will need to call MQTTAgent_Subscribe instead of MQTT_Subscribe: https://github.com/FreeRTOS/FreeRTOS/blob/master/FreeRTOS-Plus/Demo/AWS/Mqtt_Demo_Helpers/mqtt_demo_helpers.c#L784

coreMQTT APIs (such as MQTT_Subscribe) are not thread-safe and must be accessed only from the MQTT Agen task. All the application tasks must use MQTT Agent APIs.

Thanks.

Thank you for your answer, but how can I get the MQTTContextHandle_t from the agent?

As per the doc of MQTTAgent_Init API, MQTTContextHandle_t is index of the MQTT context to be used. MQTT Agent manages an internal context array and the application chooses which context to use (by choosing the index akaMQTTContextHandle_t). The size of the internal context array is controlled using MQTT_AGENT_MAX_SIMULTANEOUS_CONNECTIONS configuration macro.

This sub-pub example uses the first MQTT context in the array: https://github.com/FreeRTOS/Lab-Project-coreMQTT-Agent/blob/main/source/simple_sub_pub_demo.c#L97

Thanks.

Thank you,
So I guess using the agent together with the shadow API will not work as this API calls MQTT core services like MQTT_Subscribe and MQTT_ProcessLoop and as you said the MQTT core is not thread safe so this will not work.

Hello @EyalG , The Shadow API is MQTT agnostic, i.e, you can use any MQTT stack with it. I believe you are referring to xSubscribeToTopic() function used in Shadow demo taking the context pointer. That function is not part of the Shadow API, it is just a common helper function used by our demos. You can instead use MQTTAgent_Subscribe. You should able to use Shadow library with MQTT Agent API. I hope it answers your question. Please let us know if you have any further questions.

Thank you for getting back to me on that.

I started to port my existing application that is based on 202002 by using the MQTT agent demo but after long hours of porting and trying to figure out what will be the best approach I abounded that direction, mostly because I saw that the agent is not done yet and I feel its too risky to port to it now.

I took the device shadow demo and I used it as my reference for the porting to 202012.

I believe that by calling the MQTT_ProcessLoop in a single task that will handle both the MQTT receive messages (Acks and subscription responses, mainly delta messages) as well as request for publish (Mainly reported updates) I will have most of the agent functionality that I need and it will be based on the more mature core.

Any input on that approach?

Thanks

I’d like to understand why you had to abandon the earlier approach. Do you have time for a quick call? If so, please DM me your email.

Thanks.

No, that is not correct. MQTT Agent APIs are thread safe and can be called from multiple threads. So you can have 2 threads both of which share the same MQTTContextHandle_t:

  • MQTT Thread - Subscribes and publishes messages using MQTT Agent APIs (MQTTAgent_Subscribe and MQTTAgent_Publish).
  • Shadow Thread - Subscribes and publishes shadow messages using MQTT Agent APIs (MQTTAgent_Subscribe and MQTTAgent_Publish).

You can share the MQTTContextHandle_t by defining it in a common header file. Lets say you have a file app_config.h which contains all the configurations for your application. You define the following in this file:

#define appMQTT_CONTEXT_HANDLE                  ( ( MQTTContextHandle_t ) 0 )

The updated implementation of xSubscribeToTopic should look something like:

BaseType_t xSubscribeToTopic( MQTTContextHandle_t mqttContextHandle,
                                                      const char * pcTopicFilter,
                                                      uint16_t usTopicFilterLength ) <-- May need additional callbacks too. 
{
...
/* Call MQTTAgent_Subscribe. */
...
}

The application should call xSubscribeToTopic like the following:

xSubscribeToTopic( appMQTT_CONTEXT_HANDLE, "/example/topic", sizeof( "/example/topic" ) - 1 );

Thanks.