Skip to content

15. Interface and application programming

Group assignment:

Compare as many tool options as possible

Group Assignment

Individual assignment:

For this week, it was required to write an application that interfaces with an input &/or output device that you made.

I use Processing as Interface and application programming Langauge and program ESP32CAM with arduino IDE.

ON/OFF LED with GUI Button Demo

Let’s make a application for the ESP32CAM shield board that I made before.

First try to make the board communicate with the serial port to see if the component transmits the detection value normally. Use Serial.read() to get “H” and “L” to control LED on GPIO 4.

Change the Application Background with Button Demo

I use Serial.write because Serial.write is more down to earth , it is simple and fast, it is made to talk binary, one byte at a time. Serial.print in the other hand is more versatile , it will do the conversion for you from ASCII to binary it also can convert to BIN/ HEX/OCT/DEC.

Arduino Code Example

int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)
void setup()
{
  Serial.begin(115200);
  delay(100); // give me time to bring up serial monitor
}
void loop()
{
  // read the analog in value:
  sensorValue = analogRead(13);
  // map it to the range of the analog out:
  outputValue = map(sensorValue, 0, 4095, 0, 255);
  Serial.write(outputValue);
  // wait 50 milliseconds before the next loop for the analog-to-digital
  // converter to settle after the last reading:
  delay(50);
}

Processing Code Example (Change Background with Button)

import processing.serial.*;
Serial myPort;
int x; 
void setup(){
  size(640,360);
  myPort=new Serial(this,"COM12",115200);
}
void draw(){
  background(x);
}
void serialEvent(Serial p){
  x=myPort.read();
}

Processing Code Example (Move Circle with Potentiometer)

import processing.serial.*;
Serial myPort;
int x; 
void setup(){
  size(640,360);
  myPort=new Serial(this,"COM12",115200);
}
void draw(){
  background(100);
  ellipse(x+200,180,60,60);
}
void serialEvent(Serial p){
  x=myPort.read();
}

ESP32CAM with 18B20 Temperature Server and Processing PC Station

The sample rate is 0.5S. Wifi Server Application use ESPAsyncWebServer method to display the content with html. PC Station get the data with serial port.

Processing Code Example (18B20 PC Station)

import meter.*;
import processing.serial.*;
Serial port;
Meter M1, M2;
void setup() {
  size(850, 350);
  background(0);
  //port = new Serial(this, "COM3", 9600);
  port = new Serial(this, "COM12", 115200);
  fill(120, 50, 0);
  M1 = new Meter(this, 10, 100);
  // Adjust font color of meter value  +
  M1.setMeterWidth(400);
  M1.setTitleFontSize(20);
  M1.setTitleFontName("Arial bold");
  M1.setTitle("Temperature (°C)");
  M1.setDisplayDigitalMeterValue(true);

  // Meter Scale
  String[] scaleLabelsT = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100", "110", "120", "130", "140", "150"};
  M1.setScaleLabels(scaleLabelsT);
  M1.setScaleFontSize(18);
  M1.setScaleFontName("Times New Roman bold");
  M1.setScaleFontColor(color(200, 30, 70));

  M1.setArcColor(color(141, 113, 178));
  M1.setArcThickness(10);
  M1.setMaxScaleValue(150);

  M1.setNeedleThickness(3);

  M1.setMinInputSignal(0);
  M1.setMaxInputSignal(150);
  // A second meter for reference
  int mx = M1.getMeterX();
  int my = M1.getMeterY();
  int mw = M1.getMeterWidth();

  M2 = new Meter(this, mx + mw + 20, my);
  M2.setMeterWidth(400);
  M2.setTitleFontSize(20);
  M2.setTitleFontName("Arial bold");
  M2.setTitle("Temperature (°F)");
  M2.setDisplayDigitalMeterValue(true);

  String[] scaleLabelsH = {"20", "40", "60", "80", "100", "120", "140", "160", "180", "200", "220", "240", "260", "280", "300"};
  M2.setScaleLabels(scaleLabelsH);
  M2.setScaleFontSize(18);
  M2.setScaleFontName("Times New Roman bold");
  M2.setScaleFontColor(color(200, 30, 70));
  M2.setArcColor(color(141, 113, 178));
  M2.setArcThickness(10);
  M2.setMaxScaleValue(300);
  M2.setNeedleThickness(3);
  M2.setMinInputSignal(0);
  M2.setMaxInputSignal(300);

}
public void draw() 
{
  textSize(30);
  fill(255, 255, 255);
  text("ESP32 18B20 Temperature PC Station", 150, 50);

  if (port.available() > 0) {
      String val = port.readString();
      float TempC = float(val);
      float TempF = (TempC * 1.8) + 32;
      M1.updateMeter(int(TempC));
      M2.updateMeter(int(TempF));
  }
}

