Modular ESP Firmware - MQTT - Individual Functions
Main Functions
These go in the file: MQTT.cpp
This file starts with:
1 #include "functions.h"
2
3 ////////////////////////////////////////////////////////////////
4 extern char* MQTT_broker;
5 extern char* MQTT_user;
6 extern char* MQTT_pass;
7 extern char* MQTT_ClientName;
8 ////////////////////////////////////////////////////////////////
9
10 #include "MQTT.h"
11
12 WiFiClient espClient;
13 PubSubClient MQTT_client(espClient);
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
These go in the file: Supplimentary.cpp
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 }