Code to Force client To Refresh on Event?

I’ve been playing around with using an ESP8266-01 with an Ardiono Mega2560, using the WiFiEsp.h library. Everything seems simple enough, but I think my lack of HTML experience is starting to become evident.

I understand how to have the page reload on the client on an interval, but what I’m looking for is a way to not require a continual refresh.

I’m essentially using the WebServerLED example code, and adding a button to the Arduino to also control the state of the LED.

So the LED can be turned on/off on the webpage, but also can be turned on/off with a physical button.

When the button is used, I’d like the Arduino code to force a refresh on the network client; but not by having the network client refresh every 1 second (or every 5 seconds, etc …)

In the below code (my modified version of the WebServerLED example), I added this line to the HTTP header:

 client.println("Refresh: 4;URL='//192.168.0.158:80/'>");

Which works to refresh every 4 seconds and display the state of the LED, if it was toggled by the button. But like I said, I’d rather find a way to only refresh when needed.

Here is the full code as it sits right now. I understand it’s not as efficient as it can be, and I have’t gone through and fully commented it yet; as I’m just experimenting right now with my approach.

#include "WiFiEsp.h"


// ********************************************************* DEFINITIONS *********************************************************
// PIN DEFINITIONS -----------------------------------------------
int LED_PIN = 46;
int Button_PIN = 10;

// VARIABLE DEFINITIONS -----------------------------------------------
char ssid[] = "xxxxxxx";         // your network SSID (name)
char pass[] = "yyyyyyy";      // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status
WiFiEspServer server(80);
RingBuffer buf(8);               // use a ring buffer to increase speed and reduce memory allocation
bool ledStatus = LOW;
int ButtonState = 0;
int PrevButtonState = 0;


// ********************************************************* INITIALIZE *********************************************************
void setup() {
// Pin Modes -----------------------------------------------
pinMode (LED_PIN, OUTPUT);
pinMode (Button_PIN, INPUT_PULLUP);

  Serial.begin(115200);                         // initialize serial for debugging
  Serial1.begin(115200);                        // initialize serial for ESP module
  WiFi.init(&Serial1);                          // initialize ESP module
  ConnectWiFi();
  server.begin();

}

// ********************************************************* MAIN LOOP *********************************************************
void loop() {
  WiFiEspClient client = server.available();  // listen for incoming clients
  CheckButtonState(client);
  HandleClient(client);
  digitalWrite(LED_PIN, ledStatus);

}

// *********************************************************  FUNCTION DEFINITIONS *********************************************************
void CheckButtonState(WiFiEspClient client) {
  ButtonState = !digitalRead(Button_PIN);
  if (ButtonState != PrevButtonState) {
    Serial.print("Button State: ");
    Serial.println(ButtonState);
    ledStatus = ButtonState;
    Serial.print("LED Status: ");
    Serial.println(ledStatus);
    PrevButtonState = ButtonState;
    sendHttpResponse(client);
  }

}

