This is unfortunately not a trivial problem, and I believe it cannot really be fixed in a generic way.
1 Custom ElementToChannelConverter
One way to fix the problem is to a logic to the conversion from Modbus-Register to Channel. In this example I used a custom ElementToChannelConverter
for that purpose:
new FC3ReadRegistersTask(4004, Priority.HIGH, //
m(SymmetricMeter.ChannelId.ACTIVE_POWER, new SignedWordElement(4004),
SIGNED_POWER_CONVERTER_AND_INVERT)), //
followed by
private static final ElementToChannelConverter SIGNED_POWER_CONVERTER_AND_INVERT = new ElementToChannelConverter(//
value -> {
if (value == null) {
return null;
}
int intValue = (Short) value;
if (intValue == -10_000) {
return 0; // ignore '-10_000'
}
return intValue * -1; // invert
}, //
value -> value);
Source
You can use this approach if you simply want to ignore certain values - e.g. zero in your case.
2 Additional Channel + OnChange listener
Second option is to introduce a second channel with a custom On-Change listener, like in this example:
ORIGINAL_SOC(new IntegerDoc()//
.onInit(channel -> { //
final EvictingQueue<Integer> lastSocValues = EvictingQueue.create(100);
((IntegerReadChannel) channel).onChange((oldValue, newValue) -> {
Integer originalSocValue = newValue.get();
Integer correctedSocValue = null;
if (originalSocValue != null) {
lastSocValues.add(originalSocValue);
OptionalDouble averageSoc = lastSocValues.stream().mapToInt(Integer::intValue).average();
if (averageSoc.isPresent()) {
correctedSocValue = (int) averageSoc.getAsDouble();
}
}
SymmetricEss parent = (SymmetricEss) channel.getComponent();
parent._setSoc(correctedSocValue);
});
})),
Benefit of this approach is, that you get a nice onChange
callback, that gives access to the previous and new value, so that you can easily filter whenever the next value is less.
This approach still does not fix the problem, when you restart OpenEMS during the period of the error.
3 Apply persisted value after restart
Third option is to make sure, that the new data is never less than the previous data - even on a restart of OpenEMS. We use this approach in the [CalculateEnergyFromPower](https://github.com/OpenEMS/openems/blob/develop/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/utils/CalculateEnergyFromPower.java)
class, where we apply the new value only after validating it with the data loaded from a Timedata provider like RRD4j.