Multi-protocol communication tutorial
- Auto-generated Table of Content
About Project:
This project consist of 4 different Nodes.
Once user Start Node 1 it dose a self test and connect to Wifi.
and print info in UART log and on OLED Screen, Then Connect to MQTT Server, based on info in the code below. Then start to publish NoT Pressed until we Touch the Button ,that run interrupt to toggle the value of control Boolean parameter called (is_pressed)into our example.
So the MCU will send by next loop a "Pressed" to Node 2 over Topic called "Button". and subscribe to Topic " Temp".
Node 2, which is ESP32 DOIT ESP DEVKITV1, at that time ,
subscribe to "Button" Topic and if Get NoT Press , do nothing, just continue looping , BUT if got "Pressed" Then it send '1' over Socket to Node 3,Which is my computer, that Run Python code, and Listen on Port 8888 To generate a random number between (-20,50).then send 'G' (If number bigger than -10), or 'R' (if Number smaller than-10) back on the same socket to Node 2! then disconnect the socket.
Node 2 will take the Read rom socket and send Either :
"Green" over Topic "Temp" if it got 'G' or
"RED " over Topic "Temp" if it got 'R'.
Node 1, is subscribing to "Temp" so in function "callback" will get the Payload and blink the RED or Green according to bytes received Using Function "Blink".
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
Executing Sequance over 4 nodes - schema
Each Line of this table describe what happen in each node
I triend to minimise the waiting time of our MCU as well as storage needed for code and dynamic memory.
so in node #1
Sketch uses 292108 bytes (27%) of program storage space. Maximum is 1044464 bytes.
Global variables use 28484 bytes (34%) of dynamic memory,
leaving 53436 bytes for local variables.
and in Node #2 :
Sketch uses 715114 bytes (54%) of program storage space. Maximum is 1310720 bytes.
Global variables use 40200 bytes (12%) of dynamic memory,
leaving 287480 bytes for local variables.
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
List of Materials?
Node 1: The Slave or Edge Device:
How connect prephirales to Adafruit Feather HUZZAH:
- Connect The Interrupt Touch Button to GPIO14, We can connect to any but GPIO16.
- Connect the Red LED to to GPIO 13
- Connect the Green LED to to GPIO 12
- I2C SSD1306 Oled to SCL @GPIO-05 , and SDA@GPIO-04
How about Interrupt:
Interrupts are useful for making things happen automatically in microcontroller programs and can help solve timing problems.
With interrupts you don’t need to constantly check the current pin value. When a change is detected, an event is triggered – a function is called. This function is called interrupt service routine (ISR).
When an interrupt happens, the processor stops the execution of the main program to execute a task, and then gets back to the main program as shown in the figure below
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
This is especially useful to trigger an action whenever motion is detected or whenever a pushbutton is pressed without the need to constantly check its state.
attachInterrupt() Function
To set an interrupt in the Arduino IDE, you use the attachInterrupt() function, that accepts as arguments: the GPIO interrupt pin, the name of the function to be executed, and mode:
attachInterrupt(digitalPinToInterrupt(GPIO), ISR, mode);
GPIO interrupt pin
The first argument is a GPIO interrupt. You should use digitalPinToInterrupt(GPIO) to set the actual GPIO as an interrupt pin. For example, if you want to use GPIO 14 as an interrupt, use:
digitalPinToInterrupt(14)
The ESP8266 supports interrupts in any GPIO, except GPIO16.
ISR
The second argument of the attachInterrupt() function is the name of the function that will be called every time the interrupt is triggered – the interrupt service routine (ISR).
The ISR function should be as simple as possible, so the processor gets back to the execution of the main program quickly.
The best approach is to signal the main code that the interrupt has happened by using a global variable and within the loop() check and clear that flag, and execute code.
ISRs need to have ICACHE_RAM_ATTR before the function definition to run the interrupt code in RAM.
Interrupt modes
The third argument is the mode and there are 3 different modes:
- CHANGE: to trigger the interrupt whenever the pin changes value – for example from HIGH to LOW or LOW to HIGH;
- FALLING: for when the pin goes from HIGH to LOW;
- RISING: to trigger when the pin goes from LOW to HIGH.
The Code of Node 1:
The code is well commeted with all info and links to libraries , for more info don't hesitate to contact me at ammar@dsna.se
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET LED_BUILTIN
const char* ssid = "*********";
const char* password = "********";
const char* mqtt_server = "test.mosquitto.org";
int mqtt_port = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
const byte interruptPin = 14;
bool is_Pressed=false;
long lastReconnectAttempt = 0;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const byte RED_L=13;
const byte GREEN_L=12;
void Blink (byte led,int dur);
void setup() {
Serial.begin(115200);
pinMode(RED_L,OUTPUT);
pinMode(GREEN_L,OUTPUT);
Blink (RED_L,50);
Blink (GREEN_L,50);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
My_loop_Flash_text("DSNA" , 35,10,2);
display.clearDisplay();
My_loop_Flash_text("Connecting to Wifi" , 0,10,1);
display.clearDisplay();
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
Serial.println("Connected ");
Serial.print("MQTT Server ");
Serial.print(mqtt_server);
Serial.print(":");
Serial.println(String(mqtt_port));
Serial.print("Node 1 ESP8266 IP : ");
Serial.println(WiFi.localIP());
Serial.println("Modbus RTU Master Online");
My_loop_Flash_text("Connected to MQTT" , 0,10,1);
display.clearDisplay();
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, FALLING);
}
void loop() {
reconnect();
client.loop();
delay(10000);
}
void setup_wifi() {
delay(10);
WiFi.mode(WIFI_STA);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
My_loop_Flash_text("Connectd to Wifi" , 0,10,1);
String IP_addr = WiFi.localIP().toString();
My_loop_Flash_string( IP_addr, 16,10,1);
display.clearDisplay();
}
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.println();
if ((char)payload[0]=='R'){
Serial.println("RED Recived from Node 2!");
My_loop_Flash_text("RED Rcv." , 0,10,1);
display.clearDisplay();
Blink (RED_L,1000);
is_Pressed=false;
}
else {
if ((char)payload[0]=='G'){
Serial.println("GREEN Recived from Node 2!");
My_loop_Flash_text("GREEN Rcv." , 0,10,1);
display.clearDisplay();
Blink (GREEN_L,1000);
is_Pressed=false;
}
}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect("DSNA@ESP8266")) {
Serial.println("connected");
if (is_Pressed){
Serial.println(" Press is Published on Button topic");
for (int i=0;i<3;i++){
client.publish("Button", "Press");
Serial.println(" Press is Published on Button topic");
delay(1000);}
My_loop_Flash_text("Published: Press" , 0,10,1);
display.clearDisplay();
is_Pressed=false;
client.subscribe("Temp");
}
else {
client.publish("Button", "Not_Press");
Serial.println(" NoT_Press is Published on Button topic");
My_loop_Flash_text("Published: NoT Press" , 0,10,1);
display.clearDisplay();
}
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
ICACHE_RAM_ATTR void handleInterrupt() {
Serial.println("Button Pressed");
if (is_Pressed){
is_Pressed=false;
Serial.println("Switch OFF");
}
else {
is_Pressed=true;
Serial.println("Switch ON");
}
}
void Blink (byte led,int dur){
digitalWrite(led,HIGH);
delay(dur);
digitalWrite(led,LOW);
delay(dur);
}
void My_loop_Flash_text(const char *Text , int posX, int posY, int Font_Size)
{
display.clearDisplay();
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
display.write(Text);
display.display();
delay(2000);
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
}
void My_loop_Flash_string(String Text , int posX, int posY, int Font_Size)
{
display.clearDisplay();
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
int str_len = Text.length() + 1;
char char_array[str_len];
Text.toCharArray(char_array, str_len);
display.write(char_array);
display.display();
delay(2000);
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
}
void My_loop_Flash_Number(double My_Number , int posX, int posY, int Font_Size)
{
display.clearDisplay();
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
display.println(My_Number);
display.display();
delay(2000);
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
}
void My_loop_Flash_Number(int My_Number , int posX, int posY, int Font_Size)
{
display.clearDisplay();
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
display.println(My_Number);
display.display();
delay(2000);
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
}
void My_loop_Flash_Number_con (int My_Number , int posX, int posY, int Font_Size)
{
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
display.println(My_Number);
display.display();
delay(2000);
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
}
void My_text(const char *Text , int posX, int posY, int Font_Size)
{
display.clearDisplay();
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
display.write(Text);
display.display();
delay(2000);
}
Node 2 : the main hub or router
How connect prephirales to DOIT ESP32 DEVKIT V1:
- Connect I2C SSD1306 Oled to SCL @GPIO-22 , and SDA@GPIO-21
Have Look for my other projects with this MCU to get a toturial of how to manage this board with arduino IDE here
The Code of Node 2:
The code is well commeted wit hall info and links to libraries , for more info don't hesitate to contact me at ammar@dsna.se
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET LED_BUILTIN
const char* ssid = "*********";
const char* password = "*********";
const char* mqtt_server = "test.mosquitto.org";
const int mqtt_port = 1883;
const char * Node_3_IP = "**********";
const int socket_port = 8888;
WiFiClient esp32Client;
PubSubClient client(esp32Client);
WiFiServer server(socket_port);
WiFiClient S_client;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
bool setup_wifi(void);
void callback(char* topic, byte* payload, unsigned int length);
void reconnect(void);
bool setup_Socket(void);
char*My_Socket_reader();
void My_Socket_Writer(char cmd);
void My_loop_Flash_text(const char *Text , int posX, int posY, int Font_Size);
void My_loop_Flash_string(String Text , int posX, int posY, int Font_Size);
void My_Socket();
bool My_socket_Connected;
bool Is_Pressed = false;
void setup() {
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
My_loop_Flash_text("DSNA" , 45,15,2);
display.clearDisplay();
My_loop_Flash_text("Connecting to Wifi" , 0,10,1);
display.clearDisplay();
if (setup_wifi()){
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
Serial.println("Connected ");
Serial.print("MQTT Server ");
Serial.print(mqtt_server);
Serial.print(":");
Serial.println(String(mqtt_port));
Serial.print("Node2 ESP32 IP ");
Serial.println(WiFi.localIP());
Serial.println("Modbus RTU Master Online");
My_loop_Flash_text("Connected to MQTT" , 0,10,1);
display.clearDisplay();
My_socket_Connected=setup_Socket();
}
}
void loop() {
reconnect();
client.loop();
delay(10000);
}
bool setup_wifi() {
delay(10);
WiFi.mode(WIFI_STA);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
My_loop_Flash_text("Connected to Wifi" , 0,10,1);
String IP_addr = WiFi.localIP().toString();
My_loop_Flash_string( IP_addr, 16,10,1);
display.clearDisplay();
return true;
}
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.println();
if ((char)payload[0]=='P'){
Serial.println("Button pressed in Node 1!");
Serial.println("sending 1 in Socket to Node 3!");
My_Socket_Writer('1');
My_loop_Flash_text("Button Pressed" , 0,10,1);
display.clearDisplay();
char S_payload;
while (S_client.connected()){
S_payload = (char)S_client.read();
Serial.println(S_payload);
Serial.print("Socket Payload : ");
Serial.println(S_payload);
if ( S_payload=='R'){
for (int i=0;i<3;i++){
client.publish("Temp","Red");
Serial.println("Red is Published on TEMP Topic to Node 1");
My_loop_Flash_text("RED Pub" , 0,10,1);
display.clearDisplay();
delay(1000);
}
}
else {
if ( S_payload=='G')
for (int i=0;i<3;i++){
client.publish("Temp","Green");
Serial.println("Green is Published on TEMP Topic to Node 1");
My_loop_Flash_text("GREEN Pub" , 0,10,1);
display.clearDisplay();
delay(1000);
}
}
}
}
else{
Serial.println("Button NOT pressed in Node 1!");
Serial.println("Nothing to send to Node 3!");
My_loop_Flash_text("Button NOT Pressed" , 0,10,1);
display.clearDisplay();
delay(10);
}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect("ESP32Client_DSNA")) {
Serial.println("connected");
My_loop_Flash_text("Sub on Button" , 0,10,1);
display.clearDisplay();
client.subscribe("Button");
Serial.println(" Subbscribe button ");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
bool setup_Socket(){
server.begin();
Serial.print("Socket Server is connected to ");
Serial.print(WiFi.localIP());
Serial.print(" on port ");
Serial.println(socket_port);
My_loop_Flash_text("Socket Srv is READY" , 0,10,1);
display.clearDisplay();
return true;
}
void My_Socket_Writer(char cmd){
if(!S_client.connect(Node_3_IP,socket_port))
{ Serial.println("Failed to Connect to 8888 socket ");
My_loop_Flash_text("Failed Con.8888" , 0,10,1);
display.clearDisplay();
}
else{
Serial.println("Write->Read Socket Connected");
S_client.print(cmd);
My_loop_Flash_text("1 to Node_3 " , 0,10,1);
display.clearDisplay();
Serial.println("cmd sent");
}
}
void My_Socket(){
WiFiClient client = server.available();
if (client) {
if(client.connected())
{
Serial.println("read Socket Connected");
}
while(client.connected()){
while(client.available()>0){
Serial.write(client.read());
}
while(Serial.available()>0)
{
client.write(Serial.read());
}
}
client.stop();
Serial.println("socket read");
}
}
void My_loop_Flash_text(const char *Text , int posX, int posY, int Font_Size)
{
display.clearDisplay();
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
display.write(Text);
display.display();
delay(2000);
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
}
void My_loop_Flash_string(String Text , int posX, int posY, int Font_Size)
{
display.clearDisplay();
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
int str_len = Text.length() + 1;
char char_array[str_len];
Text.toCharArray(char_array, str_len);
display.write(char_array);
display.display();
delay(2000);
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
}
void My_loop_Flash_Number(double My_Number , int posX, int posY, int Font_Size)
{
display.clearDisplay();
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
display.println(My_Number);
display.display();
delay(2000);
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
}
void My_loop_Flash_Number(int My_Number , int posX, int posY, int Font_Size)
{
display.clearDisplay();
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
display.println(My_Number);
display.display();
delay(2000);
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
}
void My_loop_Flash_Number_con (int My_Number , int posX, int posY, int Font_Size)
{
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
display.println(My_Number);
display.display();
delay(2000);
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
}
void My_text(const char *Text , int posX, int posY, int Font_Size)
{
display.clearDisplay();
display.setTextSize(Font_Size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(posX, posY);
display.cp437(true);
display.write(Text);
display.display();
delay(2000);
}
Node 3 : the Socket Server
How to connect :
Just Network or Wifi Ethernet Connection.
The Code of Node 3:
The code is well commeted wit hall info and links to libraries , for more info don't hesitate to contact me at ammar@dsna.se
How it gonna Work :
Here come a guid of using this setup:
Filmed by DSNA!
https://youtu.be/wCLGnwUo1hA
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
Some Output of project:
Node #1

Node#2
Fullscreen with Pyton NOde 3 Output

Node#3
The Socket Server output example from PYCharm :

DSNA22 OTHER Projects :
Thanks :
Thanks for Haithem S for all knowledge and experience that looks clearly in backscenes of this project!
More info about ESP32 DEVKIT V1 30 Pins
Introduction to ESP32 chip
- ESP32-WROOM-32 is a very popular chip used for the internet of things applications. The main part of this module is ESP32-D0WDQ6 chip.
- It has 48 pins but all pins are not available to use in devkit. You will see more information about it in the later part of this tutorial.
- It consists of an on-chipWiFi module, Bluetooth low energy module, and Bluetooth module. So if you are working on an embedded systems project, where you need all these modules, you can simply use this board instead of using off the shelf all components one by one. Due to these features, it can be used for many embedded systems applications.
- It is a very low-cost board and can be purchased around 10-15$.
- It consists of two cores and each core can be controlled separately.
- It can operate at the variablefrequency range from 80 MHz to 240 MHz.
- It has a special ultra-low power co-processor. A user can power off processors and can use a low power coprocessor to monitor peripherals at low power like GPIO pins.
for more info Download this Complete Datasheet

And so looks mine after once connected to 2 small size Bredboard :

In Arduino IDE : we can add it by adding this Link :
https://dl.espressif.com/dl/package_esp32_index.json
Ps. use ',' if you have other boars as well!
Under :
FILE > Preferences Ctrl+Comma

After adding it we need to choose it under tools the write board and then the right port:

Thanks , for more info drop to my inbox : ammar@dsna.se.