H4AsyncMQTT is an asynchronous library. To receive messages, don't call us: we'll call you! Most often this will be when some other user somewhere publishes an MQTT topic that matches one of your subscriptions.
The main process flow for you App is:
- Define two functions: one to handle your incoming messages subscriptions (The "message handler") and one to handle server connections (The "connection handler"). You may if you like also define a server disconnection handler and/or an error handler, but those are optional; the first two are not.
- In
setup()
function , tell H4AsyncMQTT about your handler functions, so it can call you when there is data for you. Also at this point you tell H4AsyncMQTT the "obvious" stuff like your server IP/Port, logon credentials etc - Once H4AsyncMQTT has all its essential connection info, it is safe to start your WiFi connection.
It is important to note that everything done so far should only ever be done once, which is why it must be in
setup()
- When WiFi has successfully connected, you can call the
connect()
function to connect to the MQTT server you set up in step 2 - At some point in the future - over which you have no control - your connection handler will get called*. Because you cannot know the connection state until that event, you must not make any other calls in the meanhwile as it makes no sense whatsoever to do so. If you try it, 1) they will do nothing 2) they will probably call the error handler function* When the connect handler is called, you should then initialise any per-connection variables, start timers etc In most cases all you will do here is subscribe to your app's topics.
* This is obviously only on "the happy path": if your credentials are incorrect or the server is down, or any number of other reasons, your connect handler will NOT get called, but your (optional, and recommended) error handler will.
There is no need to do anything / call anything in the loop()
function.
...
H4AsyncMQTT mqttClient;
...
// My message handler - gets called when you have data to process
// can only ever happen AFTER Step 5 has been successful
void onMqttMessage(const char* topic, const uint8_t* payload, size_t len,uint8_t qos,bool retain,bool dup) {
Serial.printf("Topic %s qos%d dup=%d retain=%d len=%d\n",topic,qos,dup,retain,len);
/*
...do whatever your app does with your topic(s)
*/
}
// My connection handler, happens AFTER Step 4
void onMqttConnect() {
// STEP 5
Serial.printf("Connected to MQTT max payload size=%d\n",getMaxPayloadSize());
mqttClient.subscribe("mytopic1"); // defaults to @ QoS0
mqttClient.subscribe("mytopic2"); // defaults to @ QoS0
// ... and whatever else you need to do when u get a valid connection
}
void setup(){
mqttClient.setWill("DIED",2,"probably still some bugs",false);
// define your connection
// tell pangolin the names of your handler functions:
mqttClient.onConnect(onMqttConnect); // mandatory!
mqttClient.onMessage(onMqttMessage); // mandatory!
mqttClient.onMqttError(onMqttError);
mqttClient.onDisconnect(onMqttDisconnect); // optional
// STEP 3
// now connect To Wifi();
...
// STEP 4
// when Wifi connects:
mqttClient.connect(MQTT_URL,mqAuth,mqPass,"Pangolin_101");
}
Most of the previous example applies here, too. Trying to publish()
when there is no valid connection to an MQTT server is obviously going to fail. Your app therefore needs to keep track of when it has a connection and when it doesn't.
If you define a global bool mqttlink=false;
and set it true
in your connect handler and false
in your disconnect handler, then you will always know when its safe to publish:
if(mqttlink) mqttClient.publish("mytopic"... etc
This way, it doesn't matter what event (GPIO change, timer expiry, synchronous call from main loop etc) causes you to publish()
it will only happen when it is sensible to do so.
There are many variations of the publish
API to deal with the different types of data you may want to send. For fruther information, read:
Payload Handling API Definition
I am always grateful for any $upport on Patreon :)
(C) 2020 Phil Bowles