Week 14 – Interface & Application Programming

Week 14 Interface & Application Programming

  • Individual assignment:
  • Write an application that interfaces a user with an input &/or output device that you made
  • Group assignment:
  • Compare as many tool options as possible

Individual Assignment

This week focuses on creating an application that allows a user to interact with a custom embedded system. In this assignment, I developed a web-based interface to control LEDs using Bluetooth Low Energy (BLE).

This was also my first experience using Visual Studio Code and GitHub Copilot to generate UI and logic, which I later modified manually.

This project demonstrates the transition from wired communication (I2C in Week 11) to wireless interaction using BLE, marking a key step toward IoT system development.


System Overview

The system connects a web application directly with the ESP32 microcontroller using BLE. User actions are converted into commands that control physical outputs.

Image generated using ChatGPT

Create a simple infographic diagram of a BLE LED control system. Show flow from left to right: Web App → Web Bluetooth → ESP32-C6 Transmitter → BLE Channel → ESP32-C6 Receiver → LED Driver → 4 LEDs. Add arrows labeled Input, Transmit, Receive, and Output. Use minimal text, clean boxes, simple icons, and a white background.

Hardware

Board: This board was used in Week 11, which is why the RP2040 is shown in this image. RP2040 does not have built-in Wi-Fi or Bluetooth, which is why I switched to the ESP32-C6.
View Week 11
ESP32-C6
ESP32-C6 Datasheet

Week 11 Comparison

View Week 11 used RP2040 for I2C (wired communication). Week 14 uses ESP32-C6 for BLE (wireless communication).

Feature RP2040 ESP32-C6
Communication I2C, SPI BLE, Wi-Fi ⚡
Wireless No ❌ Yes ✔
Application Sensors IoT 🔥

Bluetooth Low Energy (BLE)

BLE enables low-power wireless communication between the browser and ESP32.

UUID Concept


Service UUID: 1234
Characteristic UUID: ABCD

"1" → LED ON
"0" → LED OFF

Tools Used

This is my first time using VS Code and Copilot. I used prompts to generate UI and logic and then refined the code manually.

🌐 Web Application Development

Step 1: Create Project Folder

First, I created a new folder named "page1" on my computer. This folder will contain all the files of my web application.

Step 2: Open Folder in VS Code

I opened Visual Studio Code and selected File → Open Folder → page1.

Step 3: Create HTML File

Inside the folder, I created a new file named index.html. This file is the main structure of the web application.

Step 4: Create ui uing claude

Instead of designing the UI manually, you used Claude AI to generate the interface.

Prompt

For Week 14 (Interface and Application Programming), I needed to create a mobile application to communicate with my Xiao RP2040 board, which has 4 LEDs.

Abstract:
The Smart Hair Oil Dispenser is an innovative personal care device designed to improve hair nourishment and scalp health through controlled oil heating, precise dispensing, and therapeutic massage...

The device features a precision nozzle that ensures smooth and direct oil delivery to the hair roots...

For safety and reliability, the dispenser is equipped with wireless charging technology...

Who Will Use This Project?
The Smart Hair Oil Dispenser is designed for individuals who regularly apply hair oil...

  • Home users – People who apply hair oil as part of their routine
  • People with hair/scalp issues – Hair fall, dry scalp, or slow growth
⚠️ Important Note:

Initially, this prompt was written for the Xiao RP2040 board. However, RP2040 does not support Wi-Fi or Bluetooth, so later I switched to ESP32-C6.

I used GitHub Copilot to modify the project according to ESP32-C6 and expanded it for my final project.

For Week 14, this full system is not required. Since this is my first time building a mobile interface, I simplified the implementation to only control 4 LEDs using buttons.

Step 5: Re genarate ui using github copilot

Side by Side Images
HTML 1 HTML 2
⚠️ Note:

I initially faced an error because the prompt was written for the XIAO RP2040. However, RP2040 does not support Wi-Fi or Bluetooth, which caused issues in my implementation.

Later, I switched to ESP32-C6 and updated the prompt and code accordingly, which resolved the problem.

