Modular ESP Firmware - MQTT - Individual Functions

From The TinkerNet Wiki
Jump to navigation Jump to search

Main Functions

void setup_mqtt();

Called from inside setup() to configure your MQTT connection.

 1 void setup_mqtt()
 2 {
 3     MQTT_client.setServer(MQTT_broker, 1883);
 4     MQTT_client.setCallback(MQTT_callback);
 5 
 6     //  Build the topic names
 7     strcpy(MQTT_inTopic, "cmnd/"); //  in - Commands
 8     strcat(MQTT_inTopic, MQTT_ClientName);
 9     strcat(MQTT_inTopic, "/#");
10     strcpy(MQTT_teleTopic, "tele/"); // out - Telemetry
11     strcat(MQTT_teleTopic, MQTT_ClientName);
12     strcpy(MQTT_statTopic, "stat/"); // out - Status
13     strcat(MQTT_statTopic, MQTT_ClientName);
14     strcpy(MQTT_outTopic, "noti/"); // out - Notifications
15     strcat(MQTT_outTopic, MQTT_ClientName);
16 
17     MQTT_reconnect();
18     Serial.printf("+---------------------------------------+\n");
19 }

void DOtheBloodyMQTT();

Called from inside loop() to actually handle MQTT stuff.

1 void DOtheBloodyMQTT()
2 {
3     if (!MQTT_client.connected())
4     {
5         MQTT_reconnect();
6     }
7     MQTT_client.loop();
8     MQTT_beacon();
9 }

This function exists simply to get ALL of the checking & such out of main.cpp...

void MQTT_callback(char *topic, byte *payload, int length);

Actually... Called by the libraries built-in client.loop() function.

 1 void MQTT_callback(char *topic, byte *payload, int length)
 2 {
 3 
 4   char MQTT_msg_in[MQTT_BUFFER_SIZE];
 5   char *MQTT_command = strrchr(topic, '/');
 6 
 7 #ifdef DEBUG
 8   Serial.printf("|                                       |\n");
 9   Serial.printf("| Message arrived                       |\n");
10   Serial.printf("| Command: %28s |\n", MQTT_command);
11 #endif
12 
13   if (length < MQTT_BUFFER_SIZE)
14   {
15     for (int i = 0; i < length; i++)
16     {
17       MQTT_msg_in[i] = (char)payload[i];
18       MQTT_msg_in[i + 1] = '\0';
19     }
20 
21 #ifdef DEBUG
22     Serial.printf("| Message: %28s |\n", MQTT_msg_in);
23 #endif
24     /////////////////////////////////////////////////////
25     // Message handling goes here...
26     /////////////////////////////////////////////////////
27     if (strcmp(MQTT_command, "/lights") == 0)
28     {
29       DoLights(MQTT_msg_in);
30     }
31     else if (strcmp(MQTT_command, "/respond") == 0)
32     {
33       DoAnswer(MQTT_msg_in);
34     }
35     else if (strcmp(MQTT_command, "/control") == 0)
36     {
37       DoControl(MQTT_msg_in);
38     }
39     else
40     {
41 #ifdef DEBUG
42       Serial.printf("| Dunno Whatcha want...                 |\n");
43 #endif
44     }
45   }
46   else
47   {
48 #ifdef DEBUG
49     Serial.printf("| But, it's TOO Bloody Big!             |\n");
50 #endif
51   }
52 }

void MQTT_reconnect();

Called from inside loop() (Actually, now from inside DoTheBloodyMQTT()) to ensure persistent communications.

Also called once inside setup_mqtt() just to show connection details at bootup.

 1 void MQTT_reconnect()
 2 {
 3     // Loop until we're reconnected
 4     while (!MQTT_client.connected())
 5     {
 6         Serial.printf("|                                       |\n");
 7         Serial.printf("| Attempting MQTT connection...         |\n");
 8         // Create a random client ID
 9         String clientId = MQTT_ClientName;
10         clientId += String(random(0xffff), HEX);
11         // Attempt to connect
12         if (MQTT_client.connect(clientId.c_str()))
13         {
14             Serial.printf("| connected to %-24s |\n", MQTT_broker);
15             Serial.printf("| My Name:  %-27s |\n", MQTT_ClientName);
16             // Once connected, publish an announcement...
17             char MQTT_statTopic_Device[100];
18             strcpy(MQTT_statTopic_Device, MQTT_statTopic);
19             strcat(MQTT_statTopic_Device, "/HELLO");
20             MQTT_client.publish(MQTT_statTopic_Device, "world");
21             // ... and resubscribe
22             MQTT_client.subscribe(MQTT_inTopic);
23         }
24         else
25         {
26             Serial.printf("|                                       |\n");
27             Serial.printf("| failed, rc=%d                         |\n", MQTT_client.state());
28             Serial.printf("| trying again in 5 seconds             |\n");
29             // Wait 5 seconds before retrying
30             delay(5000);
31         }
32     }
33 }

