The leader in industrial automation and control solutions

Maple Systems’ Web HMIs can connect to a web server hosted by a microcontroller like Arduino. Our Web HMI’s integrated browser is used as a means to control GPIO outputs of an off-the-shelf Arduino microcontroller and Arduino Ethernet Shield 2 module.

This article walks you through the process of connecting a Web HMI to an Arduino web server. We’ll also cover programming the Arduino to host a web server using custom code. You’ll find detailed wiring diagrams and program files at the end of the article to help you easily replicate the setup.


Our WP4000 series Web HMIs provide an ideal way to interact with the Arduino Web Server. It’s easy to configure and deploy, offering a very bright physical touch screen for seamlessly viewing and controlling web applications.

Access the Configuration Screen

Firstly, power on the WP4000 series Web HMI and allow it to boot. A settings icon will appear after the device starts, alongside a countdown timer.

Click the settings icon before the system settings timer expires:

The initial Settings Timeout screen of the Web HMI is depicted with a red square highlighting its importance.

Open the Web App URL Menu

Then, navigate to the web app URL entry screen. Enter the device password if prompted:

The Main Settings Menu of the Web HMI is depicted with the Web Apps page tab highlighted with a red square.

Enter the IP Address of the Arduino

Enter the Arduino’s IP address into the URL selection screen. Our Arduino was assigned an IP address of 192.168.150.187 via DHCP, so we enter that below.

Once the IP address is added, hit “Save” to save the configuration:

The Web Application menu of the Web HMI is depicted with a single link assigned.

Reboot and Access the Web Interface

After the HMI reboots, allow the settings timer to expire. The Web HMI will then load the index.htm file loaded onto the Arduino Ethernet Shield 2 board’s SD card. We’ll then be greeted by the interface provided by the web server:

A picture of the web UI running on a physical Web HMI.

Controlling the Arduino

The web interface enables users to control LED lights connected to digital GPIO pins on the Arduino from the Web HMI:

A short GIF depicts LED lights connected to a microcontroller turning on in response to a browser UI.

The Arduino is also able to report input to digital GPIO pins, displayed on the Web HMI:

A short GIF depicts a browser UI responding to the user pressing buttons connected to a microcontroller.

Finally, the Arduino can report input to analog GPIO pins in real-time as they update:

A short GIF depicts a browser UI responding to the user turning a potentiometer knob connected to a microcontroller.

The Arduino platform is a versatile tool for learning, prototyping, and developing small-scale applications. Although this demo focuses on interacting with small LED lights, buttons, and a dial, you can apply these same concepts to a wide range of other hardware and data sources, such as sensors or control relays.


The Web HMI

Our 7″ resistive touch-screen Web HMIs, the WP4070A, is used to connect to the Web Server hosted by the Arduino. The installation and deployment of the unit is very straight-forward and requires the least effort out of all the setup for this demonstration.

A picture of a Web HMI.

The touchscreen of the Web HMI provides the perfect interface for visualizing and controlling the Arduino’s GPIO once connected.

A small selection of off-the-shelf parts and the Maple Systems Web HMI were used to build this demonstration. The hardware selected requires no soldering, and can be assembled at an office desk.

A picture of a small breadboard circuit connected to a microcontroller with additional parts installed.

Arduino Development Board

An official Arduino MEGA 2560 R3 is used for running the web server program. This development board features the ATMEGA2560 microcontroller, as well as all the necessary GPIO capabilities for controlling a variety of devices. In our demonstration, we use some LED lights and buttons.

Ethernet Module

Since the Arduino MEGA does not feature an ethernet interface, an additional daughterboard (known as a “shield”) is installed to the base board. The board selected for use is the Arduino Ethernet Shield 2.

The Ethernet Shield 2 is designed to be installed into the GPIO pins on top of an Arduino microcontroller board, fitting nicely above and providing additional ports as well as pass-through GPIO pins. The ethernet module is equipped with a Micro SD card slot, which can be used to store files accessed by the program running on the Arduino. In this demonstration, an SD card containing the HTML file will be used to serve a web page to clients connecting from the Web HMI.

Test Circuit

Alongside the Arduino board, a simple circuit was assembled on a solderless breadboard to provide a few LED lights, buttons, and a potentiometer. These will all be connected to the GPIO pins available on the Arduino.

A picture of a small breadboard circuit to be connected to a microcontroller.

The Arduino running the Web Server program will send signals to these components. The Web UI served up by the program allows users to control control the LED lights and view input information from the buttons and potentiometer knob.


All of the programming for the Arduino including writing the code, downloading the program, and monitoring debug output is done using the Arduino IDE software. The code provided at the end of this article can be opened in Arduino IDE and downloaded to another Arduino board for recreating the demo!

Code Explanation

