MQTT

 

MQTT is a machine-to-machine (M2M) data transfer protocol . MQTT was created with the goal of collecting data from many devices and then transporting that data to the IT infrastructure. It is lightweight, and therefore ideal for remote monitoring, especially in M2M connections that require a small code footprint or where network bandwidth is limited.

 

How MQTT work 

 

MQTT is a publish/subscribe protocol that allows edge-of-network devices to publish to a broker. Clients connect to this broker, which then mediates communication between the two devices. Each device can subscribe, or register, to particular topics. When another client publishes a message on a subscribed topic, the broker forwards the message to any client that has subscribed.

MQTT is bidirectional, and maintains stateful session awareness. If an edge-of-network device loses connectivity, all subscribed clients will be notified with the “Last Will and Testament” feature of the MQTT server so that any authorized client in the system can publish a new value back to the edge-of-network device, maintaining bidirectional connectivity.

The project is divided in 3 parts

First, we create MQTT server on RPi and install some libraries.

Second, we will install libraries in Arduino IDE for NodeMCU to be work with MQTT, upload the code and check whether server is working or not.

Third, we create a script in Rpi ,upload the required code in NodeMCU and run the python script to control leds from both server and client side.

 

Here, server is RPi and client is NodeMCU.

 

Raspberry Pi

 

First, we install latest MQTT server and client in RPi

 

To use the new repository you should first import the repository package signing key

 

wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key
sudo apt-key add mosquitto-repo.gpg.key

Then make the repository available to apt

cd /etc/apt/sources.list.d/ 

Depending on which version of Debian you are using:

sudo wget http://repo.mosquitto.org/debian/mosquitto-jessie.list 
sudo wget http://repo.mosquitto.org/debian/mosquitto-stretch.list
sudo apt-get update

 

Then install Mosquitto server using .

sudo apt-get install mosquitto 

After, installing MQTT server install client using command.

sudo apt-get install mosquitto-clients 

You can check services using command.

systemctl status mosquitto.service 

 

 

We successfully installed MQTT server and client .

 

Next install the paho-mqtt using command.

sudo apt-get update 
sudo apt-get install python python-pip
sudo pip install RPi.GPIO paho-mqtt

 

How to setup static ip address

 

Go to directory cd /etc and open file dhcpcd.conf using any editor. At the end, write these four lines.

interface eth0
static ip_address=192.168.1.100 // ip you want to use 
interface wlan0
static ip_address=192.168.1.68
static routers=192.168.1.1 // your Default gateway
static domain_name_servers=192.168.1.1

 

After that save it and reboot your pi

 

NodeMCU

 

Here we install required libraries in Arduino IDE. We need two libraries.

1. Go to Sketch ==> Include library ==> Manage libraries.

2. Search for mqtt and install library by Adafruit or you can install any library.

3. It depend on sleepydog library so we need this library also.

 

Program (used in NodeMCU)

 

#include <ESP8266WiFi.h> 
#include "Adafruit_MQTT.h" 
#include "Adafruit_MQTT_Client.h" 
/************************* WiFi Access Point *********************************/ 
#define WLAN_SSID "YOURS SSID" 
#define WLAN_PASS "PASSWORD" 
#define MQTT_SERVER "RPi IP address" // give static address
#define MQTT_PORT 1883  
#define MQTT_USERNAME "" 
#define MQTT_PASSWORD "" 
// Create an ESP8266 WiFiClient class to connect to the MQTT server. 
WiFiClient client; 
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. 
Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD); 
/****************************** Feeds ***************************************/ 
// Setup a feed called 'pi_led' for publishing. 
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname> 
Adafruit_MQTT_Publish pi_led = Adafruit_MQTT_Publish(&mqtt, MQTT_USERNAME "/leds/pi"); 
// Setup a feed called 'esp8266_led' for subscribing to changes. 
Adafruit_MQTT_Subscribe esp8266_led = Adafruit_MQTT_Subscribe(&mqtt, MQTT_USERNAME "/leds/esp8266"); 
/*************************** Sketch Code ************************************/ 
void MQTT_connect(); 
void setup() { 
 Serial.begin(115200); 
 delay(10); 
 Serial.println(F("RPi-ESP-MQTT")); 
 // Connect to WiFi access point. 
 Serial.println(); Serial.println(); 
 Serial.print("Connecting to "); 
 Serial.println(WLAN_SSID); 
 WiFi.begin(WLAN_SSID, WLAN_PASS); 
 while (WiFi.status() != WL_CONNECTED) { 
  delay(500); 
  Serial.print("."); 
 } 
 Serial.println(); 
 Serial.println("WiFi connected"); 
 Serial.println("IP address: "); Serial.println(WiFi.localIP()); 
 // Setup MQTT subscription for esp8266_led feed. 
 mqtt.subscribe(&esp8266_led); 
} 
uint32_t x=0; 
void loop() { 
 // Ensure the connection to the MQTT server is alive (this will make the first 
 // connection and automatically reconnect when disconnected). See the MQTT_connect 
 MQTT_connect(); 
 // this is our 'wait for incoming subscription packets' busy subloop 
 // try to spend your time here 
 // Here its read the subscription 
 Adafruit_MQTT_Subscribe *subscription; 
 while ((subscription = mqtt.readSubscription())) { 
  if (subscription == &esp8266_led) { 
  Serial.print(F("Got: ")); 
  Serial.println((char *)esp8266_led.lastread); 
  } 
 } 
} 
// Function to connect and reconnect as necessary to the MQTT server. 
void MQTT_connect() { 
 int8_t ret; 
 // Stop if already connected. 
 if (mqtt.connected()) { 
  return; 
 } 
 Serial.print("Connecting to MQTT... "); 
 uint8_t retries = 3; 
 while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected 
  Serial.println(mqtt.connectErrorString(ret)); 
  Serial.println("Retrying MQTT connection in 5 seconds..."); 
  mqtt.disconnect(); 
  delay(5000); // wait 5 seconds 
  retries--; 
  if (retries == 0) { 
  // basically die and wait for WDT to reset me 
  while (1); 
  } 
 } 
 Serial.println("MQTT Connected!"); 
}  

 

