Skip to content

[Edge] Add ESS SMA Sunny Boy Storage 2.5#3727

Open
Christoph-87 wants to merge 5 commits into
OpenEMS:developfrom
Christoph-87:feature/ess-sma-sunnyboystorage
Open

[Edge] Add ESS SMA Sunny Boy Storage 2.5#3727
Christoph-87 wants to merge 5 commits into
OpenEMS:developfrom
Christoph-87:feature/ess-sma-sunnyboystorage

Conversation

@Christoph-87
Copy link
Copy Markdown

Implements the SMA Sunny Boy Storage 2.5 (SBS 2.5) as a ManagedSymmetricEss via Modbus TCP, using the SMA CmpBMS external control interface.

Key implementation details:

  • Non-standard addressing: the SBS 2.5 uses the SMA register number directly as the 0-based Modbus PDU address (confirmed by live device testing)
  • SoC and Energy registers use FC3 (holding), not FC4 (input)
  • All 6 CmpBMS control registers must be refreshed within every 60 s window
  • Includes OpenemsApp (App.Ess.Sma.SunnyBoyStorage) with read-only mode option

Tested on SMA Sunny Boy Storage 2.5, firmware 3.11.14.R

Closes #3222

Christoph-87 and others added 3 commits May 12, 2026 15:19
Implements the SMA Sunny Boy Storage 2.5 (SBS 2.5) as a ManagedSymmetricEss
via Modbus TCP, using the SMA CmpBMS external control interface.

Key implementation details:
- Non-standard addressing: the SBS 2.5 uses the SMA register number directly
  as the 0-based Modbus PDU address (confirmed by live device testing)
- SoC and Energy registers use FC3 (holding), not FC4 (input)
- All 6 CmpBMS control registers must be refreshed within every 60 s window
- Includes OpenemsApp (App.Ess.Sma.SunnyBoyStorage) with read-only mode option

Tested on SMA Sunny Boy Storage 2.5, firmware 3.x

Closes OpenEMS#3222
Copy link
Copy Markdown
Contributor

@sfeilmeier sfeilmeier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation looks good so far! Please see my comments.

bnd.identity;id='io.openems.edge.ess.fenecon.commercial40',\
bnd.identity;id='io.openems.edge.ess.generic',\
bnd.identity;id='io.openems.edge.ess.samsung',\
bnd.identity;id='io.openems.edge.ess.sma.sunnyboystorage',\
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move your implementation to the existing bundle io.openems.edge.sma

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Implementation moved to io.openems.edge.sma (package io.openems.edge.sma.ess.sunnyboystorage). The separate bundle io.openems.edge.ess.sma.sunnyboystorage has been removed.

int capacity() default 2000;

@AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.")
String Modbus_target() default "(enabled=true)";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Followed the full migration guide: removed Modbus_target from Config and MyConfig, added @GenerateTargetsFromReferences("Modbus") on the class, switched to the 5-argument super.activate() (no ConfigurationAdmin), and removed the DummyConfigurationAdmin reference from the tests.

}
this.config = config;
this._setCapacity(config.capacity());
this.getAllowedChargePowerChannel().setNextValue(-MAX_APPARENT_POWER);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the same approach for all channels. Recommended is ChannelUtils.setValue()

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. All four channel initializations in activate() now use ChannelUtils.setValue().

* FC16 @ 40801 : Grid Power Setpoint [W] int32 (CmpBMS.GridWSpt)
*/
return new ModbusProtocol(this, //
new FC4ReadInputRegistersTask(30775, Priority.HIGH, //
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some registers are similar to the existing Ess.SMA.SunnyIsland implementation. Please check for compatibility.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked. Registers 30775 (ACTIVE_POWER, int32) and 30845 (SOC, uint32) are identical to the SunnyIsland implementation in address and type. Register 30513 (ENERGY_TOTAL) is SBS-specific and not present in SunnyIsland.

new FC3ReadRegistersTask(30513, Priority.LOW, //
m(EssSmaSunnyBoyStorage.ChannelId.ENERGY_TOTAL, //
new UnsignedQuadruplewordElement(30513))), //
new FC3ReadRegistersTask(30845, Priority.HIGH, //
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually SOC is not required to be HIGH Priority, because it does not change so frequently

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. SOC task changed to Priority.LOW.

Christoph-87 and others added 2 commits May 25, 2026 22:54
…r limits

- Set GRID_MODE=ON_GRID on activate() to prevent cluster GridMode=UNDEFINED
- Set initial ALLOWED_CHARGE/DISCHARGE_POWER defaults (-2500/+2500 W) on activate()
- Read live ALLOWED_CHARGE/DISCHARGE_POWER from registers 40189/40191 at Priority.LOW
- Rewrite applyPower(): use BMS_MODE 2289/2290/2424 with exact min=max power windows;
  standby (0 W) locks device at 0 W instead of allowing autonomous charging
- Add ENERGY_TOTAL channel (register 30513) and debugLog with SoC, power, limits, GridMode
- Add unit tests for static limits, discharge, charge, standby and read-only mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sunny Boy Storage 2.5 Support

2 participants