Our program is designed to perform a specific set of tasks, including setting up GPIO pins for the Arduino to use, initializing the ethernet interface and connecting it to a network, and serving up an HTML file to the Web HMI.

Initializing the Ethernet Shield

The SPI, Ethernet, and SD libraries are required in order to use the Arduino Ethernet Shield 2 network interface and SD card slot. Basic parameters like the device’s MAC address and IP address info that will be used must be defined.

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
...
// Initialize MAC address of Ethernet Module in use. This must be changed if deploying on a different device!
byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x09, 0xEB};

// Initialize default network configurations should DHCP configuration fail
byte staticIP[] =         {192, 168, 5, 20};
byte staticGateway[] =    {192, 168, 5, 1};
byte staticDNS[] =        {8, 8, 8, 8};
byte staticSubnetMask[] = {255, 255, 255, 0};Code language: PHP (php)

Setting up the ethernet interface with a network configuration is as simple as invoking the Ethernet.begin() method:

Ethernet.begin(mac, staticIP, staticDNS, staticGateway, staticSubnetMask);Code language: CSS (css)

Note that the full program available at the end of this article uses the Ethernet.begin() method to first get an IP address over DHCP, then defaults to the “static” values above.

Setting Up the SD Card

An HTML/CSS file must be served to any clients (web browsers) that connect to the web server. We load an “index.htm” file onto an SD card. This SD card can be installed into the Ethernet Shield 2. There is HTML code and CSS styling that the browser will use to display our control interface and transmit formatted information to the Arduino web server.

A picture of a populated SD card slot on a microcontroller with an additional daughter board installed.

The file is loaded in our program using the SD.begin() and SD.exists() methods, paired with some logical statements to notify when the file can’t be found on the card:

// Initialize SD card with web server files
Serial.println("Initializing SD card...");
if (!SD.begin(4)) {
      Serial.println("Error: SD card initialization failed!");
      return; // Init failed
}
Serial.println("SD card initialized successfully.");
// check for index.htm file
if (!SD.exists("index.htm")) {
      Serial.println("Error: Can't find index.htm file!");
      return; // Can't find index file
}
Serial.println("Found index.htm file.");Code language: JavaScript (javascript)

Later on, the server will provide the HTML file to a web browser client using the SD.open() method:

...

// Send web page file stored on the SD card
webFile = SD.open("index.htm"); // open web page file
if (webFile) {
  while(webFile.available()) {
    client.write(webFile.read()); // send web page to client
    }
webFile.close();
}

...Code language: JavaScript (javascript)

Controlling GPIO Pins

Our program will provide a web UI to control and monitor the GPIO pins. They’ll be programmed to do the following:

  • Turning 4 LEDs on and off
  • Registering when any of 3 buttons are pressed
  • Reading an analog value from a potentiometer dial

The Arduino program must include statements that initialize pins for usage as either inputs or outputs. This is done with the pinMode() method:

// Initialize GPIO pins for hardware controlled by web server
// Pins 2, 3, and 5 for button inputs
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(5, INPUT);

// Pins 6-9 for LED outputs
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);Code language: JavaScript (javascript)

The analog pin on the Arduino used in our test circuit, pin A2, is input-only, so there is no need for configuring it as an input or output.

Using the digitalWrite() and digitalRead() methods, our program can check the status of our button presses (on pins 2, 3, and 5) as well as turn our LEDs on/off (on pins 6-9):

// Read button states
for (count = 0; count < 3; count++) {
      cl.print("<switch>");
      if (digitalRead(sw_arr[count])) {
            cl.print("ON");
      }
      else {
            cl.print("OFF");
      }
      cl.println("</switch>");
}

...

for (count = 0; count < 4; count++) {
   pin = count + 6; // Consecutive LED pin offset for pins 6-9
   
   // Unique HTML text for turning individual LEDs on or off
   on_string = "LED" + String(count + 1) + "=1";
   off_string = "LED" + String(count + 1) + "=0";

   // Convert strings to char arrays for use with StrContains()
   on_string.toCharArray(on_message, 7);
   off_string.toCharArray(off_message, 7);

   if (StrContains(HTTP_req, on_message)) {
      LED_state[count] = 1; // Save LED state as ON
      digitalWrite(pin, HIGH);
   }
   else if (StrContains(HTTP_req, off_message)) {
      LED_state[count] = 0; // Save LED state as OFF
      digitalWrite(pin, LOW);
   }
}Code language: PHP (php)

Reading the analog value for pin A2 is done using the analogRead() method:

