6.0 KiB
External modules. Plugging your own C modules. BETA
Note: this feature is still in beta. Configuration files / API may change.
In order to make the most of NodeMCU, you will undoubtedly have to connect your ESP device to many different hardware modules, which will require you to write driver code in C and expose a Lua interface.
To make this easy, we have come up with the concept of "external modules". External modules allow you to refer to an external git repository containing the module, which will be downloaded/updated and built along the firmware. It is similar to git submodules, but without the complexity and having to alter the parent repository, while also adapted to the compilation requirements of NodeMCU and Lua.
How to use external modules:
To use external modules, simply create an extmods.ini
file in the repository root, with the following syntax:
[lua_mount_point]
url=<git repo URL>
ref=<branch name, tag or commit id>
...
Where:
- lua_mount_point: Name you want the referenced module to have in Lua.
- url: Repository URL where to fetch the code from
- ref: branch, tag or commit hash of the version of the module you want to pull in.
- disabled: (optional) Whether or not to actually compile the module (see below)
For example:
[helloworld]
url=git@github.com:espore-ide/nodemcu-module-helloworld.git
ref=master
You can add further sections to extmods.ini
, one for each module you want to add. Once this file is ready, run the update command:
make extmod-update
This will download or update the modules to the external modules directory, components/modules/external
.
You can now compile the firmware with make
as usual. The build system will find your external modules and compile them along the core modules.
After this is flashed to the device, the module in the example will be available in lua as helloworld
.
Updating to the latest code
If your external module entry in extmods.ini
points to a branch, e.g., master
, you can update your local version to the latest code anytime by simply running make extmod-update
.
Temporarily disabling an external module
If you want to stop compiling and including a module in the build for any reason, without having to remove the entry from extmods.ini
, simply add a disabled=true
entry in the module section and run make extmod-update
.
Example:
[helloworld]
url=https://github.com/espore-ide/nodemcu-module-helloworld.git
ref=master
disabled=true
Mounting different module versions
Provided the module is well written (no global variables, etc), it is even possible to easily mount different versions of the same module simultaneously for testing:
[helloworld]
url=https://github.com/espore-ide/nodemcu-module-helloworld.git
ref=master
[helloworld_dev]
url=https://github.com/espore-ide/nodemcu-module-helloworld.git
ref=dev
Note that the second one points to a different branch, dev
. Both modules will be visible in Lua under helloworld
and helloworld_dev
respectively.
How to write external modules:
To write your own external module do the following:
- Create an empty repository in your favorite remote, GitHub, BitBucket, GitLab, etc, or fork the helloworld example.
- Create an entry in
extmods.ini
as explained above, with theurl=
key pointing to your repository. For modules that you author, it is recommended to use an updateable git URL in SSH format, such asgit@github.com:espore-ide/nodemcu-module-helloworld.git
. - Run
make extmod-update
You can now change to components/modules/external/your_module
and begin work. Since that is your own repository, you can work normally, commit, create branches, etc.
External module scaffolding
External modules must follow a specific structure to declare the module in C. Please refer to the helloworld.c example, or use it as a template. In particular:
- Include
module.h
- Define a Module Function Map with name
module
- Define a
module_init
function - Include the module lua entries by adding a call to the
NODEMCU_MODULE_STD
macro
Here is a bare minimum module:
#include "module.h"
// Module function map
LROT_BEGIN(module)
/* module-level functions go here*/
LROT_END(module, NULL, 0)
// module_init is invoked on device startup
static int module_init(lua_State* L) {
// initialize your module, register metatables, etc
return 0;
}
NODEMCU_MODULE_STD(); // define Lua entries
For a full example module boilerplate, check the helloworld.c file.
Special makefile or compilation requirements
If your module has special makefile requirements, you can create a module.mk
file at the root of your module repository. This will be executed during compilation.
What is this "component.mk" file that appeared in my repo when running make extmod-update
?
This file is ignored by your repository. Do not edit or check it in!. This file contains the necessary information to compile your module along with the others.
Note that you don't even need to add this file to your .gitignore
, since the make extmod-update
operation configures your local copy to ignore it (via .git/info/exclude
).
Further work:
- Support for per-module menuconfig (
Kconfig
). This is actually possible already, but need to work around potential config variable collisions in case two module authors happen to choose the same variable names. - Module registry: Create an official repository of known external modules.
- Move all non-essential and specific hardware-related C modules currently in the NodeMCU repository to external modules, each in their own repository.
- Create the necessary scaffolding to facilitate writing modules that will work both in ESP8266 and ESP32.
- Port this work to the ESP8266 branch. Mostly, the scripts that make this possible could work in both branches directly.