Detailed Technical Understanding of OpenEMS Edge
1. Project Overview
OpenEMS Edge is the software stack designed to run on a local energy management controller. It is built on Java and OSGi (Open Services Gateway initiative), providing a modular, dynamic, and robust environment for managing energy storage systems, photovoltaic plants, electric vehicle chargers, and other energy hardware.
2. Core Architecture & Concepts
The architecture is centered around a unified data model and a synchronous execution cycle.
2.1. OSGi & Modularity
OpenEMS uses OSGi to manage Components. Each driver (e.g., for a specific generic ESS) or controller is an OSGi Bundle.
- Service-Oriented: Components register as OSGi Services (e.g., ManagedSymmetricEss, Controller).
- Dynamic: Components can be started, stopped, or updated at runtime without restarting the entire system.
- Configuration: The standard OSGi Configuration Admin is used to configure components (e.g., IP addresses, Modbus IDs).
2.2. The Data Model: Natures, Components, and Channels
- Nature: A Java Interface defining a set of standard capabilities. For example,
SymmetricEssis a Nature that guarantees the existence of aSoc(State of Charge) channel. - Component: A concrete instance (Java Class) that implements one or more Natures.
- Channel: The atomic unit of data. Every point of data in OpenEMS is a Channel.
ReadChannel: Represents "Inputs" (e.g., Measured Power, SoC).WriteChannel: Represents "Outputs" or "Setpoints" (e.g., Set Active Power).StateChannel: Represents boolean states, often faults or warnings.
2.3. The Process Image
OpenEMS operates on a synchronized Process Image to avoid race conditions and ensure data consistency during a control cycle. * NextValue: Controllers and Drivers write to the "NextValue" buffer during a Cycle. * Value (Current): At the beginning of a Cycle, the "NextValue" is promoted to the current "Value". All Controllers reading data in step N see the same stable snapshot of data from step N-1.
3. The Execution Cycle (Heartbeat)
The core logic is driven by the Cycle Worker, typically running once per second.
sequenceDiagram
participant Timer
participant Cycle
participant Channels
participant Scheduler
participant Controllers
participant Hardware
Timer->>Cycle: Tick (1s)
rect rgb(240, 248, 255)
Note over Cycle, Channels: Phase 1: Process Image Switch
Cycle->>Channels: nextProcessImage()
Note right of Channels: NextValue becomes CurrentValue
end
rect rgb(255, 250, 240)
Note over Cycle, Controllers: Phase 2: Control Logic
Cycle->>Scheduler: Execute Schedulers
loop For each Controller
Scheduler->>Controllers: run()
Controllers->>Channels: Read Inputs (Sensors)
Controllers->>Channels: Write Next Setpoints
end
end
rect rgb(240, 255, 240)
Note over Cycle, Hardware: Phase 3: Execute Writes
Cycle->>Hardware: Trigger Write to External Devices
end
4. Automation Logic: Controllers in Detail
OpenEMS follows a modular controller concept. A controller is a logic block that reads component data and calculates new setpoints.
4.1. Scheduler
The Scheduler determines the execution order. This is critical because multiple controllers might try to influence the same hardware.
* Prioritization: Typical priority: High Priority (Emergency) > Balancing > Optimization > Low Priority.
* Constraint Solving: Controllers can add Constraints (e.g., "Power must be <= 2000 W"). A central solver then finds the optimal value satisfying all constraints.
4.2. Functional Implementation Logic
I. ESS Controllers (Energy Storage)
1. Symmetric Balancing Controller (Self-Consumption)
* Objective: Minimize Grid Exchange (Target: 0 W).
* Logic:
1. Read GridActivePower (Meter) and EssActivePower (ESS).
2. Calculate RequiredPower = GridActivePower + EssActivePower - TargetSetpoint.
3. Apply PID Filter to smooth the request.
4. Write result to the ESS SetActivePowerEquals channel.
2. Peak Shaving Controller
* Objective: Prevent grid consumption from exceeding a limit (e.g., 20 kW).
* Logic:
1. Read GridActivePower.
2. If GridActivePower > PeakShavingLimit:
* Calculate Delta = GridActivePower - PeakShavingLimit.
* Discharge Battery by Delta.
3. Else, if GridActivePower < RechargePower:
* Charge Battery slowly to prepare for next peak.
3. Limit Total Discharge (Deep Discharge Protection)
* Objective: Protect Battery health.
* Logic: Uses a State Machine.
* Normal: SoC > MinSoC. No action.
* MinSoC: SoC <= MinSoC. Set Constraint SetActivePowerLessOrEquals(0) (Block Discharge).
* ForceCharge: SoC <= ForceChargeSoC. Enforce Charging Power (e.g., -2000 W).
4. Emergency Capacity Reserve
* Objective: Reserve specific capacity (e.g., 20%) for backup power.
* Logic:
* If Soc <= ReserveSoc, set Constraint SetActivePowerLessOrEquals(0).
* This stops "economic" discharging (like Balancing), saving the energy for physical backup hardware (Emergency Power Switch).
5. Time of Use Tariff * Objective: Arbitrage (Buy Low, Sell High). * Logic: Calculates a schedule based on electricity prices. * ChargeGrid: Force charge during price valleys. * DelayDischarge: Prevent discharge during medium prices to save capacity for high price peaks.
II. EVCS Controllers (Electric Vehicle Charging)
1. EVCS Smart Charging
* Objective: Charge EV with excess PV power.
* Logic: The controller has two priority modes:
* Priority: Car: Charge as fast as possible (or using all excess, ignoring battery).
* Priority: Storage: Fill the home battery first, then charge the car.
* Calculation:
* ExcessPower = PV_Production - House_Load.
* The controller continuously adjusts the ChargePowerLimit of the EVCS to match ExcessPower.
* Hysteresis: Applied to prevent toggling charging on/off too rapidly during passing clouds.
III. PV Inverter Controllers
1. Fix Power Limit (Curtailment)
* Objective: Limit PV production (e.g., due to grid operator request).
* Logic:
* Write a fixed percentage or Watt value to the Inverter's ActivePowerLimit channel.
2. Sell-To-Grid Limit
* Objective: Limit the power fed into the public grid (e.g., "70% Rule" or "Zero Export").
* Logic:
1. Read GridActivePower (Meter) and PvActivePower.
2. Calculate Allowed PV Power:
MaxPv = PvActivePower + GridActivePower + ConfiguredLimit
(Note: GridActivePower is negative when selling).
3. Write MaxPv to the Inverter's ActivePowerLimit.
IV. IO Controllers (Inputs/Outputs)
1. Channel Single Threshold
* Objective: Switch a Relay (Digital Output) based on a data value (e.g., Turn on Heater if Excess Power > 2000 W).
* Logic:
* Read Input Channel (e.g., GridActivePower).
* Hysteresis: Wait for MinimumSwitchingTime.
* If Value > Threshold: Set Output = ON.
* If Value <= Threshold: Set Output = OFF.
V. Meter Controllers?
- Clarification: In OpenEMS, "Meters" are typically Components that provide data, not Controllers that execute logic.
- However, logic related to meters (like "Sell-To-Grid Limit") is handled by the controllers described above, which take the Meter data as a primary input variable.
5. Key Interface: ManagedSymmetricEss
Any Energy Storage System in OpenEMS implements this interface. Key Channels include:
Measurements & State (Read-Only)
Inherited from SymmetricEss.
| Channel Name | Unit | Description |
|---|---|---|
Soc |
% | State of Charge (0-100) |
ActivePower |
W | Current Output (+ Discharge, - Charge) |
ReactivePower |
var | Current Reactive Power |
Capacity |
Wh | Total utilization capacity |
MaxApparentPower |
VA | Maximum apparent power limit |
GridMode |
- | 1=On-Grid, 2=Off-Grid |
ActiveChargeEnergy |
Wh | Total Energy Charged (Counter) |
ActiveDischargeEnergy |
Wh | Total Energy Discharged (Counter) |
MinCellVoltage |
mV | Minimum Cell Voltage in the pack |
MaxCellVoltage |
mV | Maximum Cell Voltage in the pack |
MinCellTemperature |
°C | Minimum Cell Temperature |
MaxCellTemperature |
°C | Maximum Cell Temperature |
Control & Setpoints (Write)
Defined in ManagedSymmetricEss. These are the targets written by Controllers.
| Channel Name | Access | Unit | Description |
|---|---|---|---|
AllowedChargePower |
Read | W | Max power the battery can currently accept (negative value, e.g. -5000) |
AllowedDischargePower |
Read | W | Max power the battery can currently deliver (positive value, e.g. 5000) |
SetActivePowerEquals |
Write | W | Target Setpoint: The main target power requested by a controller. |
SetActivePowerEqualsWithPid |
Write | W | Target setpoint that passes through a PID filter before being applied. |
SetActivePowerLessOrEquals |
Write | W | Constraint: "Do not be more positive than X" (limits Discharge). |
SetActivePowerGreaterOrEquals |
Write | W | Constraint: "Do not be more negative than X" (limits Charge). |
SetReactivePowerEquals |
Write | var | Target Reactive Power. |
SetReactivePowerLessOrEquals |
Write | var | Reactive Power Constraint. |
SetReactivePowerGreaterOrEquals |
Write | var | Reactive Power Constraint. |
ApplyPowerFailed |
Read | Bool | True if the system failed to apply the requested power. |