Search in sources :

Example 1 with SymmetricEssNature

use of io.openems.api.device.nature.ess.SymmetricEssNature in project openems by OpenEMS.

the class EssClusterNature method loadEss.

private void loadEss() {
    Set<DeviceNature> natures = repo.getDeviceNatures();
    JsonArray essIds;
    try {
        essIds = esss.value();
        // remove old ess
        for (SymmetricEssNature ess : this.essList) {
            soc.removeChannel(ess.soc());
            gridMode.removeChannel(ess.gridMode());
            systemState.removeChannel(ess.systemState());
            allowedCharge.removeChannel(ess.allowedCharge());
            allowedDischarge.removeChannel(ess.allowedDischarge());
            allowedApparent.removeChannel(ess.allowedApparent());
            activePower.removeChannel(ess.activePower());
            reactivePower.removeChannel(ess.reactivePower());
            apparentPower.removeChannel(ess.apparentPower());
            maxNominalPower.removeChannel(ess.maxNominalPower());
            capacity.removeChannel(ess.capacity());
            setWorkState.removeChannel(ess.setWorkState());
            power.removeEss(ess);
        }
        essList.clear();
        if (essIds != null && isInitialized) {
            for (DeviceNature nature : natures) {
                if (nature instanceof SymmetricEssNature) {
                    if (essIds.toString().contains(nature.id())) {
                        SymmetricEssNature ess = (SymmetricEssNature) nature;
                        essList.add(ess);
                        soc.addChannel(ess.soc());
                        gridMode.addChannel(ess.gridMode());
                        systemState.addChannel(ess.systemState());
                        allowedCharge.addChannel(ess.allowedCharge());
                        allowedDischarge.addChannel(ess.allowedDischarge());
                        allowedApparent.addChannel(ess.allowedApparent());
                        activePower.addChannel(ess.activePower());
                        reactivePower.addChannel(ess.reactivePower());
                        apparentPower.addChannel(ess.apparentPower());
                        maxNominalPower.addChannel(ess.maxNominalPower());
                        capacity.addChannel(ess.capacity());
                        setWorkState.addChannel(ess.setWorkState());
                        power.addEss(ess);
                    }
                }
            }
        // capacity.channelUpdated(null, null);
        }
    } catch (InvalidValueException e) {
        log.error("esss value is invalid!", e);
    }
}
Also used : JsonArray(com.google.gson.JsonArray) InvalidValueException(io.openems.api.exception.InvalidValueException) DeviceNature(io.openems.api.device.nature.DeviceNature) SystemDeviceNature(io.openems.impl.protocol.system.SystemDeviceNature) SymmetricEssNature(io.openems.api.device.nature.ess.SymmetricEssNature)

Example 2 with SymmetricEssNature

use of io.openems.api.device.nature.ess.SymmetricEssNature in project openems by OpenEMS.

the class SymmetricPowerClusterImpl method writePower.

