Skip to main content

v0.25.0 Release Notes

EnerOS v0.25.0 Release Notes

Release Date: 2025-09-14 Codename: Plugin Git Tag: v0.25.0 Support Status: Stable Total Crates: 64 (3 new) Test Cases: 8100+ (500+ new)

Overview

EnerOS v0.25.0 “Plugin” is a plugin-system-focused release that upgrades EnerOS from a closed system to an extensible platform. The power industry features fragmented scenarios, numerous protocols, and diverse devices — a single kernel cannot cover all requirements. v0.25.0 introduces a complete plugin system that allows third parties to extend kernel capabilities via plugins — adapting proprietary protocols, customizing device models, extending analysis algorithms, and integrating external systems — while ensuring kernel security and stability.

This release introduces five core capabilities: Plugin System, Plugin SDK, Dynamic Loading, Plugin Marketplace, and Sandbox Isolation. Plugins are distributed as WebAssembly (WASM) modules, run inside a sandbox, and access kernel resources through explicit capability-based authorization.

In terms of design philosophy, v0.25.0 adheres to “security first” — all plugins run in a sandbox by default and can only access explicitly granted capabilities; “hot-pluggable” — plugins support runtime loading and unloading without restart; “governable” — plugin installation, updates, and removal are all audit-logged.

Key Metrics

MetricValueDescription
Plugin load time< 50msWASM module
Plugin invocation latency120μsInside sandbox
Sandbox isolation strengthProcess-levelWASM + capability authorization
Initial marketplace plugins32Official + community
New Crates4Plugin-related
New tests500+Includes security tests

New Features

1. Plugin System

Introduces the eneros-plugin Crate, providing a complete plugin runtime. Plugins exist as WASM modules and access kernel capabilities through host-provided interfaces.

Plugin Registration

use eneros_plugin::{PluginManager, Plugin, PluginManifest};

let mut manager = PluginManager::new()
    .sandbox(Sandbox::strict())
    .capability_store(CapabilityStore::new());

// Install plugin
let manifest = PluginManifest::from_file("modbus-advanced.wasm")?;
let plugin: Plugin = manager.install(manifest).await?;

// Grant capabilities
plugin.grant(Capability::Network("modbus-tcp"))?;
plugin.grant(Capability::Device("read-only"))?;

// Start plugin
plugin.start().await?;

Plugin Manifest

# plugin.toml
name = "modbus-advanced"
version = "1.2.0"
author = "EnerOS Community"
description = "Advanced Modbus protocol plugin"

[capabilities]
network = ["modbus-tcp", "modbus-rtu"]
device = ["read-only"]
storage = ["config"]

[entry]
init = "plugin_init"
poll = "plugin_poll"
cleanup = "plugin_cleanup"

Plugin Types

TypePurposeExample
Protocol AdapterDevice accessModbus, IEC 104, DNP3
Device ModelDevice extensionProprietary device parameter library
Analysis AlgorithmAnalysis extensionCustom stability algorithm
Data SourceData integrationExternal database access
UI ComponentInterface extensionCustom dashboard

2. Plugin SDK

Introduces the eneros-plugin-sdk Crate, providing a Rust SDK for plugin developers. The SDK encapsulates interaction logic with the host; developers only need to implement traits.

SDK Example

use eneros_plugin_sdk::{Plugin, Context, Result};

struct ModbusPlugin {
    client: ModbusClient,
}

impl Plugin for ModbusPlugin {
    fn init(ctx: &Context) -> Result<Self> {
        let addr = ctx.config("address")?;
        let client = ModbusClient::connect(addr)?;
        Ok(ModbusPlugin { client })
    }

    fn poll(&mut self, ctx: &Context) -> Result<()> {
        // Read registers
        let values = self.client.read_holding(0, 10)?;

        // Write to kernel timeseries store
        for (i, v) in values.iter().enumerate() {
            ctx.write_timeseries(
                &format!("modbus.register.{}", i),
                *v as f64,
            )?;
        }
        Ok(())
    }

    fn cleanup(&mut self) -> Result<()> {
        self.client.close();
        Ok(())
    }
}

eneros_plugin_sdk::export_plugin!(ModbusPlugin);

SDK Capability API

APIDescriptionRequired Capability
ctx.read_bus(id)Read busdevice.read
ctx.write_timeseries(key, val)Write timeseriesstorage.write
ctx.send_event(event)Send eventevent.publish
ctx.http_get(url)HTTP requestnetwork.http
ctx.log(level, msg)Log(default)

