In previous post I wrote about programming ESP module with BASIC language and it was pretty cool, but only for simple code. The main problem with BASIC for ESP was small amount of libraries to handle peripherals. I planned to plug a popular monochrome LCD display - PCD8544 - which is used in old, good known Nokia 3310/5110. I tried things like flashing ready software with PCD8544 support, but that didn't work properly. I couldn't event get a SPI connection to work. Finally I found something that can use JavaScript as controller language. Meet...
Mongoose OS
It's operating system (as manufacturer says) that can be used on ESP modules. It provides us features like:
- Dashboard with devices - modules can be easy managed and updated just by selecting them from list
- OTA updates - also with rollback on failure
- RPC - procedures can be called remotely
- Encrypted software - increases security and make reverse engineering harder
- IoT integration - can be easily integrated with Google IoT, AWS IoT, MS Azure etc.
- JavaScript support - Embedded JavaScript engine - better for prototyping
- C/C++ support - better for production
- Free (GPLv2 license)
You can find usage and flashing instructions there: https://mongoose-os.com/docs/quickstart/setup.html
mJS
We are ready to write first code just after flashing software. Mongoose OS uses init.js
in fs
directory on startup. There are few ways to put init.js
on a controller.
- Prepare binary and flash it from console or GUI
- Override file in
mos
GUI - Put file from console with
mos
executable
In my opinion the quickest and the easiest way to develop software is to use the mos
executable, because for fast prototyping it is possible to write simple script watching *.js
files and put them on device using command above.
For example (I used nodemon
because I had it installed on my machine)
# Put file with
# mos put init.js --port ws://IP_ADDR/rpc
# And restart device
# mos --port ws://IP_ADDR/rpc call Sys.Reboot '{\"delay_ms\":0}'
nodemon --exec "mos put init.js --port ws://IP_ADDR/rpc && mos --port ws://IP_ADDR/rpc call Sys.Reboot '{\"delay_ms\":0}'" init.js
Now we can put follwing code to blink our led every one second.
load('api_config.js');
load('api_gpio.js');
load('api_timer.js');
let led = Cfg.get('pins.led');
GPIO.set_mode(led, GPIO.MODE_OUTPUT);
// Call every second
Timer.set(1000, true, function() {
let value = GPIO.toggle(led);
print(value ? 'Tick' : 'Tock');
}, null);
We have to load
libraries - each one maps C
function to JS
function.
api_*
files are automatically flashed with firmware, so there is no need to put it manually.
You can look here https://mongoose-os.com/docs/reference/api.html for complete API list.
For example look into api_timer.js
file.
load('api_math.js');
let Timer = {
_f: ffi('int mgos_strftime(char *, int, char *, int)'),
// ## **`Timer.set(milliseconds, repeat, handler)`**
// Setup timer with `milliseconds` timeout and `handler` as a callback.
// If `repeat` is set to true, the call will be repeated indefinitely,
// otherwise it's a one-off.
//
// Return value: numeric timer ID.
set: ffi('int mgos_set_timer(int,bool,void(*)(userdata),userdata)'),
// ## **`Timer.now()`**
// Return current time as double value, UNIX epoch (seconds since 1970).
now: ffi('double mg_time(void)'),
// ## **`Timer.del(id)`**
// Cancel previously installed timer.
del: ffi('void mgos_clear_timer(int)'),
// ## **`Timer.fmt(fmt, time)`**
// Formats the time 'time' according to the strftime-like format
// specification 'fmt'
fmt: function(fmt, time) {
if (!fmt) return 'invalid format';
let res = 0, t = Math.round(time || Timer.now()), s = ' ';
while (res === 0) {
res = this._f(s, s.length, fmt, t);
if (res === -1) return 'invalid time';
if (res === 0) s += ' ';
}
return s.slice(0, res);
},
};
You can see the ffi
function which maps C API to JavaScript code and makes it easier to map not existing JS functions to C functions.
Advantage of Mongoose OS may be that you can also add own C++ code to software and map them to mJS.
So it looks interesting for my purposes - I will try to make PCD8544 and ESP module work together in next post.