void MQTT_beacon();

Called inside loop() to provide reassurance that things are alive.

 1 void MQTT_beacon()
 2 {
 3     /* Beacon signal published at set interval to indicate the device
 4    * is still powered up and actively connected to MQTT...
 5    * A keepalive of sorts
 6    * also updates state within MQTT so it can be captured for
 7    * indicator light elsewhere
 8    */
 9     char MQTT_teleTopic_Device[100];
10     strcpy(MQTT_teleTopic_Device, MQTT_teleTopic);
11     strcat(MQTT_teleTopic_Device, "/beep");
12     if (getTimer(beacon_timer, BEACON_INTERVAL))
13     {
14         MQTT_client.publish(MQTT_teleTopic_Device, "boop");
15         // blinkLED();
16     }
17 }

void MQTT_Status(char const *Device, char const *Status);

 1 void MQTT_Status(char const *Device, char const *Status) // Send status messages
 2 {
 3     char MQTT_statTopic_Device[100];
 4     strcpy(MQTT_statTopic_Device, MQTT_statTopic);
 5     strcat(MQTT_statTopic_Device, "/");
 6     strcat(MQTT_statTopic_Device, Device);
 7 
 8 #ifdef DEBUG
 9     Serial.printf("}- %16s = %-16s -{\n", Device, Status);
10 #endif
11     MQTT_client.publish(MQTT_statTopic_Device, Status);
12 }

Supplimentary Functions

bool getTimer(unsigned long &timer, unsigned long interval);

 1 bool getTimer(unsigned long &timer, unsigned long interval)
 2 /* Global timer function, used a lot
 3  *
 4  * @param unsigned long time - The current timer
 5  * @param unsigned long interval - Length of time to run timer
 6  *
 7  * @return bool True when timer is complete
 8  * @return bool False when timer is counting
 9  */
10 {
11 
12   if (timer < 1)
13   {
14     timer = millis();
15   }
16 
17   if (millis() - timer >= interval)
18   {
19     timer = 0;
20     return true;
21   }
22 
23   return false;
24 }

void blinkLED(); // Just a little function to blink the LED for the beacon function.

Don't forget to set up the LED pin in the setup() function:

 pinMode(LED_BUILTIN, OUTPUT);
 digitalWrite(LED_BUILTIN, HIGH);
 1 void blinkLED() // Just a little function to blink the on-board LED for the beacon function.
 2 {
 3   digitalWrite(LED_BUILTIN, LOW);
 4   delay(10);
 5   digitalWrite(LED_BUILTIN, HIGH);
 6   delay(10);
 7   digitalWrite(LED_BUILTIN, LOW);
 8   delay(10);
 9   digitalWrite(LED_BUILTIN, HIGH);
10 }

Some CMND Handlers

void DoLights(char *WhatToDo); // Turn LED on/off

Don't forget to set up the LED pin in the setup() function:

 pinMode(LED_BUILTIN, OUTPUT);
 digitalWrite(LED_BUILTIN, HIGH);
 1 void DoLights(char const *WhatToDo) // Turn LED on/off
 2 {
 3     bool LEDstatus = digitalRead(LED_BUILTIN);
 4 
 5     Serial.printf("[- Lights - %-6s                     -]\n", WhatToDo);
 6     if (strcmp(WhatToDo, "ON") == 0)
 7     {
 8         digitalWrite(LED_BUILTIN, LOW);
 9         MQTT_Status("lights", "ON");
10     }
11     if (strcmp(WhatToDo, "OFF") == 0)
12     {
13         digitalWrite(LED_BUILTIN, HIGH);
14         MQTT_Status("lights", "OFF");
15     }
16     if (strcmp(WhatToDo, "TOGGLE") == 0)
17     {
18         if (LEDstatus == false)
19         {
20             digitalWrite(LED_BUILTIN, HIGH);
21             MQTT_Status("lights", "OFF");
22         }
23         else
24         {
25             digitalWrite(LED_BUILTIN, LOW);
26             MQTT_Status("lights", "ON");
27         }
28     }
29 }

void DoAnswer(char *WhatToDo); // Send back text

1 void DoAnswer(char *WhatToDo) // Send back text
2 {
3   Serial.printf("[- Responding: %-23s -]\n", WhatToDo);
4   MQTT_client.publish(MQTT_outTopic, WhatToDo);
5 }

void DoControl(char *WhatToDo); // Send MQTT to another device/topic

 1 void DoControl(char *WhatToDo) // Send MQTT to another device/topic
 2 {
 3   /*
 4   Should be something along the lines of,
 5 
 6   MQTT_client.publish(TopicFromMessage, MessageFromMessage);
 7 
 8   Where
 9     TopicFromMessage
10   is an MQTT topic for sending to another device
11   and
12     MessageFromMessage
13   is the message to publish to that topic...
14   */
15 }