Interface and Application Programming

This weeks individual assignment:

  • write an application that interfaces a user with an input &/ output device that you made

This weeks learnings:

This week, I learned that it can be quite simple to send and process commands via an interface (in my case, a webpage). If you'd like to test how easy it is, I´ve integrated my work from this week into this website and will describe how you can control an LED with a simple code and a microcontroller.

Unfortunately, I had a number of other commitments this week, so I decided to keep my assignment very simple. I'll simply send "OnClick" commands for various buttons to my board from week 8 via the serial interface to control the LEDs attached there.

That pretty much describes the assignment itself. Besides the already finished board, all that's left is to write code for the microcontroller and a web application. I'll show you a video of the initial result here, followed by a discussion of the underlying code; I think that makes it easier to understand.



Let's start with the code for the microcontroller, which I've uploaded here using the Arduino IDE: It's quite obvious that the code is very simple. We identify the pin for our LED, start the serial monitor with a clock rate of 115200 (important for ESP32C3!), and for initial debugging, I'll start the program with an illuminated LED.

In the loop function, we read the serial interface, if available. This outputs a character, which in this configuration is either '1' or '0'. Depending on this, we act on or, in this case, switch our LED on pin 9. Of course, we can generally switch anything we want. The serial outputs are also used for debugging purposes to identify potential errors or to see whether the intended functions and queries are being executed.

											
int LED_PIN = 9;

void setup() {
	pinMode(LED_PIN, OUTPUT);
	Serial.begin(115200);
	digitalWrite(LED_PIN, HIGH);
	Serial.println("ESP ready...");
}

void loop() {
	if (Serial.available()) {
	char c = Serial.read();
	Serial.print("Char: "); Serial.println(c);

	if (c == '1') {
		digitalWrite(LED_PIN, HIGH);
		Serial.println("LED ON");
	} else if (c == '0') {
		digitalWrite(LED_PIN, LOW);
		Serial.println("LED OFF");
	}
	} 
}
                                            
										
This brings us to the HTML document. Similar to the explanation in Week 1, we first see the normal prefixes and structures in HTML. Things get more interesting when we move on to the body. This is where the buttons previously defined in the styles come into play, and we see that the one that is supposed to turn the LED on returns a '1' onClick. To turn it off, we return '0'. We could return any character here; the important thing is that they match our corresponding functions on the microcontroller board.

Now we get to the interesting part for this week – the communication between our web interface and the microcontroller via the serial interface.
First, we set up the connection. In the connect() function, the browser asks the user to select a serial port using navigator.serial.requestPort(). Once the port is selected, it is opened with a baud rate of 115200 – the same rate we set on the microcontroller (important!).

Then, we set up an encoder and decoder: TextEncoderStream() is used to convert regular text commands (like "1\n" or "0\n") into bytes that can be sent over the serial port. This encoder is piped into the port’s writable stream.
On the other side, TextDecoderStream() converts incoming bytes from the microcontroller into readable text and pipes it to the readable stream of the port.

Communication in both directions: With writer.write(cmd + "\n"), the send(cmd) function sends a command to the microcontroller. Just like in our example: send("1") turns on the LED, and send("0") turns it off. The readLoop() function constantly checks whether new data is being received from the microcontroller. If so, it displays the data inside a HTML element which is also useful for debugging or status messages.

											
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>XIAO ESP32C3 LED Control</title>
	<style>
	body { font-family: sans-serif; padding: 20px; }
	button { margin: 5px; padding: 10px; font-size: 16px; }
	#output { background: #111; color: #0f0; padding: 10px; white-space: pre-wrap; max-height: 200px; overflow-y: auto; }
	</style>
</head>
<body>
	<h2>🔌 XIAO ESP32C3 LED Control</h2>
	<button onclick="connect()">🔗 connect</button>
	<button onclick="send('1')">💡 LED on</button>
	<button onclick="send('0')">💤 LED off</button>
	
	<script>
	let port, writer, reader;

	async function connect() {
		try {
		port = await navigator.serial.requestPort();
		await port.open({ baudRate: 115200 });

		const encoder = new TextEncoderStream();
		encoder.readable.pipeTo(port.writable);
		writer = encoder.writable.getWriter();

		const decoder = new TextDecoderStream();
		decoder.readable.pipeTo(port.readable);
		reader = decoder.readable.getReader();

		readLoop();
		} catch (err) {
		alert("no connection established: " + err);
		}
	}

	async function readLoop() {
		while (true) {
		const { value, done } = await reader.read();
		if (done) break;
		if (value) {
			const output = document.getElementById("output");
			output.textContent += value;
			output.scrollTop = output.scrollHeight;
		}
		}
	}

	function send(cmd) {
		if (writer) writer.write(cmd + "\n");
	}
	</script>
</body>
</html>
                                            
										
To enhance the whole thing a bit, I've included the buttons at the top of this page that can be used to control a microcontroller via the serial port. If you connect a microcontroller to your device and load it with this code—adapted to your circumstances (pin assignment)—you too can use an interface to control something you've created. This is also the reason why I'm skipping a hero shot this week and replacing it with hero buttons. You can see what that looks like in the video at the bottom. If, like me, you have three LEDs on your board, I've created another code for it because I found the blunt switching of LEDs on and off a bit too boring. This triggers a minimalist LED animation that should match the rhythm of a world-famous song. Have fun guessing and watching the video.



Download this weeks files