fbpixel
Draw curves on your Web App with Chart.js

Draw curves on your Web App with Chart.js

It’s possible to plot curves in real time on a web app using Chart.js. When you create a web app, you’re bound to want to display data. The Chart.js library integrates with your html files and JavaScript scripts to plot data from sensors, files or databases.

To test the library, you can create a web app using Flask.

Implementing Chart.js

To use the Chart.js library in your html file, simply call the script at the following url

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

Chart.js is a Javascript library for drawing interactive curves on an HTML page. Implementation is similar for all curves.

  • Define a canvas element in the body of your page with an identifier (e.g. myChart)
<body>	
	<div width="60%">
		<h1>Chart.js</h1>
		<canvas id="myChart"></canvas>
	</div>
</body>
  • Create a script to retrieve this element
<script>	
  const ctx = document.getElementById('myChart');
</script>
  • Finally, in the same script, edit a function that will specify the curve to be drawn

The schematic type is defined by “type: ‘bar'”, the names displayed on the axis are defined in the data.labels structure (here, apple, banana, etc.) and finally the ordinates are defined in the data.datasets.data structure (here, 12, 19, etc.).

 new Chart(ctx, {
    type: 'bar',
    data: {
      labels: ['Apple', 'Banana', 'Orange', 'Ananas', 'Kiwi', 'Pear'],
      datasets: [{
        label: '# of Fruits',
        data: [12, 19, 3, 5, 2, 3],
        borderWidth: 1
      }]
    },
    options: {
      scales: {
        y: {
          beginAtZero: true
        }
      }
    }
  });

There are a number of charts you can play with. To use them, simply replace the “type” variable in the Chart function.

bar’, ‘line’, ‘doughnut’, ‘pie’, ‘polarArea’, ‘radar’, ‘bubble’, ‘scatter’.

N.B.: bubble and scatter use numerical data and additional information.

Drawing a histogram

Here’s a complete example of how to plot a histogram,

<!DOCTYPE html>
<html>
<meta charset="UTF-8">
	
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

<head>
	<title>HelloWorld</title>
	<link rel="stylesheet" href='../static/style.css'/>
</head>

<body>	
	<div width="60%">
		<h1>Chart.js</h1>
		<canvas id="myChart"></canvas>
	</div>
</body>

<script>
	Chart.defaults.backgroundColor = '#9BD0F5';
	Chart.defaults.borderColor = '#555555';
	Chart.defaults.color = '#FFFFFF';	
	
  const ctx = document.getElementById('myChart');
  
  new Chart(ctx, {
    type: 'bar',
    data: {
      labels: ['Apple', 'Banana', 'Orange', 'Ananas', 'Kiwi', 'Pear'],
      datasets: [{
        label: '# of Fruits',
        data: [12, 19, 3, 5, 2, 3],
        borderWidth: 1
      }]
    },
    options: {
      scales: {
        y: {
          beginAtZero: true
        }
      }
    }
  });
  
</script>
</html>

Draw a line

<body>
        <div width="60%">
		<canvas id="myLine"></canvas>
	</div>
</body>
<script>
	Chart.defaults.backgroundColor = '#9BD0F5';
	Chart.defaults.borderColor = '#555555';
	Chart.defaults.color = '#FFFFFF';	
	
  const cvs = document.getElementById('myLine');
  const labels = [2018,2019,2020,2021,2022,2023]
  const datas=[1560, 2310, 1700.20, 2500, 998, 100];
  new Chart(cvs, {
    type: 'line', //
    data: {
      labels: labels,
      datasets: [{
        label: '€ Expenses',
        data: datas,
        borderWidth: 1,
		fill: false,
		borderColor: 'rgb(255, 0, 0)',
		backgroundColor: 'rgb(255, 0, 0)',
		tension: 0.5
      }]
    },
    options: {
      scales: {
        y: {
          beginAtZero: true
        }
      }
    }
  });
</script>

With these examples, you can do quite a lot to display beautiful graphics on your web pages. I’m now going to show you two advanced functions you may find useful:

  • plot from csv file
  • perform actions when you click on a part of the graph

Bonus: plot curves from a CSV file

To import a cs file, we use the d3 library

<script src="https://d3js.org/d3.v7.min.js"></script>

This library will enable us to import the values contained in the inventory.csv file in the form of a table, with the column names in the first line.

"category";"value"
"electronics";"200"
"mechanics";"100"
"microcomputer";"50"
"sensors";"132"

