monstrenyatko / ArduinoMqtt

MQTT client for Arduino
MIT License
72 stars 13 forks source link

How to get topic name in message callback function? #21

Closed kregiel closed 3 years ago

kregiel commented 3 years ago

Hello, I can't get the topic name in useful format (e.g string) from "MqttClient :: MessageData & md" object in message callback. I tried to do this via md.topicName.cstring but it's empty? The variable md.topicName.lenstring.data does contain the topic name but with the payload appended without any separator... Finally, I did it through the so-called "substring" using md.topicName.lenstring.data and md.topicName.lenstring.len, but could this be done easier? Is there any function or variable with plain topic name in message callback function?

monstrenyatko commented 3 years ago

Hi @kregiel, The MqttClient :: MessageData :: topicName uses the Paho MQTTString type. The MQTTString usualy contains c-string (with string termination character at the end) or char-array + char-array-length.

Unfortunately, this is how the MQTTString object is used by the Paho library. You need to handle two possible variants.

What exactly are you trying to do with the topic?

Please take a look on int MQTTPacket_equals(MQTTString* a, char* bptr) function from MQTTPacket/MQTTPacket.h as example, it compares an MQTTString to a c-string.

kregiel commented 3 years ago

I have one message callback for all subscribtions e.g te'mperture/room1' and 'temperature/room2' and I need to know where this temperature is coming from in order to take the right action. Of course, I can change the naming of topics or/and feed data to include an ID as well, but before reorganizing everything, I'd like to try to handle it as I have it configured now ;) MQTTPacket_equals (...) is also based on lenstring.data and lenstring.len, so unfortunately, since md.topicName.cstring is empty (maybe could you check if cstring variable is really filled for topicName and how to get it? now I've try to get it like 'md.topicName.cstring') then my way is ok to get topic name? char topicName[md.topicName.lenstring.len + 1]; memcpy(topicName, md.topicName.lenstring.data, md.topicName.lenstring.len); topicName[md.topicName.lenstring.len] = '\0'; But in my opinion cstring should be always filled when you create MQTTString or at least to have function to get it on the fly...

monstrenyatko commented 3 years ago

Sorry if I missed something, I believe the MQTTPacket_equals does exactly what you need. It allows you to compare an MQTTString with a c-string. In your single/global message callback, you can use it to test the topic like MQTTPacket_equals(md.topicName, "temperature/room2") and as a nice bonus it gracefully handles the dual internal representation of the MQTTString object, see:

int MQTTPacket_equals(MQTTString* a, char* bptr)
{
    int alen = 0,
        blen = 0;
    char *aptr;

    if (a->cstring)
    {
        aptr = a->cstring;
        alen = strlen(a->cstring);
    }
    else
    {
        aptr = a->lenstring.data;
        alen = a->lenstring.len;
    }
    blen = strlen(bptr);

    return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
}

You can do exactly as you proposed initially, in case you need to analyze a piece of the topic string, using lenstring only but in this case, you blindly ignore the possibility of the c-string internal representation.

My suggestion is to use the existing int MQTTstrlen(MQTTString mqttstring) and int MQTTPacket_equals(MQTTString* a, char* bptr) or build your own methods that properly tests all fields including cstring and lenstring.

monstrenyatko commented 3 years ago

I am using the Paho library as the base (everything under the MQTTPacket directory), this is how Paho returns the topic using MQTTString type, probably this is because of the memory optimization to avoid unnecessary allocations and coping, I know this is inconvenient but important for microcontrollers.

What kind of helper method would you like to have, It looks like the already existing MQTTPacket_equals and MQTTstrlen should cover most of cases.

kregiel commented 3 years ago

ok Oleg, thanks for the clarification. In fact, the function MQTTPacket_equals() is enough for comparing, but not for getting topic name itself e.g. to display to Serial port or for other string/char operations... am I right or I've missed somethig? so maybe I will write something suitable only for my project ;) I think we can close the issue...

monstrenyatko commented 3 years ago

@kregiel, you right, you need another function for printing or manipulations with the topic name. The MQTTPacket_equals is a good example of MQTTString type usage. Please let me know if I can help more. Good luck with your project!