GitHub Copilot was used to integrate the HTML front-end with the Arduino code, enabling interaction between the interface and the hardware.

Advantage of html Code

Code


/*
 * Xiao ESP32C6 LED Controller - BLE (Bluetooth Low Energy) Version
 * Professional Edition - Final Version
 * 
 * Features:
 * - Bluetooth Low Energy (BLE) GATT Server
 * - Mobile & Desktop Web App Control
 * - Real-time Status Monitoring
 * - Characteristic-based Protocol
 * 
 * LED Connections:
 * LED 1 (Red)    → GPIO 0 (D0)
 * LED 2 (Green)  → GPIO 1 (D1)
 * LED 3 (Blue)   → GPIO 2 (D2)
 * LED 4 (Yellow) → GPIO 3 (D3)
 */

#include 
#include 
#include 
#include 

// ==================== BLE CONFIGURATION ====================
#define SERVICE_UUID           "180A"
#define LED_CHARACTERISTIC_UUID "2A58"
#define STATUS_CHARACTERISTIC_UUID "2A19"

const char* BT_NAME = "Ali";
BLEServer* pServer = nullptr;
BLEService* pService = nullptr;
BLECharacteristic* pLedCharacteristic = nullptr;
BLECharacteristic* pStatusCharacteristic = nullptr;

bool deviceConnected = false;
bool oldDeviceConnected = false;

// LED Pin Configuration (Xiao ESP32C6 - D0, D1, D2, D3)
const int LED_PINS[4] = {0, 1, 2, 3};
bool led_states[4] = {false, false, false, false};

// Forward declaration
void handleBLECommand(String command);

// ==================== SERVER CALLBACKS ====================
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
      Serial.println("[BLE] ✓ Device connected!");
    }

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
      Serial.println("[BLE] ✗ Device disconnected!");
    }
};

class MyCharacteristicCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      String rxValue = String(pCharacteristic->getValue().c_str());
      if (rxValue.length() > 0) {
        String command = rxValue;
        command.trim();
        command.toLowerCase();
        Serial.println("[CMD] " + command);
        handleBLECommand(command);
      }
    }
};

// ==================== SETUP ====================
void setup() {
  Serial.begin(115200);
  delay(1000);
  
  Serial.println("\n\n");
  Serial.println("╔════════════════════════════════════════╗");
  Serial.println("║   Xiao ESP32C6 LED Controller - BLE    ║");
  Serial.println("║         Professional Edition           ║");
  Serial.println("╚════════════════════════════════════════╝");
  
  // Initialize LED pins
  for (int i = 0; i < 4; i++) {
    pinMode(LED_PINS[i], OUTPUT);
    digitalWrite(LED_PINS[i], LOW);
    Serial.println("[SETUP] GPIO " + String(LED_PINS[i]) + " initialized");
  }
  
  Serial.println("[SETUP] ✓ All LED pins ready");
  
  // Initialize BLE
  initBLE();
  
  Serial.println("\n[READY] System Ready - Waiting for connection...\n");
}

// ==================== BLE INITIALIZATION ====================
void initBLE() {
  Serial.println("[BLE] Starting initialization...");
  
  BLEDevice::init(BT_NAME);
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  
  pService = pServer->createService(SERVICE_UUID);
  
  pLedCharacteristic = pService->createCharacteristic(
    LED_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY
  );
  pLedCharacteristic->addDescriptor(new BLE2902());
  pLedCharacteristic->setCallbacks(new MyCharacteristicCallbacks());
  pLedCharacteristic->setValue("0000");
  
  pStatusCharacteristic = pService->createCharacteristic(
    STATUS_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );
  pStatusCharacteristic->addDescriptor(new BLE2902());
  pStatusCharacteristic->setValue("Ready");
  
  pService->start();
  
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);
  BLEDevice::startAdvertising();
  
  Serial.println("[BLE] ✓ Service UUID: " + String(SERVICE_UUID));
  Serial.println("[BLE] ✓ Device Name: " + String(BT_NAME));
  Serial.println("[BLE] ✓ Advertising started");
}

