Publishing Multiple Digital Input Data of an ESP32 Device to Ubidots Over MQTT Protocol

by NORVI Controllers in Circuits > Microcontrollers

2567 Views, 3 Favorites, 0 Comments

Publishing Multiple Digital Input Data of an ESP32 Device to Ubidots Over MQTT Protocol

1.PNG

In this instructable, we'll be looking at how to read multiple digital inputs of an ESP32 based Industrial IoT Device and publish those data to Ubidots over MQTT protocol.

Ubidots is an IoT platform for managing IoT devices and collecting, storing, visualizing, and analyzing data from those devices.

Here, we'll be using the Ubidots dashboard to control the relay outputs of the Norvi device.

So what do you need to get started?

Check this instructable to understand more about the device - Getting started with Norvi devices

The MQTT Protocol​

  • MQTT is a messaging protocol that was developed to establish a reliable standard for communication between machine and machine. It's a publish-and-subscribe protocol, where client devices and applications publish and subscribe to topics handled by a broker instead of communicating with a server.
  • MQTT Messages - These are the information that you want to exchange between your devices. It can be data or commands.
  • MQTT Topics - Through Topics, you register your interest in incoming messages or you specify where you want to publish the message. These topics are managed by MQTT brokers
  • MQTT Client - Anything that runs an MQTT library and links to a broker over a network will essentially become an MQTT client (from a microcontroller to a large server). Clients do not explicitly send messages to and from each other, but instead, connect with MQTT broker-managed Topics.
  • MQTT Broker - The duty of the broker to accept all messages, sort the messages, determine who is interested in them and then publish the message to all subscribing customers according to the topics.
  • MQTT Subscribe & Publish - A device may post a message on a topic through a publish or it can subscribe to the desired topic to accept messages. Here, as we are going to control the inbuilt relays of the Norvi device, only subscribing to the topics is considered to achieve our goal.

Here, as we are going to read the digital inputs of the Norvi device, only publishing is considered to achieve our goal.

For subscribing multiple topics and to control sensors, check our previous instructable - Connecting the ESP32 Based Norvi IOT Device to Ubidots Over MQTT Protocol and Controlling Multiple Relay Outputs

Setting Up the Device With Ubidots and Creating the Widgets

1.PNG
2.PNG
3.PNG
3.PNG
5.PNG
6.PNG
1.PNG
8.PNG
4.PNG
1.PNG

After creating an Ubidot account, follow the below steps in order to set up the Norvi Device with the Ubidot account and to add the dashboards & widgets to read the digital inputs.

  • After creating the account, select "Setup My First Device".
  • Then click "Add Device" and name your device (In our case, it's named ESP32). Next, choose the created device.
  • Using the "Add Variable" option, create 8 variables inside the device and name them accordingly. (In our example, the variables are named as Input1-Input8)
  • Then select the data button which is at the top middle of our account screen and create a dashboard.
  • Select the "Add new widget" option available in the top right corner and choose the Indicator widget.
  • Click the add variable option.
  • Select our device " ESP32".
  • Then choose the variable Input1. Ensure that the right variable option selected and save the widget.
  • After these steps, you'll see an Indicator widget is created which corresponds to the variable Input1. Repeat the above steps and create 8 such Indicator widgets.

Programming the Device

  • First install the PubSubClient library and upload the below sketch to the Norvi device.
#include <WiFi.h>
#include <PubSubClient.h>

#define WIFISSID "" // Put your WifiSSID here
#define PASSWORD "" // Put your wifi password here
#define TOKEN "" // Put your Ubidots' TOKEN
#define MQTT_CLIENT_NAME "" // MQTT client Name, please enter your own 8-12 alphanumeric character ASCII string; 
//it should be a random and unique ascii string and different from all other devices


#define VARIABLE_LABEL1 "input1"// Assing the variable label
#define VARIABLE_LABEL2 "input2"
#define VARIABLE_LABEL3 "input3"
#define VARIABLE_LABEL4 "input4"
#define VARIABLE_LABEL5 "input5"
#define VARIABLE_LABEL6 "input6"
#define VARIABLE_LABEL7 "input7"
#define VARIABLE_LABEL8 "input8"

#define DEVICE_LABEL "esp32" // Assig the device label
#define INPUT1 18
#define INPUT2 39
#define INPUT3 34
#define INPUT4 35
#define INPUT5 19
#define INPUT6 21
#define INPUT7 22
#define INPUT8 23

char mqttBroker[]  = "industrial.api.ubidots.com";
char payload[100];
char topic[150];
char str_sensor1[10];
char str_sensor2[10];
char str_sensor3[10];
char str_sensor4[10];
char str_sensor5[10];
char str_sensor6[10];
char str_sensor7[10];
char str_sensor8[10];
/****************************************
   Auxiliar Functions
 ****************************************/
WiFiClient ubidots;
PubSubClient client(ubidots);


void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");

  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }

  Serial.write(payload, length);
  Serial.println();
}


