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
| Metric | Value | Description |
|---|---|---|
| Plugin load time | < 50ms | WASM module |
| Plugin invocation latency | 120μs | Inside sandbox |
| Sandbox isolation strength | Process-level | WASM + capability authorization |
| Initial marketplace plugins | 32 | Official + community |
| New Crates | 4 | Plugin-related |
| New tests | 500+ | 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
| Type | Purpose | Example |
|---|---|---|
| Protocol Adapter | Device access | Modbus, IEC 104, DNP3 |
| Device Model | Device extension | Proprietary device parameter library |
| Analysis Algorithm | Analysis extension | Custom stability algorithm |
| Data Source | Data integration | External database access |
| UI Component | Interface extension | Custom 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
| API | Description | Required Capability |
|---|---|---|
ctx.read_bus(id) | Read bus | device.read |
ctx.write_timeseries(key, val) | Write timeseries | storage.write |
ctx.send_event(event) | Send event | event.publish |
ctx.http_get(url) | HTTP request | network.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
| Operation | Duration | Description |
|---|---|---|
| Compile WASM | 35ms | Cranelift backend |
| Instantiate | 8ms | Includes memory allocation |
| Start | 5ms | init function |
| Unload | 3ms | Includes 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 Name | Category | Version | Downloads |
|---|---|---|---|
| modbus-advanced | Protocol | 1.2.0 | 12k |
| iec104-pro | Protocol | 2.0.1 | 8.5k |
| dnp3-master | Protocol | 1.5.0 | 3.2k |
| pq-analyzer | Analysis | 0.9.2 | 5.1k |
| gridvis-ui | UI | 1.1.0 | 9.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
| Level | Isolation Mechanism | Applicable Scenario |
|---|---|---|
| Strict | WASM + capability + resource limit | Untrusted plugins |
| Standard | WASM + capability | Community plugins |
| Trusted | WASM | Official plugins |
| Native | Process isolation | Kernel 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-loaderlosing state during hot update migration (#2508) - Fixed
eneros-plugin-sandboxhost memory leak when plugin crashed (#2513) - Fixed
eneros-plugin-sdkContext deadlock during concurrent calls (#2519) - Fixed
eneros-plugin-marketnot checking certificate chain during signature verification (#2524)
Breaking Changes
PluginManager::install: Return type changed fromResult<()>toResult<Plugin>; the return value must be savedCapabilityenum:Networkvariant changed fromNetworktoNetwork(&str); specific address must be specified
Upgrade Guide
- Run
cargo update -p eneros-plugin - Update
PluginManager::installcalls to save the returnedPlugin - Update
Capability::Networkauthorization to specify the specific address - Refer to
docs/migration/v0.25.0.mdfor detailed migration steps