EnerOS v0.35.0
Release Date: 2026-04-11 Codename: Edge Git Tag: v0.35.0 Support Status: Stable Total Crates: 78 (6 new) Test Cases: 10000+ (700 new)
Overview
EnerOS v0.35.0 “Edge” is an edge computing-focused release, extending EnerOS’s running scope from centralized data centers to grid edge nodes such as substations, distribution rooms, and towers. This release enables EnerOS to run a lightweight runtime on resource-constrained edge devices, supporting scenarios such as localized data acquisition, real-time control, offline autonomy, and data synchronization.
The core design philosophy of the Edge release is “edge autonomy + cloud-edge collaboration” — edge nodes act as extensions of the central cluster when the network is normal, and automatically switch to offline autonomy mode when the network is interrupted, ensuring that protection and control functions are not disrupted; after network recovery, data generated during the offline period is incrementally synchronized back to the center. This enables EnerOS to adapt to the physical characteristics of the power grid: “wide-area distribution, weak network environments, high real-time requirements.”
This release introduces five core capabilities: Lightweight Runtime, Edge Node Management, Offline Autonomy Mode, Data Synchronization Engine, and Cloud-Edge Collaboration Framework. All capabilities are implemented through five new crates: eneros-edge, eneros-edge-runtime, eneros-edge-manager, eneros-edge-offline, and eneros-edge-sync.
Key Metrics
| Metric | Value | Description |
|---|---|---|
| Edge runtime memory usage | 48 MB | Minimum configuration |
| Edge runtime binary size | 12 MB | stripped |
| Offline switch time | < 50ms | Network interruption detection |
| Data sync throughput | 100K points/sec | Between cloud and edge |
| New Crates | 6 | Edge-related |
| New tests | 700+ | Includes 130 end-to-end |
New Features
1. Lightweight Runtime
Adds the eneros-edge-runtime crate, providing a lightweight EnerOS runtime for resource-constrained environments. Through feature trimming, memory pool pre-allocation, and allocation-free hot paths, runtime memory usage is kept within 48MB, adapting to ARM Cortex-A series edge devices.
Runtime Profiles
| Profile | Memory | CPU | Applicable Device | Feature Subset |
|---|---|---|---|---|
| nano | 48 MB | 1 core | Data acquisition terminal | Timeseries + read-only topology |
| micro | 128 MB | 2 cores | Distribution terminal | + Protection + Control |
| small | 256 MB | 4 cores | Substation gateway | + Agent + ML inference |
| standard | 512 MB | 4 cores+ | Regional center | Full-featured |
Lightweight Runtime Initialization
use eneros_edge_runtime::{EdgeRuntime, EdgeConfig, Profile};
let runtime = EdgeRuntime::new(EdgeConfig {
profile: Profile::Micro,
node_id: EdgeNodeId::from("feeder-rtu-042"),
data_dir: "/data/eneros",
max_memory: 128 * 1024 * 1024, // 128 MB
max_agents: 8,
features: FeatureSet {
topology: true,
timeseries: true,
powerflow: false, // Disable power flow in micro profile
constraint: true,
agent: true,
ml: false, // Disable ML in micro profile
llm: false, // Disable LLM in micro profile
},
}).await?;
runtime.start().await?;
Memory Optimization Strategy
// Allocation-free hot path: zero allocation for timeseries data writes
let writer = runtime.timeseries_writer()
.preallocated_buffer(4096) // Pre-allocated buffer
.zero_copy(true); // Zero-copy write
// Data acquisition loop triggers no heap allocation
loop {
let sample = pmu.read().await; // Stack allocation
writer.write(&sample)?; // Zero-copy
}
Resource Usage Comparison
| Component | Standard Runtime | Edge Runtime (micro) | Trimming Ratio |
|---|---|---|---|
| Kernel services | 256 MB | 48 MB | 81% |
| Agent runtime | 128 MB | 32 MB | 75% |
| Timeseries engine | 512 MB | 24 MB | 95% |
| ML/LLM | 1 GB | 0 MB | 100% |
| Total | ~1.9 GB | ~104 MB | 95% |
2. Edge Node Management
Adds the eneros-edge-manager crate, providing full lifecycle management of edge nodes including registration, discovery, health monitoring, remote configuration, and OTA upgrades.
Node Registration and Discovery
use eneros_edge_manager::{EdgeManager, EdgeNode, NodeStatus};
let manager = EdgeManager::new(¢er_ctx);
// Register edge node
let node = EdgeNode::new("feeder-rtu-042")
.location("110kV SS-04 Distribution Room")
.profile(Profile::Micro)
.capabilities(vec![Capability::DataAcquisition, Capability::Protection])
.network("10.20.30.42:7890")
.register(&manager).await?;
// Discover all online nodes
let nodes = manager.list_nodes(NodeStatus::Online).await?;
for n in &nodes {
println!("{} @ {} ({}): CPU {:.0}%, MEM {:.0}MB",
n.id, n.location, n.profile,
n.health.cpu_usage * 100.0, n.health.memory_used_mb);
}
Node Health Monitoring
| Metric | Collection Frequency | Alert Threshold | Description |
|---|---|---|---|
| CPU usage | 10s | > 85% | Sustained 60s |
| Memory usage | 10s | > 90% | Sustained 30s |
| Disk usage | 60s | > 85% | Sustained 5min |
| Network latency | 5s | > 500ms | Sustained 10s |
| Clock skew | 60s | > 100ms | NTP sync |
Remote Configuration Deployment
// Deploy configuration to edge node
manager.deploy_config("feeder-rtu-042", ConfigPatch {
topology_source: "snapshot-20260411.bin",
protection_settings: ProtectionSettings {
overcurrent_pickup: 1200.0, // A
overcurrent_delay: Duration::milliseconds(500),
},
collection_points: vec![
CollectionPoint::new("bus_5_voltage", 50.0), // 50 Hz
CollectionPoint::new("line_3_current", 50.0),
],
}).await?;
OTA Upgrade
// Batch OTA upgrade
let rollout = manager.ota_rollout()
.target_nodes(vec!["feeder-rtu-042", "feeder-rtu-043"])
.package("eneros-edge-0.35.1.bin")
.strategy(RolloutStrategy::Canary {
canary_count: 1,
observation_period: Duration::minutes(30),
})
.rollback_on_failure(true)
.execute().await?;
3. Offline Autonomy Mode
Adds the eneros-edge-offline crate, enabling edge nodes to continue running protection and control functions during network interruptions and seamlessly switch back when the network recovers.
Offline Switching
use eneros_edge_offline::{OfflineManager, OfflinePolicy};
let offline_mgr = OfflineManager::new(&runtime)
.policy(OfflinePolicy {
detection_timeout: Duration::seconds(3), // 3 seconds without heartbeat = offline
switch_latency: Duration::milliseconds(50), // Switch target < 50ms
autonomy_scope: AutonomyScope::LocalOnly, // Local autonomy only
max_offline_duration: Duration::hours(72), // Max 72 hours offline
})
.build().await?;
// Monitor network status
offline_mgr.on_state_change(|state| {
match state {
OfflineState::Online => log::info!("Cloud-edge connection normal"),
OfflineState::Degraded => log::warn!("Network quality degraded, preparing to switch"),
OfflineState::Offline => {
log::warn!("Entering offline autonomy mode");
// Local protection and control continue to run
// Data written to local WAL, synced after recovery
}
OfflineState::Recovering => log::info!("Network recovered, syncing data"),
}
}).await?;
Offline Capability Matrix
| Function | Online Mode | Offline Mode | Description |
|---|---|---|---|
| Data acquisition | Full | Full | Unaffected |
| Protection logic | Full | Full | Local real-time execution |
| Local control | Full | Full | Within autonomy scope |
| Global dispatching | Full | Frozen | Uses last plan |
| AI inference | Cloud | Local lightweight | Degraded mode |
| Historical query | Full | Local cache | Limited scope |
| Alert reporting | Real-time | Buffered | Sent after recovery |
Offline Data Persistence
// Data written to local WAL during offline period
let offline_store = offline_mgr.local_store();
offline_store.configure(OfflineStoreConfig {
max_size: 500 * 1024 * 1024, // 500 MB
rotation: RotationPolicy::Size(50 * 1024 * 1024),
compression: Compression::Zstd,
});
// Auto-write when offline
offline_mgr.on_offline(|ctx| {
// Redirect timeseries writes to local WAL
ctx.redirect_timeseries_to_local();
// Buffer protection events
ctx.buffer_protection_events();
});
4. Data Synchronization Engine
Adds the eneros-edge-sync crate, incrementally synchronizing data generated by edge nodes during offline periods back to the center after network recovery, and handling conflicts.
Synchronization Strategies
| Strategy | Description | Applicable Scenario |
|---|---|---|
| Incremental sync | Sync only changed data | Default |
| Full validation | Validate full data consistency | Periodic |
| Bidirectional sync | Merge cloud-edge bidirectional data | Collaborative scenarios |
| Conflict resolution | Last-write-wins / source-priority | Configurable |
Data Synchronization API
use eneros_edge_sync::{SyncEngine, SyncConfig, ConflictResolver};
let sync = SyncEngine::new(&edge_runtime, ¢er_connection)
.config(SyncConfig {
batch_size: 4096,
parallelism: 4,
compression: Compression::Zstd,
conflict_resolver: ConflictResolver::EdgeWins, // Edge data priority
checkpoint_interval: Duration::minutes(5),
})
.build().await?;
// Auto-sync after network recovery
sync.on_recover(|| {
sync.start_incremental().await?;
}).await?;
// Sync progress monitoring
sync.on_progress(|progress| {
println!("Sync progress: {:.1}% ({}/{} records)",
progress.percentage, progress.synced, progress.total);
}).await?;
Conflict Handling
// Custom conflict resolver
let resolver = ConflictResolver::custom(|conflict| {
match conflict.data_type {
DataType::Timeseries => {
// Timeseries data: use edge value (closer to source)
Resolution::UseEdge(conflict.edge_value)
}
DataType::Topology => {
// Topology data: use center value (authoritative source)
Resolution::UseCenter(conflict.center_value)
}
DataType::Configuration => {
// Configuration data: merge
Resolution::Merge(conflict.merge()?)
}
}
});
5. Cloud-Edge Collaboration Framework
Adds the eneros-edge crate (edge core), providing cloud-edge task collaboration, model deployment, and joint inference capabilities.
Task Offloading
use eneros_edge::{CloudEdgeCoordinator, TaskOffload};
let coordinator = CloudEdgeCoordinator::new(&edge_runtime);
// Offload tasks to cloud when edge resources are insufficient
coordinator.on_resource_pressure(|pressure| {
if pressure.memory > 0.85 {
// Offload ML inference tasks to cloud
coordinator.offload(TaskType::MlInference).await?;
}
});
// Cloud deploys tasks to edge
coordinator.on_remote_task(|task| {
match task {
RemoteTask::Inspect(bus_id) => {
edge_runtime.execute_inspection(bus_id).await?;
}
RemoteTask::UpdateModel(name, version) => {
coordinator.download_model(name, version).await?;
}
}
}).await?;
Collaboration Mode Comparison
| Mode | Compute | Data | Latency | Applicable Scenario |
|---|---|---|---|---|
| Pure edge | Edge | Edge | Lowest | Real-time control |
| Edge + cloud | Division of labor | Layered | Low | Hybrid |
| Pure cloud | Cloud | Cloud | High | Big data analysis |
| Federated | Collaborative | Stays on-site | Medium | Privacy protection |
Improvements
- Timeseries Engine: Edge mode supports RocksDB backend, write performance improved 2x
- Topology Loading: Binary snapshot format optimized, load time reduced by 40%
- Agent Runtime: Edge Agent supports sleep/wake, reducing idle power consumption
- Security Gateway: Cloud-edge communication enforces mTLS mutual authentication
- Observability: Edge node metrics integrated into central Prometheus cluster
Bug Fixes
- Fixed
eneros-edge-runtimecrash on ARMv7 devices due to memory alignment (#3503) - Fixed
eneros-edge-managernode discovery failing in NAT environments (#3510) - Fixed
eneros-edge-offlinenot saving last known topology during offline switch (#3516) - Fixed
eneros-edge-syncexcessive memory peaks during large data synchronization (#3522) - Fixed
eneros-edgecloud-edge task offload not retrying on timeout in weak networks (#3528)
Breaking Changes
EdgeRuntime::new: Parameter changed from&strtoEdgeConfigOfflineManager:switch_to_offlinerenamed toactivate_autonomySyncEngine:sync_allsplit intostart_incrementalandstart_full
Upgrade Guide
- Update the
enerosdependency inCargo.tomlto0.35.0 - Deploy
eneros-edge-runtimebinary on edge devices - Configure
eneros-edge-managerconnection info in the central cluster - Run
eneros edge registerto register edge nodes
Acknowledgments
Thanks to the 32 contributors who submitted 480+ commits, and to edge device manufacturers for hardware testing support.