Basics of Design CC Blog Research & Design Hub

GUI-O: A “Virtual” Front Panel

Written by Brian Millier

For ESP32 Projects

The ESP32 family is a powerful, yet inexpensive choice for an MCU with Wi-Fi and Bluetooth capabilities. In this article, I introduce GUI-O, an Android app that allows you to develop complex graphical user interfaces on your smartphone or tablet. This GUI communicates wirelessly with an ESP32 device, acts as a “virtual” front panel, and also can display complex data in a graphics format. 

  • Can I develop GUIs on my smartphone or tablet?
  • How do I use my smartphone as a front panel for an ESP32?
  • How can I use an ESP32?
  • ESP32
  • GUI-O
  • Android smartphone

Many projects require a user interface or “front-panel.” Let’s take a look at the basic ways that ESP32 “front panels” have been implemented in the past. They may be needed on an ongoing basis, or maybe these front-panels are needed only once or infrequently, for configuration purposes. There are certainly projects where a small, character-based LCD screen, a rotary encoder, and a few switches are all that’s required. However, many complex projects require a TFT touchscreen to properly display values in graphic form, or enter many wide-ranging parameters that are difficult to enter without something like a keypad. I’ve described several projects in Circuit Cellar articles [1] that featured the Bridgetek BT61x graphics controllers with capacitive touchscreens, and they make a functional, impressive display.

With the ESP32’s Wi-Fi capabilities, another viable option is to let the ESP32 serve up a webpage. With just HTML experience, you can write an ESP32 program for a webpage containing text boxes, sliders, buttons, and other widgets. This simple webpage may serve as your “virtual” front panel. Since the ESP32 is a dual-mode device, it can act as either a Wi-Fi Access Point, or it can connect to an existing Wi-Fi network. Either way, it’s not difficult to navigate to the webpage that the ESP32 is serving up, using a phone, tablet or computer, and to interact with your ESP32-based device in that way.

However, if you want a more complex, fancier-looking virtual front panel, the other approach is to write an app for your phone or tablet. This app would still communicate wirelessly with the ESP32 device, but you would have the choice of Wi-Fi, Bluetooth or Low Energy Bluetooth (BLE). It would have the advantage of being able to use the phone’s API support for the touchscreen, any sensors in the phone, and the Internet.

Writing such a program is not trivial, and also depends heavily on whether you are using an iPhone (iOS) or an Android phone. In the case of iOS, it is not a simple task. You need an Apple computer to run the SDK needed to generate the code for the app, and you must pay a fee to Apple to be an iOS developer. If you want to distribute this app to others, you have to have it approved to be listed in the App Store by Apple. Even if you have experience programming MCUs using C, or C++, getting used to Apple’s SDK is not easy. I owned only iOS devices—iPhones and iPads—for many years, but these barriers to entry for writing iOS apps, were more than I wanted to take on.

In the Android world, it is somewhat easier to write your own app. You don’t need a specific computer, nor do you necessarily have to go through the Google Play Store (with approval) to get the app on the phone. There are frameworks available to make writing an Android app easier, such as Xamarin, which is open-source and multi-platform.

When I received an email from the GUI-O team, inviting me to try out GUI-O, I was initially both intrigued and disappointed, since it was an Android app, not iOS. My curiosity prevailed, and I dug up my old Samsung Galaxy Note 10.1—the OS of which Samsung had stopped updating many years back. I replaced its ancient Android OS with Lineage 16 Android. The GUI-O app loaded nicely on this updated tablet, so I was set to go. 


Advertise Here

Note that while I refer to an ESP32 host exclusively in this article, GUI-O will also work with any MCU that has or can be provided with Bluetooth or Wi-Fi capability. Alternately, you could use it in the USB mode, where it connects to your ESP32 by using the USB-OTG port on your phone or tablet.

Since Espressif has expanded the ESP32 line, some members of the family now either don’t support Bluetooth at all (-S2 model), or only support Bluetooth LE. Which ESP32 MCU you choose will affect which of GUI-O’s transport modes you can use.

