Adventures in LLMs and microPython land¶
Introduction¶
I have been dabbling in AI-supported software for a while, and was inspired to extend this to my other area of dabbling - ESP32 micro projects. The inspiration came from the Coding from the Beach recent workshops, which focused on programming external hardware. These workshops used the Arduino C-oriented approach, but being a Python tragic, I chose micropython as my target.
Cursor¶
Rationale (why Cursor)¶
I am using Cursor as my LLM provider. I have free subscriptions to most of the usual providers (Perplexity, ChatGPT, Codex, etc), but decided to get a paid subscription to Cursor. The main reason was the familarity of a VS Code interface, and the fact there was a reasonable amount of documentation available at my level of skill (very low).
Initial Reactions¶
My first toe in the water was requesting a minor enhancement to a Dashboard-style web-base app for which I am currently the custodian (I do volunteer software work for a local environmental non-profit). It uses the Dash framework, and the UI includes maps to display georeferenced data. I wanted an extra dropdown to be an alternative to clicking an object on the map. I was pleasently suprised at how good the result was.
My next attempt was to ask Cursor to generate the test suite for the app, and again (after some nudging) it did a pretty good job of building unit level test suite.
Cursor was even able to generate a viable simple demonstraion in R+shiney for displaying eco-data.
MicroPython: a little harder¶
The bar was raised a little, when I moved on to microPython, because I wanted to have the generated code to be automatically downloaded to the ESP32, and run there. I elected to assume the ESP32 had been equiped with microPython as a seperate process.
Part of the problem is that it is quite hard in Windows 11 to determine the current owner of a serial port (e.g. COM 7). A lot of the churning in my initial attempts was Cursor churning the trying to get access to the serial port connected (via USB) to the ESP32, because previous commands run by Cursor had left the Port in use.
Enter Skills¶
Skills are a way for the user to specify a detailed process to achieve some goal. I wound up defining three Skills:
- conda_run_from_environment
- copy_file
- esp32_python
I show these below in case they may be of use (suggestions for improvement welcome)
conda_run_from_environment¶
---
name: conda_run_from_environment
description: Use when running an application from a conda environment
---
# conda run from environment
## workflow
1. confirm that conda.exe is available at C:\Users\donrc\anaconda3\Scripts\conda.exe
2. confirm the environment is in the list of conda environments
3. confirm the application is present in the list returned by the `conda list` command line command
2. run `C:\Users\donrc\anaconda3\Scripts\conda.exe -n "environment_name" application_name`
## errors
Inform the user if conda.exe is not available
Inform the user if the application is not available in the conda environment
copy_file¶
---
name: copy_file
description: Use when copying a file to an ESP32
---
# copy file
## workflow
1. confirm that mpremote is available in a conda environment
2. obtain the esp32 com port number by running `wmic path Win32_SerialPort get Caption, DeviceID`
3. connect to the com port, reset the esp32, run a micropython file by a command, and disconnect by a windows command `mpremote connect PORT_NAME cp "file_name" :"file_name" `
## errors
Inform the user if mpremote is not available
Inform the user if no esp32 COM port can be found
Inform the user when the `mpremote` command returns
esp32_python¶
---
name: esp32_python
description: Use when running a micropython program on an esp32
---
# conda esp32_python
## workflow
1. confirm that mpremote is available in a conda environment
2. obtain the esp32 com port number by running `wmic path Win32_SerialPort get Caption, DeviceID`
3. connect to the com port, reset the esp32, run a micropython file by a command, and disconnect by a windows command `mpremote connect PORT_NAME soft-reset run --no-follow "python_file_name" disconnect`
## errors
Inform the user if mpremote is not available
Inform the user if no esp32 COM port can be found
Inform the user when the `mpremote` command returns
Initial success¶
So the very first program I tried to create and download was the Hello World of microPython: blinking the on-board LED. And it worked!
This not a great effort saving event, because to be honest, the effort involved in use Thonny to load and run a python file is minimal. However, with more complex systems with multiple packages to download, the ability to run aumated checks might be very useful
Second success¶
In the next example, I was driving MAX7219 8x8 LED matrix displays (to display decimal digits), daisy chained to minimize GPIO Port usage. Because of connection issues that precented abutting the 8x8 matrices, I had Cursor modify the MAX7219 library to (optionally) rotate programmatically each 8x8 display by either 90 or 270 degrees. And Cursor did the job - there was a minor glitch where rotaed digits were mirror flipped, but Cursor fixed this up in one iteration.
Subsequent failure¶
Sadly when I tried to extend this approach to a slightly more complex problems (driving a MAX7219 7 segment 8 digit display), the wheels fell off! It turns out that Cursor (unaided) has a very shakey grasp of what is allowed in microPython, calling for imports that microPython doesn't support.
This is my fault: I have no Rules defined at all: I should have Rules that point to the microPython documentation. I probably should also have micropython-esp32-stubs, in my conda environment, so that Cursor can do the lint and type checking of the code it creates
Conclusions¶
Use of Cursor is clearly worth pursuing. I will be attempting more informed automation in my ESP32 future.