Just for checking whether its works or not. Here I have not created any script in RPi . we are just using commands to subscribe and publish. We will create script for controlling later on.

 

mosquitto_pub -h raspberrypi -t "/leds/pi" -m "ON"

mosquitto_pub -h raspberrypi -t "/leds/pi" -m "OFF"

mosquitto_pub -h raspberrypi -t "/leds/pi" -m "TOGGLE"

mosquitto_pub -h raspberrypi -t "/leds/esp8266" -m "ON"

mosquitto_pub -h raspberrypi -t "/leds/esp8266" -m "OFF"

mosquitto_pub -h raspberrypi -t "/leds/esp8266" -m "TOGGLE"

-h == > host name

-t == > topic

-m == > message

 

 

Complete code to be used in Arduino IDE (NodeMCU)

 

/*************************************************** 
  NodeMCU
****************************************************/ 
#include <ESP8266WiFi.h> 
#include "Adafruit_MQTT.h" 
#include "Adafruit_MQTT_Client.h" 
/************************* WiFi Access Point *********************************/ 
#define WLAN_SSID "Your SSID" 
#define WLAN_PASS "PASSWORD" 
#define MQTT_SERVER "192.168.1.68" // static ip address
#define MQTT_PORT 1883  
#define MQTT_USERNAME "" 
#define MQTT_PASSWORD "" 
#define LED_PIN 5 // Pin connected to the LED. GPIO 2 (D4) 
#define BUTTON_PIN 4 // Pin connected to the button. GPIO 15 (D8) 
/************ Global State ******************/ 
// Create an ESP8266 WiFiClient class to connect to the MQTT server. 
WiFiClient client; 
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. 
Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD); 
/****************************** Feeds ***************************************/ 
// Setup a feed called 'pi_led' for publishing. 
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname> 
Adafruit_MQTT_Publish pi_led = Adafruit_MQTT_Publish(&mqtt, MQTT_USERNAME "/leds/pi"); 
// Setup a feed called 'esp8266_led' for subscribing to changes. 
Adafruit_MQTT_Subscribe esp8266_led = Adafruit_MQTT_Subscribe(&mqtt, MQTT_USERNAME "/leds/esp8266"); 
/*************************** Sketch Code ************************************/ 
void MQTT_connect(); 
void setup() { 
 Serial.begin(115200); 
 delay(10); 
 pinMode(LED_PIN, OUTPUT); 
 digitalWrite(LED_PIN, LOW); 
 // Setup button as an input with internal pull-up. 
pinMode(BUTTON_PIN, INPUT_PULLUP); 
 Serial.println(F("RPi-ESP-MQTT")); 
 // Connect to WiFi access point. 
 Serial.println(); Serial.println(); 
 Serial.print("Connecting to "); 
 Serial.println(WLAN_SSID); 
 WiFi.begin(WLAN_SSID, WLAN_PASS); 
 while (WiFi.status() != WL_CONNECTED) { 
  delay(500); 
  Serial.print("."); 
 } 
 Serial.println(); 
 Serial.println("WiFi connected"); 
 Serial.println("IP address: "); Serial.println(WiFi.localIP()); 
 // Setup MQTT subscription for esp8266_led feed. 
 mqtt.subscribe(&esp8266_led); 
} 
uint32_t x=0; 
void loop() { 
  // Check if the button has been pressed by looking for a change from high to 
 // low signal (with a small delay to debounce). 
 int button_first = digitalRead(BUTTON_PIN); 
 // Ensure the connection to the MQTT server is alive (this will make the first 
 // connection and automatically reconnect when disconnected). See the MQTT_connect 
 MQTT_connect(); 
 // this is our 'wait for incoming subscription packets' busy subloop 
 // try to spend your time here 
 // Here its read the subscription 
 Adafruit_MQTT_Subscribe *subscription; 
 while ((subscription = mqtt.readSubscription())) { 
  if (subscription == &esp8266_led) { 
  char *message = (char *)esp8266_led.lastread; 
  Serial.print(F("Got: ")); 
  Serial.println(message); 
  // Check if the message was ON, OFF, or TOGGLE. 
  if (strncmp(message, "ON", 2) == 0) { 
  // Turn the LED on. 
  digitalWrite(LED_PIN, HIGH); 
  } 
  else if (strncmp(message, "OFF", 3) == 0) { 
  // Turn the LED off. 
  digitalWrite(LED_PIN, LOW); 
  } 
  else if (strncmp(message, "TOGGLE", 6) == 0) { 
  // Toggle the LED. 
  digitalWrite(LED_PIN, !digitalRead(LED_PIN)); 
} 
  } 
 } 
 delay(20); 
 int button_second = digitalRead(BUTTON_PIN); 
 if ((button_first == HIGH) && (button_second == LOW)) { 
  // Button was pressed! 
  Serial.println("Button pressed!"); 
  pi_led.publish("TOGGLE"); 
 } 
} 
// Function to connect and reconnect as necessary to the MQTT server. 
void MQTT_connect() { 
 int8_t ret; 
 // Stop if already connected. 
 if (mqtt.connected()) { 
  return; 
 } 
 Serial.print("Connecting to MQTT... "); 
 uint8_t retries = 3; 
 while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected 
  Serial.println(mqtt.connectErrorString(ret)); 
  Serial.println("Retrying MQTT connection in 5 seconds..."); 
  mqtt.disconnect(); 
  delay(5000); // wait 5 seconds 
  retries--; 
  if (retries == 0) { 
  // basically die and wait for WDT to reset me 
  while (1); 
  } 
 } 
 Serial.println("MQTT Connected!"); 
} 

 

