Control a WiFi / MQTT Enabled Relay with Machinechat's JEDI Dashboard and Virtual Toggle Switch

Description

This project demonstrates a wireless electromechanical relay controlled by a virtual toggle switch control on Machinechat’s JEDI Pro dashboard. The wireless relay hardware consists of a ESP32 microcontroller board and a Seeed Grove relay. The ESP32 subscribes to a topic on the MQTT broker running on Machinechat JEDI Pro and changes the Grove relay state depending on the topic value. The MQTT topic subscribed to is the value of a virtual toggle switch control on JEDI Pro’s dashboard. Arduino is used to implement the ESP32 relay application and JEDI Pro is installed and running on a Seeed Odyssey Blue x86 Mini PC running Ubuntu Linux.

Hardware

Software

  • JEDI Pro
    Adaptable software for IoT data collection, visualization, monitoring and data storage that can be integrated into IoT solutions. Capabilities include: collect data from sensors, devices and machines; build intuitive real-time and historical data and system view dashboards; create rules to monitor and respond to data conditions automatically; receive alert notifications by email and SMS.
  • Arduino
    Arduino is an open-source electronics platform based on easy-to-use hardware and software.

Background

Machinechat JEDI Pro is IoT application software that is able to collect data from multiple sources including HTTP, serial, LoRaWAN, MQTT and internal. Collected data can be visualized, stored, acted upon and accessed via the MQTT broker running on JEDI. JEDI MQTT topics include all data coming into JEDI from any source (not just MQTT).
In version 3.1, JEDI introduced an ability to add controls to data dashboards. With a control, a user can input a value via a dashboard graphic which is then saved into a predefined data metric. The resulting data metric can be accessed over the MQTT broker running on JEDI (see Machinechat article Adding Controls to Data Dashboards )

Implementation

The project uses a Beetle ESP32C3 module and a Grove electromechanical relay board to implement a WiFi enabled relay. An Arduino PubSub library is utilized to implement a MQTT client on the ESP32 module. The ESP32 client subscribes to a virtual toggle switch value on JEDI and changes state of the relay (open/closed) dependent on the switch value.
image

Below schematic and associated BOM can be accessed at Scheme-it project link BeetleESP32relay.

Set up the ESP32 based WiFi relay Arduino application

1 - Set up Arduino on the Beetle ESP32C3 module. See link Beetle ESP32C3 Wiki link

2 - Install libraries needed for application. Add these libraries thru Arduino’s Library Manager:

3 - Code walkthrough (filename: BeetleESP32cMqttRelay1.ino)

Connect to WiFi network, connect to JEDI MQTT broker and parse JSON MQTT messages

 /*
 WiFi/MQTT enabled relay example implemented on DFRobot Beetle ESP32C3
 filename: BeetleESP32cMqttRelay1.ino
 project hardware: DFRobot Beetle ESP32C3 board and Seeed Grove Relay board
 project function: ESP32 mqtt client connects to the Machinechat MQTT broker and subscribes to multiple topics (including a 
 virtual toggle switch on the JEDI data dashboard with two states "true" and "false").
 The virtual toggle switch value topic is monitored and used to control the state of the relay.


*/

#include "WiFi.h"
#include <WiFiClient.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include "arduino_secrets.h" 

// Update these with values suitable for your network.
char ssid[] = SECRET_SSID;     // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)

// MQTT server info for JEDI Pro on Odyssey Ubuntu machine
const char* mqttServer = "192.168.1.23";
const int mqttPort = 1883;

StaticJsonDocument<256> doc;

int led = 10;

int data1 = 5;  //data1 of MQTT json message
int data2 = 5;  //data2 of MQTT json message
int data3 = 5;  //data3 of MQTT json message
int data4 = 5;  //data3 of MQTT json message
bool button = true;  //boolean variable of MQTT message
int msg = 0;
const char* timestamp = "dummy data";  //the is the MQTT message timestamp (this works)
String recv_payload;
const char* subtopic1 = "datacache/Button1boolean";                //test button control
const char* subtopic2 = "datacache/SeeedLoRaE5sensorTwo";  //LoRaE5 temp humidity sensor
const char* subtopic3 = "datacache/A84041F1B186136D"; //LHT65N garage temp humidity sensor

// wio terminal wifi 
// Beetle esp32c3 wifi
WiFiClient wclient;

PubSubClient client(wclient); // Setup MQTT client

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  randomSeed(micros());
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

