CircuitPython on ThingPulse Color Kit Grande
12 Nov 2025
I found the ESP32-based ThingPulse Color Kit Grande and thought it would be a good way for my son (who is getting into robotics) and I to learn how to solder and put something like this together. It comes with a cool example project written in C using VSCode and PlatformIO. However, I’ve been teaching my son Python instead as his first programming language (after Scratch) and I don’t want to add C to the mix right now, so I thought to use CircuitPython as it supports ESP32. Unfortunately, there is not a out-of-the-box image for the ThingPulse, so in this post I explain how to get it working.
One note about CircuitPython support for this board: because it uses an ESP32 variant without have native USB support, you can only use the web-based environment over WiFi to work with it. Normally, CircuitPython boards export a CIRCUITPY folder where you can just copy code and libraries to the device. This also means the serial console (via USB) must be used to configure the wifi settings. Another caveat here is I used a board image with very similar hardware and I don’t know if there will be any potential issues with that (although I’ve found none so far).
I’ll first go over the steps I used to get it working then after provide some discussion on how I figured this out.
Hardware Setup and CircuitPython Installation
- Using the kit’s guide, make sure the board is built properly and that you are able to run the test application where you can draw on the screen.
- Download the
.binfile for CircuitPython for the ESP32-DevKitC-VE-WROVER board. I used the latest stable version when writing this post, 10.0.3. - Follow the CircuitPython on ESP32 Quick Start guide on Adafruit. My board was in the included enclosure and the flashing process worked without having to push boot and reset buttons as it describes. Once your device is connected to wifi and you can access the code editor at http://circuitpython.local/code/ (or at its IP address if you have issues with MDNS), you can proceed to getting the display and touch working.
Using the ILI9488 Display
For the next step, we will get the display working.
- Start a new file in the code editor
- Paste the content from ili9488.py then pick “Save
As” and choose
ili9488.pyas file name. -
The device runs
code.pywhen it starts up. Let’s create a program to test the display. Start a new file in the code editor, paste the following content and save ascode.py:import ili9488 ili9488.make_display() - Saving the file should soft reboot the device and you should see the REPL console on the device screen. If you enter the REPL by pushing enter in the web interface or serial connection you should see the device’s screen mirror the serial console except with a top bar showing IP address and CircuitPython version on the display.
- You can also use the test_display.py content to show a red screen.
Using the FT6236 Touch
Fortunately, the kit’s FT6236 touch is supported by the CircuitPython Libraries.
Installing the CircuitPython Libraries
Unfortunately, you cannot use the CircUp tool to upload the libraries because this device does not have native USB
support. Instead, you must upload them manually. On the CircuitPython Libraries
page, download the bundle for your CircuitPython version (10.x at time of writing) and unzip the file to a directory of
your choice. Go to http://circuitpython.local/fs/ and create a folder lib if it does
not already exist. In the lib folder, use the file upload and folder upload buttons (they are titled “Browse…” with a
file or folder icon beside them) to upload the following:
adafruit_focaltouch.mpyadafruit_ticks.mpy- folder
adafruit_bus_device - folder
adafruit_display_shapes - folder
adafruit_display_text - folder
adafruit_register
The resulting folder will look like:

Demo Application
Now let’s make a demo application with some neat scrolling text and a “cursor” where the user clicks. The cursor won’t do anything, but it will demonstrate that we can record touches properly.
- Start a new file in the code editor, paste the content
of touch.py and save as
touch.py - Open
code.pyin the editor and paste in the content of labels_and_cursor.py and save. - You should see a red, green and blue scrolling label and a cursor. When you touch the screen the cursor should move to the location.
- A second demo app is available as halloween.py. Touch the left or right side of the screen to reveal a meme Easter egg.
Extra Note on Display Rotation
The code in ili9488.py configures the screen with a 270 degree rotation (USB port at top; horizontal orientation). You
can change this by updating the A0 in command b"\x36\x01\xA0": 00 normal, 60 90 degrees, C0 180 degrees, or
A0 for 270 degrees. For 0 or 180 degrees, update the BusDisplay line to swap width and height (
width=320, height=480).
If you change the display rotation, you also need to update touch.py’s _TS_ORIENT to match if you want to translate
the touch coordinates to match the rotated screen.
Note for Linux Users
- Users on Linux systems don’t necessarily have permissions to use serial ports out-of-the-box. On my Kubuntu system, I
had to add my user to the
dialoutgroup (sudo adduser $(whoami) dialout) then log back in to access the port detected as/dev/ttyACM0. In my case I could usescreen /dev/ttyACM0 115200to get to the serial console ( CircuitPython’s REPL). This same approach also allows Chromium-based browsers to use web flashing tools. Other distributions will have different ways to grant access to serial ports. - On Linux, if you don’t know the file for the serial port, watch kernel messages while you plug in the device, using
journalctl -k -f, orsudo dmesg -wdepending on your distribution.
Research Discussion
When I wrote this article, I found two GitHub repositories (1 and 2) with ILI9488 code, but they didn’t work for a combination of reasons, and not just because they used and older version of the CircuitPython APIs from version 8 (in version 9 the fourwire and busdisplay modules became separate). The following are the key ingredients that I used to make this work:
- I used the weather station example code file
platformio.inito learn the pins for the display and the SPI frequency. - The weather station example code uses the TFT_eSPI library, so I used the init data it sends to the display as a starting point. I used the datasheet to understand the commands.
- The datasheet highlighted that ILI9488 does not support 16-bit color mode on 4-wire SPI used with the ThingPulse. It only supports 3-bit and 18-bit color mode. In the 18-bit color mode, it actually expects 8 bits per color, or 24 bits / 3 bytes per pixel, with the least significant 2 bits of each color dropped. This is why the BusDisplay is configured as a depth=24. Unfortunately, 3 bytes per pixel means it takes 1.5x longer to refresh the screen versus 2 bytes per pixel.
- Auto refresh caused a lot of display flicker. Manual refresh results in a much better quality and this is how I
configured in
ili9488.py, but it requires a call torefresh()after any graphics have changed.
Reference Repository
All files mentioned are available at the GitHub repository.