Moddable SDK on Zephyr RTOS Advancing Quickly with Networking, BLE, and More Storage

November 6, 2025 | Peter Hoddie, Principal

Zephyr Update

Our work to bring modern JavaScript to the popular Zephyr RTOS is advancing with unprecedented speed. The latest update adds support for many key capabilities, including network communication, a BLE central, storage, and support for Espressif's ESP32 silicon family. All of the APIs are based on the efficient, interoperable ECMA-419 standard.

To learn more about our work to bring the Moddable SDK to Zephyr, check out Modern JavaScript for Zephyr.

Networking

Our Zephyr port now features comprehensive support for networking. We've started with Wi-Fi connectivity, the most popular way for IoT products to get connected. Establishing a Wi-Fi connection is a snap:

const wifi = new WiFi({
    onChanged() {
        if (this.state >= 500)
            trace("connected\n");
    }
});

wifi.connect({
    SSID: "my wi-fi network",
    password: "my secret password"
});

Discovering local Wi-Fi networks is just as easy:

wifi.scan({
    onFound(accessPoint) {
        trace(`Found ${accessPoint.SSID}\n`);
    }
    onComplete() {
        // scan finished
    }
});

We've brought up our full suite of network sockets – UDP, TCP, and TCP Listener. These sockets are the foundation of all of our network protocol implementations. We've already successfully tested our DNS, NTP, HTTP, and MQTT protocol implementations – they all run unchanged on Zephyr, further validating the ECMA-419 sockets design as a portable network layer for JavaScript.

You can start exploring our HTTP client with a single command line that configures the Wi-Fi network and runs the app:

cd $MODDABLE/examples/io/tcp/httpclient
mcconfig -d -m -p zephyr/esp32s3_devkitc ssid="my wi-fi network" password="my secret password"

Storage

We've added support for the Zephyr File System API so you can easily work with any file system Zephyr supports, including FAT32 and littlefs. The ECMA-419 File APIs are designed around the familiar POSIX file system model, so there's no learning curve.

const file = new device.files.openFile({
    path: "test.txt",
    mode: "r"
});
const text = file.read(files.status().size. 0);
file.close();

We also now support Resources, the Moddable SDK's tool for lightweight access to named data. Resources use zero RAM because they are accessed directly from flash, and also avoid the code-space overhead of a file system. Resources are perfect for projects that only need to access a handful of assets.

const resource = new Resource("test.txt");

BLE Central

One of the most powerful new features in this update is our BLE Central (aka BLE Client) support. This uses the new ECMA-419 BLE Central APIs that are slated to be part of the fourth edition. This includes both the GAP Client for discovering BLE devices and the GATT client for communicating with BLE devices. The API is simple and powerful.

Moddable has also implemented the Web Standard Web Bluetooth API on top of the ECMA-419 BLE API. Web Bluetooth provides a very straightforward and direct API that reduces the familiar heart-rate monitor example to just a few lines:

const device = await bluetooth.requestDevice({
    filters: [{ services: ['heart_rate'] }]
});

const server = await device.gatt.connect();
const service = await server.getPrimaryService('heart_rate');

const characteristic = await service.getCharacteristic('heart_rate_measurement');
await characteristic.startNotifications();

characteristic.addEventListener('characteristicvaluechanged', function(event) {
    trace(`Heart Rate: ${event.target.value.getUint8(1)} BPM\n`);
});

Real-Time Clock

We support the Real-Time Clock peripheral in Zephyr, allowing easy initialization of the time and date. Some devices, like several from ST Micro, have an RTC built into the microcontroller. Here's how you synchronize the time on the microcontroller with the RTC:

const rtc = new device.rtc.io(device.rtc);
Time.set(rtc.time / 1000);
rtc.close();

Setting the RTC is just as easy:

const rtc = new device.rtc.io(device.rtc);
rtc.time = 1762192170_000;  // Unix milliseconds
rtc.close();

The alarm feature of the RTC is available for efficient wake-up from deep sleep.

const rtc = new device.rtc.io({
    ...device.rtc,
    onAlarm() {
        trace(`alarm fired at ${this.time}\n`);
    }
});

rtc.configure({
    alarm: Date.now() + 2000
});

Espressif ESP32 Silicon Support

This update includes support for ESP32 silicon from Espressif. We had to make some updates to our Device Tree tool to support Espressif silicon, but otherwise the code we developed on ST hardware pretty much "just works" on Espressif silicon.

We used the ESP32S3 DevKitC board for our testing. That Zephyr board target conveniently runs well on our own Moddable Six hardware.

Looking Ahead

The Moddable SDK is running well on Zephyr. The foundation we've established has been powerful and robust, allowing us to quickly bring up new capabilities.

There's more to do:

  • Developer tools
    • test262 and testmc for thorough testing
    • mcpack to integrate with the npm ecosystem
  • BLE
    • BLE Peripheral / Server
    • BLE Security
  • Networking
    • WebSocket
    • TLS
    • fetch
    • Ethernet
  • Hardware support
    • SPI
    • Analog input
    • PWM
  • Display driver

We are looking for developers, especially those with Zephyr experience, to help us finish and harden the Zephyr port. Please reach out through GitHub Discussions if you are interested in contributing.