BatteryProtection - help in understanding


As per my previous posts, I have been continuing the development work of our battery system in OpenEMS, following the example of the Fenecon Commercial battery system.

I notice that the Fenecon battery system is using the BatteryProtection function of OpenEMS, which appears to allow the definition of parameters which are monitored by the EMS to prevent over/undervoltage scenarios.

Can someone please provide some more information on this functionality and how to use it? Some of the parameters are clear - e.g setting the max charge/discharge currents, but I am unsure how to use others - e.g the Polyline for getDischargeVoltageToPercent.

Any information about the meaning of each of the potential parameters in a BatteryProtectionDefinition and how it is used by Openems would be greatly appreciated!


I also noticed the following code in the activate function:

private void activate(ComponentContext context, Config config) throws OpenemsException {
	this.config = config;
	if (super.activate(context,, config.alias(), config.enabled(), config.modbusUnitId(),, "Modbus", config.modbus_id())) {

	// Initialize Battery-Protection
	this.batteryProtection = BatteryProtection.create(this) //
			.applyBatteryProtectionDefinition(new BatteryProtectionDefinition(), this.componentManager) //

It looks to me as if the BatteryProtection.create function will not be called if super.activate returns true.
The docs for the activate method on AbstractOpenemsModbusComponent indicate say it will return true “if the target filter was updated. You may use it to abort the activate() method.”.

Can someone shed some light on what this means? And why it will not prevent the BatteryProtection from being activated?


Hi Thomas,

the Battery (better the Battery-Management-System - BMS) provides information on the allowed charge and discharge current. The BatteryProtection serves as an additional layer to these limits on an Energy Management System (EMS) level. Its features are are:

  • Soften the ramp-up of charge/discharge power:

    • Often the current limits provided by BMS change in big steps (e.g. from 0 A to 40 A). BatteryProtection applies a MaxIncreaseAmperePerSecond that will steadily increase the value from 0 A to 40 A in this example.
    • Why is this important? The values for DC charge/discharge current are used to calculate the AllowedCharge- and -DischargePower of an Energy Storage System (ESS). Many Controllers will use the maximum available power, so softening these values reduces the stress on the battery.
  • Max charge/discharge current per Cell-Voltage/-Temperature:

    • ChargeVoltageToPercent, DischargeVoltageToPercent, etc. allow the definition of PolyLines to calculate limitations for charge/discharge current based on the minimum/maximum cell voltage or cell temperature.
    • The X-value of the polyline is the cell-voltage or -temperature; Y-value is percentage of actual max current (see InitialBmsMaxEverChargeCurrent)
    • Additionally there are some internal logics implemented to reduce fluctuating
  • Block discharge/Force charge on low battery (and vice versa)

    • ForceDischargeParams and ForceChargeParams allow definition of thresholds. They mark the threshold values for ‘forbid discharge’, ‘force charge’ and ‘stop force-charge’ on empty battery and ‘forbid charge’, ‘force discharge’ and ‘stop force-discharge’ on full battery.
    • Force Charge/Discharge is represented as negative values for allowed charge/discharge current.

All BatteryProtection limits are applied additionally to the BMS limits, i.e. the minimum of all values wins.

Hope that clarifies the features.

To wire OpenEMS Components with each other by Component-ID (e.g. the Battery Components ‘battery0’ requires a Reference to the Modbus Bridge ‘modbus0’), they need a so called ‘target’ filter (see the OSGI Reference 112.3.10 Selecting Target Services).

OpenEMS Components set this target filter automatically using the method you mentioned. A target filter counts as a Component configuration, and a side effect of applying a new configuration is, that the Component will be reinstantiated (as long as there is no ‘@Modified’ method defined).

This means: when the activate method on AbstractOpenemsModbusComponent returns true, the Component configuration was changed, which means the Component will be deativated and activated again. In that case it is feasible to not execute any other tasks in the activate-method. This is true especially for running a task, etc… You will find appropriate code in many places in OpenEMS.


Hi Stefan

Thank you very much for this information - makes it a lot clearer!

In the BatteryProtection, if we are only able to specify certain values (e.g because the manufacturer didn’t provide us with a threshold cell voltage under which the battery should be charged), is it possible to leave these values blank? (i.e will it function correctly if only certain of the BatteryProtection values are defined?

Hi Stefan,

I have run into an issue when testing our ESS where it stopped charging at SOC=98% and the inverter (KACO) reports ‘Charge cut-off voltage reached’.

The funny thing is that the total battery voltage is below the Battery.ChannelId.CHARGE_MAX_VOLTAGE and the max cell voltage is below the limits in the BatteryProtection getForceDischargeParams. So this is puzzling.

I did not specify many of the BatteryProtection parameters and left most of these blank (didn’t override them in the definition).
I notice when I examine the channels using MQTT that many channels like BP_CHARGE_MAX_VOLTAGE and BP_CHARGE_MAX_TEMPERATURE have defaulted to a value of 180. These are the BP channels where I didn’t specify a value.

I am wondering if this could be the source of my problem. And if the BatteryProtection could be stopping the system from charging because these values are being exceeded. I am not totally convinced because the system did indeed charge previously and this did not stop it… but in any case I would like to understand why the values default to 180.

Hi Thomas,

the Battery-Protection only works on the Battery-side. In your case it seems like you are exceeding the DC voltage on the Battery-Inverter side. This is not covered by the BatteryProtection (as it does not know anything about the used Battery-Inverter).

We have an internal dev project on implementing something similar like the Battery-Protection on a Battery-Inverter or rather Generic-ESS level, but nothing published yet.

If you know, that (for now) you anyway only use the Battery in combination with the KACO Battery-Inverter, I would just define the BatteryProtection limits so that it can never exceed the KACO Battery-Inverter limits.