A free demo version of the GUI-O app is available at the Google Play Store. This demo version is fully operational in all of GUI-O’s communication (transport) modes. However, the demo is limited in that you can only place up to six widgets on the screen. For some simple home control projects this number of widgets may be all that you need. The Pro version of GUI-O (with no widget limits) costs about $10.


GUI-O contains a wide variety of widgets—enough to cover most applications. Table 1 shows all the available widgets at the time of this writing, and Figure 1 shows a screen capture with a montage of about half of the available widgets. Note that in addition to many high-level functions such as Video, Calendar and Charts, there are also the graphics primitives needed to draw custom structures—Line, Rectangle, Ellipse, and others.

Table 1
 All available GUI-O widgets, at the time of writing.
Table 1
All available GUI-O widgets, at the time of writing.
Figure 1
Montage of various GUI-O widgets that I incorporated into a GUI screen.
Figure 1
Montage of various GUI-O widgets that I incorporated into a GUI screen.

Every widget can be customized in every conceivable way, including size, orientation, background, foreground color, and 3D effect. A widget “Cheat-sheet” in the GUI-O Developer Manual shows the minimum command needed to render each widget on the screen. A section of the manual is devoted to each widget, showing all the available parameters that can be set.

To create an instance of a button widget for example, you would send out the following command :

|BT UID:bt1 X:50 Y:50\r\n

Notice that every widget’s creation command starts with the symbol “|” and is followed by the widget’s mnemonic (which is usually an abbreviation of the widget’s name). Following that is “UID bt1” which assigns a unique UID identifier to that widget. You can use any word you want here, but it makes sense to create a UID that is recognizable as a specific widget, followed by a number to differentiate it from other widgets of the same type.

After that, any parameters to be set are entered in uppercase, followed by a colon and the value. All commands use the standard carriage return, line feed combo “\r\n” (or just a “\n” which is the standard Linux terminator).

Some widget parameters require values that are ASCII text strings. This text is delimited using double quote marks—“text,” for example. You’ll see examples of setting text parameters shown this way in the Developer Manual.


Advertise Here

Here is where a complication comes in. You are sending these commands from the ESP32 in the form of a String. However, the normal delimiter for a String is a quote mark (“). As a result, when you attempt to send a command that has an embedded parameter that is text, the quote symbol used to start that parameter’s text instead acts as the end of the command String that the ESP32 is trying to send out. 

This issue has come up long before GUI-O, and is handled in C by preceding the quote mark with a backslash (“\”). In C, the “\” is known as an escape character. After handling this issue with the backslash escape character repeatedly in my coding, I discovered that GUI-O contains a TSC parameter (part of the GSE command) that allows you to change the text parameter encapsulation character from double quotes to an apostrophe (‘), asterisk (*), or tilde (~). 

After a widget is created,\ as described above, any additional parameter settings, or changes to the existing parameter values, are performed as follows:

@bt1 TXT:”Hello”\r\n

This is similar to the widget creation command except that the pipe character (“|”) is replaced with the at sign (“@”), and instead of the BT:UID bt1 you merely have to quote the UID name itself. Note that here I am showing the command the way it would be shown in the Developer Manual, and not including the backslash escape characters for the quotes.

Any time GUI-O has something to report, such as a screen touch or other hardware-related reports, it reports it in a way similar to what is described above:

@bt1 Button pressed

where “button pressed” is a message saying that button widget, UID bt1, has been pressed.

Because GUI-O can run on various Android devices, different screen resolutions are an issue. GUI-O could end up running on a small cell phone or a large tablet, so the screen’s X,Y pixel count could vary widely. The GUI-O application uses DIP (device-independent pixel) units as a base for the sizing of all widgets. Therefore, all widget sizes are specified as a percentage of effective DIP screen width (DPW) and DIP screen height (DPH). If, for example, you place a widget at X=50, Y=50, it will be centered on the screen. Similarly if a widget has a width of 20, it will occupy 20% of the screen width.

