Friday, January 13, 2023

Digital Redneck Engineering: a Trip Timer for the Mazda CX-5

We recently leased a Mazda CX-5. While it surprised us with it's comprehensive feature set (heads up display, baby!), it was missing one important aspect: a simple trip timer. This is nothing more than a stopwatch that starts when the car is turned on. The idea is that you can glance at it to see just how long you've been stuck in traffic, or just how quickly you got home from a daycare run.

Fortunately of all the features offered by a car, this is an easy one to add on. I know this because our Acura RDX had the same issue. Having built my own timer in the past, I had a good idea as to how to do this again.

First off, I visited adafruit.com and did a bit of shopping. I was looking for the components I'd need to create a simple programmable display. It didn't take long before I found the ESP32-S2 TFT Feather. This combined an ESP32 chip with a tiny, but sharp, display. It looked it would be perfect for a timer. I purchased one and patiently waited for it arrive.

When the board arrived I put Circuit Python 8 on it by following these instructions. The installation process went smoothly and I was able access the top level web page offered by the web workflow. Unfortunately, my luck stopped there and I wasn't able to access the Web REPL or file browser. While I wanted to try these features, I realized I didn't actually need them for this project so I gave up on trying to use the Web Workflow.

Starting with a simple Hello World example, I was able to create a code.py file that implemented my timer. Here it is in all its glory:

##
## Shows how long the car has been turned on for
##

import time
import board
import terminalio
from adafruit_display_text import bitmap_label

scale = 5

started = time.monotonic();
text_area = bitmap_label.Label(terminalio.FONT, text="---", scale=scale)
text_area.x = 0
text_area.y = 60
board.DISPLAY.show(text_area)

def digit(value):
    return str(value) if value > 10 else "0" + str(value)

def time_string(started):
    now = time.monotonic()
    t = round(now - started)
    ss = t % 60
    mm = (t // 60) % 60
    hh = (t // (60*60)) % 60
    return digit(hh) + ":" + digit(mm) + ":" + digit(ss)


while True:
    text_area.text = time_string(started)
    time.sleep(1);

Deploying this code to the board is easy: I connected the ESP32 to my laptop via a USB-C cable, mounted it as a drive, and copied code.py into the root directory. Copying the file into places causes the board to reboot and execute code.py. It's all very slick and coder friendly.

The trickiest part of the process was installing the various library dependencies that code.py imported. I did this through trial and error. The board would run code.py, and display an error message as to which library was missing. I'd copy the relevant library from the bundle I'd downloaded, and repeat the process.

Eventually my code ran without issue. I grabbed a cigarette lighter* to USB-A adapter, USB-C cable and some mounting putty and brought it out our car. I then quickly rigged up this demo:

Success!

I'm in awe of the Adafruit ESP32-S2-TFT. For $24, I've now own tiny computer that includes a brilliant color screen, a built in neopixel and WiFi support. Trivially, I'm able to program it over the air using Python, and with effort I could almost certainly turn it into a forth or scheme computer. My timer scratches only the surface of these capabilities. I'm not sure whether I'll build a v2.0 of my timer, or use the board in another project altogether. But I almost certainly need to do something with this device, it's amazing.


*Kids today must be baffled as to why the strange shaped power plug on a vehicle is a called a cigarette lighter. Have no fear, YouTube can explain. I have a vague memory of being a kid figuring out that this oddly shaped knob could pressed in and would eventually get red hot. Perfect for lighting up your cigarette. Crazy, right?

No comments:

Post a Comment