A Mongoose OS app is a firmware that does something specific. It could be built and flashed on a microcontroller. For example, a blynk app is a firmware that makes a device controllable by the Blynk mobile app.
Another example is a default app
that gets flashed when you press a "Flash" button on a Web UI "device control"
dialog, or type mos flash <arch>
on a terminal. That default app
blinks an LED periodically, can talk to an MQTT server, and allows user
to extend the logic by editing JavaScript code directly on a device filesystem.
An app can use any number of libs. A lib is a reusable library. It
cannot be built directly into a working firmware, because it only provides
an API but does not actually use that API. An app can include a lib by
listing it in the libs:
section of the
mos.yml file.
mos build
command generates code that calls library initialisation
functions. Libraries are initialised in the order of their reference.
By default, a mos build
command that builds an app's firmware, is using so-called
remote build - it packs apps's sources and sends them over to the Mongoose OS
build machine. This is the default behavior, cause it does not require a Docker
installation on the workstation.
However, if a Docker is installed, then it is possible to build locally.
This is done by adding an extra --local
flag (see below). In this case,
everything is done on the local machine. This is a preferrable option for the
automated builds, and for those who do not want their sources leaving their
workstations. Summary:
Build type | Build command |
---|---|
Remote (default) | mos build --platform PLATFORM |
Local (requires Docker) | mos build --platform PLATFORM --local --verbose |
mos.yml
file drives the way Mongoose apps are built. Below is a description
of the sections (keys) in this file. Libraries also have mos.yml
files, the
only difference with apps is that they have type: lib
key and they cannot
be built into a firmware. So the following applies to both apps and libraries.
A string, FirstName SecondName <Email>
of the author, example:
author: Joe Bloggs <joe@bloggs.net>
List of Makefile variables that are passed to the architecture-specific
Makefile when an app is getting built. See next section for a build process
deep-dive. An example of arch-specific Makefile is:
platforms/esp32/Makefile.build.
The others are in the respective directories: fw/platforms/*/Makefile.build
.
The example below changes ESP32 SDK configuration by disabling brownout detection:
build_vars:
ESP_IDF_SDKCONFIG_OPTS: "${build_vars.ESP_IDF_SDKCONFIG_OPTS} CONFIG_BROWNOUT_DET="
Another example is the dns-sd library that enables DNS-SD:
build_vars:
MGOS_ENABLE_MDNS: 1
A list of .a
libs or directories with those. Do not put trailing slashes to
directory names:
binary_libs:
- mylib/mylib.a
Additional preprocessor flags to pass to the compiler, example:
cdefs:
FOO: BAR
That gets converted into the -DFOO=BAR
compilation option, for both C and C++
sources.
Modify compilation flags for C (cflags
) and C++ (cxxflags
). For example, by
default warnings are treated as errors. This setting ignores warnings when
compiling C code:
cflags:
- "-Wno-error"
If what you're after is defining preprocessor variables, cdefs
makes it
easier. This snippet:
cdefs:
FOO: BAR
Is the same as:
cflags:
- "-DFOO=BAR"
cxxflags:
- "-DFOO=BAR"
This can define a new configuration section for the device, and also override
a previosly defined configuration entries defined elsewhere. For example, the
following snippet defines a new section foo
and overrides a default
value of mqtt.server
set by the mqtt
library:
config_schema:
- ["foo", "o", {title: "my app settings"}]
- ["foo.enable", "b", true, {title: "Enable foo"}]
- ["mqtt.server", "1.2.3.4:1883"]
A string, one-line short description, example:
description: Send BME280 temperature sensor readings via MQTT
A list of files or directories with files to be copied to the device's filesystem, example:
filesystem:
- fs
- other_dir_with_files
- foo/somepage.html
A list of directories with C/C++ include files. Do not put trailing slash to the directory name. Example:
includes:
- my_stuff/include
Library dependencies. Each library should have an origin
and optionally can
have name
and version
. origin
is a GitHub URL, like
https://github.com/mongoose-os-libs/aws
(note: it must be a repo with
mos.yml
in the repo root!).
Name is used to generate the code which calls
library initialization function: e.g. if the lib name is mylib
, it should have
the function bool mgos_mylib_init(void)
. Also, for local builds, name is used
as a directory name under deps
: that's where mos
clones libraries.
version
is a git tag name, or branch name, or SHA of the library's
repository. If omitted, it defaults to the libs_version
in mos.yml
, which,
in turn, defaults to the mos tool version. So e.g. if the mos tool version is
1.21, then by default it will try to use libs with the tag 1.21
. Latest mos
will use the master
branch.
Example:
libs:
# Use aws lib on the default version
- origin: https://github.com/mongoose-os-libs/aws
# Use aws lib on the version 1.20
- origin: https://github.com/mongoose-os-libs/aws
version: 1.20
# Use the lib "mylib" located at https://github.com/bob/mylib-test1
- origin: https://github.com/bob/mylib-test1
name: mylib
Override app or lib name. By default, the name is set equal to the directory name.
name: my_cool_app
A list of C/C++ source files or directories with those. Do not put trailing slashes to directory names:
sources:
- src
- foo/bar.c
A list of free-form string tags, used for Web UI search.
Some tags are predefined, they place the app or library in a certain category.
Those predefined tags are: cloud
(cloud integrations),
hardware
(hardware peripherals or API),
remote_management
(remote management), core
(core functionality). Example:
tags:
- cloud
- JavaScript
- AWS
When mos build [FLAGS]
command is executed in the app directory,
the following happens:
mos
scans libs:
section of the mos.yml
file and imports all
libraries into the libs directory (~/.mos/libs
, could be overridden
by --libs-dir ANOTHER_DIR
flag)
Each library also has mos.yml
file, and a library could have a libs:
section as well - this way the library can depend on other library. mos
imports all dependent libraries too, recursively.
When all required libraries are imported, mos
executes git pull
in each
of them, in order to update. That could be switched off by --no-libs-update
flag.
At this point, all required libraries are imported and updated.
mos
combines app's mos.yml
file together with the mos.yml
files of
all dependent libraries, merging them into one file. The order of merging
is this: if my-app
depends on library lib1
, and library lib1
depends
on library lib2
, then
result_yml = lib2/mos.yml + lib1/mos.yml + my-app/mos.yml
. Meaning, the
application's mos.yml
has the highest priority.
If --local --verbose --repo PATH/TO/MONGOOSE_OS_REPO
flag is specified,
then mos
starts a local build by invoking docker.cesanta.com/ARCH-build
docker image. That image encapsulates a native SDK for the given architecture
together with Mongoose OS sources, https://github.com/cesanta/mongoose-os.
mos
tool invokes make -f fw/platforms/ARCH/Makefile.build
for the given
platform. The result of this docker invocation is a build/
directory with
build artifacts and build/fw.zip
firmware zip file which could be flashed
to the device with mos flash
command.
If --local
flag is not specified, packs source and filesystem
files and sends them to the Mongoose OS cloud build backend at
http://mongoose.cloud, which performs an actual build as described in the
previous step, and sends back a build/
directory with built build/fw.zip
and artifacts.
Generated artifacts in the build/
directory is as follows:
build/fw.zip - a built firmware
build/fs - a filesystem directory that is put in the firmware
build/gen - a generated header and source files
The best way to develop a new library is as part of an app development.
In your app, do a local build, which creates a deps/
directory. That is
the directory where you should place your new library.
Clone an empty
library, which is a skeleton for the new library,
into the deps/mylib
directory (change mylib
to whatever name you want):
git clone https://github.com/mongoose-os-libs/empty deps/mylib
Create include/mgos_mylib.h
and src/mgos_mylib.c
files in your library:
#include "mgos_mylib.h"
// NOTE: library init function must be called mgos_LIBNAME_init()
bool mgos_mylib_init(void) {
return true;
}
#include "mgos.h"
mgos_mylib.h
and implementation
in mgos_mylib.c
.mos.yml
file, add a reference to the new library:libs:
- name: mylib
mylib/src
, build myapp
until a test app
works as intented.mylib/src
directory,
and .h files into the include/
directorymjs/api_mylib.js
file
with the FFI JS wrappers.myapp
until it works.If you would like to share your project with a community and publish it under the Apache 2.0 license, please follow these steps:
mos.yml
, set author
field as Your Name <your@email.address>
.README.md
file.mjs_fs/api_<name>.js
file if your library has JavaScript API.arduino-compat
library in mos.yml
file, see arduino-adafruit-ssd1306 lib for an exampleNew contribution: ...
,
show a link to your code on GitHub / Bitbucket / whatever, or
attach a zip file with the app sources.