Then, in the makeChart function, we can call variables using data.map (category or value)

      var category = data.map(function(d) {return d.category;});
      var value = data.map(function(d) {return d.value;});
<script>  
// CSV chart
d3.csv("./inventory.csv").then(makeChart);
 
 function makeChart(data) {
      var category = data.map(function(d) {return d.category;});
      var value = data.map(function(d) {return d.value;});
	var canvas=new Chart(document.getElementById("myCanvas"), {
          type: 'bar', //'line', //'bar', //
          data: {
            labels: category,
            datasets: [
              {
                label: "Category (units)",
                backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
                data: value
              }
            ]
          },
          options: {
			responsive: true,
			scaleFontColor: "#FFFFFF",
            legend: { display: false },
            title: {
              display: true,
              text: 'Inventory 2023'
            } 
          }
      });     
}
</script>

Bonus: Perform an action on a click event

To be able to execute a function when a part of the chart is clicked, we need to define a listen function. These functions already exist in Chart.js. We just need to know where to modify them.

In the options, we’ll modify the function to be executed when the graph is clicked.

          options: {
		events: ['mousemove', 'click'], //select event handled
		onClick: (e) =&gt; {
            const canvasPosition = Chart.helpers.getRelativePosition(e, canvas);

            // Substitute the appropriate scale IDs
            const dataX = canvas.scales.x.getValueForPixel(canvasPosition.x);
            const dataY =canvas.scales.y.getValueForPixel(canvasPosition.y);
            console.log(canvas.data.labels[dataX],' -&gt; ',canvas.data.datasets[0].data[dataX]);
            alert(canvas.data.labels[dataX] +' -&gt; '+ canvas.data.datasets[0].data[dataX])       
        },

In this example, we’ll retrieve the label and value of the selected zone and display them in an alert window.

<script>  
// Bar chart
d3.csv("./static/file/inventory.csv").then(makeChart);
 
 function makeChart(data) {
      var category = data.map(function(d) {return d.category;});
      var value = data.map(function(d) {return d.value;});
	var canvas=new Chart(document.getElementById("myCanvas"), {
          type: 'bar', //'line', //'bar', //
          data: {
            labels: category,
            datasets: [
              {
                label: "Category (units)",
                backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
                data: value
              }
            ]
          },
          options: {
		events: ['mousemove', 'click'], //select event handled
		onClick: (e) => {
            const canvasPosition = Chart.helpers.getRelativePosition(e, canvas);

            // Substitute the appropriate scale IDs
            const dataX = canvas.scales.x.getValueForPixel(canvasPosition.x);
            const dataY =canvas.scales.y.getValueForPixel(canvasPosition.y);
            console.log(canvas.data.labels[dataX],' -> ',canvas.data.datasets[0].data[dataX]);
            alert(canvas.data.labels[dataX] +' -> '+ canvas.data.datasets[0].data[dataX])       
        },
			
			responsive: true,
			scaleFontColor: "#FFFFFF",
            legend: { display: false },
            title: {
              display: true,
              text: 'Inventory 2023'
            } 
          }
      });     
}
</script>

Sources

Configuring port forwarding

Configuring port forwarding

When you want to connect to a device outside your Wifi network, you need to set up port forwarding. Once your Raspberry Pi or ESP is connected to your Internet router, you can access it from anywhere by configuring port forwarding.

N.B: For cybersecurity reasons, it can be very dangerous to set up a port forwarding without taking care. For this reason, you should only set up a redirection if you’re sure of what you’re doing, and you should put in place the necessary safeguards (password, etc.).

Principle

On the same network, devices will communicate with their local addresses (e.g. 192.168.x.xxx). Only the router has a public address. When we configure port forwarding, we ask the router to open a public port and link it to a local address.

Ex:

  • public router IP: 82.95.256.144
  • router local IP: 192.168.1.254
  • local device IP: 192.168.1.17 (default port 80)

So if we redirect port 600 to the device’s IP address, we’ll be able to access the device by typing 82.95.256.144:600.

This procedure can be very useful for developing advanced home automation or IoT functions requiring remote access on Raspberry Pi, ESP8266, EP32 or any other device with an Internet connection.

Find your router’s IP address

  • Under Raspberry Pi or Linux
ip route
  • Under Windows
ipconfig

These commands give, among other things, the local IP address of your router (here 192.168.1.254).

You can use the netstat -a command to get a list of connections to the device and the ports used.

Configure port forwarding

In your browser, you can enter the IP address to access the router’s home page. You will be asked for your login details.

N.B: The port forwarding procedure differs from one box to another. If you search for “box-name Port Forwarding” on the Internet, you should come across the procedure to follow.

Luego busca la opción “Redirección de Puertos” o NAT/PAT. En un bbox, Servicios de la Box > Redirección de Puerto> Configuración.

Click on “Add a rule” and enter the redirection information

From the previous example:

  • Rule name: MyPortForwarding
  • Protocol: TCP
  • Device local IP address: 192.168.1.17
  • Internal port: 80 (can be a set value)
  • External port: 600

N.B: The external port can take a value between 0 and 65535. Port numbers below 1024 or above 49150 are reserved for the system.

Applications

Sources

Send an email with Arduino and a web interface

Send an email with Arduino and a web interface

When a microcontroller has a remote connection, it is interesting that it can communicate with the outside world and, in particular, send information in the form of mail. We will see in this tutorial how to send an email using an Arduino with a Wifi connection and a JavaScript script.

This tutorial can be applied to any microcontroller with a Wifi connection. It is enough to adapt the part of the code relating to the connection to the network. The only drawback is that the web interface must be opened in a web browser for the mail to be sent.

Material

  • Arduino
  • Wifi or Ethernet module
  • Gmail account

As a reminder, some examples of modules with Wifi connection:

Principle of operation

To send an email with Arduino, we will use the SMTP protocol (Simple Mail Transfer Protocol), we will go through a server that manages the sending of mail. Like the smtp server of Gmail. To use this server, you need a Gmail account (free creation) and you have to activate the two-step validation.

Gmail account configuration

On the account management page, go to the “Security” tab, then look for the “Sign in to Google” box.

Add two-step validation.

Generate an account access password for a given application

You just have to copy in the JavaScript code below, the user ID (the Gmail address) and the password issued by Google (yellow insert above).

JavaScript code to send an email

The code that will allow us to send emails is the JavaScript code present in the HTML code of the web interface. Before creating the mail sending function, we will import the smtp.js library

  <script src='https://smtpjs.com/v3/smtp.js'></script>

Then we can add the definition of the sendEmail function.

  <script>
  function sendEmail() {
  Email.send({
    Host: 'smtp.gmail.com',
    Username : '*************@gmail.com',
    Password : '**********************',
    To : 'destinataire@gmail.com',
    From : 'emetteur@aranacorp.com',
    Subject : 'Data from "+nom+"',
    Body : 'The sensor value is : "+String(analogRead(A0))+"',
    }).then(
      message => alert('mail sent successfully')
    );
  }
  </script>

This function is voluntarily simplified to show the sending of mail but it is possible to modify it to send different subject, message body and information.

Full code with Ethernet Shield W5100

//Libraries
#include <Ethernet.h>//https://github.com/CisecoPlc/Arduino-W5100-W5200/tree/master/Ethernet

//Parameters
String request ;
String nom = "Arduino";
unsigned long refreshCounter  = 0;
IPAddress ip(192, 168, 1, 179) ;
byte mac [6] = {0x54, 0x34, 0x41, 0x30, 0x30, 0x31};

//Objects
EthernetServer server(80);
EthernetClient client;

void setup() {
  //Init Serial USB
  Serial.begin(9600);
  Serial.println(F("Initialize System"));
  //Init W5100
  Ethernet.begin(mac, ip);
  while (!Ethernet.begin(mac)) {
    Serial.println(F("failed. Retrying in 1 seconds."));
    delay(1000);
    Serial.print(F("Starting W5100..."));
  }
  pinMode(2, OUTPUT);
  server.begin();
  Serial.println(F("W5100 initialized"));
  Serial.print(F("IP Address: "));
  Serial.println(Ethernet.localIP());
}

void loop() {
  client = server.available();
  clientRequest();
  handleRequest();
}
void clientRequest( ) { /* function clientRequest */
  ////Get client request
  if (!client) {
    return;
  }
  // Wait until the client sends some data
  while (!client.available()) {
    delay(1);
  }
  request = client.readStringUntil('\r'); // Read the first line of the request
  Serial.println(request);
  client.flush();
}

void handleRequest( ) { /* function handleRequest */
  ////Handle web client request
  if (request.indexOf("/dig2on") > 0) {
    digitalWrite(2, HIGH);
  }
  if (request.indexOf("/dig2off") > 0) {
    digitalWrite(2, LOW);
  }
  if (request.indexOf("GET") >= 0) {
    webpage(client);
    client.stop();
  }
}

void webpage(EthernetClient client) { /* function webpage */
  ////Send wbepage to client
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); //  do not forget this one
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head>");
  client.println("<meta name='apple-mobile-web-app-capable' content='yes' />");
  client.println("<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />");
  client.println("<script src='https://smtpjs.com/v3/smtp.js'></script>");
  client.println("<script>");
  client.println("function sendEmail() {");
  client.println("Email.send({");
  client.println("  Host: 'smtp.gmail.com',");
  client.println("  Username : '*************@gmail.com',");
  client.println("  Password : '**********************',");
  client.println("  To : 'destinataire@gmail.com',");
  client.println("  From : 'emetteur@aranacorp.com',");
  client.println("  Subject : 'Data from Arduino" + nom + "',");
  client.println("  Body : 'The sensor value is : " + String(analogRead(A0)) + "',");
  client.println("  }).then(");
  client.println("    message => alert('mail sent successfully')");
  client.println("  );");
  client.println("}");
  client.println("</script>");
  client.println("</head>");
  client.println("<body bgcolor = '#70706F'>");
  client.println("<hr/><hr>");
  client.println("<h1 style='color : #3AAA35;'><center> " + nom + " Device Control </center></h1>");
  client.println("<hr/><hr>");
  client.println("<br><br>");
  client.println("<br><br>");
  client.println("<center>");
  client.println("  Pin A0");
  client.println("  <input value=" + String(analogRead(A0)) + " readonly></input>");
  client.println("  </center>");
  client.println("<center>");
  client.println("Send email");
  client.println("<input type='button' value='Send Email' onclick='sendEmail()'/>");
  client.println("</center>");
  client.println("<br><br>");
  client.println("<center>");
  client.println("<a style='color : #3AAA35;' href='https://www.aranacorp.com'>www.aranacorp.com</a>");
  client.println("</center>");

  client.println("<br><br>");
  client.println("</body></html>");
  client.println();
  delay(1);
}