@Override
protected void writePower() {
    super.writePower();
    if (dynamicLimitations.size() > 0) {
        synchronized (this.ess) {
            Point p = reduceToZero();
            try {
                setGeometry(p);
            } catch (PowerException e1) {
            }
            long activePower = (long) p.getCoordinate().x;
            long reactivePower = (long) p.getCoordinate().y;
            long socSum = 0;
            for (SymmetricEssNature ess : this.ess) {
                socSum += ess.soc().valueOptional().orElse(0L) - ess.minSoc().valueOptional().orElse(0);
            }
            if (activePower > 0) {
                /*
					 * Discharge
					 */
                // sort ess by useableSoc asc
                Collections.sort(ess, (a, b) -> {
                    return (int) ((a.soc().valueOptional().orElse(0L) - a.minSoc().valueOptional().orElse(0)) - (b.soc().valueOptional().orElse(0L) - b.minSoc().valueOptional().orElse(0)));
                });
                for (int i = 0; i < ess.size(); i++) {
                    SymmetricEssNature ess = this.ess.get(i);
                    // calculate minimal power needed to fulfill the calculatedPower
                    long minP = activePower;
                    for (int j = i + 1; j < this.ess.size(); j++) {
                        if (this.ess.get(j).soc().valueOptional().orElse(0L) - this.ess.get(j).minSoc().valueOptional().orElse(0) > 0) {
                            minP -= this.ess.get(j).getPower().getMaxP().orElse(0L);
                        }
                    }
                    if (minP < 0) {
                        minP = 0;
                    }
                    // check maximal power to avoid larger charges then calculatedPower
                    long maxP = ess.getPower().getMaxP().orElse(0L);
                    if (activePower < maxP) {
                        maxP = activePower;
                    }
                    double diff = maxP - minP;
                    /*
						 * weight the range of possible power by the useableSoc
						 * if the useableSoc is negative the ess will be charged
						 */
                    long power = (long) (Math.ceil(minP + diff / socSum * (ess.soc().valueOptional().orElse(0L) - ess.minSoc().valueOptional().orElse(0))));
                    PEqualLimitation limit = new PEqualLimitation(ess.getPower());
                    limit.setP(power);
                    try {
                        ess.getPower().applyLimitation(limit);
                        activePower -= power;
                    } catch (PowerException e) {
                        log.error("Failed to set activePower on " + ess.id());
                    }
                }
            } else {
                /*
					 * Charge
					 */
                /*
					 * sort ess by 100 - useabelSoc
					 * 100 - 90 = 10
					 * 100 - 45 = 55
					 * 100 - (- 5) = 105
					 * => ess with negative useableSoc will be charged much more then one with positive useableSoc
					 */
                Collections.sort(this.ess, (a, b) -> {
                    return (int) ((100 - (a.soc().valueOptional().orElse(0L) - a.minSoc().valueOptional().orElse(0))) - (100 - (b.soc().valueOptional().orElse(0L) - b.minSoc().valueOptional().orElse(0))));
                });
                for (int i = 0; i < this.ess.size(); i++) {
                    SymmetricEssNature ess = this.ess.get(i);
                    // calculate minimal power needed to fulfill the calculatedPower
                    long minP = activePower;
                    for (int j = i + 1; j < this.ess.size(); j++) {
                        minP -= this.ess.get(j).getPower().getMinP().orElse(0L);
                    }
                    if (minP > 0) {
                        minP = 0;
                    }
                    // check maximal power to avoid larger charges then calculatedPower
                    long maxP = ess.getPower().getMinP().orElse(0L);
                    if (activePower > maxP) {
                        maxP = activePower;
                    }
                    double diff = maxP - minP;
                    // weight the range of possible power by the useableSoc
                    long power = (long) Math.floor(minP + diff / (this.ess.size() * 100 - socSum) * (100 - (ess.soc().valueOptional().orElse(0L) - ess.minSoc().valueOptional().orElse(0))));
                    PEqualLimitation limit = new PEqualLimitation(ess.getPower());
                    limit.setP(power);
                    try {
                        ess.getPower().applyLimitation(limit);
                        activePower -= power;
                    } catch (PowerException e) {
                        log.error("Failed to set activePower on " + ess.id());
                    }
                }
            }
            // sort ess by maxNominalPower asc
            Collections.sort(ess, (a, b) -> {
                return (int) (a.maxNominalPower().valueOptional().orElse(0L) - b.maxNominalPower().valueOptional().orElse(0L));
            });
            if (reactivePower > 0) {
                for (int i = 0; i < ess.size(); i++) {
                    SymmetricEssNature ess = this.ess.get(i);
                    // calculate minimal power needed to fulfill the calculatedPower
                    long minQ = reactivePower;
                    for (int j = i + 1; j < this.ess.size(); j++) {
                        if (this.ess.get(j).maxNominalPower().valueOptional().orElse(0L) > 0) {
                            minQ -= this.ess.get(j).getPower().getMaxQ().orElse(0L);
                        }
                    }
                    if (minQ < 0) {
                        minQ = 0;
                    }
                    // check maximal power to avoid larger charges then calculatedPower
                    long maxQ = ess.getPower().getMaxQ().orElse(0L);
                    if (reactivePower < maxQ) {
                        maxQ = reactivePower;
                    }
                    double diff = maxQ - minQ;
                    /*
						 * weight the range of possible power by the useableSoc
						 * if the useableSoc is negative the ess will be charged
						 */
                    long power = (long) (Math.ceil(minQ + diff / getMaxApparentPower() * ess.maxNominalPower().valueOptional().orElse(0L)));
                    QEqualLimitation limit = new QEqualLimitation(ess.getPower());
                    limit.setQ(power);
                    try {
                        ess.getPower().applyLimitation(limit);
                        reactivePower -= power;
                    } catch (PowerException e) {
                        log.error("Failed to set reactivePower on " + ess.id());
                    }
                }
            } else {
                for (int i = 0; i < this.ess.size(); i++) {
                    SymmetricEssNature ess = this.ess.get(i);
                    // calculate minimal power needed to fulfill the calculatedPower
                    long minQ = reactivePower;
                    for (int j = i + 1; j < this.ess.size(); j++) {
                        minQ -= this.ess.get(j).getPower().getMinQ().orElse(0L);
                    }
                    if (minQ > 0) {
                        minQ = 0;
                    }
                    // check maximal power to avoid larger charges then calculatedPower
                    long maxQ = ess.getPower().getMinQ().orElse(0L);
                    if (reactivePower > maxQ) {
                        maxQ = reactivePower;
                    }
                    double diff = maxQ - minQ;
                    // weight the range of possible power by the useableSoc
                    long power = (long) Math.floor(minQ + diff / getMaxApparentPower() * ess.maxNominalPower().valueOptional().orElse(0L));
                    QEqualLimitation limit = new QEqualLimitation(ess.getPower());
                    limit.setQ(power);
                    try {
                        ess.getPower().applyLimitation(limit);
                        reactivePower -= power;
                    } catch (PowerException e) {
                        log.error("Failed to set reactivePower on " + ess.id());
                    }
                }
            }
        }
    }
}
Also used : Point(com.vividsolutions.jts.geom.Point) Point(com.vividsolutions.jts.geom.Point) SymmetricEssNature(io.openems.api.device.nature.ess.SymmetricEssNature)