Esp32_DS18B20_Async_Web_Server

/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com  
*********/

// Import required libraries
#ifdef ESP32
  #include <WiFi.h>
  #include <ESPAsyncWebServer.h>
#else
  #include <Arduino.h>
  #include <ESP8266WiFi.h>
  #include <Hash.h>
  #include <ESPAsyncTCP.h>
  #include <ESPAsyncWebServer.h>S
#endif
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is connected to GPIO 0
#define ONE_WIRE_BUS 0

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature sensor 
DallasTemperature sensors(&oneWire);

// Variables to store temperature values
String temperatureF = "";
String temperatureC = "";

// Timer variables
unsigned long lastTime = 0;  
unsigned long timerDelay = 500;

// Replace with your network credentials
const char* ssid = "fablab";
const char* password = "27796851";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

String readDSTemperatureC() {
  // Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus
  sensors.requestTemperatures(); 
  float tempC = sensors.getTempCByIndex(0);

  if(tempC == -127.00) {
    Serial.println("Failed to read from DS18B20 sensor");
    return "--";
  } else {
    //Serial.print("Temperature Celsius: ");
    //Serial.println(tempC); 
    Serial.print(tempC); 
  }
  return String(tempC);
}

String readDSTemperatureF() {
  // Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus
  sensors.requestTemperatures(); 
  float tempF = sensors.getTempFByIndex(0);

  if(int(tempF) == -196){
    Serial.println("Failed to read from DS18B20 sensor");
    return "--";
  } else {
   // Serial.print("Temperature Fahrenheit: ");
    //Serial.println(tempF);
  }
  return String(tempF);
}

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
  <style>
    html {
     font-family: Arial;
     display: inline-block;
     margin: 0px auto;
     text-align: center;
    }
    h2 { font-size: 3.0rem; }
    p { font-size: 3.0rem; }
    .units { font-size: 1.2rem; }
    .ds-labels{
      font-size: 1.5rem;
      vertical-align:middle;
      padding-bottom: 15px;
    }
  </style>
</head>
<body>
  <h2>ESP DS18B20 Server</h2>
  <p>
    <i class="fas fa-thermometer-half" style="color:#059e8a;"></i> 
    <span class="ds-labels">Temperature Celsius</span> 
    <span id="temperaturec">%TEMPERATUREC%</span>
    <sup class="units">&deg;C</sup>
  </p>
  <p>
    <i class="fas fa-thermometer-half" style="color:#059e8a;"></i> 
    <span class="ds-labels">Temperature Fahrenheit</span>
    <span id="temperaturef">%TEMPERATUREF%</span>
    <sup class="units">&deg;F</sup>
  </p>
</body>
<script>
setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("temperaturec").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/temperaturec", true);
  xhttp.send();
}, 500) ;
setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("temperaturef").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/temperaturef", true);
  xhttp.send();
}, 500) ;
</script>
</html>)rawliteral";

