Beginner Questions

Hello!

I’m new here and I don’t have much background in Java. Really good work! I would like to learn more about how does OpenEMS does the allocation of loads. I could see that when the battery is completely full it will automatically send the power to the grid. Where exactly can I see this part of the code? For example, if I want to add more storage sources, for instance, another type of battery, what should I do?

My idea is to create my own system with PV production (maybe also other sources) and different storage systems, that with the EMS the user can decide how to allocate the loads i.e: the user prefers to charge the battery until 80% only and the rest of production goes to the grid.

Hi Carlos,

Thanks for getting in touch. Power is not actually ‘sent to grid’. It rather follows the simple formula that in each point in time Consumption = Grid + Production + Storage (where Grid and Storage may also be negative values, meaning ‘sell-to-grid’ or ‘charge battery’ respectively). I posted some slides of my lecture a while ago here (sorry - German): FH Kiel: Pro 9-12 + OpenEMS Potential.

With this formula in mind we can control:

  • charge/discharge the battery
  • curtail photovoltaics production
  • start additional generators
  • start/stop/reduce consumption

and as a result the grid exchange power will change. And this is what OpenEMS Controllers do.In our Gidpod Live-Demo you can play with this yourself, using OpenEMS as a simulator:

For your use-case you could write a Controller that evaluates with how much power you would want to charge/discharge any of your storage systems (e.g. stop at 80 %). The rest is solved by physicis :wink:

Regards,
Stefan

Hello Stefan,

Thanks a lot for the prompt reply. I read the presentation and it helped me to understand much more. Now I have some other questions:

  • So I’m still quite new with Java but I wanted to know exactly where is it stated this simple formula of the consumption is equal to the sum of production, grid, and storage.
  • I can change the values of Grid, Storage, and PV production for fixed values in the simulator, so I can put negative values if I want them to change direction/charge. But of course, all these values including the PV production vary throughout the day. Is it possible to input a series of values? Maybe real-time data?
  • About the Energymonitor feature, I’m not able to make it show trends, do I have to do something specific for it to work?

Thanks again, it is really interesting for me, I’ll keep playing with the simulator and reading the codes so that I can write a controller with the function you suggested.

Best regards,
Carlos

Hi Carlos,

The calculation for the _sum/ConsumptionActivePower-Channel is here:

Yes of course. The example simulation is just very simplified to not get overwhelmed with everything at once. The simulator uses Datasources to provide the data. In the Gitpod there are three Simulator.Datasource.Single.Direct configured (- by the way: the configuration file for the docker container is here)

You could easily enter multiple values in that configuration (e.g. via Apache Felix or OpenEMS UI) or e.g. use a simulator that takes a CSV-file (see openems/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource at develop · OpenEMS/openems · GitHub).

What do you mean by “show trends” exactly?

Regards,
Stefan

Hi Stefan

Thanks a lot for replying. As you see I took some time to understand more about the code. I’ve been looking into more details and I had some questions about it, hope you or anyone can help me with it.

*I’m thinking of doing optimization of the power allocation, for example, I would like the EMS to allocate the energy efficiently to my system, fulfill my consumption first, then charge the storage system and then sell it to the grid if possible. Of course, here there would be some factors like the market selling price: if the selling price is good, and it is better than storing it, then the EMS should automatically change the first approach to this one. And maybe other factors apart from the market price can be added here. Is it feasible what I’m thinking? Or maybe openEMS already do this?

*Also I have a question about the CSV files, so if I want to use new data sets for my simulation I should just add a csv file in the csv/predefined folder? Going few more steps ahead, is it possible to save data acquired from a meter (say for example in the PV modules), save it automatically as a csv file and make the code read the most recent one?

Regarding my previous last question, I was referring to this:


It shows nothing when I tried, I guess I need to activate some other functions first! I will check it out.

Best regards,
Carlos

Hi Carlos,

Optimization of power allocation:
As we discussed in person, good examples for similar Controllers are:

and