3. Dynamic Loading

Introduces the eneros-plugin-loader Crate, supporting runtime dynamic loading and unloading of plugins without system restart.

Hot Loading

use eneros_plugin_loader::{Loader, LoadOptions};

let loader = Loader::new(&manager);

// Runtime load
let plugin = loader.load("modbus-advanced-1.2.0.wasm")
    .options(LoadOptions {
        sandbox_level: SandboxLevel::Strict,
        auto_start: true,
    })
    .await?;

// Runtime unload
loader.unload(&plugin.id).await?;
// Unload automatically cleans up resources and disconnects

Hot Update

// Plugin version upgrade (zero downtime)
loader.upgrade(&plugin.id, "modbus-advanced-1.3.0.wasm")
    .migrate_state(true)  // Migrate runtime state
    .await?;

Loading Performance

OperationDurationDescription
Compile WASM35msCranelift backend
Instantiate8msIncludes memory allocation
Start5msinit function
Unload3msIncludes resource cleanup

4. Plugin Marketplace

Introduces the eneros-plugin-market Crate, providing a plugin marketplace client. Users can search, install, and update plugins from official and community sources.

Marketplace Operations

use eneros_plugin_market::{Market, SearchQuery};

let market = Market::connect("https://market.eneros.io")?;

// Search plugins
let results = market.search(SearchQuery::new("modbus"))
    .category("protocol")
    .sort_by(SortBy::Downloads)
    .top(10).await?;

for p in results {
    println!("{} v{} - {} downloads, rating {:.1}",
        p.name, p.version, p.downloads, p.rating);
}

// Install
market.install("modbus-advanced", "1.2.0").await?;

// Update check
let updates = market.check_updates().await?;

Official Plugin List

Plugin NameCategoryVersionDownloads
modbus-advancedProtocol1.2.012k
iec104-proProtocol2.0.18.5k
dnp3-masterProtocol1.5.03.2k
pq-analyzerAnalysis0.9.25.1k
gridvis-uiUI1.1.09.8k

5. Sandbox Isolation

Introduces the eneros-plugin-sandbox Crate, providing WASM-based sandbox isolation. Plugins run in independent instances and cannot directly access host memory or the file system.

Sandbox Configuration

use eneros_plugin_sandbox::{Sandbox, SandboxLevel, ResourceLimit};

let sandbox = Sandbox::new()
    .level(SandboxLevel::Strict)
    .memory_limit(64 * 1024 * 1024)      // 64 MB
    .cpu_limit(Duration::milliseconds(100)) // 100ms per call
    .fs_access(FsAccess::None)
    .network_access(NetworkAccess::Denied);

manager.set_sandbox(sandbox);

Capability Authorization

// No capabilities by default; must be explicitly granted
plugin.grant(Capability::Network("modbus-tcp:502"))?;
plugin.grant(Capability::Timeseries("write:modbus.*"))?;
plugin.grant(Capability::Log("info"))?;

// Revoke capability
plugin.revoke(Capability::Network("modbus-tcp:502"))?;

Sandbox Security Model

LevelIsolation MechanismApplicable Scenario
StrictWASM + capability + resource limitUntrusted plugins
StandardWASM + capabilityCommunity plugins
TrustedWASMOfficial plugins
NativeProcess isolationKernel modules

Improvements

  • WASM Engine: Upgraded to Wasmtime 25, execution performance improved by 18%
  • Capability Granularity: Capability authorization refined from “category-level” to “resource-level”
  • Plugin Audit: All plugin operations (load/unload/invoke) are recorded in audit logs
  • Dependency Management: Plugin interdependencies are automatically resolved to avoid conflicts

Bug Fixes

  • Fixed eneros-plugin-loader losing state during hot update migration (#2508)
  • Fixed eneros-plugin-sandbox host memory leak when plugin crashed (#2513)
  • Fixed eneros-plugin-sdk Context deadlock during concurrent calls (#2519)
  • Fixed eneros-plugin-market not checking certificate chain during signature verification (#2524)

Breaking Changes

  • PluginManager::install: Return type changed from Result<()> to Result<Plugin>; the return value must be saved
  • Capability enum: Network variant changed from Network to Network(&str); specific address must be specified

Upgrade Guide

  1. Run cargo update -p eneros-plugin
  2. Update PluginManager::install calls to save the returned Plugin
  3. Update Capability::Network authorization to specify the specific address
  4. Refer to docs/migration/v0.25.0.md for detailed migration steps