void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.println("Attempting MQTT connection...");

    // Attemp to connect
    if (client.connect(MQTT_CLIENT_NAME, TOKEN, "")) {
      Serial.println("Connected");
    } else {
      Serial.print("Failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 2 seconds");
      // Wait 2 seconds before retrying
      delay(2000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  WiFi.begin(WIFISSID, PASSWORD);
  // Assign the pin as OUTPUT
  pinMode(INPUT1, INPUT);
  pinMode(INPUT2, INPUT);
  pinMode(INPUT3, INPUT);
  pinMode(INPUT4, INPUT);
  pinMode(INPUT5, INPUT);
  pinMode(INPUT6, INPUT);
  pinMode(INPUT7, INPUT);
  pinMode(INPUT8, INPUT);
  Serial.println();
  Serial.print("Wait for WiFi...");

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("");
  Serial.println("WiFi Connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  client.setServer(mqttBroker, 1883);
  client.setCallback(callback);
}

void loop() {

if(WiFi.status() != WL_CONNECTED) 

{   

   Serial.print("wifi disconnected\n");
  
   WiFi.begin(WIFISSID, PASSWORD);
  }
  
  if (!client.connected()) {
    reconnect();

  }
  float sensor1 = (!digitalRead(INPUT1));
  float sensor2 = (!digitalRead(INPUT2));
  float sensor3 = (!digitalRead(INPUT3));
  float sensor4 = (!digitalRead(INPUT4));
  float sensor5 = (!digitalRead(INPUT5));
  float sensor6 = (!digitalRead(INPUT6));
  float sensor7 = (!digitalRead(INPUT7));
  float sensor8 = (!digitalRead(INPUT8));

   
  dtostrf(sensor1, 4, 2, str_sensor1);
  dtostrf(sensor2, 4, 2, str_sensor2);
  dtostrf(sensor3, 4, 2, str_sensor3);
  dtostrf(sensor4, 4, 2, str_sensor4);
  dtostrf(sensor5, 4, 2, str_sensor5);
  dtostrf(sensor6, 4, 2, str_sensor6);
  dtostrf(sensor7, 4, 2, str_sensor7);
  dtostrf(sensor8, 4, 2, str_sensor8);

  
  sprintf(topic, "%s%s", "/v1.6/devices/",DEVICE_LABEL);
  
  sprintf(payload, "%s", ""); // Cleans the payload
  sprintf(payload, "{\"%s\":%s,",VARIABLE_LABEL1,str_sensor1 );
  sprintf(payload, "%s \"%s\":%s,", payload,VARIABLE_LABEL2, str_sensor2); // Adds the variable label
  sprintf(payload, "%s \"%s\":%s}", payload, VARIABLE_LABEL3, str_sensor3); 
  client.publish(topic, payload);
  
  sprintf(payload, "{\"%s\":%s,",VARIABLE_LABEL4,str_sensor4 );
  sprintf(payload, "%s \"%s\":%s,", payload,VARIABLE_LABEL5, str_sensor5); // Adds the variable label
  sprintf(payload, "%s \"%s\":%s}", payload, VARIABLE_LABEL6, str_sensor6); 
  client.publish(topic, payload);
  
  sprintf(payload, "{\"%s\":%s,",VARIABLE_LABEL7,str_sensor7 );
  sprintf(payload, "%s \"%s\":%s}", payload,VARIABLE_LABEL8, str_sensor8);
  client.publish(topic, payload);
  


  Serial.println("\nPublishing data to Ubidots Cloud");
  Serial.print("Value of Sensor1 is:- ");   Serial.println(sensor1);
  Serial.print("\nValue of Sensor2 is:- "); Serial.println(sensor2);
  Serial.print("\nValue of Sensor3 is:- "); Serial.println(sensor3);
  Serial.print("\nValue of Sensor4 is:- "); Serial.println(sensor4);
  Serial.print("\nValue of Sensor5 is:- "); Serial.println(sensor5);
  Serial.print("\nValue of Sensor6 is:- "); Serial.println(sensor6);
  Serial.print("\nValue of Sensor7 is:- "); Serial.println(sensor7);
  Serial.print("\nValue of Sensor8 is:- "); Serial.println(sensor8);
  
  Serial.println("\nPublishing data to Ubidots Cloud");

  client.loop();
  delay(1000);
}

(For installing the ESP32 board and booting up the device, check the steps 1 and 2 of our previous instructable -Getting Started With Norvi Devices )

Code Explanation

  • We begin by adding the required libraries. The PubSubClient will operate to allow an MQTT connection. The WiFi library is required to establish the WiFi connection.

#include <WiFi.h>
#include <PubSubClient.h>
  • Then give your WiFi name and password.

<pre>#define WIFISSID "" // Put your WifiSSID here
#define PASSWORD "" // Put your wifi password here
#define MQTT_CLIENT_NAME "" 
  • Next, insert your Ubidots token here. Follow the below steps to find your unique token.
  1. Select your profile

  2. Select "API Credentials"

  3. Under Token, copy the "default token"

#define TOKEN "" // Put your Ubidots' TOKEN
  • MQTT_CLIENT_NAME is the ID with which your device will be identified by the broker. If your device tries to connect with the same ID that has already been taken by another device, the connection will be refused. So a unique client name should be provided.

#define MQTT_CLIENT_NAME "" 
  • Include the variable label names where the data have to be published and the device label name in order to read the digital inputs.

#define VARIABLE_LABEL1 "input1"// Assing the variable label
#define VARIABLE_LABEL2 "input2"
#define VARIABLE_LABEL3 "input3"
#define VARIABLE_LABEL4 "input4"
#define VARIABLE_LABEL5 "input5"
#define VARIABLE_LABEL6 "input6"
#define VARIABLE_LABEL7 "input7"
#define VARIABLE_LABEL8 "input8"

#define DEVICE_LABEL "esp32" // Assig the device label<br>
  • Next, the GPIOs of the relays are defined.

#define INPUT1 18
#define INPUT2 39
#define INPUT3 34
#define INPUT4 35
#define INPUT5 19
#define INPUT6 21
#define INPUT7 22
#define INPUT8 23
  • In the below lines the necessary char arrays are defined. The MQTT broker variable contains the Ubidots broker. The payload reserves memory space for data to be sent later in the routine. Additional memory storage and prompt data transfer are made possible by the topic array.

char mqttBroker[]  = "industrial.api.ubidots.com";
char payload[100];
char topic[150];
char str_sensor1[10];
char str_sensor2[10];
char str_sensor3[10];
char str_sensor4[10];
char str_sensor5[10];
char str_sensor6[10];
char str_sensor7[10];
char str_sensor8[10];
  • Then we will initialize the wifi client (ubidots) that will be pass as the parameter to the PubSubClient constructor.

WiFiClient ubidots;
PubSubClient client(ubidots);
  • Next, we need to define a role for a callback. This function is very important because controls the modifications of the variables in Ubidots and it is unique to the PubSubClient library. Below, the arguments for this function are clarified.
  1. char* topic: The topic is the endpoint of your variable, according to the API it should be /v1.6/devices/{LABEL_DEVICE} for publishing and /v1.6/devices/{LABEL_DEVICE}/{LABEL_VARIABLE}/lv for subscribing.

  2. byte* payload - It is the response obtained directly from the broker once a change in one of your subscribed variables has taken place.

  3. unsigned int length -This refers to the length of the payload.

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");

  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }

  Serial.write(payload, length);
  Serial.println();
}
  • An additional function for reconnecting (in case the MQTT goes down) is written.

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.println("Attempting MQTT connection...");

    // Attemp to connect
    if (client.connect(MQTT_CLIENT_NAME, TOKEN, "")) {
      Serial.println("Connected");
    } else {
      Serial.print("Failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 2 seconds");
      // Wait 2 seconds before retrying
      delay(2000);
    }
  }
}
  • In the setup() function, we initialize the serial port baud rate and set the GPIOs as Input of the Norvi device to read them. Then we connect to the wifi access point and print some debug messages. The function, client.setServer() is a method of PubSubClient to set the broker URL and the port to begin communications. And the client.setCallBack() makes sure that callback() function defined previously is available.

