Using the ESP Component Registry with the Moddable SDK

The ESP Component Registry is a central repository of components designed for the ESP‑IDF. Hosted by Espressif, creator of the ESP32, the Registry contains a wealth of ready-to-go software components for the ESP32 family of microcontrollers. You can easily embed components from the Registry in your Embedded JavaScript projects by adding it to your project's Moddable SDK manifest. This accelerates the process of integrating new software capabilities for Embedded JavaScript developers on ESP32.

This article walks you through adding a component from the Registry to your project and explains how to wrap a JavaScript API around the component.

Using components

The Moddable SDK port for ESP32 is implemented using components built into the ESP‑IDF. For example, support for SPI, I²S, and timers are necessary to draw graphics to the display, play audio, and animate sprites. Additional components from Espressif and community supplied components are available to the ESP‑IDF through the ESP Component Registry.

JavaScript APIs in the Moddable SDK are provided by standard JavaScript modules. JavaScript modules in the Moddable SDK are implemented using JavaScript or C. Implementing in C allows us to integrate existing native code into the Moddable runtime. However, in the past it has been complex to add existing native code to Moddable SDK builds on ESP32, oftentimes requiring the modification of makefiles and build scripts. This has been an impediment to integrating some capabilities.

Manifests use the dependency property to include components from the ESP Component Registry. This automatically integrates the component into your project by doing the following:

  1. Downloads the component from the Registry
  2. Adds the component to your project's build
  3. Makes the component's native header files available to your native code

Note: The dependency property was introduced in Moddable SDK 5.0.

Finding components

The ESP Component Registry web site is a great way to discover components to use in your projects. Use the tools on the front page of the Registry to find a component and select the component to the information you'll need to add it to your project.

1. Search field

2. Tabs to restrict the search by Board Support Package, ESP‑IDF version, or target

 

3. The title of the component contains the namespace, name and version. In this case, the namespace is espressif, the name is onewire_bus and the version is 1.0.2. You will use these values in the dependency property described below.

4. Links to the component's home page and repository

 


1‑Wire example

Let's look at a specific component, 1‑Wire support, to understand how the pieces fit together. This component is used in the Moddable SDK, so it is a complete, fully functional starting point for your own explorations.

Integrating the component

The ESP Component Registry has a driver for the Dallas 1‑Wire Bus. The functionality of this driver is what I needed to support the DS18x20 thermometer that uses that bus.

The manifest for the onewire module contains a section for the ESP32 platform that contains the dependency property:

"platforms": {
    "esp32": {
        "dependency": [
            { "name": "onewire_bus", "version": "^1.0.2" }
        ].
        "modules": {
            "*": "$(MODULES)/drivers/onewire/esp32/*"
        }
    }
    // other platforms can go here
}

The esp32 section of platforms is used only when building the project for ESP32 targets. The dependency on onewire_bus is what imports the component from the Registry, downloading it to your build/tmp directory and adding it to the build. The modules section includes the files in the $(MODULES)/drivers/onewire/esp32/ directory that implement the JavaScript module that provides JavaScript API to use the onewire_bus component from the Registry.

dependency property

The dependency property only applies to the esp32 platform at this time, and should always be placed in the esp32 section of the manifest. The components listed in the dependency array are included in your project's build as described above.

Each entry in the dependency array has four properties, two of which are required.

  • namespace – Namespace of the component. (optional - defaults to espressif)
  • name – Component's name. Here, it is onewire_bus. (required)
  • version - Version of the component. Here it specifies version 1.0.2 or greater. (required)
  • includes – Array of subdirectories within the component to map as include paths for your native code. (optional – defaults to empty array)

    "dependency": [{
        "name": "esp32-camera",
        "version": "^2.0.10",
        "includes": [
            "conversions/include",
            "driver/include"
        ]
    }]

Writing the JavaScript module

The Moddable SDK on ESP32 has long supported 1‑Wire, but this was broken by ESP‑IDF v5 which deprecated the RMT driver that was used for that. We reimplemented the 1‑Wire support for ESP32 using the one_wire component from the Registry.

An important goal of the reimplementation is to retain compatibility with applications that were written to use the original 1‑Wire driver. The JavaScript API for the onewire module wraps underlying C functions that we will implement using the one_wire component.

class OneWire @ "xs_onewire_destructor" {
  constructor(dictionary) @ "xs_onewire";
  close() @ "xs_onewire_close";
  read(count) @ "xs_onewire_read";
  write(data) @ "xs_onewire_write";
  // ...
}

The ESP32 implementation, written in C, can now include the header files from the ESP Component Registry module:

#include "onewire_bus.h"
#include "onewire_cmd.h"
#include "onewire_crc.h"
#include "onewire_device.h"

It can make calls to the component APIs. Here is the 1‑Wire search, which returns a JavaScript array. The APIs that begin with xs are the XS in C API used to bridge between JavaScript and C code.

void xs_onewire_search(xsMachine *the)
{
    modOneWire onewire = xsmcGetHostData(xsThis);

    onewire_device_iter_handle_t iter = {};
    onewire_device_t device = {};
    esp_err_t err;

    xsmcVars(1);
    xsResult = xsNewArray(0);

    err = onewire_new_device_iter(onewire->bus, &iter);

    while (ESP_OK == err) {
        err = onewire_device_iter_get_next(iter, &device);
        if (ESP_OK == err) {
            swap(&device.address, 8);
            xsmcSetArrayBuffer(xsVar(0), &device.address, 8);
            xsCall1(xsResult, xsID_push, xsVar(0));
        }
    }

    onewire_del_device_iter(iter);
}

The full source code of the 1‑Wire driver is included in the Moddable SDK.

DS18X20 Sensor

The DS18B20 is a popular temperature sensor that uses the 1‑Wire bus. The Moddable SDK supported this sensor on ESP8266 and ESP32.

Since our new ESP32 onewire module implements the same JavaScript API that the DS18X20 sensor was using, no code change was necessary to the support the DS18X20 module. Applications that use the ds18x20 and onewire modules do not require changes, including the 1‑Wire example application is the Moddable SDK.

Conclusion

Integrating native capabilities from the ESP‑IDF ecosystem has become easier with the dependency functionality. Contact us on GitHub Discussions if you have questions or need guidance.