Custom Firmware
Our flashing tool lowsync (see Getting Started) can be used to build custom firmware images, which include:
- A pinned version of low.js Basic or low.js Professional
- If low.js Professional is used: Optionally disabled IDE and Over-The-Air updating support for less Flash usage
- npm packages
- Custom settings (for example Wifi SSID and password)
- Static read-only user files, optimized for speed
- User files to prepopulate the file system with
These firmware images can be bulk flashed on to devices with lowsync, or be used by a device to update itself. For updating, the firmware can be uploaded to the device in any way, for example via HTTPS.
Example project
You can find a fully featured example project on GitHub.
This example project shows how to
- Create a low.js project which is compiled into a custom firmware image. This firmware image can then be bulked flashed onto ESP32-WROVER devices or used to update the device over the website served by the low.js program (Over-The-Air updating)
- Program a password protected single-page website application in Vue, to be served from the microcontroller. On this website, you can change settings (Wifi SSID & password, website password) and, as written above, upload a newer version of the firmware image to update the device through the website.
Create a firmware image
To create a firmware image, call:
lowsync build --firmware-config=path-to-configuration-file path-to-output-image
The configuration file must be a file in JSON format, with the following content (values are examples):
{ "lowjs": { "version": "20200105", <- "latest" or date in format YYMMDDDD for pinned version "pro": true, <- true for low.js Professional, false for low.js basic "system_flash_size": 8388608 <- how much Flash space to use for firmware, rest is used for file system "ide_support": false, <- include the IDE? "ota_update_support": true <- include Over-The-Air updating support? }, "static_files": "file_system/", <- null for no static files or path to directory which included static files "factory_files": null, <- null for no factory files or path to directory which included files to prepopulate the file system on factory reset "modules": { <- npm modules, specified as in any package.json file "ws": "^7.2.1" }, "settings": { <- low.js settings to overwrite, see documentation for options "code": { "main": "/server/index.js", "auto_restart_on_fatal": true, "console_kb": 0, "only_static_files": true }, "wifi": { "ssid": "Custom Firmware Example", "password": "customfirmware" }, "web": { "http_enabled": false, "https_enabled": false } } } }
After a build, lowsync outputs the flash usage by the image:
****** Used flash space: ****** low.js code 2097152 bytes low.js data 791876 bytes Static files 993970 bytes Factory files 0 bytes Modules 53810 bytes Settings 1155 bytes OTA support 3937963 bytes Reserved 512682 bytes ------------------------------- Total 8388608 bytes
Static files vs factory files
Static files are interleaved with the editable file system for fs.open*() and fs.stat*() calls, however cannot be changed or deleted. If a file is created in the file system, this is used instead of the static file. Static files are not listed when calling fs.readdir*().
The setting code.main.only_static_files (only used for custom firmware and not documentated on the low.js Settings documentation page) makes low.js only look for code files (everything accessed via require()) in the static files. Static files can be accessed far faster than file system files, so this makes program loading faster. Also, by putting the user code into the static files, with a firmware update the user program gets updated too.
The factory files are placed into the newly formatted file system on every factory reset of the device. Thus, every factory file will need double the Flash space: for the firmware image and for the file system. When updating the firmware, the files in file system are not touched.
Flash firmware image
Flashing is done via:
lowsync flash --port=portname --firmware-file=page-to-firmware-image
portname is the name of the port under which lowsync can connect to the ESP32-WROVER board. Under Windows the port usually begins with COM, under other platforms it is a file beginning with /dev/tty. If you cannot find the port, chances are you need to install a device driver for the USB to UART adapter chip.
This call needs Internet access to sign the low.js code. This feature ensures that the firmware cannot be copied from one microcontroller to the other - the flashed firmware only works on the device it is flashed on with lowsync. None of the static or factory files (together the user files) are transferred to the neonious servers, however.
Over-The-Air updating
The firmware can be transferred to the device in any way.
All the user program has to do is pipe it to a stream created with lowsys.createFirmwareStream() to update the device, and then call lowsys.restart(true) to trigger a microcontroller restart. lowsys.createFirmwareStream() can throw Errors, also make sure to handle 'error' events on the stream (see example project highlighted above).
In this case low.js signs the new firmware itself automatically.
Do not save the file on the file system and then write it at once to the firmware stream, as typically the resources for this (Flash, RAM) are not available.