234 lines
6.7 KiB
C++

/*
Project: 02_MQTT_Client_Digital
Author: Luis Quintero
Date: 2025-10-03
Board: ESP32-S2 (Adapt Pin Layout for ESP32 or ESP32-S3)
Description:
Basic sketch demonstrating DIGITAL inputs and outputs
with MQTT.
Behavior:
- The built-in button toggles the built-in LED.
All communication goes through MQTT Messages. Note that
the WiFi and MQTT values default to the credentials
required to connect with the MQTT Broker at Extrality Lab.
*/
#include <WiFi.h>
#include <PubSubClient.h>
// WiFi setup - Default setup to connect to Extrality Lab WiFi
const char *wifi_ssid = "dsv-extrality-lab"; // Enter your Wi-Fi name
const char *wifi_password = "expiring-unstuck-slider"; // Enter Wi-Fi password
WiFiClient espClient; // variable in charge of WiFi connection
// MQTT Broker setup - Default setup to connect to ExtralityLab Broker
const char *mqtt_broker = "inf-liva-server-eth.dsv.local.su.se";
const int mqtt_port = 1883;
const char *mqtt_username = "esp32";
const char *mqtt_password = "extrality";
PubSubClient client(espClient); // variable in charge of Mqtt connection
String client_id = "";
////////////////////////////////////
//////////// PIN DEFINITION
////////////////////////////////////
// PIN INPUTS
const int PIN_BTN = 0; //Built in button
bool boardBtnState; // variable to store current button state
bool lastBoardBtnState = HIGH; // using INPUT_PULLUP: HIGH = not pressed (pullup), LOW = pressed
// PIN OUTPUT LED CONTROL
const int PIN_LED_DIG = 13; // Onboard LED Digital (GPIO 13 in SparkFun ESP32S2 board)
bool ledDigitalState = LOW;
////////////////////////////////////
//////////// MQTT SETUP
////////////////////////////////////
//// Topics (Inputs sent to MQTT Broker)
// Digital
char topicBoardButton[50] = "/D0_BoardBtn";
//// Subscribers (Actuators received from MQTT Broker)
//Digital
char subsD13_out_BoardLED[50] = "/D13_boardLED";
////////////////////////////////////
//////////// CUSTOM FUNCTIONS
////////////////////////////////////
String getMacAddress() {
// Get the MAC address of the ESP32
String macStr = String(WiFi.macAddress()); // Format: "AA:BB:CC:DD:EE:FF"
Serial.print("Full MAC address:");
Serial.println(macStr);
// Optional: Remove colons if you want a clean topic name
macStr.replace(":", "");
String macStr4 = macStr.substring(macStr.length() - 4);
macStr4.toLowerCase();
Serial.print("Device ID (Last four characters): ");
Serial.println(macStr4);
return macStr4;
}
bool ensureMqtt() {
if (client.connected()) return true;
while (!client.connected()) {
Serial.printf("The client %s connects to the ExtralityLab MQTT broker\n", client_id.c_str());
bool isConnected = client.connect(client_id.c_str(), mqtt_username, mqtt_password);
if (isConnected) {
Serial.println("ExtralityLab MQTT broker connected");
return true;
} else {
Serial.print("Failed with state ");
Serial.print(client.state());
delay(2000);
}
}
}
// Notify that there is a function called `mqttCallback`. Implementation is further below.
void mqttCallback(char *subscriber, byte *payload, unsigned int length);
////////////////////////////////////
//////////// SETUP
////////////////////////////////////
void setup() {
// Set software serial baud to 115200;
Serial.begin(115200);
while (!Serial && millis() < 5000);
delay(100);
//// Set up pinModes
// Inputs
pinMode(PIN_BTN, INPUT_PULLUP); // Built-in button
// Outputs/Actuators
pinMode(PIN_LED_DIG, OUTPUT); // Built-in LED as Digital
digitalWrite(PIN_LED_DIG, LOW);
///////////////////
// Connecting to a WiFi network
WiFi.begin(wifi_ssid, wifi_password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the Wi-Fi network");
///////////////////
// Connecting to MQTT broker
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(mqttCallback); // What would happen with each MQTT message
// Get MAC Address to create client ID
String deviceMacID = getMacAddress();
client_id = "esp32-client-";
client_id += deviceMacID; // unique clientID based on MAC address
bool connectedMqtt = ensureMqtt();
///////////////////
// Publish Topics (one per input)
Serial.println("\t[[MQTT Published Topics]]");
// Build the topics strings, preceding the client_id
String topic;
topic = deviceMacID + topicBoardButton;
topic.toCharArray(topicBoardButton, sizeof(topicBoardButton));
Serial.println(topicBoardButton);
///////////////////
///// Subscribe to topics (one per actuator)
Serial.println("\t[[MQTT subscriptions]]");
// Build the subs strings, preceding the client_id
String subs;
subs = deviceMacID + subsD13_out_BoardLED;
subs.toCharArray(subsD13_out_BoardLED, sizeof(subsD13_out_BoardLED));
client.subscribe(subsD13_out_BoardLED);
Serial.println(subsD13_out_BoardLED);
}
////////////////////////////////////
//////////// MAIN LOOP
////////////////////////////////////
void loop() {
// Ensure connections
ensureMqtt();
client.loop();
// ---- topicBoardButton: Publish on change ---
boardBtnState = digitalRead(PIN_BTN);
if (boardBtnState != lastBoardBtnState) {
lastBoardBtnState = boardBtnState;
client.publish(topicBoardButton, String(boardBtnState).c_str());
Serial.print("Board button: ");
Serial.println(boardBtnState);
///////////
//// EDIT: Here we manually also announce the topics of the actuator
// that we would like to control with the input
client.publish(subsD13_out_BoardLED, "toggle");
///////////
}
delay(5); // small idle
}
////////////////////////////////////
//////////// MQTT SUBSCRIPTION CALLBACKS
////////////////////////////////////
void mqttCallback(char *subscriber, byte *payload, unsigned int length)
{
Serial.print("Message arrived in Subscriber: ");
Serial.println(subscriber);
Serial.print("Message:");
String message;
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
message += (char)payload[i];
}
Serial.println("-----------------------");
///// Select actuator based on subscriber's name:
// ---- subsD13_out_BoardLED: Built-in Board LED as Digital---
if (strcmp(subscriber, subsD13_out_BoardLED) == 0)
{
Serial.println("Built in Led...");
if (message == "true") {
digitalWrite(PIN_LED_DIG, true);
} else if (message == "false") {
digitalWrite(PIN_LED_DIG, false);
} else if (message == "toggle") {
digitalWrite(PIN_LED_DIG, !digitalRead(PIN_LED_DIG));
} else {
Serial.println("Error! Unknown message. Valid messages: ['true','false','toggle']");
}
} else {
Serial.println("Error! Unknown subscriber.");
}
}