Environment
-
OpenEMS Edge version: 2026.3.0
-
Deployment: Docker container on ARM (Raspberry Pi)
-
Bundle type: Custom ESS bundle (
ManagedSymmetricEss) -
Modbus bridge:
Bridge.Modbus.Tcp
Summary
We have developed a custom OpenEMS Edge bundle for a third-party ESS inverter that uses Modbus Function Code 4 (FC4 Read Input Registers) for monitoring data. All channels consistently return 0 despite the Modbus device responding correctly to FC4 requests when tested independently.
What Works
-
The Modbus bridge connects successfully (no connection errors)
-
The component shows active in Felix with all references satisfied
-
GridModecorrectly shows1 (On-Grid)— meaningactivate()completes -
Independent Python test from the same host confirms correct FC4 responses:
-
All other assets on the same OpenEMS instance using FC3 work correctly
-
The Modbus bridge, Felix wiring, and OSGi component lifecycle are all healthy
What Fails
-
All channels mapped via
FC4ReadInputRegistersTaskreturn 0 -
No errors in OpenEMS logs related to FC4 reads
-
SOC,ACTIVE_POWER,MAX_APPARENT_POWERall show 0 -
The component is not marked as defective in the bridge worker
Bundle Structure
The bundle follows standard OpenEMS patterns:
@Component(name = "Ess.MyDevice", immediate = true,
configurationPolicy = ConfigurationPolicy.REQUIRE)
public class EssMyDeviceImpl extends AbstractOpenemsModbusComponent
implements ManagedSymmetricEss, SymmetricEss,
ModbusComponent, OpenemsComponent {
@Reference(policy = ReferencePolicy.STATIC,
policyOption = ReferencePolicyOption.GREEDY,
cardinality = ReferenceCardinality.MANDATORY)
protected void setModbus(BridgeModbus modbus) {
super.setModbus(modbus);
}
@Activate
protected void activate(ComponentContext context, Config config)
throws OpenemsException {
if (super.activate(context, config.id(), config.alias(),
config.enabled(), config.modbusUnitId(),
this.cm, "Modbus", config.modbus_id())) {
return;
}
this._setGridMode(GridMode.ON_GRID);
}
@Override
protected ModbusProtocol defineModbusProtocol() {
return new ModbusProtocol(this,
new FC4ReadInputRegistersTask(0x0203, Priority.HIGH,
m(SymmetricEss.ChannelId.SOC,
new UnsignedWordElement(0x0203),
ElementToChannelConverter.DIRECT_1_TO_1),
m(ChannelId.BATTERY_SOH,
new UnsignedWordElement(0x0204),
ElementToChannelConverter.DIRECT_1_TO_1)
)
);
}
}
Things Already Verified and Fixed
-
"Modbus"reference name — must matchsetModbus()with capital M. Using lowercase"modbus"causesupdateReferenceFilterto always returntrue, causing infinite early return and GridMode staying-1 (Undefined).Fixed — GridMode now shows1 (On-Grid)correctly. -
activate()early return — addedif (super.activate(...)) return;pattern matching Fenecon/Voltfang bundles. Fixed. -
@Deactivatewith@Override— added to match standard pattern.Fixed. -
DefectiveComponents backoff — after connection errors, the bridge worker applies exponential backoff up to 5 minutes. Cleared by Docker restart with simulator running first. Not the current issue.
-
FC4ReadInputRegistersTask exists in the deployed bridge bundle — confirmed by inspecting the bridge jar. The class is present and correctly sends
ReadInputRegistersRequest.
Current Symptom
After all fixes above, the component is healthy, GridMode is correct, no errors, but all FC4-mapped channels return 0. FC3-based bundles on the same bridge work perfectly.
Questions for the Community
-
Is there any known issue with
FC4ReadInputRegistersTaskin OpenEMS Edge 2026.x where values are read but not propagated to channels? -
Does
AbstractOpenemsModbusComponentrequire any additional setup for FC4 tasks compared to FC3 tasks? -
Are there any working examples of custom bundles using
FC4ReadInputRegistersTaskthat we can reference? -
Is there a difference in how the Modbus bridge worker handles FC4 vs FC3 read tasks in terms of scheduling or response handling?
Device Register Map (relevant excerpt)
| Address | Type | Accuracy | Meaning |
|---|---|---|---|
| 0x0117 | int16 | 0.1 kW | Total Active Power |
| 0x0118 | int16 | 0.1 kVar | Total Reactive Power |
| 0x0119 | uint16 | 0.1 kVA | Total Apparent Power |
| 0x0203 | uint16 | direct % | Battery SOC |
| 0x0204 | uint16 | direct % | Battery SOH |
| 0x0500 | uint16 | direct | System State |
| 0x0501 | uint16 | direct | Grid State |
All registers are Input Registers (FC04) per the official device register map.
Any guidance or pointers to working FC4 bundle examples would be greatly appreciated.
FC4 0x0203 → [65, 100] (SOC=65%, SOH=100%)FC4 0x0117 → [345, ...] (ActivePower=34500W)