void setup() {
  Serial.begin(115200);
  WiFi.begin(WIFISSID, PASSWORD);
  // Assign the pin as OUTPUT
  pinMode(INPUT1, INPUT);
  pinMode(INPUT2, INPUT);
  pinMode(INPUT3, INPUT);
  pinMode(INPUT4, INPUT);
  pinMode(INPUT5, INPUT);
  pinMode(INPUT6, INPUT);
  pinMode(INPUT7, INPUT);
  pinMode(INPUT8, INPUT);
  Serial.println();
  Serial.print("Wait for WiFi...");

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("");
  Serial.println("WiFi Connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  client.setServer(mqttBroker, 1883);
  client.setCallback(callback);
}
  • Inside the void loop() function, first, we verify that the device is connected; if not, the function reconnect() is called to establish the connection. Once connected, we subscribe to the variable topics in Ubidots for retrieving data and to control the relays of the Norvi device.

  • Then the digital input values are read and published to the variable topics accordingly.

  • The client.loop() function is a built-in function that will read the receive and send buffers, and process any messages it finds. It looks at the messages on the receiving side, and it will trigger the callback function depending on the message type.

    void loop() {
    
      if(WiFi.status() != WL_CONNECTED) {
        Serial.print("wifi disconnected\n");
      
        WiFi.begin(WIFISSID, PASSWORD);
      }
      
      if (!client.connected()) {
        reconnect();
    
      }
      float sensor1 = (!digitalRead(INPUT1));
      float sensor2 = (!digitalRead(INPUT2));
      float sensor3 = (!digitalRead(INPUT3));
      float sensor4 = (!digitalRead(INPUT4));
      float sensor5 = (!digitalRead(INPUT5));
      float sensor6 = (!digitalRead(INPUT6));
      float sensor7 = (!digitalRead(INPUT7));
      float sensor8 = (!digitalRead(INPUT8));
    
       
      dtostrf(sensor1, 4, 2, str_sensor1);
      dtostrf(sensor2, 4, 2, str_sensor2);
      dtostrf(sensor3, 4, 2, str_sensor3);
      dtostrf(sensor4, 4, 2, str_sensor4);
      dtostrf(sensor5, 4, 2, str_sensor5);
      dtostrf(sensor6, 4, 2, str_sensor6);
      dtostrf(sensor7, 4, 2, str_sensor7);
      dtostrf(sensor8, 4, 2, str_sensor8);
    
      
      sprintf(topic, "%s%s", "/v1.6/devices/",DEVICE_LABEL);
      
      sprintf(payload, "%s", ""); // Cleans the payload
      sprintf(payload, "{\"%s\":%s,",VARIABLE_LABEL1,str_sensor1 );
      sprintf(payload, "%s \"%s\":%s,", payload,VARIABLE_LABEL2, str_sensor2); // Adds the variable label
      sprintf(payload, "%s \"%s\":%s}", payload, VARIABLE_LABEL3, str_sensor3); 
      client.publish(topic, payload);
      
      sprintf(payload, "{\"%s\":%s,",VARIABLE_LABEL4,str_sensor4 );
      sprintf(payload, "%s \"%s\":%s,", payload,VARIABLE_LABEL5, str_sensor5); // Adds the variable label
      sprintf(payload, "%s \"%s\":%s}", payload, VARIABLE_LABEL6, str_sensor6); 
      client.publish(topic, payload);
      
      sprintf(payload, "{\"%s\":%s,",VARIABLE_LABEL7,str_sensor7 );
      sprintf(payload, "%s \"%s\":%s}", payload,VARIABLE_LABEL8, str_sensor8);
      client.publish(topic, payload);
      
    
    
      Serial.println("\nPublishing data to Ubidots Cloud");
      Serial.print("Value of Sensor1 is:- ");   Serial.println(sensor1);
      Serial.print("\nValue of Sensor2 is:- "); Serial.println(sensor2);
      Serial.print("\nValue of Sensor3 is:- "); Serial.println(sensor3);
      Serial.print("\nValue of Sensor4 is:- "); Serial.println(sensor4);
      Serial.print("\nValue of Sensor5 is:- "); Serial.println(sensor5);
      Serial.print("\nValue of Sensor6 is:- "); Serial.println(sensor6);
      Serial.print("\nValue of Sensor7 is:- "); Serial.println(sensor7);
      Serial.print("\nValue of Sensor8 is:- "); Serial.println(sensor8);
      
      Serial.println("\nPublishing data to Ubidots Cloud");
    
      client.loop();
      delay(1000);
    }<br>

To check more about the Norvi Lineup - www.norvi.lk