GUI-O seems to be targeted to cell phones primarily, so its default orientation is Portrait. My only Android device to use GUI-O on was a Samsung Galaxy Note 10.1 tablet. Like all tablets, it’s basically designed for Landscape orientation. Using GUI’s SORI command, you can switch orientation to Portrait or Landscape, with Inverted versions of both also available. Initially, I tried switching orientation to Landscape to match my device better. I found that some widgets worked OK in Landscape mode, whereas others, such as the Grid widget, couldn’t be positioned properly. This may just have been my lack of knowledge, and the developer is looking into it. The GUI-O Live Designer PC application now operates in both Portrait and Landscape mode.

I had no aspect ratio problems when using my Note 10.2 tablet, and I don’t have any other Android devices with which to test GUI-O. However, there is an ASR parameter of the “guis” command that can be used to modify aspect ratio.


GUI-O can display text in many different typefaces and sizes. Beyond the expected fonts, there are a few that are uniquely useful for instrumentation. Font2 can be used to emulate a 14-segment LED display, for example, and Font8 can emulate a standard LCD character display. And for specialized use, there is a barcode font that produces a barcode in the -C39 code format. Figure 2 shows all of these fonts.

Figure 2
Fonts available in GUI-O, including a C49 bar-code font.
Figure 2
Fonts available in GUI-O, including a C49 bar-code font.

Android devices, in particular cell-phones, contain many internal sensors and other hardware-related function blocks. For my applications, most of these sensors were not relevant, but I’ll discuss them since they might interest you. Note that the ability of GUI-O to interact with the Android’s API for a particular function doesn’t necessarily mean that your phone or other Android device actually contains such a sensor.

Table 2 contains a list of the Android hardware devices that GUI-O supports. As you can see, virtually all types of sensors that might be found in a phone can be monitored. Also, you can play audio files, or generate simple musical notes with various synthesizer voices. Both of the cell-phone’s internal cameras can be triggered and the image collected. Various GPS readings can be obtained, assuming the device has a GPS receiver. Last, but not least, you can perform various file operations on the Android device’s file storage system. 

Table 2
All the physical sensors and other hardware devices for which GUI-O can send reports back to the ESP32 host. Not all of these may be present on your particular Android device.
Table 2
All the physical sensors and other hardware devices for which GUI-O can send reports back to the ESP32 host. Not all of these may be present on your particular Android device.

Although I haven’t tried it, I expect that you can specify a path to an SD card, if one is present. This could simplify your project, if data-logging were necessary, by eliminating the need for your project’s MCU to have an SD-card interface. To access files in your Android’s file system from your computer (aside from popping out a mounted SD card), the following procedure may need to be done on your device.

You’ve probably plugged your Android phone into your computer at some point—if only for charging. With older versions of Android, your computer may not even acknowledge your phone as a USB device. If so, you must configure your phone’s USB port to act as a USB flash drive. In Android’s “Setting” app, there is a “System” menu. Choose “Advanced,” “Developer options,” “Default USB configuration,” and click on the “File Transfer” icon. When you next plug your phone into your PC, your Android device will show up as a USB flash disk. This is a handy way of accessing any files that GUI-O may have saved on the Android device. They will be located in the directory Android/data/com.guio.guioapp/files (or in the same path on an SD card if it is mounted).

On the new Android 11 phone that I just purchased, the Android OS treats the USB port in a more user-friendly way. By default, it will connect to your computer in the Debug mode (ADB Mode). But, it will prompt you to tap a notification screen to take it out of Debug mode. You then get a screen where you can select many different modes. If you click on File Transfer mode, the phone will appear as a flash-drive in a pop-up Windows Explorer window.


Advertise Here

Images can be superimposed on some of GUI-O’s widgets. The light bulb icon in the demo programs is an example of this. You can give GUI-O a URL to specify an icon when you are configuring a widget. Note that GUI-O will fetch the image from that URL the first time it runs. However, after that it will cache it in the Android device’s file system. Alternately, you can save images to this folder yourself, if you don’t have a URL link to that image. See Appendix D in the GUI-O Developer Manual for details about this.  

