Week 12: Interface and Application Programming 

Application Programming For Servo Motor

The individual assignments this week is to write an application that interfaces a user with an input and/or output device that I made. Specifically, I planned to make an application that interfaces with a servo motor (output device). 

Since my final project is to make a motor that is timer-controlled, I decided I wanted to make an app with Google AppSheet. AppSheet reads data from a Google Sheets file which is great, because the ESP32 microcontroller is capable of reading / communicating with a Google Sheets File! For example, this person in the video link below connected an ESP32 to communicate with Google Sheets: 

https://www.youtube.com/watch?v=0LoeaewIAdY

So, the first step I took was to create a Google Sheets file and populate it with some key data that I would want to then drive the behavior of the motor: 

Next, I went to script.google.com > New Project. 

Next, I used the following tutorial for ESP32 communication with Google Sheets: 

https://docs.leafony.com/en/docs/examples/advanced/2_p/esp32/esp32_googlesheets_1/

First, I copied the part of the url in google sheets after the https://docs.google.com/spreadsheets/d/

12uV6i5-bm_KL8Ydc3ERwt6YUTzVqRkSRn95GLOafwXM/edit#gid=0 

Next, I copy-pasted the Leafony example code into my new project within script.google.com as follows: 

Then, I edited line 3 and line 4 per the tutorial instructions. For line 3 I replaced 'google_sheets_id' with the copied url from my google sheets as explained above, and on line 4 I replaced 'sheet_name' with the name of my google sheets file (HTMAA-Motor-Data). 

Next, click on Publish > Deploy (in the newer version of the software, just click on Deploy > New Deployment. 

After clicking on New Deployment, click the gear icon and select Web App. 

Change access permissions to Anyone (not just people with a google account and not just yourself). Then click the Deploy button. 

Next, copy the web app URL. In my case, this is:

 https://script.google.com/macros/s/AKfycbzxYmu2w9IVbgTiYWXlnFaj4X2fgBE3cYZqDqEW2-_2SlWz-fQEBPVpZCeiNI8GxBLPYw/exec 

Unfortunately, I kept getting an error when trying to paste the url into my browser: 

Unfortunately, I got stuck and wasn't sure what to do at this point.

This is what I want my app to look like (and what the user interface looks like in AppSheet): 

Since it wasn't working well for me and it was too late to get TA help at this point after Thanksgiving break, I moved on to attempt to use Processing. Below is a tutorial I tried to follow for connecting my Servo Motor to an app using Processing: 

https://www.instructables.com/Servo-Motor-Control-Using-Arduino-and-Processing/

Here's the associated Arduino code: 

Unfortunately, I didn't have a tilt-able Servo with me and was unable to get it to work. But, here's how I would connect the ESP32 to the Servo motor: 


After going to office hours later, I learned that perhaps just a basic interface in Processing would be best. For example, Jordan Gowen from 2020 for HTMAA class has a wonderful example of an app in processing: 

http://fab.cba.mit.edu/classes/863.20/Architecture/people/JordanGowen/week12.html

My goal, in preparation for the final project, is to make an interface with several buttons that can start timers: 

1) 50 min timer button

2) 10 min timer button

Each of these buttons, respectively, should start timers so that the motor will turn in a particular direction after that time is up. 


Ok, time to start over... I found a good ESP32 web app tutorial here! 

https://randomnerdtutorials.com/esp32-web-server-arduino-ide/

This worked wonderfully!!! Hooray!! I was able to click the different buttons to change the state of LED's or other output devices on the ESP32. 


Below are two views of the web app for the ESP32 that I made. You can click on a button to change the state of an LED or other output device, and it will change color in real time in the web app, and show that you have pressed the button. 




Yay! Super easy and it worked great, especially with the EECS_Labs wifi in the EECS shop! I plan to use a similar interface for my final project. 


Note that this was the ESP32 Board that I used: 

You can see below the pins specified: 

I used a 3.3V FTDI-to-USB cable to attach the GND, CTS, 5V, TX, and RTS to my laptop. When uploading the Arduino IDE code, I switched the switch so the black switch faces towards the ESP32, press the tactile button, then click Upload arrow symbol in Arduino. After that, once the code gets processed in the Arduino IDE, I then turn the black little switch in the other direction away from the ESP32 microcontroller component on the board, and press the tan-colored tactile button one last time. 

