TL;DR - If you do not care about the details, please read the summary below and last three paragraphs at the bottom of this post.
Summary of the nature of the changes proposed (summarized by Paul):
- This is backwards-incompatible change to the behavior of MicroPython regarding WiFi setup, i.e. functionality each user starts with their usage of MicroPython on ESP8266.
- Not only this changes MicroPython behavior, this changes "normal" ESP8266 behavior, how everyone who had some experience with ESP8266 got used to.
- However, in general, this change is good, for example it makes ESP8266 port of MicroPython more compatible with the behavior of other ports.
- It also helps to avoid wearing FlashROM, which may be a problem for some modules, or some usages, but generally not a problem if you use WiFi setup functions as intended (once, for setup, not to call every second).
This pull request points out the fact that the "WLAN.connect(<ssid>, <wlan-secret>)" method on the ESP8266 platform does write a special flash segment of the EEPROM, which does hold the flash for the ESP8266 microcontroller. The intent of that pull request is to change the call to WLAN.connnect(...) in the way to introduce an optional argument to avoid the saving to flash.
The flash segment holding the network configuration of the ESP8266 microcontroller is made of an fixed size of 16KB and positioned "at the end of the flash".
This is written in the "NON-OS SDK API Reference" by Espressif. That document describes the "vendor API" often also called "propriatary binary blob" used by the MicroPython ESP8266 port to implement network and other hardware features.
In the discussion of the pull request Paul did mentioned that this is "the natural way" on the ESP8266 from the beginning. Of course he is correct about this fact and everyone who has used Paul's fantastic work we all rely upon, the "ESP Open SDK" (https://github.com/pfalcon/esp-open-sdk) does know that this as is the default behavior for nearly every ESP8266 out in the wild.
There are of course quite a few thousands of persons out there, who are aware of this. Let's say about everyone who does software development on this microcontroller.
So he has a good point on not to change this well-known behavior. And also being the maintainer of this port he of course has the final decision on this topic.
My additional examination made me aware of the fact that not only the method "WLAN.connect(...)" does write the flash segment, but also every writing call to WLAN.active(<state>).
This is bad. Why you should ask of course! I will tell you why:
I have 5 ESP8266 based sensor nodes in my home monitoring different environmental states (temperature, humidity and since last week air pressure). Of course they are now implemented in MicroPython. Each sensor node does wake up every 5 minutes to send sensor data to my MQTT broker. From there I do the usual stuff (feeding this into home automation stack and an InfluxDB for statistics and so on...).
My problem is that 4 of my sensor nodes are battery based and therefore I do need to reduce power consumption whenever possible. At the end of the day the ESP8266 is quite power hungry and not well suited for real low power usage. That of course is the burden of using WLAN for data transmission.
Back to my problem with writing the flash segment: I do deactivate the wireless interface right at boot to save power and also to reduce the impact of RF signals to my environmental sensors. This is done using the following steps:
- Call "WLAN.active(False)" to bring down the wireless station interface
- Read the sensor(s)
- Bringing up the wireless station interface by calling "WLAN.active(True)"
- Connect top my WLAN by calling "WLAN.connect(...)"
- Send data to the MQTT broker and go into deep sleep for 5 minutes.
If you count the "flash writing" methods mentioned above there are 3 writes to the EEPROM in my program on each run every 5 minutes.
So the flash EEPROM of my sensor nodes will die someday after 4 months, because the EEPROM only has more than 100.000 flash and erase cycles (It is a Winbond W25Q16BV 16mb chip).
Of course one could argue several ways:
- "Let the station interface stay on all the time then!"
- "Use longer deep-sleep durations!"
- "Dude, you have a security issue by keeping your WLAN credentials in plaintext! Oops, everyone has stored them in flash anyways, forget this argument!"
- "Read sensors often but send data once every 20 minutes only!"
- ...
But in the world of the C-API (the initially mentioned vendor SDK) we have a cure for this problem: The vendor does provide methods which are avoiding the write to flash. These methods got introduced during the early 1.0er versions of the ESP vendor API.
So I could implement my sensor node in C (e.g. using the easy Arduino oprt for the ESP) and use them right away.
Hell, no! I did not back all official MicroPython kickstarter campaigns to fall back to C for my code.
So I did file a pull request nearly two weeks ago (https://github.com/micropython/micropython/pull/2564). This does alter the behavior of the WLAN.connect(...) and WLAN.active(...) method by not writing to flash. Additionally adding a method to the "esp" module called "save_config()", doing the obvious left-over steps to write the current network configurations to the flash chip. This must be called manually whenever one wants to store network settings.
No changes to the existing API, but adding a new method doing the previously undocumented things when wanted.
Of course this breaks with the well-known behavior on the ESP platform!
And guess how often my sensor nodes would need to write the flash segment: "Not even once... Never ever!"
Paul did argue me down in my pull request then and I did hold tight. Until yesterday night, when he did encourage me to write this story on the forum. What are your thoughts on this topic? Please discuss my pull request here!