CSV file
The way we usually do it, is:

  • Record data via Timedata.InfluxDB into an InfluxDB database
  • Analyze data using Grafana (https://grafana.com/)
  • Export data from Grafana to CSV
  • Import to OpenEMS

This gives good control about what data we want to use for simulation and in which resolution (e.g. one value per second or one value per 15 minutes).

Otherwise, see also this post for details on how to implement your own Datasource: EMS-Simulation durch Daten aus DB statt CSV-Dateien - #2 by stefan.feilmeier

UI historic view

The Datasource for simulated meters is a different concept than the Timedata provider. I understand, that those can easily get mixed up.

  • Datasource provides a new value on each Cycle for live simulation
  • Timedata provides access to historic data that it was previously recording

Regards,
Stefan

Hi Stefan,

Thanks as always for the reply. I’m looking at the controllers and also as suggested by you the balancing controller.

  • First I have a question about the balancing controller. We have below the definition of the “calculateRequiredPower” method, it uses the “meter.getActivePower().getOrError()” which I understand represents the current buying or selling power from the grid, then it sums “ess.getActivePower().getOrError()” that represents the current power charging or discharging the battery, and lastly it subtracts “config.targetGridSetpoint()” which if I believe it is predetermined as 0. What does this last term mean? and why it is subtracted?

      private int calculateRequiredPower(ManagedSymmetricEss ess, SymmetricMeter meter) throws InvalidValueException {
      	return meter.getActivePower().getOrError() /* current buy-from/sell-to grid */
      			+ ess.getActivePower().getOrError() /* current charge/discharge Ess */
      			- config.targetGridSetpoint(); /* the configured target setpoint */
    
  • Now, I’m doing a simple example of optimization, so I consider a system with PV production, a battery and grid connected. So based in the grid optimized charge controller I thought about the some possible scenarios to model, all of them with if/else commands. For example, one case would be with my system having insufficient PV energy production, and the logic would be: if I have charge in my battery, use it, otherwise get from grid. I think it would look like this (not sure yet how to write it):

       if (meter.getActivePower().getOrError() + ess.getActivePower().getOrError() > 0) {
              if (battery?.getCapacity() > 0){
                  return "use battery for consumption";
              }else{
                  "get from grid"
              }
          } else if ...
    

Does it makes sense? Is there a way to have the “use battery” or “get from grid”?

Best regards,
Carlos

Hi Carlos,

First question you got completely correct. The targetGridSetpoint configuration settings allows to balance to a different value than 0 on the grid - e.g. if you set it to -1000 it would continuously try to feed 1 kW to grid, i.e. charging the battery when there is more feed-to-grid power and discharging the battery when in the evening there is less feed-to-grid power by PV.

Regarding the calculation, see this example:

  • Initial setting:
    • currently measured grid power = 5000 (i.e. 5 kW buy from grid)
    • current battery-inverter power = 0 (i.e. no charging or dischargin)
    • target set-point: -1000 (i.e. continously sell to grid 1 kW)
    • set-point for battery: 5000 - 0 + 1000 = 6000 (discharge battery with 6 kW to compensate buy-from-grid power plus sell-to-grid with 1 kW)
  • Next Cycle (ideally):
    • currently measured grid power = -1000 (i.e. as result of discharging the battery)
    • current battery-inverter power = 6000 (i.e. discharge with 6 kW)
    • target set-point: -1000 (i.e. continously sell to grid 1 kW)
    • set-point for battery: -1000 - 6000 + 1000 = 6000 (stay same because grid power is already exactly matching)

I say “ideally”, because in reality battery-inverters have a power ramp, meters take some time to measure, communication takes a while and consumption may change inbetween. There is a PID filter in place to compensate this.

Regarding your second point: you do not necessarily have to check here if the battery still has remaining capacity. This is internally handled here, wenn the battery-inverter set-point is checked against its current min-/max-values:

If you wanted to e.g. stop discharging early - lets say at 30 % state-of-charge, your approach would be correct. Just use battery.getSoc() instead; it gives state-of-charge in percentage. Capacity is the nominal capacity of the (full) battery.

In the end your algorithm should come up with set-points for devices you can actually control, i.e. a energy storage system (battery+battery-inverter), a CHP, a Diesel generator,… as you are not able to directly control the “get from grid” power.

Regards,
Stefan

Hi Stefan,

Thank you, the example was really helpful. Now I have another question about it, so as for the initial setting, the currently measured grid power is 5kW because we want to consume it, or charge the battery? how does the consumption or charging is differentiated? Why is it that in the set point for battery we “discharge the battery with 6kW”? the battery is not in 0? or is it that we buy from the grid in total 6kW and charge the battery? (going again through the first question, does the power bought from the grid always go through the battery before consumption?)

What I understand is that we need 5kW and always sell 1kW, then we need 6kW to fulfill the next cycle requirement. As for the next ideal cycle, the measured grid power is -1000 because we are fulfilling the target setpoint (selling from our 6kW) and the setpoint for battery stays the same because in this example we do not require more power either for consumption or battery. If we, e.g. need 4kW more, then the setpoint for the battery would be different right? (9kW in total)

And regarding this:

Perfect, then I will rethink the algorithm with controllable devices.

Best regards,
Carlos

We measure the power at Grid Buy/Sell (1), Production (2) and Battery Charge/Discharge (3). From those values Consumption (4) can be calculated. The measured power the the grid can only be influenced by production, battery charge/discharge or consumption. As we know about production and battery, because we measure them, it can only come from consumption.

In first cycle, the measured battery charge/discharge is 0 kW. We give a set-point of 6 kW, so that ideally in the second cycle we measure a power of 6 kW for charge/discharge. No, power is of course not always going through the battery.

In the example 6 kW would actually be required to fulfil the requirement of the first cycle, but in control systems we always lag (at least) one cycle behind.

For your example: yes, if either the consumption would increase by 4 kW (e.g. some device turned on) or the production would decrease by 4 kW (e.g. a cloud above the pv system), this would get directly reflected on the measured grid power. The grid value would then be 3000 instead of -1000 and as such the new set-point for discharging the battery would be 9000.

Hello again!

Thanks for the reply as always. After some time of planning and understanding openEMS, we decided for our thesis work to use something similar to the “gridoptimizedcharge” controller that you shared previously, maybe adding other optimization parameters like “priorities” of usage e.g. if we have different sources of production (wind, PV or even diesel generator) which one should take priority for consumption or charging. I still need to think about how is it going to be, do you think this approach makes sense?

And here it comes another question, I’ve been able to implement new controllers and meters from what there is already in openEMS, but now I would like to simulate, as said before, more production devices and also storage. I understand that in the UI we see the sum of all the production and the ess as a whole, what should I do to be able to see them separately? For example, below I edited a screenshot:

Hi Carlos,

ok, good to know that gridoptimizedcharge is a good example for you. (Just pinging the developer here: @sebastian.asen)

Yes, that approach is very good for now.

Additional production or storage will simply show up additionally under “Production” and “Storage”. The OpenEMS Gitpod (Gitpod - Dashboard) is a good example.

The current logic for showing all storage devices in the UI is here. As a side note, we are currently refactoring the UI-Widgets, see #1414 and 1445.

Hello again!

I’ve been trying to implement a new generation device (specifically a diesel generator) that starts working only when the production is less than expected (from a prediction). But I’m having a hard time finding the way to do this.

What do you recommend?

Best regards,
Carlos

I typically like approaching the problem using a state-machine. If all the power values were very static, you could easily do some if... else logic to solve the problem. But power values change all the time and you typically want to establish some more advanced logics in time - e.g.

  • define a hysteresis for allowed error of the prediction before the generator starts
  • start the generator only after some hysteresis time
  • set a minimum running time for the diesel generator

A state-machine allows to clearly separate the logic and makes development and debugging easier. See this example for a state-machine:

mermaid-diagram-20210502212137

(Created using Mermaid JS Live Editor)

You will find state-machines used a lot throughout the OpenEMS project, example: openems/statemachine.md at develop · OpenEMS/openems · GitHub

Regards,
Stefan

Hello Stefan!

Sorry for taking so long to keep you updated, a lot of things have happened.

Taking into account the approach you suggested to me of the state-machine I started working on it, taking as reference the one that you also suggested. So in order to make it work, I need to define the hysteresis time and the prediction. For the first, how should it look like?

Regarding the prediction, I know that in OpenEMS there’s already the simple prediction component, but since I wanted to add something new, I looked at the WEKA time series forecasting API. I was able to get a generation data for one month, every 15 minutes, and I wanted to forecast 2 days ahead with that data. Using the time series forecaster I was able to get this result:


I might need to change the x-axis to show the actual dates. But the last 192 results are the prediction. The error is quite high for the last results but I think more than that is not possible without some Machine Learning. Anyway, since I was able to get this result, and also run it with the code in eclipse I decided to integrate it. I read how to integrate an external library to OSGi, but I had no luck, first I tried creating the .bnd file containing the following information:

-classpath: timeseriesforecasting1.1.27.jar
-output: timeseriesforecasting-1.1.27.jar
Export-Package: *;-split-package:=merge-last;-noimport:=true
Import-Package: *
Bundle-Version: 1.1.27
Bundle-Name: Time Series Forecasting
Bundle-SymbolicName: 

But after that, I don’t know what to do, and it does not seem like it became a bundle. What am I missing?

Below is the code for the forecasting provided as an example from WEKA, I modified some lines to use the mathematical model that fits the best and other numbers of prediction.

 package io.openems.edge.forecaster;

import java.io.*;

import java.util.List;
import weka.core.Instances;
import weka.classifiers.functions.SMOreg;
import weka.classifiers.evaluation.NumericPrediction;
import weka.classifiers.timeseries.WekaForecaster;
//import weka.classifiers.timeseries.core.TSLagMaker;
 
/**
 * Example of using the time series forecasting API. To compile and
 * run the CLASSPATH will need to contain:
 *
 * weka.jar (from your weka distribution)
 * pdm-timeseriesforecasting-ce-TRUNK-SNAPSHOT.jar (from the time series package)
 * jcommon-1.0.14.jar (from the time series package lib directory)
 * jfreechart-1.0.13.jar (from the time series package lib directory)
 */
public class TimeSeriesForecaster {
 
  public static void main(String[] args) {
    try {
      // path 
      String pathToWindData = weka.core.WekaPackageManager.PACKAGES_DIR.toString()
        + File.separator + "timeseriesForecasting" + File.separator + "sample-data"
        + File.separator + "wind.arff";
 
      // load the data
      Instances wind = new Instances(new BufferedReader(new FileReader(pathToWindData)));
 
      // new forecaster
      WekaForecaster forecaster = new WekaForecaster();
 
      // set the targets we want to forecast. This method calls
      // setFieldsToLag() on the lag maker object for us
      forecaster.setFieldsToForecast("capacity (kW)");
 
      // default underlying classifier is SMOreg (SVM)
      forecaster.setBaseForecaster(new SMOreg());
      
      forecaster.getTSLagMaker().setTimeStampField("Date"); // date time stamp
      forecaster.getTSLagMaker().setMinLag(1);
      forecaster.getTSLagMaker().setMaxLag(3); // monthly data
      
      // add a month of the year indicator field
      //forecaster.getTSLagMaker().setAddMonthOfYear(true);
 
      // add a quarter of the year indicator field
      //forecaster.getTSLagMaker().setAddQuarterOfYear(true);
 
      // build the model
      forecaster.buildForecaster(wind, System.out);
 
      // prime the forecaster with enough recent historical data
      // to cover up to the maximum lag.
      forecaster.primeForecaster(wind);
 
      // forecast for 2 days
      List<List<NumericPrediction>> forecast = forecaster.forecast(192, System.out);
 
      // output the predictions. Outer list is over the steps; inner list is over
      // the targets
      for (int i = 0; i < 192; i++) {
        List<NumericPrediction> predsAtStep = forecast.get(i);
        for (int j = 0; j < 1; j++) {
          NumericPrediction predForTarget = predsAtStep.get(j);
          System.out.print("" + predForTarget.predicted() + " ");
        }
        System.out.println();
      }
 
      // we can continue to use the trained forecaster for further forecasting
      // by priming with the most recent historical data (as it becomes available).
      // At some stage it becomes prudent to re-build the model using current
      // historical data.
 
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

Hi,

sorry for the delay in answering; I am missing spare time these days. Embedding external libraries that do not come with the correct OSGi headers can be sometimes difficult. Do you have a source for downloading the jar file - or better the maven coordinates to integrate it in the pom.xml file?

Be aware that you might also run into licensing issues. From what I see, WEKA is licensed as GPL, which ‘might’ be incompatible with OpenEMS’ EPL - but I am not a lawyer (see Eclipse Public License - Wikipedia).

Alternatively to directly embedding an external library, you could also keep the services separated and let them talk to each other with some defined (REST-) Api. See e.g. this Solcast Predictor as an example:

The author is also active here in the Community forum: Veröffentlichung Controller - #5 by stefan.feilmeier

Regards,
Stefan

Hi!

Don’t worry about the late response.

About the source for the jar file, I got it from WEKA webpage/forum. I’m using a specific tool of Weka and I downloaded this jar file from the application (it has an integrated component downloader). On the other hand, the maven coordinates to integrate it, I’m not really familiar with it, so I’m not sure what is it that I need to find, anyways I google it and I got this page:

https://mvnrepository.com/artifact/nz.ac.waikato.cms.weka/timeseriesForecasting/1.1.27

I didn’t know about the issue of the licences. I will now read about it and inform you of any news.

Best regards,
Carlos