Easiest and earliest way to control ESP8266 from a smartphone

Android smartphone sends some data through WiFi, ESP8266/ESP32 receives it, interprets it and switches something on and off accordingly. From my personal perspective, it may be considered to be a "Hello World!" of all things ESP.

As far as I know, the easiest way to implement it is programming ESP to become a web server (presumably with the use of ESP8266WebServer of WebServer library) and sending appropriate requests from a web browser of another application capable of sending HTTP requests.

But Is it, in fact, the most simple and straightforward way? When ESP-01 had just arisen, was it an unofficial standard method for making such basic projects? Or maybe folks tended to use other methods, like "WiFi to Serial" stuff I'd heard off?

I now use a web interface. I have a little skill in HTML so it is fairly easy to do simple things. When I started I used a BlueTooth serial interface. I find a web interface easier. YMMV.

Here is a state machine example I posted a year ago. It has a bit of everything web server, name server and blinking Led. I just tested it on an esp-01.

/* ***********************************************************************************************
 * 
 * oldcurmudgeon November 6 2021
 * 
 * This sketch is for an ESP8266 to provide a web interface for blinking an LED
 *
 * The onboard LED is used so no additional hardware is needed
 *
 * It is implemented as 2 state machines. The first has the state defined by the pattern
 * being run. The state is defined by currentPattern. The state transition is done via 
 * a browser request changing newState to define the next state.
 *
 * The second state machine defines the step in the pattern of blinks. The state transition
 * occurs when the current time for the LED state expires. When the time is up the LED toggles
 * to the other state and the time for that state starts. At the end of the pattern it is
 * started over from the beginning. 
 * 
 *************************************************************************************************/ 


#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

const char* ssid = "your-ssid";
const char* password = "your-pw";

ESP8266WebServer server(80);

#include <string.h>
#include <Streaming.h>   //  from "Streaming by Mikal Hart" in library manager

// Pattern selection state machine variables
volatile uint16_t newPattern = 0;  //default to first pattern volatile because it is set asynchronously
uint16_t currentPattern = 0; // default first pattern

// Pattern step state machine variables
byte step = 0;                // current step in pattern default to start
unsigned long currentTime;   // current time for test
unsigned long startTime;     // start time of this step

// led on state - the onboard led is active low (when the pin is low the led
// is on). If you are using some other pin to drive the led so that the led is on when
// the pin is high this should be changed to one.
const byte LED_ON = 0; 
byte ledState = LED_ON;     // current led state default on

// led patterns - this is a series of numbers defining the led on and off times
// This example is 4 patterns of 6 changes. A zero before the end of the pattern
// indicates a short pattern that restarts when it detects a zero.
const byte NUM_PATTERNS = 4;    // number of patterns 
const byte PATTERN_LEN = 6;    // pattern length
const unsigned long pattern[ NUM_PATTERNS][PATTERN_LEN] = 
        {{200,200,200,200,200,200},
        {1500,1500,1500,1500,1500,01500},
        {1500,1500,200,200,0,0},           // short pattern example 
        {1500,1500,1500,1500,200,200}};
/* ***************************************************************************
*
* Handle root web page
*
******************************************************************************/
void handleRoot() {
  if (server.hasArg("pattern")){ // the browser has sent a response
    // Save new value from web page browser response  
    newPattern = server.arg("pattern").toInt();
  }
   /* Build html page
    * 
    * The new lines (\n) are not required by the browser - they are formatting for a human 
    * looking at the page source on the browser
    * 
    * The "String((newPattern == x) ? " checked" : " ")"  construct is used to set the
    * pattern selected as checked when the web page is refreshed. If newPage is equal to
    * the value "checked" is added to the attributes, otherwise a blank is added. You can
    * see the result on the web page by right-click then select "View Page Source".
    * This will show the actual HTML sent to the browser.
   */ 
  String htmlPage =
    String("<!DOCTYPE HTML>\n") 
    + "<html lang='en'>\n"
    + "<head>\n"
    + "<!-- Ignore request for nonexistent favicon -->\n"
    + "<link rel='icon' href='data:,'>\n"
    + " <meta name='viewport' content='width=device-width, initial-scale=1.0'>"
    +"</head>\n"
    + "<body>\n\n"
    + "<h1 style='text-align: center;'>LED Pattern Blinker</h1>\n"
    + "<div>\n"
    + "<form style='font-size: 20px'>\n"
    +   " <input type='radio' name='pattern' value='0' required"
    +  String((newPattern == 0) ? " checked" : " ")        
    +   " > Short blink<br>\n"
    +   " <input type='radio' name='pattern' value='1' required"
    +  String((newPattern == 1) ? " checked" : " ") 
    +   "> Long blink<br>\n"
    +   " <input type='radio' name='pattern' value='2' required"
    +  String((newPattern == 2) ? " checked" : " ") 
    +   "> Long Short blink <br>\n"
    +   " <input type='radio' name='pattern' value='3' required"
    +  String((newPattern == 3) ? " checked" : " ") 
    +   "> Long Long Short blink<br>\n"
    +   "<input type='submit' value='Set Pattern'>\n"
    +   "</div>\n"
    +"</body>\n</html>\n";

  server.send(200, "text/html",htmlPage);
    
}

void handleNotFound() {
    // no clue what they sent
    String message = "File Not Found\n\n";
    message += "URI: ";
    message += server.uri();
    message += "\nMethod: ";
    message += (server.method() == HTTP_GET) ? "GET" : "POST";
    message += "\nArguments: ";
    message += server.args();
    message += "\n";

    for (uint8_t i = 0; i < server.args(); i++) {
      message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
    }

    server.send(404, "text/plain", message);

}

