Scripting languages are for large computers, right? “Real” embedded device work is a hellish, never-ending cycle of code, compile, and re-flash. Well, I used to think so too, but with the proliferation of scripting and other interactive languages to microcontrollers over the last few years, the hurdle to interactive development on the small chips has gotten a lot lower.
On the ESP8266 platform, I’ve tried out NodeMCU’s Lua and ESP8266 BASIC. (For the last half-year, I’ve been using the awesome Mecrisp-Stellaris almost exclusively on the STM32F1xx and F4xx chips, but haven’t dipped into ESP8266 Forth yet.)
NodeMCU is great because it’s got everything you could want built in, and through cloud services it’s easy to get a tailored build made that maximizes free flash memory for your projects. I just don’t dig the asynchronous Lua thing (you might, try it!). ESP BASIC has a different set of libraries, and is missing MQTT for my purposes. Still it’s pretty slick, and worth a look.
So when the MicroPython folks announced that they were releasing the binary builds for the ESP, I thought it was time to give it a spin. I’ve used Python for nearly twelve years now, so it’s like a comfortable shoe for me. Would MicroPython be the same on the ESP8266? The short answer is yes and no.
The install couldn’t have been easier, thanks to the MicroPython folks releasing binaries a few days ago (a special thanks to the Kickstarter backers on that one!).
Just download the ESP8266 binary image and flash it into the chip. I used the ever-popular esptool.py, which means typing
esptool.py -p /dev/ttyUSB0 write_flash 0x0000000 esp8266-*.bin and you’re set. A few minutes later, I reset the ESP and got a serial port. Connecting to it at 115,200 baud brings up a Python prompt.
>>> print("hello world")
That was easy.
Getting Settled In
If you type Python code into something text-based like iPython or similar, you’ll find yourself at home. The MicroPython folks really got the user-experience part right: tab-completion brings up an object’s methods, up-arrow recalls the last command for editing, and so on. A nice touch is that control-e allows you to paste entire blocks of code from a file at once. In short, it’s a nice workable Python environment entirely hosted off of the ESP8266. Kudos!
With the logistics under control, it was time to find a tutorial. The official tutorial on the MicroPython site is fantastic. If you know Python already, you’ll be up to speed with ESP8266 MicroPython in a half hour.
MicroPython and ESP8266 Extensions
Printing “hello world” over the serial terminal is great, but what about blinking LED’s — the “hello world” of the microcontroller set? There’s a
machine module which you can import, and it has a
p = machine.Pin(2, machine.Pin.OUT)
p.value(not p.value()) # toggles
If you haven’t played around with interactive environments on a microcontroller, there’s something cool about typing a command and getting an instant response. But the productivity increase from being able to test out code on the fly is what will keep you hooked in the long run.
Another standout is the ease of putting the ESP8266 to sleep, which is absolutely essential if you’re trying to run on batteries, for instance.
esp.deepsleep(10*1000000) sleeps for ten seconds — in microseconds. And don’t forget to tie the
WAKE pin, GPIO 16, to the reset pin.
Networking and the Web
But you’re using the ESP8266 because you want WiFi, right? That’s where the
network module comes in. You can go read the docs for more details, but getting set up is as simple as
n = network.WLAN(network.STA_IF)
n.connect('<your ESSID>', '<your password>')
Once the network is up, you can do networky things (more on this in a minute). The tutorial has you watching ASCII Star Wars in no time. I had to use the ctrl-e feature and paste all the commands at once to make it work. Who is going to be the first to display this on an LCD screen for a standalone device?
Although it doesn’t mention this in the docs, the settings seem to be stashed in flash somewhere. The ESP8266 comes up on my WiFi network every time I plug it in. Nice.
My first real disappointment came when digging around in the
os module — with a small-memory ESP8266 like the one I’m using, there isn’t enough space for a filesystem.
OSError: [Errno 19] ENODEV. Consulting the website, you can’t save and load files internally on the ESP8266 unless the module has 1M of flash or more. For the super-cheap ESP8266 devices like the ESP-01
or even the Wemos D1 that I’m using, that’s a show-stopper. Without the ability to save user code on the device, it’s just a toy. Get a newer module with more flash if you want to save your code to the module.
(Edit: The filesystem error that I was getting seems not to be related to the flash memory size. Adding the
--flash_size=32m option to the
esptool command got a working filesystem created on a brand-new Wemos D1 Mini, but failed on a couple of similar units that had previously been used. There’s some glitch in the install here, but it will presumably get worked out. Take my complaints about the filesystem with a grain of salt.)
Next, I looked into what HTML-parsing and web server modules were included. None. To the MicroPython team’s credit, the
socket module is a good copy of the desktop Python version, and you can get a very simple webserver coded up in a few lines, but that’s a few more lines than I wanted to type. Half the reason I use Python these days is for things like BeautifulSoup, lxml, or requests. There is no MQTT client built in either, and all of my ESP8266 devices need to speak MQTT these days.
Not having these tools at hand, and faced with doing all the low-level HTML stuff by hand, I shed a decently sized tear. Is this the end for ESP8266 MicroPython?
Then I found micropython-lib. This is where people are working on MicroPython libraries to bring exactly those functions over to the MicroPython platform in general, if not the particularly constrained ESP8266 port. So it shouldn’t be too hard to do HTML-heavy work using the libraries at hand. MQTT support is being worked on and has just recently been merged into the main micropython-lib repository.
With an ESP that has more flash than mine, you could easily add a few of these modules to your programs, and you’d be nearly in embedded nirvana. And given that all the modules are written in (a limited dialect of) Python, they’re easy to read, maintain, and expand. I have high hopes for where the community will take this.
And there are a lot of cool modules built in: SPI, I2C, OneWire, NeoPixel, Timers, PWM and Servo libraries, for instance. You can do a lot, very easily, with what’s built in.
Conclusion, and Code
Faced with an ESP8266 module with too little flash space to do anything super-fancy, I decided to try one last trick with what I had. The NeoPixel / WS2812B driver support was built-in, and it had socket support, which suggests: networked color blinkies. If you’ve never set up TCP socket connections before, it might surprise you just how simple it can be.
First, some server-side code:
s = socket.socket()
s.bind( ('', 31337) )
c, a = s.accept()
print "Client connected"
c = server_init()
server_init() creates a socket, binds it to any IP address at a given port, listens for one connection, and then sits and waits at the
s.accept() state for a client to connect, at which point it returns a client object that can send or receive arbitrary data to the other side. The data sent uses Python’s standard string encoding of hex bytes, prefixing with
\x. You can alternatively use
chr(16) + chr(42) + chr(15) if you want to type the same number out in decimal.
On the ESP8266, because it’s all in Python, the code is similar. In fact, the same basic code would work between two computers running vanilla Python just as well as the ESP8266 running MicroPython.
s = socket.socket()
s.connect( ('192.168.178.25', 31337) )
n = neopixel.NeoPixel(machine.Pin(2), 1)
n = s.recv(3)
s = connect()
Connecting to a socket connection is simpler than creating a server. All the client has to do is connect. The
remoteRGB() function then listens for three bytes, and sets the LED’s color accordingly. As long as neither side closes the connection, any three bytes coming across the WiFi will get interpreted numerically and fed out to the WS2812. If you’ve got the parts lying around, try it out.
(Some) Batteries Included
In all, MicroPython on the ESP8266 is a mixed bag. It’s awesome to be able to type code in real time and watch the LEDs light up. When you’re doing something more elaborate, like talking to peripherals over SPI, the ease of interactive debugging can get addictive. With a big community behind it, and given how simple it is to develop and port modules in Python, I can see this project getting big fast, and not just on the ESP8266.
But by ESP8266 standards, MicroPython is a memory hog.
Because I used an el-cheapo module, I didn’t even have enough flash to test out the filesystem and make full use of the available libraries. Even with a bigger part, it’s clear that the developers of the ESP8266 MicroPython are pushing the limits of what’s possible, and they are certain to run up against more memory (RAM and flash) constraints in the future.
One of the joys of Python on a big computer is the “batteries included” philosophy of having all the modules you could want at your fingertips (or easily installable) at all times, and this just won’t work on the ESP8266. There’s always going to be a tradeoff between space for user code and space for libraries and modules.
On bigger chips, or course, these tradeoffs would be less painful, but because of WiFi the ESP8266 is impossible to ignore. Personally, if MQTT support were in the mainline binary distribution, I’d switch over from NodeMCU/Lua to MicroPython for ESP8266 development right now. As it stands, I’m going to keep my eyes on the project, and buy some ESP8266’s with more flash.
Filed under: Featured
, wireless hacks