Now, we are done with NodeMCU side . As I discussed above we need python script for controlling LED's using buttons .So, we are going to create script.

 

Make an empty file let us assume mqtt_led.py

# RPi
import time 
import RPi.GPIO as GPIO 
import paho.mqtt.client as mqtt 
# Configuration: 
LED_PIN = 24 
BUTTON_PIN = 23 
# Initialize GPIO for LED and button. 
GPIO.setmode(GPIO.BCM) 
GPIO.setwarnings(False) 
GPIO.setup(LED_PIN, GPIO.OUT) 
GPIO.output(LED_PIN, GPIO.LOW) 
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) 
# Setup callback functions that are called when MQTT events happen like 
# connecting to the server or receiving data from a subscribed feed. 
def on_connect(client, userdata, flags, rc): 
  print("Connected with result code " + str(rc)) 
  # Subscribing in on_connect() means that if we lose the connection and 
  # reconnect then subscriptions will be renewed. 
  client.subscribe("/leds/pi") 
# The callback for when a PUBLISH message is received from the server. 
def on_message(client, userdata, msg): 
  print(msg.topic+" "+str( msg.payload)) 
  # Check if this is a message for the Pi LED. 
  if msg.topic == '/leds/pi': 
  # Look at the message data and perform the appropriate action. 
  if msg.payload == b'ON': 
  GPIO.output(LED_PIN, GPIO.HIGH) 
  elif msg.payload == b'OFF': 
  GPIO.output(LED_PIN, GPIO.LOW) 
  elif msg.payload == b'TOGGLE': 
  GPIO.output(LED_PIN, not GPIO.input(LED_PIN)) 
# Create MQTT client and connect to localhost, i.e. the Raspberry Pi running 
# this script and the MQTT server. 
client = mqtt.Client() 
client.on_connect = on_connect 
client.on_message = on_message 
client.connect('localhost', 1883, 60) 
# Connect to the MQTT server and process messages in a background thread. 
client.loop_start() 
# Main loop to listen for button presses. 
print('Script is running, press Ctrl-C to quit...') 
while True: 
  # Look for a change from high to low value on the button input to 
  # signal a button press. 
  button_first = GPIO.input(BUTTON_PIN) 
  time.sleep(0.02) # Delay for about 20 milliseconds to debounce. 
  button_second = GPIO.input(BUTTON_PIN) 
  if button_first == GPIO.HIGH and button_second == GPIO.LOW: 
  print('Button pressed!') 
  # Send a toggle message to the ESP8266 LED topic. 
  client.publish('/leds/esp8266', 'TOGGLE') 

 

When you run the script your script should be look like this, if result code is not zero then their is an error you can check error on paho website.

Connections

 

NodeMCU === > Button

Gnd === > Gnd

3.3V === > PIN1

GPIO4 (D2) === > PIN2

NodeMCU === > LED

Gnd === > Cathode (-ve)

GPIO5 (D1) === > Anode(+ve)

 

 

RPi === > Button

Gnd === > PIN1

GPIO 23 === > PIN2

RPi === > LED

Gnd == > Cathode(-ve)

GPIO 24 === > Anode(+ve)

 

 

 

Result

 

 

Make sure you python script is running otherwise it will not able to control led using buttons.