Part one of a series of posts on API design with neopixels.
Designing an API can be magical - you make a wish, and then it comes true!
Say you have some neopixels. Bright, colorful, and versatile strings of LEDs, but coding them may leave you wanting...
- "I wish there was a single function that could make all the neopixels sparkle with whatever colors I wanted."
- "I wish you could easily sweep a set of pixels across a colorful background."
API - Application Programming Interface
The term API is used broadly to describe the names, parameters, and formatting that define how your code interacts with some "external" code. In this case I want to create a new API that gives my Python code some new high-level functions for controlling neopixels.
API Design
Like the Architect of a building, you define what this new structure is going to look like without worrying too much about the implementation details. Think about what it's going to be like to live with your new API. Imagine that it already exists, and write a line or two of code that uses those magical new functions. Adjust it to your liking - it's easy to make changes to something that hasn't been implemented yet!
Python Modules
As you write Python code, the APIs you're using most often are defined by the modules you import using Python's "import" statement. For example, "import random" gives your code access to an API that provides random numbers and operations. That's "external" code, but where does it come from? What does "import" actually do behind the scenes? Conceptually it's pretty simple: it searches for a module with the name you specified (say, "random") and if it finds one, it makes it available to your code. By default that search is just on the local filesystem, and the importer looks for built-in modules like "random" as well as user-defined modules. In the case of MicroPython the built-in modules are not visible to you as separate files, but they are sitting in Flash memory on your device nevertheless just waiting for their moment in the sun! But what about user-defined modules? Firstly, Python looks for a file matching the import request right in the directory of the script it's currently running. For example, say you create a file called "foo.py" right next to your "main.py" program. Within "main.py" you can now successfully do "import foo". Voila! A user-defined module is born :-)
Can you use CodeSpace to create a file right next to your main program? Yes! Read on and I'll show you how. But first, about that API...
Dreaming of a New Neopixel API
Clear your mind for a moment. Take a deep breath, and exhale slowly. As you exhale, expunge all preconceived notions of how code interacts with neopixels. Now visualize the neopixel strip, in all its grace and elegance. Imagine what you want to see it do. Write a line of Python code that uses an imaginary API to command the neopixel strip. It is the perfect API. All the things you want to do with neopixels are so easy - almost too easy, with so little code to write! Begin to document the API you have now discovered. Adjust it as needed, to remove any accidental awkwardness of usage where perhaps you've misinterpreted your Muse of Inspiration. When you're happy with the API, try running your code. Uh-oh. It doesn't exist yet. It was only a dream... Time to roll up your sleeves and make that dream a reality!
Built-in NeoPixel API
There's already a basic API for controlling neopixels included with MicroPython. To see it in action, check out our blog post here NeoPixels with Python... To summarize, the basic API lets you create a NeoPixel object that acts like a Python list, letting you set colors using the square-brackets indexing syntax. Colors are represented by Python tuples of (red, green, blue) values ranging from 0 - 255. So for example if I have a 30 pixel strip and I want to set the first pixel RED and last pixel GREEN:
from microbit import *
from neopixel import NeoPixel
np = NeoPixel(pin0, 30)
np.clear()
np[0] = (255,0,0) # Note: zero index is first pixel
np[29] = (0,255,0) # Note: last pixel is index (length - 1)
np.show()
There's nothing wrong with the built-in API shown above. You can control the color and brightness of individual pixels. What more could you ask for? Well, a lot actually! What about setting a range of pixels to a certain color? Or doing animations and special effects with multiple pixels? These are "higher level" API functions, and it's quite common in Computer Science to build higher level APIs on top of lower level ones.
Dreaming of a New NeoPixel API... up next!
In the next post my new API will start taking shape!