// ==================== MAIN LOOP ====================
void loop() {
  if (deviceConnected && !oldDeviceConnected) {
    Serial.println("[BLE] ✓ Client connected!");
    oldDeviceConnected = deviceConnected;
  }
  
  if (!deviceConnected && oldDeviceConnected) {
    Serial.println("[BLE] ✗ Restarting advertising...");
    delay(500);
    BLEDevice::startAdvertising();
    oldDeviceConnected = deviceConnected;
  }
  
  delay(100);
}

// ==================== BLE COMMAND HANDLER ====================
void handleBLECommand(String command) {
  String response = "";
  
  if (command == "led1_on") { controlLED(0, true); response = "LED 1 ON"; }
  else if (command == "led1_off") { controlLED(0, false); response = "LED 1 OFF"; }
  else if (command == "led1_toggle") { controlLED(0, !led_states[0]); response = led_states[0] ? "LED 1 ON" : "LED 1 OFF"; }
  
  else if (command == "led2_on") { controlLED(1, true); response = "LED 2 ON"; }
  else if (command == "led2_off") { controlLED(1, false); response = "LED 2 OFF"; }
  else if (command == "led2_toggle") { controlLED(1, !led_states[1]); response = led_states[1] ? "LED 2 ON" : "LED 2 OFF"; }
  
  else if (command == "led3_on") { controlLED(2, true); response = "LED 3 ON"; }
  else if (command == "led3_off") { controlLED(2, false); response = "LED 3 OFF"; }
  else if (command == "led3_toggle") { controlLED(2, !led_states[2]); response = led_states[2] ? "LED 3 ON" : "LED 3 OFF"; }
  
  else if (command == "led4_on") { controlLED(3, true); response = "LED 4 ON"; }
  else if (command == "led4_off") { controlLED(3, false); response = "LED 4 OFF"; }
  else if (command == "led4_toggle") { controlLED(3, !led_states[3]); response = led_states[3] ? "LED 4 ON" : "LED 4 OFF"; }
  
  else if (command == "status") {
    response = "";
    for (int i = 0; i < 4; i++) {
      response += led_states[i] ? "1" : "0";
    }
  }
  
  else if (command == "reset") {
    for (int i = 0; i < 4; i++) {
      controlLED(i, false);
    }
    response = "All LEDs OFF";
  }
  
  else {
    response = "Unknown";
  }
  
  pStatusCharacteristic->setValue(response.c_str());
  pStatusCharacteristic->notify();
  
  String ledStatus = "";
  for (int i = 0; i < 4; i++) {
    ledStatus += led_states[i] ? "1" : "0";
  }
  pLedCharacteristic->setValue(ledStatus.c_str());
  pLedCharacteristic->notify();
  
  Serial.println("[RESPONSE] " + response);
}

// ==================== LED CONTROL ====================
void controlLED(int ledIndex, bool state) {
  led_states[ledIndex] = state;
  digitalWrite(LED_PINS[ledIndex], state ? HIGH : LOW);
  Serial.println("[LED" + String(ledIndex + 1) + "] " + (state ? "ON" : "OFF"));
}

Final Result

Now, the web application is working successfully. This is my first UI/UX design, so I kept it simple and clean. I will improve it with more advanced design in the future.

Final Output


Technical Specifications

Parameter Value
Protocol HTTP/1.1
Port 80 (configurable)
Response Format JSON
Max Concurrent Connections 4
WiFi Standard 802.11 b/g/n (2.4GHz only)
Number of LEDs 4
GPIO Pins Used 0, 1, 2, 3

Interface

Web Interface

Working

Working Demo
⚠️ Important Note

In this project, I reused the custom board designed in Week 11, which was originally developed for the XIAO RP2040.

Due to differences in pin mapping and architecture between the RP2040 and ESP32-C6, there are slight schematic mismatches.

As a result, not all LEDs function correctly, and only some LEDs respond during BLE control.

This limitation is due to hardware design differences, not a software issue.

Conclusion

This project demonstrates wireless control using BLE, extending the system from Week 11 (Wired Communication) to enable real-time IoT interaction.


References

Download Files