My previous Blog - Over the Air (OTA) Programming of ESP8266 - Part II - ended prematurely, because I clicked the "Publish" button by mistake!!
The Blog ended at the point where I had just shown the last segment of code inserted into the sketch to enable a full demonstration of OTA updating from an HTTP Server.
Here is a recap of the sketch functionality:
- Include the necessary libraries
- Define necessary constants, including current Version Number
- Start the Serial Interface
- Connect to the WiFi network (with fixed IP Address)
- Flash the built-in LED at a specified interval for a specified number of times
- Check for firmware updates:
- Construct the URL for the version file
- Read the version file
- Decode the new Version Number
- Check against the current Version Number
- If the Version Numbers are different:
- Construct the URL for the firmware binary file
- Update the device firmware
- Reboot
- Else if the Version Numbers are the same, do nothing
- If the Version Numbers are different:
In order to test the system properly, I have used two PCs - one to power the device and display the device output on the IDE Serial Monitor and the second for Sketch modification and uploading to the HTTP Server.
And here is the output from the demonstration sketch, where there is NO update available:
Making two small changes to the code:
const char* VERSION = "1.0.3"; int counterLimit = 15;
At the top of the IDE we now click on Sketch and then select Export compiled Binary. This places the compiled binary file into the same folder as the sketch .ino file
If the .ino file has a name, say, ESP8266_automatic_OTA_1.ino, then the compiled binary (in this case) has a name of ESP8266_automatic_OTA_1.ino.d1_mini.bin.
The compiled binary file can then be copied to the appropriate location on the HTTP server - in my case the folder is called otaSTORE
The device I am working with is 239ae3, so I now delete the 239ae3.bin file and rename ESP8266_automatic_OTA_1.ino.d1_mini.bin to be 239ae3.bin :
Now we can edit the 239ae3.ver file so that it contains a Version number 1.0.3.
Finally, pressing the reset switch on the ESP8266 (twice in this case, because the WiFi didn't connect first time) we can see the output from the sketch:
As can be seen from the TimeStamp (H:M:S), the OTA update starts at 16:28:28, the device is starting to reboot at 16:28:41 and is up and reporting its IP Address by 16:28:45, which is a total of approx 17 Seconds from start of update to completion of reboot. It's a reasonable sized sketch, but well within the maximum 50% of available program space.
This is copied from the IDE:-
Sketch uses 279840 bytes (26%) of program storage space. Maximum is 1044464 bytes.
Global variables use 30420 bytes (37%) of dynamic memory, leaving 51500 bytes for local variables. Maximum is 81920 bytes.
My final goal is to have the device go into Deep Sleep after checking for updates, thus producing a repetitive process, the repetition rate being approximately determined by the Sleep Time.
The following segment of code which puts the device into Deep Sleep for 15 Seconds, is added to the sketch, immediately after the checkForUpdates() routine:
checkForUpdates(); int sleepTimeSecs = 15; unsigned long int actSleepTime = sleepTimeSecs * 1000000; // Deep Sleep time expressed in useconds Serial.print("Going to Sleep for "); Serial.print(sleepTimeSecs); Serial.println(" Seconds\n"); ESP.deepSleep(actSleepTime); // Go to sleep
The version number is updated to 1.0.4:
const char* VERSION = "1.0.4";
The sketch is compiled, using the Export compiled Binary method, as above, copied to the otaSTORE folder and renamed 239ae3.bin .
A jumper is connected between the RST pin and the D0 pin on the Wemos d1 mini:
And, finally, the 239ae3.ver file in the OTA store is edited to have a version number of 1.0.4.
Pressing the reset button (again, twice!) the following output was captured from the serial monitor
The above output shows a complete automatic OTA update. Unfortunately, it also shows two examples of Sod's, or Murphy's Law: "If something can go wrong, it will". The first example is at the start, when one press of the reset button dis not result in the device connecting to the network; another reset was needed. The device did connect successfully immediately after the OTA update, but failed to connect after a further period of Deep Sleep. This is the second example of Sod's Law. A reset was necessary to get a successful connection to the network.
These failures would seem to negate the benefit of using this methodology. However, my battery powered Greenhouse temperature monitor has been running and recovering totally reliably from deep sleep for months. That firmware has been updated OTA several times, with complete success.
So how does the Greenhouse system differ from the demonstration version, apart from the obvious? I believe the failure to connect is related to the "ownership" of the IP address from the router. I think that the router sometimes refuses to connect the device because it thinks the IP address is still in use. I think perhaps the short sleep time (15 seconds) of the demonstration system, compared with the production system Sleep Time of initially 1 minute and now 2 minutes,, increases the probability of a failure to connect.
I also had another theory, which may or may not be valid: I thought that if the device was explicitly disconnected from the network, it would mean that a subsequent connection would be successful. To that end, the following modification was made (OTA, of course!), immediately after the call to checkForUpdates():
checkForUpdates(); Serial.println("Explicitly disconnecting WiFi"); WiFi.disconnect(true); // Seems to be necessary to ensure reconnection to WiFi after sleeping
And this appeared to do the trick. I won't bore you with another screen capture.
I ran it for about 3 hours and it behaved itself, except for one little hiccup - on two successive occasions it failed to find the .ver file on the server, but recovered OK. I may get it to write an error file, so that I can monitor the situation.
Another observation I made is that it consistently takes 7 iterations of the while loop before it connects:
while (WiFi.status() != WL_CONNECTED) // Wait for connection { delay(500); Serial.print("."); }
Just to see if it made any difference, I increased the Sleep Time to 30 seconds and did an OTA update. It still took 7 iterations to connect..
CONCLUSION
Automatic OTA updating of ESP8266 firmware is fairly straightforward. Although I have observed a few hiccups in running the demonstration sketches here, to show the method, As mentioned earlier, I have been running a battery powered production system for some considerable time now and have happily updated using this method on a number of occasions.
CAVEAT
The method as shown here is operating on a private network controlled by me and has no security incorporated. If this process were to be carried out over the public internet, then systems would be exposed to potential hacking and appropriate security measures should be employed.
See here for information on security for OTA updating: https://arduino-esp8266.readthedocs.io/en/latest/ota_updates/readme.html.
I hope you enjoyed reading this as much as I enjoyed doing the work.
I won't attach a complete demo sketch here, but please ask in a comment if you would like me to.
Top Comments