Result

You can open the web interface in a browser using the IP address displayed in the serial monitor. The following page should appear.

When the “Send Email” button is pressed, an email is sent according to the address and text written in the JavaScript function described above.

If you search your Gmail inbox, you should come across a similar message.

Sources

Create a web interface to control your Raspberry Pi

Create a web interface to control your Raspberry Pi

The Raspberry Pi is a very powerful microcomputer that has the particularity of integrating a chip to manage the Wifi connection. This makes it an ideal object to develop connected objects and, in particular, web servers. In this tutorial we will see how to create and host a web interface to control your Raspberry Pi.

Prerequisites: Programming your Raspberry Pi, Connecting your Raspberry to Wifi

Material

  • Computer
  • Raspberry Pi 3 B+ or Zero (with Raspbian and VNC remote connection)
  • Power supply 5V 2A

N.B.: This tutorial was written around a Raspberry Pi but it can very well be applied to any computer on which Python is installed.

Code

To create a web page, you need a file structure. An HTML file in combination with a CSS file to describe the page (front-end) and a Python script to manage requests from the browser to the server (back-end). It is possible to add PHP and JavaScript files in order to structure and add functionalities to the Web application.

To organize these files, we will place them in subfolders:

  • In the main folder (acwebapp), the script RaspWebInterface.py
  • A static sub-folder, in which we will place the css script
  • A sub-folder templates, in which we will place the HTML script