Here's the code: 

/*********

  Rui Santos

  Complete project details at https://randomnerdtutorials.com  

*********/



// Load Wi-Fi library

#include <WiFi.h>



// Replace with your network credentials

const char* ssid = "EECS_Labs";

const char* password = "";



// Set web server port number to 80

WiFiServer server(80);



// Variable to store the HTTP request

String header;



// Auxiliar variables to store the current output state

String output26State = "off";

String output27State = "off";



// Assign output variables to GPIO pins

const int output26 = 26;

const int output27 = 27;



// 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);

  // Initialize the output variables as outputs

  pinMode(output26, OUTPUT);

  pinMode(output27, OUTPUT);

  // Set outputs to LOW

  digitalWrite(output26, LOW);

  digitalWrite(output27, LOW);



  // 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();

            

            // turns the GPIOs on and off

            if (header.indexOf("GET /26/on") >= 0) {

              Serial.println("GPIO 26 on");

              output26State = "on";

              digitalWrite(output26, HIGH);

            } else if (header.indexOf("GET /26/off") >= 0) {

              Serial.println("GPIO 26 off");

              output26State = "off";

              digitalWrite(output26, LOW);

            } else if (header.indexOf("GET /27/on") >= 0) {

              Serial.println("GPIO 27 on");

              output27State = "on";

              digitalWrite(output27, HIGH);

            } else if (header.indexOf("GET /27/off") >= 0) {

              Serial.println("GPIO 27 off");

              output27State = "off";

              digitalWrite(output27, LOW);

            }

            

            // 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>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");

            client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");

            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");

            client.println(".button2 {background-color: #555555;}</style></head>");

            

            // Web Page Heading

            client.println("<body><h1>Turtle Box: Time To Shellebrate!</h1>");

            

            // Display current state, and ON/OFF buttons for GPIO 26  

            client.println("<p>50 min Work - " + output26State + "</p>");

            // If the output26State is off, it displays the ON button       

            if (output26State=="off") {

              client.println("<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>");

            } else {

              client.println("<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>");

            } 

               

            // Display current state, and ON/OFF buttons for GPIO 27  

            client.println("<p>10 min Break - " + output27State + "</p>");

            // If the output27State is off, it displays the ON button       

            if (output27State=="off") {

              client.println("<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>");

            } else {

              client.println("<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>");

            }

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

            

            // 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("");

  }

}


Group Assignment: Tool Comparisons

The group assignment for this week is to compare as many tool options as possible. 

Here is a link to the Group Assignment for this week on the Architecture site: https://docs.google.com/document/d/1hW7gOiqgb8SjjVqJJjOXGXEUXpyKwsEAWuTmP_ajesc/edit 

This document compares several different tools that can be used for application programming. On my end, I am aware of Python, Processing, and AppSheet as my primary preferences for application programming, but there are many others that exist too! 

  • Processing: Older application programming interface, commonly used with Arduino 
  • Python: Highly versatile with regards to visual appearance of the application 
  • AppSheet/Google Sheets: User-friendly to set up an easy app that can talk to an ESP32 microcontroller 

Below is a very wonderful chart comparing some of these (and other) application programming languages / tools 


Learnings & Advanced Applications 

Learnings: 

  • Appsheet seems to have a buggy error, and it seems that AppScript is quite frequently changing their user interface for scripting (e.g. 2021 instructions are already slightly out of date!) 
  • You can connect Google Sheets to ESP32, and connect an AppSheet iPhone or web app to Google Sheets, to create an app that reads or writes data to/from the ESP32 microcontroller. 

Advanced Applications: 

  • If I had more time, I would have tried setting up an application using Python! There are many other programming languages and types of interfaces that I could make for the app user interface. 
  • Both reading & writing information on a web app to then send/read signals to an input or output device 


Control of Motor & Buzzer Using Processing GUI 

To the left is a video of my Processing code (and corresponding Arduino code) which allows a motor and buzzer to be controlled by buttons on a Processing GUI interface.