ivmarkov / rust-esp32-std-demo

Rust on ESP32 STD demo app. A demo STD binary crate for the ESP32[XX] and ESP-IDF, which connects to WiFi, Ethernet, drives a small HTTP server and draws on a LED screen.
Apache License 2.0
784 stars 105 forks source link

How to get mqtt topic in received message #64

Closed brianmay closed 2 years ago

brianmay commented 2 years ago

If I replace this code: https://github.com/ivmarkov/rust-esp32-std-demo/blob/main/src/main.rs#L736-L739

With:

match msg {
    Err(e) => info!("MQTT Message ERROR: {}", e),
    Ok(Event::Received(msg)) => {
        // info!("MQTT Message: {:?}", msg);
        let token_topic =  TopicToken{};
        let topic = msg.topic(&token_topic);
        let data = msg.data();
    },
    Ok(event) => info!("MQTT event: {:?}", event),
}

Then I can "almost" access the topic of the received message. Problem is that the topic() function requires a TopicToken parameter and I have no idea how to get the required value... Or why this is required even. In fact if I look at the function definition for the topic() function, the value isn't used.

https://github.com/esp-rs/esp-idf-svc/blob/master/src/mqtt/client.rs#L519

Looking at the code for embedded-svc I do see:

let topic_token = match message.details() {
    Details::Complete(topic_token) => Some(topic_token),
    Details::InitialChunk(data) => Some(&data.topic_token),
    _ => None,
};

https://github.com/esp-rs/embedded-svc/blob/master/src/mqtt/client.rs#L53-L57

But this seems to be excessively complicated. And I have no idea what this does.

Pointers to documentation appreciated. As far as I can tell however this is a rust specific issue that doesn't happen with the C libraries, and I can't seem to find appropriate docs for the rust libraries.

Or if I should open a bug report, let me know where.

For now, this works:

let token_topic = unsafe { TopicToken::new() };

Which appears to be what the code uses internally anyway. But the comment for this function says:

/// This function is marked as unsafe because it is an internal API and is NOT supposed to be called by the user

https://github.com/esp-rs/embedded-svc/blob/master/src/mqtt/client.rs#L115

So I am guessing I am not suppose to do this.

ivmarkov commented 2 years ago

You can't easily get the topic, because not all messages are having it. Only the ones which are of type InitialChunk or Complete. Messages of type SubsequentChunk don't have it.

So you have to match on the message details, get the topic token from there (that is, if the message is of type Complete or InitialChunk) and then call get_topic with the topic token you have.

brianmay commented 2 years ago

Is there some documentation on what these messages types are for?

Maybe MQTT client is more low level then I am use to, most libraries will just give me a topic and data, and I don't have to worry about packet types.

Am I suppose to somehow process all these messages types?

ivmarkov commented 2 years ago

Its an esp-idf thing. Esp has limited memory so it might break a very large message into chunks. The first chunk will be of type InitialChunk and it will contain the message topic and the first N bytes of the data. The subsequent chunks will be of type SubsequentChunk and will contain the next N bytes of data and will not contain the topic.

That's all. If you only receive small messages, you'll see only messages of type Complete. If it is difficult for you to process chunked messages, just panic or disregard these initially.

ivmarkov commented 2 years ago

Also this is coming in embedded-svc 0.7.2 so I consider the topic closed: https://github.com/esp-rs/embedded-svc/blob/master/src/mqtt/client.rs#L59