// Replaces placeholder with DS18B20 values
String processor(const String& var){
  //Serial.println(var);
  if(var == "TEMPERATUREC"){
    return temperatureC;
  }
  else if(var == "TEMPERATUREF"){
    return temperatureF;
  }
  return String();
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);
  Serial.println();

  // Start up the DS18B20 library
  sensors.begin();

  temperatureC = readDSTemperatureC();
  temperatureF = readDSTemperatureF();

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  Serial.println("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  // Print ESP Local IP Address
  Serial.println(WiFi.localIP());

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });
  server.on("/temperaturec", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", temperatureC.c_str());
  });
  server.on("/temperaturef", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", temperatureF.c_str());
  });
  // Start server
  server.begin();
}

void loop(){
  if ((millis() - lastTime) > timerDelay) {
    temperatureC = readDSTemperatureC();
    temperatureF = readDSTemperatureF();
    lastTime = millis();
  }  
}

Flappy Bird Game

The idea of the game is to flap your bird through as many pipes as possible without hitting a single one. I use the SRF-04 Ultrasonic sensor as wireless physical controller to control flappy bird.(Source: https://www.instructables.com/Flappy-Bird-Using-Arduino-and-Processing/)

Flappy Bird Game

Hint: Processing and Arduino programes need match the COM PORT and baud rate.

Supplementary ESP32 Servo Motor Web Server with Arduino IDE

Referred by Week11 - ESP32 Input Board, I use the GPIO 13 as servo control pin. In this week we’re going to show you how to build a web server with the ESP32 that controls the shaft’s position of a servo motor using a slider.

Connecting the Servo Motor to the ESP32

Upload week13’s code to ESP32 board. After uploading the code, you should see the motor’s shaft rotating to one side and then, to the other.

Creating the ESP32 Web Server

Let’s create the web server to control a servo with the ESP32. The web server contains a slider from 0 to 180, that we can adjust to control the servo’s shaft position; The current slider value is automatically updated in the web page, as well as the shaft position, without the need to refresh the web page. For this, we use AJAX to send HTTP requests to the ESP32 on the background; Refreshing the web page doesn’t change the slider value, neither the shaft position.

#include <WiFi.h>
#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

// GPIO the servo is attached to
static const int servoPin = 13;

// Replace with your network credentials
const char* ssid     = "SB2";
const char* password = "2222112222";

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

// Decode HTTP GET value
String valueString = String(5);
int pos1 = 0;
int pos2 = 0;

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0; 
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);

  myservo.attach(servoPin);  // attaches the servo on the servoPin to the servo object

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
      currentTime = millis();
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the on/off buttons 
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");
            client.println(".slider { width: 300px; }</style>");
            client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");

            // Web Page
            client.println("</head><body><h1>ESP32 with Servo</h1>");
            client.println("<p>Position: <span id=\"servoPos\"></span></p>");          
            client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider\" onchange=\"servo(this.value)\" value=\""+valueString+"\"/>");

            client.println("<script>var slider = document.getElementById(\"servoSlider\");");
            client.println("var servoP = document.getElementById(\"servoPos\"); servoP.innerHTML = slider.value;");
            client.println("slider.oninput = function() { slider.value = this.value; servoP.innerHTML = this.value; }");
            client.println("$.ajaxSetup({timeout:1000}); function servo(pos) { ");
            client.println("$.get(\"/?value=\" + pos + \"&\"); {Connection: close};}</script>");

            client.println("</body></html>");     

            //GET /?value=180& HTTP/1.1
            if(header.indexOf("GET /?value=")>=0) {
              pos1 = header.indexOf('=');
              pos2 = header.indexOf('&');
              valueString = header.substring(pos1+1, pos2);

              //Rotate the servo
              myservo.write(valueString.toInt());
              Serial.println(valueString); 
            }         
            // The HTTP response ends with another blank line
            client.println();
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Testing the Web Server

  • Upload the code to ESP32
  • Open your browser, paste the ESP IP address, and you should see the web page you’ve created previously. Move the slider to control the servo motor.

ESP32 Servo Motor Web Server


Last update: July 3, 2021