Skip to main content

v0.35.0 Release Notes

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

MetricValueDescription
Edge runtime memory usage48 MBMinimum configuration
Edge runtime binary size12 MBstripped
Offline switch time< 50msNetwork interruption detection
Data sync throughput100K points/secBetween cloud and edge
New Crates6Edge-related
New tests700+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

ProfileMemoryCPUApplicable DeviceFeature Subset
nano48 MB1 coreData acquisition terminalTimeseries + read-only topology
micro128 MB2 coresDistribution terminal+ Protection + Control
small256 MB4 coresSubstation gateway+ Agent + ML inference
standard512 MB4 cores+Regional centerFull-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

ComponentStandard RuntimeEdge Runtime (micro)Trimming Ratio
Kernel services256 MB48 MB81%
Agent runtime128 MB32 MB75%
Timeseries engine512 MB24 MB95%
ML/LLM1 GB0 MB100%
Total~1.9 GB~104 MB95%

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(&center_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

MetricCollection FrequencyAlert ThresholdDescription
CPU usage10s> 85%Sustained 60s
Memory usage10s> 90%Sustained 30s
Disk usage60s> 85%Sustained 5min
Network latency5s> 500msSustained 10s
Clock skew60s> 100msNTP 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

FunctionOnline ModeOffline ModeDescription
Data acquisitionFullFullUnaffected
Protection logicFullFullLocal real-time execution
Local controlFullFullWithin autonomy scope
Global dispatchingFullFrozenUses last plan
AI inferenceCloudLocal lightweightDegraded mode
Historical queryFullLocal cacheLimited scope
Alert reportingReal-timeBufferedSent 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

StrategyDescriptionApplicable Scenario
Incremental syncSync only changed dataDefault
Full validationValidate full data consistencyPeriodic
Bidirectional syncMerge cloud-edge bidirectional dataCollaborative scenarios
Conflict resolutionLast-write-wins / source-priorityConfigurable

Data Synchronization API

use eneros_edge_sync::{SyncEngine, SyncConfig, ConflictResolver};

let sync = SyncEngine::new(&edge_runtime, &center_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

ModeComputeDataLatencyApplicable Scenario
Pure edgeEdgeEdgeLowestReal-time control
Edge + cloudDivision of laborLayeredLowHybrid
Pure cloudCloudCloudHighBig data analysis
FederatedCollaborativeStays on-siteMediumPrivacy 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-runtime crash on ARMv7 devices due to memory alignment (#3503)
  • Fixed eneros-edge-manager node discovery failing in NAT environments (#3510)
  • Fixed eneros-edge-offline not saving last known topology during offline switch (#3516)
  • Fixed eneros-edge-sync excessive memory peaks during large data synchronization (#3522)
  • Fixed eneros-edge cloud-edge task offload not retrying on timeout in weak networks (#3528)

Breaking Changes

  • EdgeRuntime::new: Parameter changed from &str to EdgeConfig
  • OfflineManager: switch_to_offline renamed to activate_autonomy
  • SyncEngine: sync_all split into start_incremental and start_full

Upgrade Guide

  1. Update the eneros dependency in Cargo.toml to 0.35.0
  2. Deploy eneros-edge-runtime binary on edge devices
  3. Configure eneros-edge-manager connection info in the central cluster
  4. Run eneros edge register to register edge nodes

Acknowledgments

Thanks to the 32 contributors who submitted 480+ commits, and to edge device manufacturers for hardware testing support.