In this guide we will learn how to implement device logic in C/C++. In particular, our firmware will:
mos
toolRun mos
tool without arguments to start the Web UI. After start,
the Web UI changes current working directory to the directory where
it finishes the last time. In other words, it "remembers" its settings:
the working directory, chosen port, board, etc.
In this example, it is an app1
directory, a quickstart example I have done recently:
Since we are going to create our new app in a different directory,
use the cd DIRECTORY
command to change the current directory.
I am going to do cd ..
to go up one level. Notice the current directory change:
Now we are going to use a mos clone URL DIRECTORY
command, in order to clone
some remote app into a DIRECTORY. Press Ctrl-n
- that populates the input field
with mos clone https://github.com/mongoose-os-apps/demo-js app1
. We don't
want to use demo-js
as a template, so change it to empty
to use a minimal
app, and change app1
to app2
:
Now press Enter to execute the command. Notice that the mos tool automatically changes enters into the cloned directory:
Click on the folder icon on the bottom left corner to open a system file browser in the current directory:
Here is the meaning of all files:
fs/ -- All files we put here, will end up on device's filesystem
└─ index.html -- Device's HTTP server, if enabled, will serve this file
LICENSE
mos.yml -- Describes how to build an app
README.md -- Document your app in this file
src/
└─ main.c -- Contains device logic. We are going to edit this file
Open mos.yml
file in your favorite editor and add support for DHT sensor:
libs:
- origin: https://github.com/mongoose-os-libs/rpc-service-config
- origin: https://github.com/mongoose-os-libs/rpc-service-fs
- origin: https://github.com/mongoose-os-libs/rpc-uart
- origin: https://github.com/mongoose-os-libs/wifi
- origin: https://github.com/mongoose-os-libs/dht # <-- Add this line!
Note - all available libraries are collected under the https://github.com/mongoose-os-libs organisation. They are categorised
and documented under the "API Reference" docs section.
Now, open src/main.c
, you'll see the following
skeleton code which initialises an app that does nothing:
#include "mgos.h"
enum mgos_app_init_result mgos_app_init(void) {
return MGOS_APP_INIT_SUCCESS;
}
Let's add a code that reads from a DHT temperature sensor every second.
The pin to which a sensor is attached, we make configurable by editing
a config_schema:
section in the mos.yml
, to have it like this:
config_schema:
- ["app.pin", "i", 5, {title: "GPIO pin a sensor is attached to"}]
This custom configuration section will allow us to change sensor pin
at run time, without recompiling firmware. That could be done programmatically
or via the mos
tool, e.g. mos config-set app.pin=42
.
NOTE: see mos.yml file format reference
for the full documentation about the mos.yml
.
Then, edit src/main.c
, add a timer (see timer api docs) that reads DHT and logs the value
(error handling is intentionally omitted):
#include "mgos.h"
#include "mgos_dht.h"
static void timer_cb(void *dht) {
LOG(LL_INFO, ("Temperature: %lf", mgos_dht_get_temp(dht)));
}
enum mgos_app_init_result mgos_app_init(void) {
struct mgos_dht *dht = mgos_dht_create(mgos_sys_config_get_app_pin(), DHT22);
mgos_set_timer(1000, true, timer_cb, dht);
return MGOS_APP_INIT_SUCCESS;
}
The mgos_dht.h
file comes from the dht
library that we have included to our app.
In order to find out its documentation and API, navigate to
"API Reference" -> "Drivers" -> "DHT temp sensor". This should bring you to
this page - DHT temp sensor. Similarly, you can find
out about any other library.
Connect DHT sensor to pin 5. The sensor itself has following pins:
This is an example with ESP8266 NodeMCU. Red connector is VCC 3.3 volts, black connector is ground GND, and yellow is data, connected to pin 5:
Build, flash the firmware, and attach the console to see device logs. Assume we're working with ESP8266:
Choose your board and port in the the UI, and run mos build
command:
When finished, run mos flash
to flash the firmware and see the output in the console:
Now let's use the cornerstone of Mongoose OS remote management capabilities.
We can make any hardware function be remotely accessible. This is done
by creating an RPC service. Read more about it in the Overview and Core
libraries sections, and here we jump straight to it. Looking at
MG-RPC API doc, add RPC service Temp.Read
:
#include "mgos.h"
#include "mgos_dht.h"
#include "mgos_rpc.h"
static void timer_cb(void *dht) {
LOG(LL_INFO, ("Temperature: %lf", mgos_dht_get_temp(dht)));
}
static void rpc_cb(struct mg_rpc_request_info *ri, void *cb_arg,
struct mg_rpc_frame_info *fi, struct mg_str args) {
mg_rpc_send_responsef(ri, "{value: %lf}", mgos_dht_get_temp(cb_arg));
(void) fi;
(void) args;
}
enum mgos_app_init_result mgos_app_init(void) {
struct mgos_dht *dht = mgos_dht_create(mgos_sys_config_get_app_pin(), DHT22);
mgos_set_timer(1000, true, timer_cb, dht);
mg_rpc_add_handler(mgos_rpc_get_global(), "Temp.Read", "", rpc_cb, dht);
return MGOS_APP_INIT_SUCCESS;
}
Run mos build
followed by mos flash
.
And now, call the device's RPC service by running mos call Temp.Read
.
You will see {"value": 18.6}
printed.
This call could be performed over the serial connection as well as over network connection - see RPC section to learn more.
edit this doc