MQTT to Particle Publish and Vice Versa

Hallo!

At the moment I’m using both MQTT and Particle Pub/Sub in my home as sensor nodes. I think longer term I’ll convert fully to MQTT but for the time being (basically while I’m still running some Cores and as yet unable to afford new Photons) I’m running a hybrid. So at the moment I’m hand-coding new messages I want the “converter device” (a Photon) to pick up and recognise as something it should convert to MQTT and send on.

I’m wondering how I would go about signifying to the Photon (with a prefix maybe?) that anything with that prefix should be first stripped of the prefix and then converted to a Particle Publish? Any help very appreciated with this.

Thank you!

I’ve found and slightly adapted this code online:

std::string s = "MQTTDoorOpen";
if (s.rfind("MQTT", 0) == 0) {
  // s starts with prefix
}

I guess what I’m asking is, how to a) scan an incoming subscribe for the prefix, and if the prefix is found, strip the prefix and reissue the incoming subscribe as an MQTT publish.

Anyone doing anything like this at the mo?

Ah. Doesn’t look like rfind is available in Wiring?

@netpex, you may want to consider using ‘c’ type strings which don’t require or use dynamic memory allocation (which can cause heap fragmentation). Instead of rfind, you could use strstr() or strtok() depending on your requirements.

1 Like

Do you really need 4 characters for your prefix? If you can get away with just using a single char (pick any of the special ones) testing for your mqtt commands is so much quicker and easier.

And yah, stay away from the String class.

I definitely don’t actually need four characters, but by special character, do you mean like a slash, question mark or a colon?

@peekay123 - thanks - I’ll see what I can find and cobble together.

thanks

Any character will do but something that you are not going to use as part of the naming of the actual function. So e.g. _DoorOpen or $DoorOpen etc. I know this is a bit more limiting then your 4 characters but so much quicker/easier to implement.

I’ve got to admit I’m struggling with this. I’d basically like to (as @joost suggests) send anything which comes in with $ preceding it as an MQTT message, immediately rebroadcast as a Particle Publish stripped of the $.

What I’m trying to do is to be able to send an MQTT message from Home-Assistant which I can automatically turn into a myDFPlayer.playMp3Folder(13); command.

At the moment every time I want to play a new sound file as my home automation develops I’m having to put in new lines of code, compile and flash.

I’d like to make it so that if I sent $19 as an MQTT message then I can take that ‘19’ and insert it into myDFPlayer.playMp3Folder(XX); here.

Will do some more mulling.

How are you receiving the data now?
How are you currently calling myDFPlayer.playMp3Folder(13);?
What have you tried?
@peekay123 mentioned strstr() and strtok() - have you investigated these?
I’d also throw in sscanf() for ease of use.

We usually need some code to look at before we go off suggesting all kinds of more or less helpful “solutions” for a problem we are not fully inforemed about :wink:

2 Likes

As @ScruffR said a bit of code would help to help you :wink: Include your message stream i.e., the content of your messages you are sending/receiving.

2 Likes
constexpr char * MAUD_MSSG = "STRING1";
constexpr char * PETER_MSSG = "STRING2";
constexpr char * DOWNSTAIRS_MSSG = "STRING3";
constexpr char * OUTSIDE_MSSG = "STRING4";
void callback(char * topic, byte * payload, unsigned int length) {
        char p[length + 1];
        memcpy(p, payload, length);
        p[length] = NULL;

        if (!strcmp(p, "STRING2")) {  
                Particle.publish(DEVICE_NAME, PETER_MSSG, 60, PRIVATE);
        } else if (!strcmp(p, "maud")) {
                Particle.publish(DEVICE_NAME, MAUD_MSSG, 60, PRIVATE);
        } else if (!strcmp(p, "locked")) {
                myDFPlayer.playMp3Folder(23);
        }
}
void eventHandler(const char * event,
        const char * data) {
        if (strcmp(data, DOWNSTAIRS_MSSG) == 0) {
                myDFPlayer.playMp3Folder(20);
        } else if (strcmp(data, OUTSIDE_MSSG) == 0) {
                myDFPlayer.playMp3Folder(23);
        }
}

So here are my two event handlers, the top one is for my MQTT messages in and the bottom is for my Particle messages in.
I’d realy like to be able to, if a message comes in on either platform (MQTT or Particle Pub/Sub) to be able to scan it for a preceding $, and if it has one, strip off that $, and simply insert it into where the myDFPlayer specifies the file number to be played. So for example if instead of “STRING2” coming in on MQTT triggering a manual Particle publish of PETER_MSSG (“STRING2”) it’d be cool to be able to instead send $STRING2.

Similarly if a message came through with ‘?’ preceding it such as ?24 I’d love to be able to have a handler which says - right - you’re clearly a command which is destined for myDFPlayer - and if it just took the ?24, stripped off the ? and inserted the 24 into myDFPlayer.playMp3Folder(24). Does this make sense?

I’m sort of using this particular Photon as a dual use “Rosetta stone” between Particle land and the rest of IoT land and also as an output speaker. It reacts to real world events and plays appropriate sound files.

Hope this makes sense…? Thank you and please tell me if I haven’t been clear enough.

Do you expect the $ as first chararcter in the topic or the payload?
I’ll just assume the topic, then the easiest would be if (topic[0] == '$') to check for that.
After that you could use int num = atoi(&topic[1]) to convert the rest of the topic into an integer and then check if (num != 0) to only act on topics that start with a numeric part not equal to zero.

Thanks, Scruff, and if I wanted to check the payload (payload[0] == ‘$’) ?

As a side question for me in terms of coding this and debugging it quickly, is there a C++ sort of live parser like the Jinja2 one ?
I’d love to be able to iterate really quickly rather than compiling, flashing, sending messages and seeing where I’ve gone wrong!

For payload it should be just the same.
However, MQTT also allows binary payloads and hence a '$' may be present there without actually being the payload you are looking for.
Usually you should check the topic first to judge how to treat the payload correctly.

I guess so, but while you can do short-cylce dev iterations gradually approximating your desired target, it's usually better to develop the ability to let your code mentally run in your own mind before feeding it into any tool or flashing it to the device.
These tools are helpful to quickly get to a solution when you have a deadline to meat but when you want to improve your programming skills they don't help you develop the feeling for your code - they rather support lazy programming.
With a feeling for your code and a malleable, mental image of the source code you can play around and streamline it much easier and often quicker - our brain can pick solutions from a "fuzzy map" of holistic possibilities way better than by looking at some pre-existing code and being confined to seeking potential alterations of that.

So no, I don't know of any such tool and wouldn't use it if I did :wink:

So it looks like you’re not using the topic variable. In MQTT the topic is how you separate consumers in the end-point. In your case, I would propose you have a DFPlayer topic (channel) and a MP3Player topic (channel). Then your payload can simply be the file number you like to have played. So no need for magic characters in that case.

You can create an “if strcmp() {} else if strcmp() {}” decision tree on the topic to determine where to route the payload. If you add yet another player capability, just add a topic (channel) and the consumption code.

It is fine to send your file values/numbers as the payload (converted to a string if you dont want to deal with binary topics) but it is better to send little json messages with a defined format. That will give you the ability to add features in the future. Right now your json could look like:
{“fileNumber”:4} in a future version you could expand it to include volume say: {“fileNumber”:4, “volume”:10} etc. You can use the jsmn_parser which is already part of the particle lib.

2 Likes