If your Mosquitto MQTT broker is in the cloud it is a good idea to secure it at least with a user and password.
Mosquitto offers the mosquitto_passwd utility, which allows us to create a user and a password. You will be invited to enter a password and to confirm it:
sudo mosquito_passwd -c /etc/mosquito/passwd joe
In the /etc/mosquitto directory a file named passwd will be created and in the file will be a user named joe and its encoded password as in the following screenshot:
Now let's add the passwd file into the mosquitto.conf. Use your favorite text editor and change the file /etc/mosquitto.conf to instruct Mosquitto to read and use the passwd file.
The content of the file will be:
- allow_anonymous: It is a boolean value that determines whether clients that connects without providing a username are allowed to connect. If set to false then another means a connection should be created to control authenticated client access.
- password_file: Sets the path to a password file. If defined, the contents of the file are used to control client access to the broker. If allow_anonymous is set to false, only users defined in this file will be able to connect.
After stopping and restarting the Mosquitto service using the commands:
sudo service mosquitto stop && sudo service mosquitto start
If a terminal window will try to connect as you did before, we will receive an error message like in the following screenshot:
But subscribing and publishing with the user and the password created before will work. For subscribing the command is:
sudo mosquitto_sub -t living/temperature -u joe -P joe1234
And for publishing:
sudo mosquitto_pub -t living/temperature -u joe -P joe1234 -m {"t":24.7}
You will get the following result:
Now let's use ESP8266 to send the username and password to the broker:
#include <ESP8266WiFi.h> #include <PubSubClient.h>
Update these with values suitable for your network:
const char* wifi_network = "WiFi 176-58"; const char* password = "P6etRUzaRa"; const char* mqtt_serv_address = "192.168.1.116"; const char* mqtt_user = "joe"; const char* mqtt_passwd = "joe1234"; const int mqtt_port_number = 1883; #define OUTDOOR_LIGHT 12
The mqtt_user will keep the value of the username and the mqtt_passwd will keep the user's password. We will use them in the connect method and pass them to the server:
WiFiClient espClient; PubSubClient client(espClient); long lastMsg = 0; void setup() { pinMode(OUTDOOR_LIGHT, OUTPUT); // Initialize the BUILTIN_LED pin as an output Serial.begin(115200); setup_wifi(); client.setServer(mqtt_serv_address, mqtt_port_number); client.setCallback(callback); } void setup_wifi() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(wifi_network); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { WiFi.begin(wifi_network, password); Serial.print("."); delay(5000); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void callback(char* topic, byte* payload, unsigned int msg_length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i< msg_length; i++) { Serial.print((char)payload[i]); } Serial.println(); // Switch on the LED if an 1 was received as first character if ((char)payload[0] == '0') { digitalWrite(OUTDOOR_LIGHT, LOW); // Turn the LED off } else { digitalWrite(OUTDOOR_LIGHT, HIGH); // Turn the LED on } } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection...");
Attempt to connect to the MQTT Mosquitto broker using the username and the password from mqtt_user and mqtt_passwd:
if (client.connect("ESP8266Client", mqtt_user, mqtt_passwd)) { Serial.println("connected"); client.subscribe("outdoor/light"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void loop() { if (!client.connected()) { reconnect(); } client.loop(); long now = millis(); if (now - lastMsg> 2000) { lastMsg = now; String light_state; if(digitalRead(OUTDOOR_LIGHT) == HIGH) light_state = "ON"; else light_state = "OFF"; Serial.print("Publish message: "); Serial.println(light_state); client.publish("outdoor/light/status", light_state.c_str()); } }
Publishing a message with the payload 1 will trigger the GPIO 12 and turn on the connected LED in a secure way. The ON OFF messages are the state of the GPIO where on ON will have 3V3 and on OFF 0V:
Now, sending this message from any place in the world will turn on and off any appliance from your house, if instead of the LED we will add a relay board:
Until now small messages were used, by default the maximum size allowed by the PubSubClient is 128 bytes. If your messages are bigger than 128 bytes, go to the PubSubClient.h file and change the value for MQTT_MAX_PACKET_SIZE.