Code Python with Flask

We will create a Python script using Flask in order to display the page rpi3b_webcontroller.html when requested by the web browser. The library used to generate a simple web application is the Flask micro-framework.

Functions to remember:

  • app=Flask(name) to instantiate the Flask application
  • @app.route(‘/’) decorator to handle URL requests
  • return render_template(‘rpi3b_webcontroller.html’,**templateData) to send the web page to the browser
  • return ” OK 200 ” to validate the reception of a request
  • app.run(debug=True, port=5000, host=’0.0.0.0′,threaded=True) to launch the application on the local IP with port 5000
import os
import RPi.GPIO as GPIO
from flask import Flask, render_template, Response
import datetime

GPIO.setmode(GPIO.BCM)
dataPin=[i for i in range(2,28)]
for dp in dataPin: GPIO.setup(dp,GPIO.IN)#,pull_up_down=GPIO.PUD_UP)

data=[]
now=datetime.datetime.now()
timeString=now.strftime("%Y-%m-%d %H:%M")
templateData={
	'title':'Raspberry Pi 3B+ Web Controller',
	'time':timeString,
	'data':data,
}

def getData():
	data=[]
	for i,dp in enumerate(dataPin): data.append(GPIO.input(dataPin[i]))
	
	return data

app=Flask(__name__)
	