The only hardware resource that I have accessed using GUI-O is the Android Real-Time Clock. I used this to set the RTC on an ESP32 project, eliminating the need for some form of user interface to set the RTC manually. Appendix C in the Developer Manual outlines the various time formats that GUI-O supports.


Your ESP32 project and your Android device running GUI-O can communicate in five ways:

  1. Legacy Bluetooth (4.x)
  2. Bluetooth LE (5)
  3. Wi-Fi (using an MQTT broker)
  4. Ethernet (TCP/IP connection: the Ethernet (or Wi-Fi) port on the MCU-based device, Wi-Fi port on the Android device)
  5. USB-OTG

I will discuss all five modes of operation, though I have tried only the first three, myself. The USB-OTG mode requires your Android phone or tablet to contain a USB-OTG port, and also that the Settings app has been properly configured to enable it. I only use Ethernet to connect my desktop PC to my router, so I didn’t try that option, either.

In the next sections, let’s look at my experience using both Bluetooth modes and the Wi-Fi MQTT mode. A useful thing to realize at this point is that, regardless of the communication mode (the transport mode), GUI-O sends data back and forth between your MCU-based device and your Android device, using what is often called a “transparent UART mode.” That is, the ESP32 sends all its commands as an ASCII string of various lengths. It receives status reports back from the Android phone in the same format.


Legacy Bluetooth mode is the easiest mode to learn, so that is how I started. In this mode, we are operating using the Bluetooth SPP profile (Serial Peripheral Profile). This is basically a transparent, UART-mode communication link.

To get started, the best thing to do is to load the BasicBluetooth.ino sketch into your ESP32. This is available in the “Examples” tab of the GUI-O website. Since this is Bluetooth and not Wi-Fi, you don’t have to modify this program to suit your home’s Wireless Access Point.

Figure 3
GUI-O Android app's Home screen. The three horizontal bars at the top contain all the configuration menus. The large “Link” icon in the middle starts the operation mode, where it waits for an @init command from the ESP32 host, and then displays the user-defined GUI.
Figure 3
GUI-O Android app’s Home screen. The three horizontal bars at the top contain all the configuration menus. The large “Link” icon in the middle starts the operation mode, where it waits for an @init command from the ESP32 host, and then displays the user-defined GUI.
Figure 4
Simple GUI that is used by most of the GUI-O examples (for the various transport modes).
Figure 4
Simple GUI that is used by most of the GUI-O examples (for the various transport modes).

Run the GUI-O app (Figure 3 shows its Home screen), and from the upper menu button (three horizontal bars), select the “Connections” tab, then the “Bluetooth and IoT” tab. Click on the “Available Devices” tab, and a scan of nearby devices will be displayed. The Arduino demo sketch gives the name “BasicBluetooth” to your ESP32 device, so you should see that among the nearby Bluetooth devices. If you select that, it will prompt you to do a Bluetooth pairing. This pairing only has to be done once (unless you uninstall GUI-O on your phone). Once paired, a “Bluetooth connection successful” message should appear at the bottom of the screen, momentarily. Also “connected” (in pale green) will be displayed under the BasicBluetooth device in the device list. You can then close this screen using the X at the upper right of the screen, and you will be back at the GUI-O home screen. If you press the large GUI-O symbol on this screen, you should see the GUI that your ESP32 has generated. If you tap the light bulb, it should light up on screen, and the brightness control will become visible (Figure 4). If you have a serial terminal connected to your ESP32, you’ll see the messages:

“Bluetooth ready to pair!”

“GUI-O app is requesting INITIALIZATION!”

“GUI-O app is requesting LIGHT ON!”

If your ESP32 board has a GPIO-driven LED (not the fancy RGB LED found on some newer boards), this demo sketch should light the on-board LED and vary its brightness. If not, you may have to change the following line of code:

ledcAttachPin(led::LED_BUILTIN, led::LED_CHANNEL);

