15.Interface and Application Programming¶
Summary¶

Group assignment¶
Node Red¶
What is Node-RED?¶
Node-RED is a powerful flow-based development tool created by IBM for connecting hardware devices, APIs, online services, and IoT platforms. It provides a visual, drag-and-drop programming interface where logic is built using nodes instead of traditional code. This makes Node-RED very effective for rapid prototyping, IoT experiments, home automation, and integrating different systems without writing large scripts.
Each function in Node-RED is represented as a node, and these nodes can be connected together into flows. A flow may include data input, processing logic, and an output such as controlling hardware, sending a network request, or updating a dashboard. Because of this architecture, Node-RED allows developers to visually understand the logic of their system, debug it quickly, and extend it very easily.
Node-RED also has a huge community and a large ecosystem of third-party nodes. These nodes provide additional features such as dashboards, databases, MQTT communication, GPIO control, cloud connectivity, AI services, and more. If a required node is not available by default, it can be installed directly from the palette manager with one click.
For Fab Academy, Node-RED is extremely useful because it allows fast experimentation with Raspberry Pi, ESP32, sensors, actuators, and web interfaces. You can create dashboards, buttons, sliders, graphs, and control hardware in real time — all without writing complex web code.
In short, Node-RED is a flexible, beginner-friendly yet powerful platform that enables rapid IoT development through visual programming.

In the final photo, we connected the Raspberry Pi to a breadboard through a GPIO breakout module. We used a rainbow ribbon cable to access the GPIO pins easily while working on future tasks. This setup allowed us to test LEDs, buttons, and sensors directly from Node-RED.
Upgrade and update system¶
sudo apt update
sudo apt upgrade -y
In this photo, we started the installation of Node-RED on our Raspberry Pi 4. We executed the installation script in the terminal, which downloaded all required packages, dependencies, and modules. We monitored the entire process to make sure the system was being installed correctly.

Install Node-RED¶
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
Here, we completed the initial configuration of Node-RED right after installation. We selected the data directory, enabled recommended settings, and prepared Node-RED to run as a system service. This step was important to set up the environment properly before launching the editor.

Start Node-RED¶
node-red-start


In this screenshot, we saw the message: “Server now running at http://127.0.0.1:1880/”
This confirmed that Node-RED was successfully deployed on our Raspberry Pi. Now the interface could be opened from any browser inside our network.
Stop Node-RED¶
node-red-stop
Auto run system¶
sudo systemctl enable nodered.service
By default, Node-RED runs on port 1880.¶


Here, we opened the Node-RED graphical editor in the browser. We saw the welcome screen of Node-RED 4.1.1. At this moment, we started exploring flows, adding nodes, and preparing our automation experiments.
What is Node-RED? (Short explanation)¶

In this image, I opened the Node-RED sidebar menu, which shows important tools such as Information, Help, Debug Messages, and Context Data. These tools help me understand how flows work and debug my project during development.

Here, I clicked on the hamburger menu (top right) and selected Manage palette. This is the place where you can install new nodes, remove unused ones, or check version updates. At this stage, I still did not have the dashboard node installed, so I opened this menu to search for it.

In this photo, I searched for “dashboard” inside the palette manager. The result showed node-red-dashboard, which is required to create UI elements such as buttons, switches, charts, gauges, and more. I clicked Install to add it to my Node-RED environment.
This was a key step, because at first I didn’t know why the dashboard menu was missing. After some research, I discovered that I needed to manually install this node. Once I installed it, the dashboard features appeared.

After installation, the Dashboard tab appeared in the sidebar. This confirmed that the dashboard package was successfully added. With this tab, I can configure pages, UI groups, themes, and layout settings.

In this photo, I created a new dashboard tab and named it “RPI” because I tested Node-RED with the Raspberry Pi. I also clicked Update to save the configuration. This tab will contain all UI elements, such as switches and buttons.

Here, I created a group inside my tab. Groups help organize UI widgets. I created a group called “GPIO OUTPUT”, where I will put my switches that control the Raspberry Pi’s GPIO pins.

In this image, I added a switch node to the flow and configured it:
-
Group: RPI → GPIO OUTPUT
-
Label: LED
-
Tooltip: Activate the attached LED
-
Output Payload ON: true
-
Output Payload OFF: false
This switch will send simple boolean values, which can be used to turn a GPIO pin ON or OFF using another node.
In this video, you can see how I control the LED through the Node-RED dashboard. When I toggle the switch in the web interface, the LED responds instantly.
Mqtt¶

