Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
@AttributeDefinition(name = "Watchdog", description = "The watchdog configured at the inverter to return into internal operation mode.")
int watchdog() default 30;

@AttributeDefinition(name = "Tolerance", description = "The tolerance value in watts to skip the modbus writing if the timer is not yet elapsed (smart-mode).")
int tolerance() default 20;
@AttributeDefinition(name = "Tolerance", description = "The tolerance value in watts to skip the modbus writing if the timer is not yet elapsed (smart-mode), small power values are set to 0 (idle zone).")
int tolerance() default 50;

@AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus bridge.")
String modbus_id() default "modbus0";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,53 +161,53 @@ public void applyPower(int activePower, int reactivePower) throws OpenemsNamedEx
// managed or internal mode -> switch to max. self consumption automatic
// (no writes to channel)
if (this.isManaged() && this.controlMode != ControlMode.INTERNAL) {
// allow minimum writes if values not set (zero or null)
Instant now = Instant.now();
// allows moderate differences
if (this.lastSetPower != null && activePower == 0 && this.lastSetPower == activePower
&& (this.lastSetPower - this.tolerance >= activePower
&& this.lastSetPower + this.tolerance <= activePower)
&& Duration.between(this.lastApplyPower, now).getSeconds() < this.watchdog) {

// no need to apply to new set-point
log.debug("skipped - wait for expiring watchdog (zero)");
return;
}
int powerToWrite = activePower;

// allow minimum writes if values are maximized (smart control)
if (this.lastSetPower != null && this.controlMode == ControlMode.SMART && (this.lastSetPower == activePower
// allows little differences
|| (this.lastSetPower - this.tolerance >= activePower
&& this.lastSetPower + this.tolerance <= activePower)
// at limits
|| (activePower == this.getMaxChargePower().get()
|| Math.abs(activePower) == this.getMaxDischargePower().get()) //
// in tolerance around zero
|| (Math.abs(activePower) < this.tolerance))
&& Duration.between(this.lastApplyPower, now).getSeconds() < this.watchdog) {

// no need to apply to new set-point
log.debug("skipped - wait for expiring watchdog (tolerance)");
return;
// Apply idle zone: values within +/- tolerance around zero are set to 0W
// This prevents constant charge/discharge switching on small grid fluctuations
if (Math.abs(activePower) < this.tolerance) {
powerToWrite = 0;
}

// write to channel if necessary (expired/changed)
if (this.lastSetPower == null || activePower != this.lastSetPower
|| Duration.between(this.lastApplyPower, now).getSeconds() >= this.watchdog) {
// Check if we can skip this write (must still write within watchdog interval)
if (this.lastSetPower != null && Duration.between(this.lastApplyPower, now).getSeconds() < this.watchdog) {
boolean shouldSkip = false;

// Skip if power value hasn't changed
if (powerToWrite == this.lastSetPower) {
shouldSkip = true;
log.debug("skipped - power unchanged at " + powerToWrite + "W");
} else if (this.controlMode == ControlMode.SMART) {
// Skip if change from last written value is within tolerance
if (Math.abs(powerToWrite - this.lastSetPower) <= this.tolerance) {
shouldSkip = true;
log.debug("skipped - change within tolerance (" + this.tolerance + "W): "
+ this.lastSetPower + "W -> " + powerToWrite + "W");
} else if (activePower == this.getMaxChargePower().get()
|| Math.abs(activePower) == this.getMaxDischargePower().get()) {
shouldSkip = true;
log.debug("skipped - at power limit: " + powerToWrite + "W");
}
}

// in tolerance around zero
if (Math.abs(activePower) < this.tolerance) {
activePower = 0;
if (shouldSkip) {
return;
}
}

// Write to channel: first write, value changed significantly, or watchdog expired
if (this.lastSetPower == null || powerToWrite != this.lastSetPower
|| Duration.between(this.lastApplyPower, now).getSeconds() >= this.watchdog) {

// Kostal is fine by writing one register with signed value
IntegerWriteChannel setActivePowerChannel = this.channel(KostalManagedEss.ChannelId.SET_ACTIVE_POWER);
setActivePowerChannel.setNextWriteValue(activePower);
setActivePowerChannel.setNextWriteValue(powerToWrite);

this.lastSetPower = activePower;
this.lastSetPower = powerToWrite;
this.lastApplyPower = Instant.now();

log.debug("--> activePowerWanted: " + activePower);
log.debug("--> activePowerWanted: " + powerToWrite + "W (requested: " + activePower + "W)");
}
} else {
this.lastSetPower = null;
Expand Down