by substituting the actual GPIO pin number for the constant led::LED_BUILTIN. Generally, if you have specified the actual ESP32 board that you are using (in the Tools ->board selection of Arduino), the LED_BUILTIN constant will reflect the proper GPIO pin for that board’s built-in LED (assuming it has one).

So, what happens to this simple demo program if the Bluetooth connection is lost briefly? I had to walk about 150 feet away from the ESP32 device before the GUI-O app on the Android tablet lost its connection. At this point the GUI-O app issued a “Bluetooth connection error” and stopped working. When brought back into range, it still was not working. I closed the GUI-O app, re-started it, and made the connection again, after which it regained normal operation. But, the developer says that I could have just used the quick-connect menu and regained communication that way.

This is not an issue if you enable the auto-connect option, in which case the GUI-O app should automatically reconnect to the host ESP32’s Bluetooth. Apart from that “forced” Bluetooth connection drop-out, the GUI-O app worked fine, both on this simple demo and on other more complex apps that I have written, which used GUI-O as the project’s virtual front panel.

The BasicBluetooth.ino sketch is very short and easy to follow. You should have no problems integrating the code into your own more complex, custom program. Basically it contains two functions that you have to migrate over to your own sketch.


This routine receives the incoming “init” command from the Android GUI-O app, as well as any responses returned (due to the touching/adjusting of widgets). Upon receipt of the “init” command, this function must prepare a list of commands needed to render the desired GUI Android screen and send them out. All other responses must be individually parsed, and either variables are set, or specific routines are executed in response to the screen touches.


This routine sends the String that has been passed to it over to the Android phone running the GUI-O app.

Besides these two routines, a few things are configured in the Setup() routine, such as opening the Bluetooth channel using the begin function (where it names the ESP32’s Bluetooth port “BasicBluetooth”). The Bluetooth class is instantiated with the following line (in the sketch’s Global header section):

BluetoothSerial btSerial;

In Bluetooth LE mode, you would load your ESP32 with the BasicBLE.ino sketch or the BasicBLE_NUS.ino sketch. Both sketches are quite similar. The NUS stands for Nordic UART Service—a standardized BLE profile for Nordic Semiconductor (or Nordic-compatible) devices.

If you have experience with BLE, you know that it’s much more complex than the SPP profile of legacy Bluetooth. Without going into detail, BLE devices communicate with each other in such a way that the various types of devices have their own distinct Profiles, and the various types of data have their own distinct Characteristics, Services, and Descriptors. Many of these categories have long UUIDs (Universally Unique IDs), which are 128-bit numbers expressed in hexadecimal. In all, it’s kind of a headache to deal with.

When GUI-O is used in the BLE mode, you can forget all of this complexity. Instead, GUI-O uses the same transparent UART connection that the legacy Bluetooth mode uses. For BLE, this equates to the NUS profile.

The two sketches mentioned above are somewhat more complex than the BasicBluetooth example–to handle the more-complex BLE protocol. However, extracting the necessary routines from the demo into your own custom sketch, is not much different than the BasicBluetooth.ino demo example.

I see no advantage to using Bluetooth BLE mode over the legacy Bluetooth mode when using GUI-O, since both modes communicate using a transparent UART protocol and don’t take advantage of the more involved BLE protocol. If the ESP32 were running from a battery, the lower power consumption of Bluetooth LE might be advantageous, however.


The third mode that I tried was MQTT. I don’t really have a current use case where this mode would be needed. However, for this article, I wanted at least to test it out.

MQTT (Message Queuing Telemetry Transport) is a publish/subscribe architecture that enables secure transport of messages among multiple devices. GUI-O implements MQTT protocol v3.1.1. Why do we need this? Briefly, it can be a problem for various IoT devices to communicate with each other, in cases where it is difficult or impossible for them to know the IP#s of the devices with which they need to communicate. This problem is exacerbated when all the devices don’t reside on the same local network. Another issue is whether every device is powered-up all the time to receive incoming messages.