@app.route('/')
def index():
	#return 'hello world!'
	now=datetime.datetime.now()
	timeString=now.strftime("%Y-%m-%d %H:%M")
	data=getData()
	templateData={
		'title':'Raspberry Pi 3B+ Web Controller',
		'time':timeString,
		'data':data,
	}
	#return render_template('rpi_index.html',**templateData)
	return render_template('rpi3b_webcontroller.html',**templateData)           

@app.route('/<actionid>') 
def handleRequest(actionid):
	print("Button pressed : {}".format(actionid))
	return "OK 200"   
	                      	
if __name__=='__main__':
	os.system("sudo rm -r  ~/.cache/chromium/Default/Cache/*")
	app.run(debug=True, port=5000, host='0.0.0.0',threaded=True)
	#local web server http://192.168.1.200:5000/
	#after Port forwarding Manipulation http://xx.xx.xx.xx:5000/

HTML code

The .html file contains the description of the web page and the JavaScript code to manage the buttons.

<!DOCTYPE HTML>
	<html>
		<head>
			<title> AranaCorp </title>

			<meta http-equiv='content-type' content='text/html; charset=UTF-8'>
			<meta name='apple-mobile-web-app-capable' content='yes' />
			<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />
			<meta http-equiv='refresh' content='10'>

			<link rel="stylesheet" href='../static/rpi_style.css'/>
			<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
		</head>
		
		<body bgcolor = '#70706F'> 
			<hr/><hr>
			<h1 style='color : #3AAA35;'><center> AranaCorp - {{title}} </center></h1>
			<hr/><hr>
			<br><br>
			<h2><center><p>Date and time :  {{time}}</p></center></h2>
			<br><br><h2> Digital Inputs/Ouputs </h2>
			<div id='btnContainer'>
				  <center>
				  Pin GPIO2
				  <input value={{data[0]}} readonly></input>
				  <button id='dig2on'>Turn On </button></a>
				  <button id='dig2off'>Turn Off </button></a><br /> 
				  </center>
				  <center>
				  Pin GPIO3
				  <input value={{data[1]}} readonly></input>
				  <button id='dig3on'>Turn On </button></a>
				  <button id='dig3off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO4
				  <input value={{data[2]}} readonly></input>
				  <button id='dig4on'>Turn On </button></a>
				  <button id='dig4off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO5
				  <input value={{data[3]}} readonly></input>
				  <button id='dig5on'>Turn On </button></a>
				  <button id='dig5off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO6
				  <input value={{data[4]}} readonly></input>
				  <button id='dig6on'>Turn On </button></a>
				  <button id='dig6off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO7
				  <input value={{data[5]}} readonly></input>
				  <button id='dig7on'>Turn On </button></a>
				  <button id='dig7off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO8
				  <input value={{data[6]}} readonly></input>
				  <button id='dig8on'>Turn On </button></a>
				  <button id='dig8off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO9
				  <input value={{data[7]}} readonly></input>
				  <button id='dig9on'>Turn On </button></a>
				  <button id='dig9off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO10
				  <input value={{data[8]}} readonly></input>
				  <button id='dig10on'>Turn On </button></a>
				  <button id='dig10off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO11
				  <input value={{data[9]}} readonly></input>
				  <button id='dig11on'>Turn On </button></a>
				  <button id='dig11off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO12
				  <input value={{data[10]}} readonly></input>
				  <button id='dig12on'>Turn On </button></a>
				  <button id='dig12off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO13
				  <input value={{data[11]}} readonly></input>
				  <button id='dig13on'>Turn On </button></a>
				  <button id='dig13off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO14
				  <input value={{data[12]}} readonly></input>
				  <button id='dig14on'>Turn On </button></a>
				  <button id='dig14off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO15
				  <input value={{data[13]}} readonly></input>
				  <button id='dig15on'>Turn On </button></a>
				  <button id='dig15off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO16
				  <input value={{data[14]}} readonly></input>
				  <button id='dig16on'>Turn On </button></a>
				  <button id='dig16off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO17
				  <input value={{data[15]}} readonly></input>
				  <button id='dig17on'>Turn On </button></a>
				  <button id='dig17off'>Turn Off </button></a><br /> 
				  </center>
				  <center>
				  Pin GPIO18
				  <input value={{data[16]}} readonly></input>
				  <button id='dig18on'>Turn On </button></a>
				  <button id='dig18off'>Turn Off </button></a><br /> 
				  </center><center>
				  Pin GPIO19
				  <input value={{data[17]}} readonly></input>
				  <button id='dig19on'>Turn On </button></a>
				  <button id='dig19off'>Turn Off </button></a><br /> 
				  </center>
				  <center>
				  Pin GPIO20
				  <input value={{data[18]}} readonly></input>
				  <button id='dig20on'>Turn On </button></a>
				  <button id='dig20off'>Turn Off </button></a><br /> 
				  </center>
				  <center>
				  Pin GPIO21
				  <input value={{data[19]}} readonly></input>
				  <button id='dig21on'>Turn On </button></a>
				  <button id='dig21off'>Turn Off </button></a><br /> 
				  </center>
				  <center>
				  Pin GPIO22
				  <input value={{data[20]}} readonly></input>
				  <button id='dig22on'>Turn On </button></a>
				  <button id='dig22off'>Turn Off </button></a><br /> 
				  </center>
				  <center>
				  Pin GPIO23
				  <input value={{data[21]}} readonly></input>
				  <button id='dig23on'>Turn On </button></a>
				  <button id='dig23off'>Turn Off </button></a><br /> 
				  </center>
				  <center>
				  Pin GPIO24
				  <input value={{data[22]}} readonly></input>
				  <button id='dig24on'>Turn On </button></a>
				  <button id='dig24off'>Turn Off </button></a><br /> 
				  </center>
				  <center>
				  Pin GPIO25
				  <input value={{data[23]}} readonly></input>
				  <button id='dig25on'>Turn On </button></a>
				  <button id='dig25off'>Turn Off </button></a><br /> 
				  </center>
				  <center>
				  Pin GPIO26
				  <input value={{data[24]}} readonly></input>
				  <button id='dig26on'>Turn On </button></a>
				  <button id='dig26off'>Turn Off </button></a><br /> 
				  </center>
				  <center>
				  Pin GPIO27
				  <input value={{data[25]}} readonly></input>
				  <button id='dig27on'>Turn On </button></a>
				  <button id='dig27off'>Turn Off </button></a><br /> 
				  </center>
			 </div>

			 <script>
				// Event Listener
				var buttonClick = document.getElementById('btnContainer').addEventListener('click', function(event) {
				  if (event.target.nodeName == "BUTTON") {
					var tar = event.target.id;
					console.log(tar);
					$.getJSON('/'+tar,
						function(data) {
					  //do nothing
					});

					return false;
				  }
				});
			</script>
	</body>