// mqtt message callback
void callback(char* topic, byte* payload, unsigned int length) {

  //print out message topic and payload  
  Serial.print("New message from Subscribe topic: ");
  Serial.println(topic);
  Serial.print("MQTT payload length = ");
  Serial.println(length);
  Serial.print("Subscribe JSON payload: ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);     // print mqtt payload
    //if payload[i] == "t"
  }
  Serial.println();

  msg = 1;  //set message flag = 1 when new subscribe message received

  
  //check subscribe topic for message received and decode    
  
  //********************************//
  //if message from topic subtopic1
  //********************************//
  if (strcmp(topic, subtopic1)== 0) {  

    Serial.print("decode payload from topic ");
    Serial.println(topic);
    deserializeJson(doc, (const byte*)payload, length);   //parse MQTT message
    button = doc["value"];    // boolean button value
    Serial.print("Button boolean value = ");
    Serial.println(button);

    //control state of relay    
    if (button == 1)
    {
      digitalWrite(led, HIGH);
      digitalWrite(6, HIGH);
      delay(100);  
    }
    else
    {
      digitalWrite(led, LOW);
      digitalWrite(6, LOW);
      delay(100);    
    }    
  }
  
  //********************************//
  //if message from topic subtopic2
  //********************************//
  if (strcmp(topic, subtopic2)== 0) { 
    Serial.print("decode payload from topic ");
    Serial.println(topic);
    deserializeJson(doc, (const byte*)payload, length);   //parse MQTT message
    data1 = doc["temperature"];    

    data2 = doc["humidity"];    // 
    
    Serial.print("data1 is LoRaE5 temperature = ");
    Serial.println(data1);
    Serial.print("data2 is LoRaE5 humidity = ");
    Serial.println(data2);     
  }
    
  //********************************//
  //if message from topic subtopic3
  //********************************//
  if (strcmp(topic, subtopic3)== 0) {   
 
    Serial.print("decode payload from topic ");
    Serial.println(topic);
    deserializeJson(doc, (const byte*)payload, length);   //parse MQTT message
    data3 = doc["TempF"];
    data4 = doc["Hum_SHT"];
    Serial.print("data3 = TempF = ");
    Serial.println(data3);
    Serial.print("data4 = Hum_SHT = ");
    Serial.println(data4);
  }
}

//connect to mqtt broker on JEDI One and subscribe to topics
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a unique client ID using the Wio Terminal MAC address
    String MACadd = WiFi.macAddress();
    MACadd = "WioTerminal" + MACadd;  
    String clientID = MACadd;

    // Attempt to connect
    if (client.connect(clientID.c_str())) {
      Serial.println("connected");
      // set up MQTT topic subscription     note: topic needs to be "datacache/" + Device on JEDI One 
      Serial.println("subscribing to topics:");
      Serial.println(subtopic1);        
      client.subscribe(subtopic1);        
      Serial.println(subtopic2);
      client.subscribe(subtopic2); 
      Serial.println(subtopic3);
      client.subscribe(subtopic3); 
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  pinMode(led,OUTPUT);
  //pinMode(7, INPUT);   //switch input
  pinMode(6, OUTPUT);   //relay control input 
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqttServer, 1883);  //set mqtt server
  client.setCallback(callback);
}

Main loop checks if connected, checks for MQTT messages and updates Grove Relay board state

void loop() {
  
   // try reconnecting to WiFi if not connected   
  if (WiFi.status() != WL_CONNECTED) {
        Serial.println("not connected to WiFi, try reconnecting");
        WiFi.disconnect();
        delay(5000);
        setup_wifi();
      }
 
  // check if connected to mqtt broker
  if (!client.connected()) {
    reconnect();
  }
  if (msg == 1) {                         // check if new callback message
    
    msg = 0;      // reset message flag
  }
  Serial.println("debug - in main loop");

  delay(1000);

  client.loop();

}

4 - Example Serial Monitor output from Arduino code when subscribed to MQTT topic

Several Print statements have been inserted in the example Arduino code to help during debug and code modifications. Example serial monitor output when subscribed topic received is shown below.

5 - Latest source code for the BeetleESP32cMqttRelay1.ino application is on github at below link:

Installing JEDI Pro

If Machinechat JEDI is not already installed see below:

Getting Started with machinechat’s JEDI One IoT Platform

JEDI MQTT Broker - Subscribing to a topic

JEDI topics include all data coming into JEDI One from any source. From within the MQTT client code or application, subscribe to a topic as follows:

For a specific data stream:

datacache/TargetID

Where datacache is the fixed, top level topic from JEDI One, and TargetID is the TargetID or IP address of the data stream of interest.

For this project example:
datastream will be datacache/Button1boolean
mqttServer is 192.168.1.23
mqttPort is 1883

(note: for additional info see Machinechat article Adding Controls to Data Dashboards )

Setting up JEDI Pro

1 - When creating a control, a data metric needs to be created to hold the value from the control. Select Device Dashboard from the navigation panel on the left side of JEDI

2 - Add Data Source

3 - Add Control JEDI dashboard

4 - Add virtual toggle switch to JEDI dashboard

5 - Example JEDI virtual toggle switch control.

Conclusion

A flexible and capable WiFi enabled electromechanical relay is easily implemented with two small development boards, a DFRobot BeetleESP32 module and a Grove Relay board. Virtual toggle switch control of the WiFi relay is implemented using the control capabililty of the JEDI data dashboard and JEDI’s MQTT broker. An MQTT client running on the ESP32 provides MQTT control of the WiFi relay by a virtual toggle switch control on the JEDI data dashboard. Machinechat’s JEDI IoT data management provides MQTT access to any data it is collecting as well as additional processing, alerts or other actions as required.

References