What is the MQTT Protocol?¶
MQTT (Message Queuing Telemetry Transport) is a lightweight, fast, and reliable messaging protocol designed for communication between devices. It is widely used in IoT (Internet of Things) systems, where devices often have limited processing power, small memory, or unstable network connections.
How MQTT Works¶
MQTT uses a Publish / Subscribe architecture:
-
Publisher — sends data (messages).
-
Subscriber — receives data if subscribed to the topic.
-
Broker — a central server that receives messages from publishers and delivers them to subscribers.

We began our experiment by working with the Mosquitto MQTT broker, which is one of the most popular open-source MQTT servers. Our goal was to fully understand the publish/subscribe model and see how IoT devices communicate through topics.
First, we opened two separate terminal windows on the Mackbook:
-
In the first terminal, we launched the Mosquitto broker and monitored its activity.
-
In the second terminal, we published and subscribed to various MQTT topics to observe how data flows between clients.
This simple setup allowed us to test sending messages such as "ON", "OFF", "Hello", "Test" and immediately see how they were received on the other terminal. This gave us a clear understanding of how MQTT handles lightweight message transmission. You can see the full interaction in our first demonstration video.
After successfully testing basic communication, we decided to try something more practical and hardware-related. We took a 220V AC lamp and connected it through a relay module, which in turn was controlled by an ESP32 microcontroller. Our goal was to remotely control the lamp using MQTT messages.
To do this, we installed an MQTT client application from the App Store (an MQTT Terminal app). This app allowed us to easily publish messages to the Mosquitto broker running on the Raspberry Pi.
We wrote an ESP32 program that:
-
connects to the local Wi-Fi network,
-
establishes a connection to the Mosquitto MQTT broker,
-
subscribes to specific topics (e.g., home/lamp/control),
-
and listens for incoming messages such as "1" or "0".
Whenever the ESP32 received a message, it activated or deactivated the relay, turning the lamp ON or OFF in real time. This allowed us to wirelessly control a high-voltage device using a low-power microcontroller and MQTT.
This experiment demonstrated the power of MQTT in IoT systems: it is fast, reliable, lightweight, and perfect for controlling devices remotely. Working with MQTT helped us understand how smart home systems, industrial automation, and IoT networks communicate efficiently through publish/subscribe messaging.
Here is code¶
#include <WiFi.h>
#include <PubSubClient.h>
#define RELAY_PIN 25
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* mqtt_server = "192.168.1.100";
const int mqtt_port = 1883;
const char* mqtt_client_id = "esp32-relay-1";
const char* sub_topic = "home/lamp/control";
const char* pub_topic = "home/lamp/status";
WiFiClient espClient;
PubSubClient client(espClient);
void mqttCallback(char* topic, byte* payload, unsigned int length) {
String msg;
for (unsigned int i = 0; i < length; i++) {
msg += (char)payload[i];
}
if (msg == "ON" || msg == "1") {
digitalWrite(RELAY_PIN, HIGH);
client.publish(pub_topic, "ON");
} else if (msg == "OFF" || msg == "0") {
digitalWrite(RELAY_PIN, LOW);
client.publish(pub_topic, "OFF");
}
}
void setupWifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void reconnect() {
while (!client.connected()) {
if (client.connect(mqtt_client_id)) {
client.subscribe(sub_topic);
} else {
delay(2000);
}
}
}
void setup() {
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
Serial.begin(115200);
setupWifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(mqttCallback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
}
Comparison Between Node-RED and MQTT¶
In this week, I worked with both Node-RED and MQTT, and I realized that even though they are often used together, they serve different purposes.
My Comparison
Node-RED is a visual programming tool that allows me to create flows using blocks (nodes). I use it to connect devices, process data, automate logic, and build dashboards. It is very user-friendly, because I can visually see how data moves from one node to another.
MQTT, on the other hand, is a lightweight communication protocol. It is designed only for sending and receiving messages between devices. It works with topics and uses a broker like Mosquitto. MQTT itself does not provide visualization, logic, dashboards, or automation — it only delivers messages.
How I See the Difference
Node-RED = automation + logic + interface
MQTT = communication protocol for sending messages
How They Work Together
In my work, I discovered that Node-RED can act as an MQTT client. So I can subscribe to MQTT topics, process the data visually, and then control devices. For example: ESP32 → MQTT Broker → Node-RED → Dashboard → Control device again via MQTT.
My Conclusion
Node-RED is like the brain and the UI, while MQTT is like the communication channel. Both are powerful, but they solve different problems. When combined, they create a very flexible and reliable IoT system.
Individual assignment¶
In the previous Output Devices week, I successfully made my robot platform move using hoverboard BLDC motors, the original hoverboard control board, and the custom PCB that I designed myself. This proved that the drivetrain and electronics were working correctly.
This week, my goal was to go one step further and make the robot platform controllable through a web interface. I wanted to send movement commands wirelessly and make the robot respond in real time.
To achieve this, I used the ESP32 on my custom board to host a simple web page with control buttons. When I press a button in the web interface, the ESP32 receives the command and immediately sends the corresponding steering and speed values to the hoverboard controller over UART.

Before implementing my plan, I prepared the robot platform for testing. I mounted the hoverboard BLDC motors, the original hoverboard control board, and the battery pack that powers the entire system. I also installed a main power button, my custom PCB, and a DC-DC buck converter.
The hoverboard board provides 15V output, but my ESP32 board needs 5V, so I stepped the voltage down using the buck converter.
During earlier tests, I discovered an important detail: when the ESP32 creates its Wi-Fi Access Point, it draws a high current during startup. When I powered it only from the UART-TTL programmer, the ESP32 could not start the Wi-Fi AP at all because the programmer could not provide enough current.
But when I connected everything to the hoverboard platform, the system worked perfectly — the hoverboard board can supply up to 2A, so the ESP32 was able to power up reliably and successfully start its Access Point.

My plan was the following:¶
I designed a custom board based on the ESP32-WROOM-32U module, which includes an external antenna connector. The ESP32 creates its own Wi-Fi Access Point, and inside it I host a web interface with several control buttons.
Any device connected to this Wi-Fi network can open the web interface in a browser using the ESP32’s IP address. The page sends HTTP requests to the ESP32 when a button is pressed.
When the ESP32 receives a specific command via HTTP, it immediately sends the corresponding control packet to the hoverboard main board through the UART protocol, which then drives the robot platform.
As shown in the photo, I connected an external antenna to the ESP32 module to ensure stable signal quality and to avoid any communication issues during robot control.
Here is the code that implements my plan.¶
#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#define HOVER_BAUD 115200
#define START_FRAME 0xABCD
#define HoverSerial Serial
typedef struct attribute((packed)) {
uint16_t start; // 0xABCD
int16_t steer; // поворот (-..+)
int16_t speed; // скорость (-..+)
uint16_t checksum;// XOR(start, steer, speed)
} SerialCommand;
static inline void sendCmd(int16_t steer, int16_t speed) {
SerialCommand cmd;
cmd.start = START_FRAME;
cmd.steer = steer;
cmd.speed = speed;
cmd.checksum = (uint16_t)(cmd.start ^ cmd.steer ^ cmd.speed);
HoverSerial.write((uint8_t*)&cmd, sizeof(cmd));
}
#define SPEED_MAX_HW 300
#define STEER_MAX_HW 300
#define SPEED_CMD 250
#define STEER_CMD 200
#define COMMAND_TIMEOUT_MS 1000
unsigned long lastCmdTS = 0;
int16_t lastSteer = 0;
int16_t lastSpeed = 0;
const char* AP_SSID = "HoverESP32";
const char* AP_PASS = "12345678";
WebServer server(80);
const char HTML_PAGE[] PROGMEM = R"HTML(
<!doctype html><meta name=viewport content="width=device-width,initial-scale=1">
<style>button{font-size:22px;padding:14px 20px;margin:8px;width:46%} .row{display:flex;gap:8px;flex-wrap:wrap}</style>
<h2>Hover Control</h2>
<div class=row>
<button onclick="send('F')">Forward</button><button onclick="send('B')">Backward</button>
<button onclick="send('L')">Left</button><button onclick="send('R')">Right</button>
<button onclick="send('S')">Stop</button>
</div>
<script>
async function send(c){
try{ await fetch('/cmd?c='+c); }catch(e){ console.log(e); }
}
</script>
)HTML";
void handleRoot() {
server.send(200, "text/html", HTML_PAGE);
}
void applyCommand(char c) {
int16_t steer = 0;
int16_t speed = 0;
switch (c) {
case 'F': speed = SPEED_CMD; break;
case 'B': speed = -SPEED_CMD; break;
case 'L': steer = -STEER_CMD; break;
case 'R': steer = STEER_CMD; break;
case 'S': default: steer = 0; speed = 0; break;
}
if (speed > SPEED_MAX_HW) speed = SPEED_MAX_HW;
if (speed < -SPEED_MAX_HW) speed = -SPEED_MAX_HW;
if (steer > STEER_MAX_HW) steer = STEER_MAX_HW;
if (steer < -STEER_MAX_HW) steer = -STEER_MAX_HW;
lastSteer = steer;
lastSpeed = speed;
lastCmdTS = millis();
sendCmd(lastSteer, lastSpeed);
}
void handleCmd() {
if (!server.hasArg("c")) {
server.send(400, "text/plain", "Usage: /cmd?c=F|B|L|R|S");
return;
}
char c = server.arg("c")[0];
applyCommand(c);
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", String("OK: ") + c);
}
#define LED_PIN 2
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
HoverSerial.begin(HOVER_BAUD);
WiFi.mode(WIFI_AP);
WiFi.softAP(AP_SSID, AP_PASS);
IPAddress ip = WiFi.softAPIP();
server.on("/", handleRoot);
server.on("/cmd", handleCmd);
server.begin();
Serial.begin(115200);
Serial.print("AP IP: "); Serial.println(ip);
}
void loop() {
server.handleClient();
if (millis() - lastCmdTS > COMMAND_TIMEOUT_MS) {
if (lastSpeed != 0 || lastSteer != 0) {
lastSpeed = 0; lastSteer = 0;
sendCmd(0, 0);
}
lastCmdTS = millis();
}
digitalWrite(LED_PIN, (millis() % 1000) < 500);
}
Web interface for hoverboard control
To control my hoverboard robot from a browser, I embedded a small HTML page directly in the ESP32 firmware:
const char HTML_PAGE[] PROGMEM = R"HTML(
<!doctype html><meta name=viewport content="width=device-width,initial-scale=1">
<style>button{font-size:22px;padding:14px 20px;margin:8px;width:46%} .row{display:flex;gap:8px;flex-wrap:wrap}</style>
<h2>Hover Control</h2>
<div class=row>
<button onclick="send('F')">Forward</button><button onclick="send('B')">Backward</button>
<button onclick="send('L')">Left</button><button onclick="send('R')">Right</button>
<button onclick="send('S')">Stop</button>
</div>
<script>
async function send(c){
try{ await fetch('/cmd?c='+c); }catch(e){ console.log(e); }
}
</script>
)HTML";
I store the HTML in flash memory using PROGMEM, so it doesn’t take RAM on the ESP32.
The <meta name=viewport> tag makes the page responsive and easy to use from a smartphone screen.
In the <style> block I define simple CSS: large buttons, padding, and a .row container with display:flex so the buttons automatically wrap and look good on any screen size.
The page title “Hover Control” and the five buttons correspond to the main driving commands for my hoverboard base:
-
F – Forward
-
B – Backward
-
L – Left
-
R – Right
-
S – Stop
Each button calls the JavaScript function send(c) with a single character. Inside send(c) I use the fetch() API to send an HTTP request to the ESP32 at the path /cmd?c=…. On the firmware side I parse this character and translate it into motor commands.
I chose this minimal design on purpose: no heavy libraries, just plain HTML + CSS + JavaScript. Thanks to this, the interface loads very fast, works on any device with a browser, and gives me reliable real-time control of the hoverboard robot over Wi-Fi.
After writing the firmware, I compiled the code and uploaded it to my custom ESP32 board using a USB-TTL programmer. The flashing process completed successfully without any errors.
Then I installed the board onto the robot platform and powered the system from the hoverboard battery through my 5V regulator. As soon as the board was powered, the ESP32 automatically started the Wi-Fi Access Point, and I could immediately see the network appear on my phone and laptop.
When I connected to the AP and opened the ESP32 IP address in a browser, the web interface loaded successfully, confirming that the firmware, Wi-Fi setup, and web server were all working exactly as planned.

Result¶
And finally, we were able to see the result in action. The ESP32 web interface worked perfectly, and the robot platform responded to every command in real time. All movements — forward, backward, left, right, and stop — were successfully triggered through the browser.
This confirmed that the complete chain - Wi-Fi Access Point → Web Interface → ESP32 → UART → Hoverboard Board → Motors - is fully functional.
Conclusion¶
This week, I successfully implemented wireless control for my robot platform using an ESP32-based web interface. I designed a system where the ESP32 creates its own Wi-Fi access point, hosts a simple control webpage, receives HTTP commands, and then forwards these commands through UART to the hoverboard motor controller.
I tested everything directly on my robot platform, including power distribution, signal stability, and real-time motor response. The system worked reliably — the web interface loaded instantly, commands were transmitted without delay, and the motors reacted exactly as expected.
Through this assignment, I gained practical experience in combining embedded systems, networking, and motor control into one integrated workflow. This approach will be used in my final project, where the robot needs to operate wirelessly and autonomously inside buildings.