</html>

Zoom on JavaScript code

The JavaScript code will allow us to manage the pressing of the buttons of the interface. To do this we will create a “click” event listener (eventListener) on the “btnContainer” element that will detect if a button (Button) is clicked and will return its identifier via a json request.

// Event Listener

		var buttonClick = document.getElementById('btnContainer').addEventListener('click', function(event) {

		  if (event.target.nodeName == "BUTTON") {

			var tar = event.target.id;

			console.log(tar);

			$.getJSON('/'+tar,

                function(data) {

              //do nothing

            });

            return false;

		  }

		});

File rpi_style.css

The css file contains the style of the page and in particular the buttons so that the page has a personalized aspect.

body{
background-color:#70706F;
}

h1{
	color:#3AAA35;
}

h3{
	#width:100%;
	border: 3px solid #3AAA35;
	border-radius: 6px;
	overflow: hidden; 
	text-align:center;
	padding:20px;
}


button{
  width:auto;
  height:60px;
  background-color: #3aaa35;/* Green */
  border: none;
  color: white;
  /*padding: 15px 32px;*/
  text-align: center;
  vertical-align:middle;
  text-decoration: none;
  display: inline-block;
  font-size: 20px;
  border-radius: 12px;
  -webkit-transition-duration: 0.4s; /* Safari */
  transition-duration: 0.4s;
  margin: 5px;
}
button:hover{
  background-color: #4CAF50; /* Green */
  color: white;
}

Recover the IP address of the Raspberry Pi

In order to access the web interface hosted on the Raspberry Pi, we need to know the IP address so that we can connect to the local network from a web browser. To do this, simply enter the command line ifconfig in the Raspberry Pi terminal.

N.B.: It is possible to access the Raspberry Pi outside the local network by doing a manipulation on the box to which the Raspberry Pi is connected. This procedure is called Port Forwarding.

Result

When you run the Python script on the Raspberry Pi, you can then enter the IP address of your Raspberry Pi followed by the port (here 192.168.1.200:5000) on your computer or smartphone. The web page should appear