Example 3 with SymmetricEssNature

use of io.openems.api.device.nature.ess.SymmetricEssNature in project openems by OpenEMS.

the class SimulatorGridMeter method update.

@Override
protected void update() {
    super.update();
    long activePower = 0;
    long activePowerL1 = 0;
    long activePowerL2 = 0;
    long activePowerL3 = 0;
    if (activePowerLoad != null) {
        factorL1 = SimulatorTools.addRandomDouble(factorL1, 0, 1, 0.01);
        factorL2 = SimulatorTools.addRandomDouble(factorL2, 0, 1 - factorL1, 0.01);
        factorL3 = 1 - factorL1 - factorL2;
        long load = activePowerLoad.getLoad();
        activePower = load;
        activePowerL1 = (long) (load * factorL1);
        activePowerL2 = (long) (load * factorL2);
        activePowerL3 = (long) (load * factorL3);
    }
    long reactivePower = 0;
    long reactivePowerL1 = 0;
    long reactivePowerL2 = 0;
    long reactivePowerL3 = 0;
    if (reactivePowerLoad != null) {
        reactivePower = reactivePowerLoad.getLoad();
        reactivePowerL1 = reactivePower / 3;
        reactivePowerL2 = reactivePower / 3;
        reactivePowerL3 = reactivePower / 3;
    }
    for (EssNature entry : essNatures) {
        if (entry instanceof SymmetricEssNature) {
            SymmetricEssNature ess = (SymmetricEssNature) entry;
            activePower -= ess.activePower().valueOptional().orElse(0L);
            activePowerL1 -= ess.activePower().valueOptional().orElse(0L) / 3;
            activePowerL2 -= ess.activePower().valueOptional().orElse(0L) / 3;
            activePowerL3 -= ess.activePower().valueOptional().orElse(0L) / 3;
            reactivePower -= ess.reactivePower().valueOptional().orElse(0L);
            reactivePowerL1 -= ess.reactivePower().valueOptional().orElse(0L) / 3;
            reactivePowerL2 -= ess.reactivePower().valueOptional().orElse(0L) / 3;
            reactivePowerL3 -= ess.reactivePower().valueOptional().orElse(0L) / 3;
        } else if (entry instanceof AsymmetricEssNature) {
            AsymmetricEssNature ess = (AsymmetricEssNature) entry;
            activePower -= ess.activePowerL1().valueOptional().orElse(0L) + ess.activePowerL2().valueOptional().orElse(0L) + ess.activePowerL3().valueOptional().orElse(0L);
            activePowerL1 -= ess.activePowerL1().valueOptional().orElse(0L);
            activePowerL2 -= ess.activePowerL2().valueOptional().orElse(0L);
            activePowerL3 -= ess.activePowerL3().valueOptional().orElse(0L);
            reactivePower -= ess.reactivePowerL1().valueOptional().orElse(0L) + ess.reactivePowerL2().valueOptional().orElse(0L) + ess.reactivePowerL3().valueOptional().orElse(0L);
            reactivePowerL1 -= ess.reactivePowerL1().valueOptional().orElse(0L);
            reactivePowerL2 -= ess.reactivePowerL2().valueOptional().orElse(0L);
            reactivePowerL3 -= ess.reactivePowerL3().valueOptional().orElse(0L);
        }
    }
    for (MeterNature entry : meterNatures) {
        if (entry instanceof SymmetricMeterNature) {
            SymmetricMeterNature meter = (SymmetricMeterNature) entry;
            activePower -= meter.activePower().valueOptional().orElse(0L);
            activePowerL1 -= meter.activePower().valueOptional().orElse(0L) / 3;
            activePowerL2 -= meter.activePower().valueOptional().orElse(0L) / 3;
            activePowerL3 -= meter.activePower().valueOptional().orElse(0L) / 3;
            reactivePower -= meter.reactivePower().valueOptional().orElse(0L);
            reactivePowerL1 -= meter.reactivePower().valueOptional().orElse(0L) / 3;
            reactivePowerL2 -= meter.reactivePower().valueOptional().orElse(0L) / 3;
            reactivePowerL3 -= meter.reactivePower().valueOptional().orElse(0L) / 3;
        } else if (entry instanceof AsymmetricMeterNature) {
            AsymmetricMeterNature meter = (AsymmetricMeterNature) entry;
            activePower -= meter.activePowerL1().valueOptional().orElse(0L) + meter.activePowerL2().valueOptional().orElse(0L) + meter.activePowerL3().valueOptional().orElse(0L);
            activePowerL1 -= meter.activePowerL1().valueOptional().orElse(0L);
            activePowerL2 -= meter.activePowerL2().valueOptional().orElse(0L);
            activePowerL3 -= meter.activePowerL3().valueOptional().orElse(0L);
            reactivePower -= meter.reactivePowerL1().valueOptional().orElse(0L) + meter.reactivePowerL2().valueOptional().orElse(0L) + meter.reactivePowerL3().valueOptional().orElse(0L);
            reactivePowerL1 -= meter.reactivePowerL1().valueOptional().orElse(0L);
            reactivePowerL2 -= meter.reactivePowerL2().valueOptional().orElse(0L);
            reactivePowerL3 -= meter.reactivePowerL3().valueOptional().orElse(0L);
        }
    }
    if (isOffGrid(essNatures)) {
        this.activePower.updateValue(null);
        this.activePowerL1.updateValue(null);
        this.activePowerL2.updateValue(null);
        this.activePowerL3.updateValue(null);
        this.reactivePower.updateValue(null);
        this.reactivePowerL1.updateValue(null);
        this.reactivePowerL2.updateValue(null);
        this.reactivePowerL3.updateValue(null);
    } else {
        this.activePower.updateValue(activePower);
        this.activePowerL1.updateValue(activePowerL1);
        this.activePowerL2.updateValue(activePowerL2);
        this.activePowerL3.updateValue(activePowerL3);
        this.reactivePower.updateValue(reactivePower);
        this.reactivePowerL1.updateValue(reactivePowerL1);
        this.reactivePowerL2.updateValue(reactivePowerL2);
        this.reactivePowerL3.updateValue(reactivePowerL3);
    }
}
Also used : AsymmetricEssNature(io.openems.api.device.nature.ess.AsymmetricEssNature) EssNature(io.openems.api.device.nature.ess.EssNature) SymmetricEssNature(io.openems.api.device.nature.ess.SymmetricEssNature) SymmetricMeterNature(io.openems.api.device.nature.meter.SymmetricMeterNature) AsymmetricMeterNature(io.openems.api.device.nature.meter.AsymmetricMeterNature) MeterNature(io.openems.api.device.nature.meter.MeterNature) SymmetricMeterNature(io.openems.api.device.nature.meter.SymmetricMeterNature) AsymmetricMeterNature(io.openems.api.device.nature.meter.AsymmetricMeterNature) SymmetricEssNature(io.openems.api.device.nature.ess.SymmetricEssNature) AsymmetricEssNature(io.openems.api.device.nature.ess.AsymmetricEssNature)