// Handle Client Connections ------------------------------------------------------------
void HandleClient(WiFiEspClient client) {                               // if you get a client,

  if (client) {
    Serial.println("New client");             // print a message out the serial port
    buf.init();                               // initialize the circular buffer
    while (client.connected()) {              // loop while the client's connected
      if (client.available()) {               // if there's bytes to read from the client,
        char c = client.read();               // read a byte, then
        buf.push(c);                          // push it to the ring buffer

        
        // you got two newline characters in a row
        // that's the end of the HTTP request, so send a response
        if (buf.endsWith("\r\n\r\n")) {
          sendHttpResponse(client);
          break;
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (buf.endsWith("GET /H")) {
          Serial.println("Turn led ON");
          ledStatus = HIGH;
          digitalWrite(LED_PIN, HIGH);   // turn the LED on (HIGH is the voltage level)
        }
        else if (buf.endsWith("GET /L")) {
          Serial.println("Turn led OFF");
          ledStatus = LOW;
          digitalWrite(LED_PIN, LOW);    // turn the LED off by making the voltage LOW
        }
      }
    }
    
    // close the connection
    client.stop();
    Serial.println("Client disconnected");
  }
}

// Send HTTP Response to Client ------------------------------------------------------------
void sendHttpResponse(WiFiEspClient client)
{
  // 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("Refresh: 4;URL='//192.168.0.158:80/'>");
  client.println("Content-type:text/html");
  client.println();
  
  // the content of the HTTP response follows the header:
  client.print("The LED is ");
  client.print(ledStatus);
  client.println("
");
  client.println("
");
  
  client.println("Click <a href=\"/H\">here</a> turn the LED on
");
  client.println("Click <a href=\"/L\">here</a> turn the LED off
");
  
  // The HTTP response ends with another blank line:
  
  client.println();
}

// Connect to WiFi Network ------------------------------------------------------------
void ConnectWiFi() {
  if (WiFi.status() == WL_NO_SHIELD) {          // check for the presence of the shield
    Serial.println("WiFi shield not present");
    while (true);                               // don't continue
  }
  
    // print your MAC address
  byte mac[6];
  WiFi.macAddress(mac);
  char buf1[20];
  sprintf(buf1, "%02X:%02X:%02X:%02X:%02X:%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
  Serial.print("Ardiono MAC address: ");
  Serial.println(buf1);
  
  while ( status != WL_CONNECTED) {             // attempt to connect to WiFi network
    Serial.print("Connecting to: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);            // Connect to WPA/WPA2 network
  }
  IPAddress ip = WiFi.localIP();
  Serial.print("With IP Address: ");
  Serial.println(ip);
  
    // print the MAC address of the router you're attached to
  byte bssid[6];
  WiFi.BSSID(bssid);
  char buf2[20];
  sprintf(buf2, "%02X:%02X:%02X:%02X:%02X:%02X", bssid[5], bssid[4], bssid[3], bssid[2], bssid[1], bssid[0]);
  Serial.print("Router MAC Address: ");
  Serial.println(buf2);

    // print the received signal strength
  long rssi = WiFi.RSSI();
  Serial.print("Signal strength (RSSI): ");
  Serial.println(rssi);
  
}

" I'd rather find a way to only refresh when needed."

What would the event be and how will it be initiated? The simplest method might be somebody clicking the refresh button on a client browser.

Just looking thru some old code I’ve used in the past for monitoring an analog pin, below is a basic web page that uses an iframe to display the data. I think in the server code four conditions are tested. If “datastart” is sent from the web browser, a refresh time is added to the html header for the refresh box in the iframe. If “data” is sent from the web page, a header is sent with no refresh so only that one click is displayed. If “datafast” is sent from the web page, a header is sent with the refresh time set to 0, which refreshes the data in the iframe as fast as possible. You can take the below code, copy/paste in notepad, save as test.htm, then double click it to see how it looks.

<HTML><HEAD><TITLE>Zoomkat's frame refresh test</TITLE></HEAD>
            Zoomkat's Arduino frame meta refresh test 5/25/13
            

Arduino analog input data frame:

            &nbsp;&nbsp;<a href='/datastart' target='DataBox' title=''yy''>META-REFRESH</a>
            &nbsp;&nbsp;&nbsp;&nbsp;<a href='/data' target='DataBox' title=''xx''>SINGLE-STOP</a>
            &nbsp;&nbsp;&nbsp;&nbsp;<a href='/datafast' target='DataBox' title=''zz''>FAST-DATA</a>

            <iframe src='/data' width='350' height='250' name='DataBox'>
            </iframe>
</HTML>

Thanks for the input!

The event would be a variable state change on the Arduino.

This particular build is a driveway gate monitor and control mechanism. I have a couple of reed switches I’m using to sense when the gate is open or closed, and also want to hook up the Arduino to the “Guard Station” connection points on the gate controller. So I can initiate gate open/close from the web portal.

I also want the portal to show how long the gate has been in it’s current state.

Ideally, I’d be able to have it displayed on a tablet, in the house, at all times (or within a frame, on a tablet … with other home monitors/controls in additional frames on the same screen).

The more I think about this, the more I’m realizing I probably need Ajax (or something similar) … maybe JaVa would be a good choice?

As it stands right now, I have two buttons, and they are just controlling an LED … The web page shows the status, and enables me to change it with the web page buttons. I also have two pins set for the reed switches, and the gate status programmed. So I can short them to GND and emulate the reed switches activating.

All of this is working well, aside from one small annoyance. Intermittently, the ESP gives me a timeout error due to the client reconnecting after the client.close command is executed.

Here’s what I’m seeing in the Serial Monitor:

Open Gate Button Clicked
[WiFiEsp] Disconnecting  0
[WiFiEsp] New client 0
[WiFiEsp] TIMEOUT: 47

[WiFiEsp] New client 0
Open Gate Button Clicked
[WiFiEsp] Disconnecting  0
[WiFiEsp] New client 0
[WiFiEsp] TIMEOUT: 18

[WiFiEsp] New client 0
Open Gate Button Clicked
[WiFiEsp] Disconnecting  0

[WiFiEsp] New client 0
Open Gate Button Clicked
[WiFiEsp] Disconnecting  0

[WiFiEsp] New client 0
Close Gate Button Clicked
[WiFiEsp] Disconnecting  0
[WiFiEsp] New client 0
[WiFiEsp] TIMEOUT: 26

For whatever reason, I get “New Client 0” intermittently, after the disconnect, and then a timeout … not always though.

Here’s the latest code … Maybe it’s something to do with the ESP itself instead of the code? Or the WiFiEsp library?

#include "WiFiEsp.h"

int LED_PIN = 46;
int Button_PIN = 10;
int GateClosed_PIN = 7;
int GateOpen_PIN = 6;

char ssid[] = "";         // your network SSID (name)
char pass[] = "";      // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status
WiFiEspServer server(80);
RingBuffer buf(8);               // use a ring buffer to increase speed and reduce memory allocation
bool ledStatus = LOW;
int ButtonState = 0;
int PrevButtonState = 0;
String GateStatus = "";
String PrevGateStatus = "";
int ClosedSensor = 0;
int OpenSensor = 0;

unsigned long int StateTime = millis();
unsigned long int ElapsedTime = millis();
unsigned int Hours = 0;
unsigned int Minutes = 0;
unsigned int Seconds = 0;

void setup() {
pinMode (LED_PIN, OUTPUT);
pinMode (Button_PIN, INPUT_PULLUP);
pinMode (GateClosed_PIN, INPUT_PULLUP);
pinMode (GateOpen_PIN, INPUT_PULLUP);

  Serial.begin(115200);                         // initialize serial for debugging
  Serial1.begin(115200);                        // initialize serial for ESP module
  WiFi.init(&Serial1);                          // initialize ESP module
  ConnectWiFi();
  server.begin();

}

void loop() {
  ReadGateSensors();
  SetGateStatus();
  HandleClient();
  digitalWrite(LED_PIN, ledStatus);

}

void ReadGateSensors() {
  int sum = 0;
  for (int x=0; x<5; x++){   
    sum += digitalRead(GateClosed_PIN);
    delay(1);
    }
  if (sum < 5) {
    ClosedSensor = HIGH;                                  
  }
  else {
    ClosedSensor = LOW;
  }

  sum = 0;  
  for (int x=0; x<5; x++){   
    sum += digitalRead(GateOpen_PIN);
    delay(1);
    }
  if (sum < 5) {
    OpenSensor = HIGH;                                  
  }
  else {
    OpenSensor = LOW;
  }
}

void SetGateStatus() {

  if ((ClosedSensor == 1) && (OpenSensor == 0) && (GateStatus != "Closed")) {
    PrevGateStatus = GateStatus;
    StateTime = millis();
    GateStatus = "Closed";
  }
  if ((OpenSensor == 1) && (ClosedSensor == 0) && (GateStatus != "Open")) {
    PrevGateStatus = GateStatus;
    StateTime = millis();
    GateStatus = "Open";
  }
  if (OpenSensor == 0 && ClosedSensor == 0 && GateStatus != PrevGateStatus) {
    if (GateStatus == "Closed") {
      PrevGateStatus = GateStatus;
      StateTime = millis();
      GateStatus = "Opening ...";
    }
    else if (GateStatus == "Open") {
      PrevGateStatus = GateStatus;
      StateTime = millis();
      GateStatus = "Closing ...";
    }
  }
  ElapsedTime = (millis() - StateTime);
  Hours = (((ElapsedTime/1000)/60)/60);
  Minutes = (((ElapsedTime/1000)/60)-(Hours * 60));
  Seconds = ((ElapsedTime/1000)-((Hours * 60)+(Minutes * 60)));

}

void HandleClient() {                               // if you get a client,

  WiFiEspClient client = server.available();  // listen for incoming clients
  if (client) {
//    Serial.println("New client");             // print a message out the serial port
    buf.init();                               // initialize the circular buffer
    while (client.connected()) {              // loop while the client's connected
      if (client.available()) {               // if there's bytes to read from the client,
        char c = client.read();               // read a byte, then
        buf.push(c);                          // push it to the ring buffer

        if (buf.endsWith("\r\n\r\n")) {
          sendHttpResponse(client);
          break;
        }

        if (buf.endsWith("GET /H")) {
          Serial.println("Open Gate Button Clicked");
          ledStatus = HIGH;
        }
        else if (buf.endsWith("GET /L")) {
          Serial.println("Close Gate Button Clicked");
          ledStatus = LOW;
        }
      }
    }
  }
   client.stop(); 
}

void sendHttpResponse(WiFiEspClient client)
{
  client.println("HTTP/1.1 200 OK");
//  client.println("Refresh: 1;URL='//192.168.0.158:80/'>");
  client.println("Content-type:text/html");
  client.println();
  
  client.print("The LED is ");
  client.print(ledStatus);
  client.println("
");
  client.println("
");
  
  client.println("<form method=\"get\" action=\"/H\"><button type=\"submit\">Open Gate</button></form>
");
  client.println("<form method=\"get\" action=\"/L\"><button type=\"submit\">Close Gate</button></form>
");

  
  client.print("<h1 height=\"0.8\">Gate Status: ");
  client.println(GateStatus);
  client.print("<h4 height=\"0.8\">For: ");
  if (Hours != 0) {
    client.print(Hours);
    client.print(" Hrs ");
  }
  if (Minutes != 0) {
    client.print(Minutes);
    client.print(" mins ");
  }
  client.print(Seconds);
  client.println(" secs");
  client.println();
}

// Connect to WiFi Network ------------------------------------------------------------
void ConnectWiFi() {
  if (WiFi.status() == WL_NO_SHIELD) {          // check for the presence of the shield
    Serial.println("WiFi shield not present");
    while (true);                               // don't continue
  }
    byte mac[6];
  WiFi.macAddress(mac);
  char buf1[20];
  sprintf(buf1, "%02X:%02X:%02X:%02X:%02X:%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
  Serial.print("Ardiono MAC address: ");
  Serial.println(buf1);
  
  while ( status != WL_CONNECTED) {             // attempt to connect to WiFi network
    Serial.print("Connecting to: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);            // Connect to WPA/WPA2 network
  }
  IPAddress ip = WiFi.localIP();
  Serial.print("With IP Address: ");
  Serial.println(ip);
  
    // print the MAC address of the router you're attached to
  byte bssid[6];
  WiFi.BSSID(bssid);
  char buf2[20];
  sprintf(buf2, "%02X:%02X:%02X:%02X:%02X:%02X", bssid[5], bssid[4], bssid[3], bssid[2], bssid[1], bssid[0]);
  Serial.print("Router MAC Address: ");
  Serial.println(buf2);

    // print the received signal strength
  long rssi = WiFi.RSSI();
  Serial.print("Signal strength (RSSI): ");
  Serial.println(rssi);
  
}