One solution to this problem is to introduce a “middle-man” or “broker.” This broker is basically a cloud-based server, which has either a fixed IP# or at least a fixed domain name. For a GUI-O application, the ESP32-based host and the Android device must know the domain name of this broker. But that isn’t difficult, since it doesn’t change. Both devices can send data packets to this broker, and both can receive packets from it. It’s obvious that in this scenario, neither device has to know the IP# of the other—just that of the broker. In addition, both devices don’t necessarily have to be powered-up at all times.

The most commonly used brokers use the MQTT protocol. For the moment, lets assume that your two devices are the only ones using this broker, so there is no need for security or user names, passwords, and so on.

In most cases, the data being sent through an MQTT broker represents various types of data. For example, an ESP32-based device may be monitoring temperature, humidity, and air pressure. You could, of course, combine all of this data into a single String, with both the parameter labels and values contained within that String, along with some delimiters to simplify parsing them out. However, in MQTT, it is more common to define Topics, with each topic storing one type of data.

Next you have to define which device is originating a specific Topic, and which device(s) are receiving this data. The device originating the data uses the MQTT Publish function to send its parameter data. The device(s) receiving the data use the MQTT Subscribe function to retrieve it. Any device can be both a Publisher and Subscriber, if it both sends and receives data. For example, an ESP32-based device using MQTT could publish the temperature readings it has taken to one Topic, and also subscribe to a different Topic, which tells it whether or not to perform an action—such as turning on a heater.

When GUI-O is using the IoT MQTT transport mode, only two Topics are used: In and Out. The In Topic is used by the Android device’s GUI-O app to subscribe to commands from the ESP32 host, whereas the Out Topic is used to publish the responses from actions such as screen touches. As with the other GUI-O transport modes, the data contained within the In and Out Topics are ASCII Strings of various lengths, representing the Host ESP32 commands and the Android device’s responses.

The In and Out Topics are not actually named as such in GUI-O. Instead, when you define a new IoT MQTT connection using the GUI-O Android app, it generates two, 128-bit UUIDs to represent the In and Out Topics. Because each UUID is unique, the In and Out Topics for your GUI-O application will be different from the GUI-O In and Out Topics belonging to another GUI-O application. Note that these 128-bit UUIDs are expressed as a hexadecimal String with some dashes added.

When defining a new IoT MQTT connection (using the “Add device” process), you can optionally enter a user name. If you do so, it will be appended to the ends of both 128-bit UUIDs, preceded by a “\” character. You must use these two complete UUIDs, as displayed by the GUI-O app on your Android device, in your ESP32 sketch (as described later).

While GUI-O can be configured to use any available MQTT broker, by default it is configured to use the MQTT broker that GUI-O operates. Let’s assume that you are starting out by using the BasicMQTT.ino Arduino ESP32 sketch that GUI-O provides on its website.

These are the lines of code in the demo sketch that define your ESP32-based project as a unique user.

static const char *mqttServer = “”;   // host name
static const char *mqttUser = “gui-o-mqtt-generic”; // user name
static const char *mqttPass = “lqXeZpv5VJyv0XBT”;   // password
static const char *Out = “4a78be3f-a572-4c5f-a11f-85878b08dd95”; // GUI-O app publish topic
static const char *In = “35493760-355f-4d62-8eaa-d4b7345d762d”;  // GUI-O app subscribe topic

Listing 1 shows the lines of code in that demo sketch that define your ESP32-based project as a unique user. You can see that the GUI-O MQTT server is accessed at “” and that a generic user has been defined in the second and third lines. MQTT brokers require each user to have a unique clientid. You don’t see a clientId defined in this section of the sketch, so you’re probably wondering how your ESP32-based device is differentiated from anyone else’s device. The MAC number of this ESP32, which is unique, is obtained from the Wi-Fi class using the macAddress() function. This function returns 8 uint8_t values, which are then converted to a String using the snprintf() function. The variable mqttClientId is then set to this String. The connection to the MQTT broker is made as follows:

if(mqttClient.connect(mqttClientId, mqttUser, mqttPass)) {

The combination of a unique MAC-derived clientid and the fact that each GUI-O application has unique UUIDs for the In and Out Topics, means that every GUI-O application will have its own “data space” on GUI-O’s MQTT broker. Note that you must copy both 128-bit Topic UUIDS (which were generated by the GUI-O Android app) into the fourth and fifth lines of Listing1—including the optional appended user name, if it has been defined.

In my limited experience with GUI-O in MQTT mode, I only used GUI-O’s MQTT broker, which responded well during my testing. You should understand that the way GUI-O uses the MQTT protocol is somewhat different from what you might have encountered if you have used MQTT in other situations.


Ethernet mode enables direct connection to a server device over TCP/IP protocol. The device running the GUI-O application acts as a client. The Ethernet connection is usually used in a local network scenario, but it can also be used to access the device from an external network, by setting up appropriate port-forwarding rules. Note that the data is not encrypted, and can be subject to eavesdropping or “man-in-the middle” attacks.

The ESP32 contains an internal Ethernet MAC, and the ESP-IDF framework supports both the internal Ethernet MAC (EMAC) and external Ethernet Modules that are interfaced to the ESP32 via SPI. I use the Arduino ESP32 framework, not the ESP-IDF. But I noticed that even the Arduino framework has Ethernet examples using the LAN8720 and TLK110 Ethernet transceivers. I have not tried these Ethernet chips, but there are basic examples of using GUI-O with Ethernet connectivity. These contain both MQTT-based examples and AsyncTCP and AsyncWebserver examples.


The last transport type that GUI-O supports is USB. In this mode, the USB-UART bridge, present on most ESP32 boards, can be connected to an Android device running the GUI-O app. This method only works if you have an Android phone or tablet that supports USB-OTG (which most new phones do). 

USB-OTG is a special USB port mode in which the port can act as either a Host or a Client. In general, the only USB Host port that you will encounter is on your computer (or an external USB hub connected to it). All the other USB devices you’re familiar with are Clients. For example, the USB-UART bridge chip found on ESP32 boards (FTDI FT232R, CP210x, PL2303) is a USB Client. Clients plug into a Host; no other combination works. So, any ESP32 board running GUI-O must connect to an Android device that is acting as a USB Host. 

You will need an OTG cable adapter of some sort, because the standard micro-USB (or possibly USB-C) cable that plugs into an ESP32 board will have a male USB-type A plug at the other end. If you have GUI-O installed on your device, when you plug your ESP32 into the device’s USB-OTG port (using the adapter) you will see the message shown in Figure 5. “CP2104” is the USB-Serial Bridge mounted on your ESP32 board, and may vary with different ESP32 boards. Select “OK” for this prompt.

Figure 5
This is the notification that your Android device will pop up when you connect your ESP32 board to it using a USB-OTG adapter or cable.
Figure 5
This is the notification that your Android device will pop up when you connect your ESP32 board to it using a USB-OTG adapter or cable.

Next, from the Connections menu in the GUI-O app, you can choose the USB transport mode (“USB and IoT”). Selecting that brings up a page where you can set up the baud rate, among other things. As mentioned before, all GUI-O transport modes use a transparent UART-style connection between the Android device running the GUI-O app and the MCU controlling it.


The GUI-O team provides a free Windows or Linux application called Live Designer, which allows you to choose widgets for your GUI display, and configure them for size, position, color, and functionality. You can see your GUI develop, in real time, on your Android device. To work, Live Designer needs to connect to your Android phone via USB-OTG or Bluetooth. 

There are two ways to make the Bluetooth connection. First, if your PC has Bluetooth capability, and that Bluetooth port can be configured for the Bluetooth SPP profile, you can use it to connect to your Android device. Second, you can purchase a common HC05 Serial-Bluetooth module and connect it to your PC’s USB port using a USB-Serial Bridge module or cable (Figure 6).

Figure 6
Example of an HC05 Bluetooth-to-serial adapter board
Figure 6
Example of an HC05 Bluetooth-to-serial adapter board

My PC has Bluetooth built-in, and it is possible to set it up for the SPP profile. While I managed to enable the PC’s Bluetooth, and it was visible to the GUI-O app on my Android tablet, I was unable to pair it. This seems to be an issue with either Windows 10 or my Dell XPS 8900, since both Android devices that I tried to pair failed in the same way.

Fortunately, I also had an HC05 Serial-Bluetooth module. Instructions on how to use this module can be found in many places on the Web (see the Circuit Cellar Article Materials and Resources webpage). The HC05 Bluetooth module has logic level outputs and, in order to plug it into a PC, a USB-Serial bridge cable is needed.

The HC05 module comes from the factory with a baud rate set at 9600. Live Designer uses a baud rate of 115200 by default. You could switch Live Designer to 9600 baud, but it would then communicate slowly. Instead, to change the HC05 baud rate, get into AT command mode, as follows:

  1. Push the button when powering-up the HC05. The LED will flash once every 2 seconds in this AT command mode.
     In this mode, the default baud rate is 38400, so you will have to change your PC terminal monitor to that baud rate setting.
    • Enter AT+UART=115200,1,2,
    • The HC05 returns OK.
  2. Power-up the HC05 again, without the button pressed.
  3. While the GUI-O app on the Android device is connected to the HC05, its LED will stop flashing quickly, and instead flash twice about every 7 seconds.

GUI-O Live Designer software is fairly self-explanatory. I have submitted several suggestions to make it more user-friendly, and the GUI-O team has implemented all of them—rather quickly, I must say!

Figure 7 shows the Live Designer in operation. You first have to select the proper COM port and baud rate, to match the USB-Serial Bridge cable to which the HC05 is connected. Then press “Connect.” Until you do this is, you won’t be able to do any actual design work, or even load an existing design file. 

Figure 7
Screen capture of the Live Designer program provided by GUI-O. I've reduced it in size to keep this figure reasonably small, but it would normally be run in full-screen mode.
Figure 7
Screen capture of the Live Designer program provided by GUI-O. I’ve reduced it in size to keep this figure reasonably small, but it would normally be run in full-screen mode.

You can see at the upper right side of Figure 7, about half of the command code needed to produce the montage of widgets that I designed for this article (Figure 1). The left window contains all the available widgets. You double click on the one that you want to include, and it appears in the adjacent window to the right. Clicking on any widget in that window populates the window to its right with all of that widget’s configuration parameters. As you add and configure these widgets, they show up in real time on your Android device’s screen. If you touch a widget or adjust it (when applicable), the corresponding status message, returned by GUI-O, will appear in the window at the bottom right of the screen. You can Save or Load any design that you have created by using the File menu at the top left of the screen.


In this article, I’ve tried to explain the features and advantages of the GUI-O app in conjunction with the fairly simple code requirements on your host MCU. A diverse assortment of available widgets allow you to construct most of the GUI displays you might need. I’ve covered the various transport modes that GUI-O uses, and have given my assessment of which ones are the easiest to use. Last, I’ve introduced the GUI-O Live Designer—a free PC application software that can be used to design your GUI layout- displayed in real time directly on your Android device. 

Within about an hour of discovering GUI-O, I was impressed enough with its operation to delve into it further, with the idea of integrating it with some of my pending projects. Figure 8 shows an actual GUI that I designed for a project which will be the subject of a future Circuit Cellar article. 

Figure 8
The GUI I designed for the home controller that I will be presenting in a future Circuit Cellar article.
Figure 8
The GUI I designed for the home controller that I will be presenting in a future Circuit Cellar article.

GUI-O Android app and Live Designer utility software:
GUI-0 Developer Manual


Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.

Note: We’ve made the May 2020 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article
+ posts

Brian Millier runs Computer Interface Consultants. He was an instrumentation engineer in the Department of Chemistry at Dalhousie University (Halifax, NS, Canada) for 29 years.

Supporting Companies

Upcoming Events

Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2023 KCK Media Corp.

GUI-O: A “Virtual” Front Panel

by Brian Millier time to read: 25 min