Example 4 with SymmetricEssNature

use of io.openems.api.device.nature.ess.SymmetricEssNature in project openems by OpenEMS.

the class Ess method toString.

@Override
public String toString() {
    StringBuilder b = new StringBuilder();
    b.append(// 
    ess.id() + " [" + "SOC:" + ess.soc().format() + "|");
    if (ess instanceof SymmetricEssNature) {
        SymmetricEssNature e = (SymmetricEssNature) ess;
        b.append("L:" + e.activePower().format() + ";" + e.reactivePower().format());
    }
    if (ess instanceof AsymmetricEssNature && ess instanceof SymmetricEssNature) {
        b.append("|");
    }
    if (ess instanceof AsymmetricEssNature) {
        AsymmetricEssNature e = (AsymmetricEssNature) ess;
        b.append(// 
        "L1:" + e.activePowerL1().format() + ";" + e.reactivePowerL1().format() + "|" + "L2:" + e.activePowerL2().format() + ";" + e.reactivePowerL2().format() + // 
        "|" + "L3:" + e.activePowerL3().format() + ";" + e.reactivePowerL3().format());
    }
    b.append(// 
    "|" + "Allowed:" + ess.allowedCharge().format() + ";" + ess.allowedDischarge().format());
    b.append(// 
    "|" + "GridMode:" + ess.gridMode().labelOptional().orElse("unknown"));
    List<ThingStateChannel> warningChannels = ess.getStateChannel().getWarningChannels().stream().filter(c -> c.isValuePresent() && c.getValue()).collect(Collectors.toList());
    List<ThingStateChannel> faultChannels = ess.getStateChannel().getFaultChannels().stream().filter(c -> c.isValuePresent() && c.getValue()).collect(Collectors.toList());
    if (warningChannels.size() > 0) {
        b.append("|Warn:");
        b.append(warningChannels.stream().map(c -> c.name()).collect(Collectors.joining(",")));
    }
    if (faultChannels.size() > 0) {
        b.append("|Fault:");
        b.append(faultChannels.stream().map(c -> c.name()).collect(Collectors.joining(",")));
    }
    b.append("]");
    return b.toString();
}
Also used : List(java.util.List) SymmetricEssNature(io.openems.api.device.nature.ess.SymmetricEssNature) AsymmetricEssNature(io.openems.api.device.nature.ess.AsymmetricEssNature) IsThingMap(io.openems.api.controller.IsThingMap) ThingMap(io.openems.api.controller.ThingMap) Collectors(java.util.stream.Collectors) ThingStateChannel(io.openems.api.channel.ThingStateChannel) EssNature(io.openems.api.device.nature.ess.EssNature) ThingStateChannel(io.openems.api.channel.ThingStateChannel) SymmetricEssNature(io.openems.api.device.nature.ess.SymmetricEssNature) AsymmetricEssNature(io.openems.api.device.nature.ess.AsymmetricEssNature)

Aggregations

SymmetricEssNature (io.openems.api.device.nature.ess.SymmetricEssNature)4 AsymmetricEssNature (io.openems.api.device.nature.ess.AsymmetricEssNature)2 EssNature (io.openems.api.device.nature.ess.EssNature)2 JsonArray (com.google.gson.JsonArray)1 Point (com.vividsolutions.jts.geom.Point)1 ThingStateChannel (io.openems.api.channel.ThingStateChannel)1 IsThingMap (io.openems.api.controller.IsThingMap)1 ThingMap (io.openems.api.controller.ThingMap)1 DeviceNature (io.openems.api.device.nature.DeviceNature)1 AsymmetricMeterNature (io.openems.api.device.nature.meter.AsymmetricMeterNature)1 MeterNature (io.openems.api.device.nature.meter.MeterNature)1 SymmetricMeterNature (io.openems.api.device.nature.meter.SymmetricMeterNature)1 InvalidValueException (io.openems.api.exception.InvalidValueException)1 SystemDeviceNature (io.openems.impl.protocol.system.SystemDeviceNature)1 List (java.util.List)1 Collectors (java.util.stream.Collectors)1