Fork me on GitHub

Apps and libraries

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.

How to create a new app using Web UI

An app sources is a directory with a mos.yml file which describes how to build an app. Click on mos.yml to see a well-documented mos.yml of the empty app, which is used as a app template, or see a detailed description below.

To build an app, use Web UI to either import an existing app from the existing apps collection, or to create a new app from scratch (a new app is really a clone of an empty app. Then click on a build button, and once you see a successful build log message, click on the flash button:

screenshot

How to create a new app using command line

If you like working with terminal, or if you want to integrate app build process into your favorite IDE, you can use mos in console mode:

# Clone an `empty` template app into a new directory `my-app`
git clone https://github.com/mongoose-os-apps/empty my-app
cd my-app
mos build
mos flash
mos console

mos.yml file format reference

mos.yml file drives the way Mongoose apps are biult. 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.

author

A string, FirstName SecondName <Email> of the author, example:

author: Joe Bloggs <joe@bloggs.net>

description

A string, one-line short description, example:

description: Send BME280 temperature sensor readings via MQTT

tags

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

sources

A list of C/C++ source files or directories with those. Do not put trailing slashes to directory names:

sources:
  - src
  - foo/bar.c

filesystem

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

binary_libs

A list of .a libs or directories with those. Do not put trailing slashes to directory names:

binary_libs:
  - mylib/mylib.a

config_schema

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"]

libs

Library dependencies. Each library can have an origin and a name; both are optional but either should be specified. Name is simply a directory name under ~/.mos/libs - that's where mos keeps libraries. Name is also 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). Origin describes where to get and update the library from.

If origin is specified, can be a Github URL, like https://github.com/mongoose-os-libs/aws (note: it must be a repo with mos.yml in the repo root!), or a local path, like /home/bob/projects/mos-libs/mylib. If name is omitted, the last path component from origin will be used.

And if origin is omitted, then the lib must be already present under ~/.mos/libs.

Example:

libs:
    # the aws lib will be fetched to ~/.mos/libs/aws from the given URL
  - origin: https://github.com/mongoose-os-libs/aws

    # the mylib lib will be fetched to ~/.mos/libs/mylib from the given URL
  - origin: https://github.com/bob/mylib-test1
    name: mylib

    # the mylib2 must be located at ~/.mos/libs/mylib2
  - name: mylib2

cdefs

Additional preprocessor flags to pass to the compiler, example:

cdefs:
  FOO: BAR

That gets converted into the -DFOO=BAR compilation option.

Build process deep dive

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
    

Remote build

mos build --arch ARCH

Local build

mos build --arch ARCH --local --verbose

How to create a new library

  • In the Web UI, click on New button in the libary list, choose a name, for example mylib, click OK.
  • Web UI will create a new directory ~/.mos/libs/mylib for you and clone a template library https://github.com/mongoose-os-libs/empty in there.
  • Create src/mgos_mylib.h and src/mgos_mylib.c files:

    mgos_mylib.c:

    #include "mgos_mylib.h"
    
    // NOTE: library init function must be called mgos_LIBNAME_init()
    bool mgos_mylib_init(void) {
      return true;
    }
    

    mgos_mylib.h:

    #include "fw/src/mgos.h"
    bool mgos_mylib_init(void);   // Required - initialisation function
    
  • You can add your library-specific API to mgos_mylib.h and implementation in mgos_mylib.c.

  • Create, build and flash a test app for this library.
  • Click New app button, choose a name, for example myapp click OK
  • Click on the myapp in the app list.
  • Open mos.yml file and add a reference to the mylib:
    libs:
       - name: mylib
    
  • Click on build button to build an app, and flash button to flash it
  • Edit library source files mylib/src, build myapp until a test app works as intented.

How to port an Arduino library

  • Follow the steps outlined in the previous section.
  • Copy Arduino library sources into the mylib/src directory, build / test myapp until it works.

Contributing an app or library

If you would like to share your project with a community and publish it under the Apache 2.0 license, please follow these steps:

Instructions

  • Build your app as described in the previous section, flash and test it.
  • Modify mos.yml, set author field as Your Name <your@email.address>.
  • Make sure you have a descriptive README.md file.
  • If this is a library:
  • Start a new discussion on forum with a subject New contribution: ..., show a link to your code on GitHub / Bitbucket / whatever, or attach a zip file with the app sources.

Why contributing

Once done, we add your app as a separate repo under https://github.com/mongoose-os-apps organisation (or https://github.com/mongoose-os-libs for libraries). You will get an admin rights for the repo. The app will be listed and discoverable in the mos tool UI.

Mongoose OS team will also have an access to the contributed repo. The rationale for that are Mongoose OS API changes. In case of a breaking change, we update affected repos to make sure all apps and libraries continue to build cleanly.