void setup() {
  pinMode(LED_BUILTIN,OUTPUT);

  Serial.begin(19200);
   

  // Set up WiFi network
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // Set up mDNS responder:
  // - first argument is the domain name, in this example
  //   the fully-qualified domain name is "esp8266.local"
  // - second argument is the IP address to advertise
  //   we send our IP address on the WiFi network
  if (!MDNS.begin("esp8266")) {
    Serial.println("Error setting up MDNS responder!");
    while (1) {
      delay(1000);
    }
  }
  Serial.println("mDNS responder started");

  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);
  
  // Start the server
  server.begin();
  Serial.println("TCP server started");

  // Add service to MDNS-SD
  MDNS.addService("http", "tcp", 80);
  
  startTime = millis();      // get current time for start of pattern
}

void checkPattern() {
    if (newPattern != currentPattern){     // browser has sent a new pattern
        // switch to new pattern
        ledState = LED_ON;  // start with led on
        digitalWrite(LED_BUILTIN,ledState);  // start with led on
        step = 0;   // start at beginning of pattern
        currentPattern = newPattern;  // switch to new pattern
        startTime = millis();      // get current time for start of pattern
    } 
};    

void loop() {
    
  MDNS.update();
     
  server.handleClient();      // check for connection request
  
  // Check to see if there is a new pattern request. If the check is done here
  // the new pattern starts immediately. If you want the new pattern to start 
  // after the current pattern has completed, comment out the line below and uncomment
  // the one in the end of pattern processing
  checkPattern();
  
  currentTime = millis();      // get current time for compare
  if (currentTime  - startTime > pattern[currentPattern][step]) {
     // done with this step 
     ledState ^= 1;  // toggle led state
     digitalWrite(LED_BUILTIN,ledState);  // change led state       
     step++;             // next step
     startTime = currentTime;  // start next led pattern step time
     if ((step >= PATTERN_LEN)                    // end of pattern
         || (pattern[currentPattern][step]==0)){  // or short pattern
        // end of pattern processing     
        step = 0;   //restart pattern
        
        // Check to see if there is a new pattern request. If the check 
        // is done here the new pattern starts after the current pattern
        // has completed. (Remember to comment out the call above.)
       // checkPattern();        
     }
  }     
}  

The ESP32's BT is really easy to access and use with any BT Serial Terminal app you may find (Kai Morich, mightyIT). It's pretty easy to send and receive serial.

The ESP8266 has only WiFi. If you know all about HTML and that then you can do with webpages and so.

I'd like to see a ESP-to-Serial_WiFi_Terminal (Kai Morich) implementation all laid out (step-by-step, how-to-do-it, no jargon).

Oh, me too!

with the ESP32 I would tend to use Bluetooth or BLE with smartphone app implemented using MIT app Inventor
in the case of WiFi it depends on the functionality required, e.g. ESP8266 example: Wi-Fi Access point, static IP, web-server and remote GPIO control, ESP8266 NodeMCU Web Server using Server-Sent Events, etc

@erlingsigurdson
FWIW, I used this in an '8266/NodeMCU → →

/*
 
  WebSerial Demo
  ------
  This example code works for both ESP8266 & ESP32 Microcontrollers
  WebSerial is accessible at your ESP's <IPAddress>/webserial URL.
  Author: Ayush Sharma
  Checkout WebSerial Pro: https://webserial.pro
*/
#include <Arduino.h>
#if defined(ESP8266)
  #include <ESP8266WiFi.h>
  #include <ESPAsyncTCP.h>
#elif defined(ESP32)
  #include <WiFi.h>
  #include <AsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>
#include <WebSerial.h>

AsyncWebServer server(80);

const char* ssid = ""; // Your WiFi SSID in quotes
const char* password = ""; // Your WiFi Password in quotes

/* Message callback of WebSerial */
void recvMsg(uint8_t *data, size_t len)
{
  WebSerial.println("Received Data...");
  String dd = "";
  for(int idx=0; idx < len; idx++)
  {
    dd += char(data[idx]);
  }
  WebSerial.println(dd);
  
  Serial.print("\r\n Got smartphone xmsn \r\n"); // r_p
  Serial.println(dd); // r_p
}

void setup() 
{
  Serial.begin(115200);
  delay(2000);
  Serial.print("\r\n\r\nSerMon Ready");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) 
  {
    Serial.printf("WiFi Failed!\n");
    return;
  }
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
    // WebSerial is accessible at "<IP Address>/webserial" in browser
  WebSerial.begin(&server);
    /* Attach Message Callback */
  WebSerial.msgCallback(recvMsg);
  server.begin();
}

void loop() {
}

With the WebSerial webpage on my smartphone I can type in chars there and hit the send button and '8266 sends back "Received Data..." and echoes the chars in the webpage. I added a couple of lines where the smartphone data is printed in SerialMonitor.
No provision to send data from SerialMonitor.

It can 'connect' that to Morich's Serial WiFI Terminal and it seems to 'send' a data packet, but I can't get a response from the '8266 (WebSerial webpage).

There is no "Standard". It's just what you need or prefer. Some people like to have an app - some people like to have just a web GUI (on the webserver of the ESP). Personally I prefer the all in one on the ESP - webserver on the ESP - which can be accessed by a simple browser without the need of a dedicated app. And I only have to care about one program ... the program for the ESP.

My version of a generic ESP webserver as a start:
https://werner.rothschopf.net/microcontroller/202108_esp_generic_webserver_en.htm

1 Like

Webserver on the ESP8266/ESP32 with websockets and JSon communication for the websockets. You can make almost all what you want. Many examples to find on the internet.

As example you open the webinterface on multiple devices. One of them turn the lights on. The ESP receive the (JSon) message, turn the lights on and send a (JSon)message that the lights are on. All the devices show the lights are on.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.