// Read analog inputs
for (count = 2; count <= 5; count++) { // A2 to A5
     analog_val = analogRead(count);

...Code language: JavaScript (javascript)

Hosting the Web Server on the Ethernet Interface

Once the program assigns an IP address to the ethernet interface, it just needs to host the web server and listen for clients over ethernet. The GPIO pins that were initialized previously will allow the user to control the test circuit from the web server.

The EthernetServer and EthernetClient classes, provided with libraries for the Ethernet Shield, allow the program to define objects for the hosted server and client. The following statements host a server on the default HTTP port (TCP port 80) and listen for clients:

// Configure web server
EthernetServer server(80); // Web server hosted on port 80

...

// Watch for connection to web server
EthernetClient client = server.available();

...Code language: JavaScript (javascript)

Finally, the main portion of our program is able to run. All of the above code is tied together with calls as individual methods in a large loop. The loop defines the web server and client interactions from start to finish:

void loop() {
   // Continuously check if ethernet module is connected to a network
   CheckEthernetConnection();

   // Continuously maintain DHCP lease if it was configured successfully
   if (using_DHCP) {
      MaintainDHCPLease();
   }

   // Watch for connection to web server
   EthernetClient client = server.available();

   // When client connects, begin repeatedly polling entered data
   if (client) {
         boolean currentLineIsBlank = true;
         while (client.connected()) {
               if (client.available()) {    // If client data is available to be read, read 1 byte (character) from the client
                     char c = client.read();
                     // Limit the size of the stored HTTP request from the client
                     // Buffer first part of the request in an array (string)
                     // Leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
                     if (req_index < (REQ_BUF_SZ - 1)) {
                           HTTP_req[req_index] = c;               // Store HTTP request character
                           req_index++;
                     }
                     // The last line of the client request will always be blank and end with \n
                     // Only respond to the client after the last line is received
                     if (c == '\n' && currentLineIsBlank) {
                           // Send a standard HTTP response header
                           client.println("HTTP/1.1 200 OK");
                           // Send the remainder of the header, which differs depending on whether
                           // a web page or XML file is requested
                           // For an Ajax request, send the XML file:
                           if (StrContains(HTTP_req, "ajax_inputs")) {
                                 client.println("Content-Type: text/xml");
                                 client.println("Connection: keep-alive");
                                 client.println();
                                 SetLEDs();
                                 // Send XML file containing input data
                                 XML_response(client);
                           }
                           else {   // For a web page request, send the HTML file"
                                 client.println("Content-Type: text/html");
                                 client.println("Connection: keep-alive");
                                 client.println();
                                 // Send web page file stored on the SD card
                                 webFile = SD.open("index.htm");            // open web page file
                                 if (webFile) {
                                       while(webFile.available()) {
                                             client.write(webFile.read()); // send web page to client
                                       }
                                       webFile.close();
                                 }
                           }
                           // Output any HTTP requests on the serial port
                           Serial.print(HTTP_req);
                           // Reset the buffer index and all buffer elements to 0
                           req_index = 0;
                           StrClear(HTTP_req, REQ_BUF_SZ);
                           break;
                     }
                     // Every line of text received from the client will end with \r\n
                     if (c == '\n') {
                           // last character on line of received text
                           // starting new line with next character read
                           currentLineIsBlank = true;
                     }
                     else if (c != '\r') {
                           // a text character was received from client
                           currentLineIsBlank = false;
                     }
               } // end if (client.available())
         } // end while (client.connected())
         delay(1);         // give the web browser time to receive the data
         client.stop(); // close the connection
   } // end if (client)
}Code language: PHP (php)

Running the Program

The program will execute automatically when downloaded to the Arduino. The code includes statements that initialize the serial console, allowing us to receive messages from the Arduino in Arduino IDE. This is used to get information like the IP address that’s been assigned to the device.

A picture of the Serial Output console of the Arduino IDE software providing an IP address that has been assigned to the microcontroller.

To pair with the Arduino program, we built a small circuit to connect the LEDs, buttons, and potentiometer knob to the appropriate GPIO pins:

A circuit diagram of a small breadboard circuit connecting to a microcontroller to provide LED outputs, button inputs, and a potentiometer input.
  • Pins 2, 3, and 5 connect to the outputs of switches that each connect to a pull-up resistor so that the pins are pulled HIGH when the buttons are pressed.
  • Pins 6-9 connect to the positive leads of 4 LEDs. When the pins are set HIGH by the Arduino, the LED lights will turn on.
  • Pin A2 connects to the wiper lead of a potentiometer knob. This will apply a variable resistance to the current running through the potentiometer to pin A2, which reflects on the final voltage read as an analog value on the Arduino. The resistance on the potentiometer can be adjusted by twisting the knob.

Maple Systems’ WP4000 series Web HMIs are versatile devices that offer the flexibility of a Web Browser that can be leveraged in a variety of ways. Check out our previous article on using a Web HMI with noVNC for remote-desktop access to a Raspberry Pi!

The files used for this demonstration including the source code for the Arduino program and index.htm are available for download here.

Please take the time to visit our product pages for more information on the HTML5 Web HMI series of devices, or contact us to see if Maple hardware is right for your application!

Ezekiel Hernandez-Hall Avatar