You can then see what happens when you press the buttons in the terminal via the VNC application.

Applications

  • Create a home automation system controllable via Wifi
  • Control your Raspberry Pi from anywhere

Sources

Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie

Communication between two ESP32 via WiFi

Communication between two ESP32 via WiFi

The NodeMCU ESP32 is a small microcontroller with a Wi-Fi chip. It is possible to establish a communication between two ESP32, when they are connected on the same network. In this tutorial, we will see a Master/Slave architecture, in which one ESP32 will play the role of a server and manage a web interface as well as the various “slave” requests.

Material

  • Computer
  • NodeMCU ESP32 x2 ou plus
  • USB A Male/Micro B Male Cable

Configure the server with a fixed IP address

In some cases, such as creating a server, you will need to specify a particular IP address to your microcontroller. It is possible to set a fixed address on ESP32s by specifying the IP addresses of the gateway and subnet.

At the command prompt, type arp -a to display the IP addresses already in use on your network. Choose an address that is not in the list (e.g. 192.168.1.103)

Then type ipconfig to retrieve the IP addresses for your router.

Initialise the different IP addresses in the Arduino code (don’t forget to replace these addresses with those displayed on your computer).

IPAddress ip(192, 168, 1,103 );
IPAddress gateway(192, 168, 1, 254);
IPAddress subnet(255, 255, 255, 0);

Then you can configure the Wi-Fi connection before initialising it

WiFi.config(ip, gateway, subnet); // Static IP setup
WiFi.begin(ssid, password);

ESP32 Master Code

For the Master microcontroller, we will create a server to manage the browser requests, the web interface and the requests coming from the slave microcontrollers. We use the WiFi.h library which allows the management of the WiFi chip for the ESP32 cards.

N.B.: Don’t forget to change the values of ssid and password, by the name and the password of the wifi network you want to use

//Libraries
#include <WiFi.h>

//Constants
#define NUM_SLAVES 1
#define LED 2

//Parameters
String nom = "Master";
const char* ssid = "*******";
const char* password = "**********";

//Variables
bool sendCmd = false;
String slaveCmd = "0";
String slaveState = "0";

//Objects
WiFiServer server(80);
WiFiClient browser;
IPAddress ip(192, 168, 1, 44);
IPAddress gateway(192, 168, 1, 254);
IPAddress subnet(255, 255, 255, 0);

void setup() {
  //Init Serial USB
  Serial.begin(115200);
  Serial.println(F("Initialize System"));
  //Init ESP32 Wifi
  WiFi.config(ip, gateway, subnet);       // forces to use the fix IP
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(F("."));
  }
  server.begin();
  Serial.print(nom);
  Serial.print(F(" connected to Wifi! IP address : http://")); Serial.println(WiFi.localIP()); // Print the IP address
  pinMode(LED, OUTPUT);
}

void loop() {
  clientRequest();
}

void clientRequest( ) { /* function clientRequest */
  ////Check if client connected
  WiFiClient client = server.available();
  client.setTimeout(50);
  if (client) {
    if (client.connected()) {
      //Print client IP address
      Serial.print(" ->");Serial.println(client.remoteIP());
      String request = client.readStringUntil('\r'); //receives the message from the client
      
      if (request.indexOf("Slave0") == 0) {
        //Handle slave request
        Serial.print("From "); Serial.println(request);
        int index = request.indexOf(":");
        String slaveid = request.substring(0, index);
        slaveState = request.substring(request.indexOf("x") + 1, request.length());
        Serial.print("state received: "); Serial.println(slaveState);
        client.print(nom);
        if (sendCmd) {
          sendCmd = false;
          client.println(": Ok " + slaveid + "! Set state to x" + String(slaveCmd) + "\r");
        } else {
          client.println(": Hi " + slaveid + "!\r"); // sends the answer to the client
        }
        client.stop();                // terminates the connection with the client
      } else {
        Serial.print("From Browser : "); Serial.println(request);
       
        handleRequest(request);
        webpage(client);
      }
    }
  }
}

void handleRequest(String request) { /* function handleRequest */
  ////Check if client connected
  if (request.indexOf("/light1on") > 0)  {
    digitalWrite(LED, LOW);
  }
  if (request.indexOf("/light1off") > 0)  {
    digitalWrite(LED, HIGH);
  }
  if (request.indexOf("/light2on") > 0)  {
    sendCmd = true;
    slaveCmd = "1";
  }
  if (request.indexOf("/light2off") > 0)  {
    sendCmd = true;
    slaveCmd = "0";
  }
}

