MAS.863/4.140/6.9020
Lleyton Elliott

Return to Assignments page | Return to main page

Week 12 Assignment: Write an Application that Interfaces a User with an Input &/or Output Device that you made

A core part of my final project is an interface to bridge the gap between the user and the sensor, but I have absolutely no experience with interfaces and applications. Let's get into it.

I understood the basic path that I wanted my data to take: raw sensor input converted to analog signal (between 0 and 255) by the microcontroller, then sent over serial to a Python script, which writes several pieces of dependent information to a JSON file, which is read by some Javascript code which constantly updates an HTML file on localhost (I am considering eventually localizing it all to a Javascript file using a Javascript serial library, but given that my Python serial read program works I'm going to build off of that first). As somebody with minimal Javascript experience, I had some research to do.

The first step was to learn how to write data in a Python script into a JSON file. With a lot of help from examples from this Stack Overflow discussion, I ended up with this basic structure for writing a variable to the file, with the ability to send over lists as well (which will become relevant later):


		import json
		import io

		# Define data
		data = 'Hello world!'

		# Write JSON file
		with io.open('C:\\Users\\lleyt\\OneDrive\\Desktop\\Schoolwork\\4.140\\Final Project\\Code\\test_data.json', 'w', encoding='utf8') as outfile:
			str_ = json.dumps(data,
							  indent=4, sort_keys=True,
							  separators=(',', ': '), ensure_ascii=False)
			outfile.write((str_))
		

This code worked perfectly on the first try; I could change the "data" variable to anything I wanted and the JSON file would express the change when I ran the Python file. I owe this quick success to the thorough documentation on that Stack Overflow issue. I then had to decide how I wanted to express the raw data of my sensor output in a way a user could understand. I decided to have a little bit of fun (and also prepare for my final project!) and have the screen flash either red, yellow, or green (corresponding to a "bad", "ok", or "good" handshake, respectively) with response strings based on how hard the sensor is being squeezed. At this point, a "good" handshake is entirely subjective and the cutoffs are loosely based on empirical data, for now this is just a proof of concept.

interface outputs
This robot is a little bit audacious

With the variable s being the analog output of my sensor, the data list should contain everything I need to display sufficient information for the user to understand how hard they are squeezing the sensor. The next step was to integrate this with the serial read code. I did run into an issue with this: the when trying to write the data from the serial port into the JSON file, the code threw an error that read "TypeError: Object of type 'bytes' is not JSON serializable". Fortunately, I was not the first person to run into this issue, and I simply needed to decode the serial bytes data from utf-8 before I cast it as an int.


		import serial
		import time
		import json
		import io

		ser = serial.Serial('COM5', 115200, timeout=0)
		s = 255
		color = "red"
		response = "Are you even shaking my hand right now?"
		count = 0

		while count < 1000:
			if ser.in_waiting:
				try:
					s = int(ser.readline().decode('utf-8'))
				except:
					s = s

			if s < 80:
				color = "red"
				response = "Are you even shaking my hand right now?"
			elif s < 190:
				color = "yellow"
				response = "Could be a little firmer"
			elif s < 215:
				color = "green"
				response = "Nice handshake!"
			elif s < 230:
				color = "yellow"
				response = "Whoa, a little hard there"
			else:
				color = "red"
				response = "Are you trying to break my hand or something?"

			data = [s, color, response]

			with io.open('C:\\Users\\lleyt\\OneDrive\\Desktop\\Schoolwork\\4.140\\Final Project\\Code\\data.json', 'w', encoding='utf8') as outfile:
				str_ = json.dumps(data,
							  indent=4, sort_keys=True,
							  separators=(',', ': '), ensure_ascii=False)
				outfile.write((str_))
			time.sleep(0.1)
			count += 1

I thus had a constantly updating JSON file with the exact data I wanted. Now, I needed to take this data and put it into an updating HTML file. Again, I am completely new to Javascript, but luckily there is a lot of documentation online for using JSON data in Javascript scripts (also, Sam has been a huge help with general Javascript/HTML stuff for this assignment). With the help of online discussions, ChatGPT, and the people around me, I got the below HTML/Javascript code. My understanding of how it works is as follows: the HTML portion of the code sets up the area in which the data is displayed. In the Javascript portion of the code, a script called updateData is set to repeat at 10Hz. Every time the script runs, the data is pulled from the JSON file using the fetch API, then each paragraph element in the HTML is set to one of the three items in the list and the background is changed to the color. The line with "response.json()" is responsible for parsing the JSON data into variables usable by Javascript, and the .catch line is one I saw online that is meant to gracefully handle any errors that occur.

interface test code
I honestly like the way Javascript reads, I'd love to explore it more after this class

The last thing I needed to do was setup a locally hosted webserver. It took two simple lines of code in the command prompt, one to navigate to the directory with my html file (I put it in my final project folder because that's where my final interface code will go):


			cd C:\Users\lleyt\OneDrive\Desktop\Schoolwork\4.140\Final Project\Code
	

Next, I just had to host a Python webserver in that directory:


			python -m http.server
	

Opening a web browser and going to http://localhost:8000/interface_test.html yielded me a page that looked like this:

data display test
It changed in real time but I lacked the foresight to screen record it

Design Files

Microcontroller Code: rp2040_sensor_send.ino
Test Script for Writing to JSON File: json_write_test.py
Python Serial Read & JSON Write Script: serial_write_to_json.py
HTML/Javascript Interface: interface_test.html

Thoughts, Lessons, & Takeaways:

This week was so satisfying, especially because I was diving into multiple things I had never done before. This is also a massive step in the right direction for my final project and will ground my presentation in reality rather than requiring users to read sensor data in a serial plotter. As I alluded to in the overlay text of one of my images, I'd like to learn a lot more Javascript as well. Entering the final stretch, this was a big pick-me-up and I'm ready to move forward with putting my final project together!