void webpage(WiFiClient browser) { /* function webpage */
  ////Send webpage to browser
  browser.println("HTTP/1.1 200 OK");
  browser.println("Content-Type: text/html");
  browser.println(""); //  do not forget this one
  browser.println("<!DOCTYPE HTML>");
  browser.println("<html>");
  browser.println("<head>");
  browser.println("<meta name='apple-mobile-web-app-capable' content='yes' />");
  browser.println("<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />");
  browser.println("</head>");
  browser.println("<body style = ' background-color:#000000; color:white;'>");
  browser.println("<hr/><hr>");
  browser.println("<h1><center> Esp32 Electrical Device Control </center></h1>");
  browser.println("<hr/><hr>");
  browser.println("<br><br>");
  browser.println("<br><br>");
  browser.println("<h2> Commands </h2>");
  browser.println("<center>");
  browser.println("Built-in LED");
  browser.println("<a href='/light1on'><button>Turn On </button></a>");
  browser.println("<a href='/light1off'><button>Turn Off </button></a><br />");
  browser.println("</center>");
  browser.println("<br><br>");
  browser.println("<center>");
  browser.println("Device 2");
  browser.println("<a href='/light2on'><button>Turn On </button></a>");
  browser.println("<a href='/light2off'><button>Turn Off </button></a><br />");
  browser.println("</center>");
  browser.println("<br><br>");
  browser.println("<br><br>");
  browser.println("<h2> Data </h2>");
  browser.println("<center>");
  browser.println("<table border='5'>");
  browser.println("<tr>");
  if (digitalRead(LED))
  {
    browser.print("<td>LED is OFF</td>");
  }
  else
  {
    browser.print("<td>LED is ON</td>");
  }
  browser.println("<br />");
  if (slaveState == "1") //(digitalRead(4))
  {
    browser.print("<td>Light 2 is OFF</td>");
  }
  else
  {
    browser.print("<td>Light 2 is ON</td>");
  }
  browser.println("</tr>");
  browser.println("</table>");
  browser.println("</center>");
  browser.println("</body></html>");
  delay(1);
}

Code ESP32 Esclave

In the slave code, we will connect to the server using the previously used IP address.

N.B.: Don’t forget to modify and use the same ssid and password values as in the Master module so that both ESP32 cards are connected to the same network.

//Libraries
#include <WiFi.h>

//Constants
#define LED 2
#define UPDATE_TIME 500

//Parameters
String nom = "Slave0";
const char* ssid = "*******";
const char* password = "*******";

//Variables
String command;
unsigned long previousRequest = 0;

//Objects
WiFiClient master;
IPAddress server(192, 168, 1, 44);

void setup() {
  //Init Serial USB
  Serial.begin(115200);
  Serial.println(F("Initialize System"));
  //Init ESP32 Wifi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(F("."));
  }
  Serial.print(nom);
  Serial.print(F(" connected to Wifi! IP address : ")); Serial.println(WiFi.localIP()); // Print the IP address
  pinMode(LED, OUTPUT);
}

void loop() {
  requestMaster();
}

void requestMaster( ) { /* function requestMaster */
  ////Request to master
  if ((millis() - previousRequest) > UPDATE_TIME) { // client connect to server every 500ms
    previousRequest = millis();

    if (master.connect(server, 80)) { // Connection to the server
      master.println(nom + ": Hello! my current state is x" + String(!digitalRead(LED)) + "\r");

      //answer
      String answer = master.readStringUntil('\r');   // receives the answer from the sever
      master.flush();
      Serial.println("from " + answer);
      if (answer.indexOf("x") >= 0) {
        command = answer.substring(answer.indexOf("x") + 1, answer.length());
        Serial.print("command received: "); Serial.println(command);
        if (command == "1") {
          Serial.println("LED ON");
          digitalWrite(LED, LOW);
        } else {
          Serial.println("LED OFF");
          digitalWrite(LED, HIGH);
        }
      }
    }
  }
}



Result

When the microcontrollers are connected to the Wi-Fi and communication between the two ESP32s is established, we can see that information and commands are exchanged between the two boards. It is also possible to control the LEDs on both boards using the buttons on the interface.

In this tutorial, we have seen how to make two ESP32s communicate over the local Wi-Fi network. It is also possible to reproduce this tutorial using the ESP32 Master card in Access Point mode.

Applications

  • Create a network of Esp32 NodeMCUs (or other microcontrollers) to manage different devices or sensors

Sources