Working with timeseries in rules

Hello,

I am trying to “miss use” the openhab-spot-price-optimizer. During winter I am using to optimize when using energy, but now in summer I am using it to optimize when selling energy at the most expencive moment.

Currently I do this via “inversed” logic → 0 for OK to sell energy, 1 for NOK. Problem is this doesn’t represent nicely in a graph.

In order to solve this I was looking into inverting the control points from the time series before persisting it. I am writing the rules in a ECMAScript/Javascript. Is this possible, or is there an obvious way I am missing to do this?

// Load module and create service.
var { GenericOptimizer } = require('openhab-spot-price-optimizer/generic-optimizer.js');
var optimizer = new GenericOptimizer();

// Define price item and control item here.
var priceItem = items.getItem('SpotPrice');
var controlItem = items.getItem('MEB_Discharge_Control'); 

// Read how many hours are needed from the BoilerHours item.
var period =24.0;
var item = items.getItem("MEB_DischargingHours");
var hours = period - parseFloat(item.numericState);
//var hours = parseFloat(item.numericState);

// Define the optimization window here, this example optimizes tomorrow.
var start = time.toZDT('12:00').plusDays(0);
var end = start.plusHours(period);
// Define the delay (seconds) to ensure prices have been saved first.
var delay = 60;

// Read prices from the database, optimize and save the control points.
var delayedFunction = function() {
  var prices = priceItem.persistence.getAllStatesBetween(start, end);
  optimizer.setPrices(prices);
  optimizer.allowIndividualHours(hours);
  optimizer.blockAllRemaining();
  var timeseries = optimizer.getControlPoints();
  //here I am looking how to inverse the control points from the timeseries...
  controlItem.persistence.persist(timeseries);
};
// Create a timer that calls delayedFucntion after the delay.
actions.ScriptExecution.createTimer(time.toZDT().plusSeconds(delay), delayedFunction);

Get the states from the timeseries, iterate and flip the 1s and 0s before persisting them.

timeseries.states.forEach((s, i, a) => a[i][1] = (s[1] == 0) ? 1 : 0);

That iterates over all the states. s is the current state, i is the index, and a is the array of states being iterated. We set the entry in the array to 1 if it’s currently 0 and 0 if it’s anything else (presumably 1).

This works because from the docs: JavaScript Scripting - Automation | openHAB

states: States of the TimeSeries together with their timestamp and sorted by their timestamps. Be aware that this returns a reference to the internal state array, so changes to the array will affect the TimeSeries.

1 Like

Thank you! It gives an error when when just copying the code. I am trying to understand it now, never used foreach…The array is filled with floats, I don’t know if this matters:

PersistedItem (Timestamp=2025-05-14T20:45+02:00[Europe/Brussels], State=0.0)

I tried to adjust if for floats, but it still fail.

timeseries.states.forEach((s, i, a) => a[i][1] = (s[1] == 0.0) ? 1.0 : 0.0);

I was able to log the timeseries, this is how it looks like…

TimeSeries (Begin=2025-05-14T10:00:00Z, End=2025-05-15T09:45:00Z, Size=96, States=[2025-05-14T10:00:00Z -> 1], [2025-05-14T10:15:00Z -> 1], ...

It’s always important to post the error.

It doesn’t.

And the code that builds the states array is:

  add (timestamp, state) {

    const ts = _isInstant(timestamp) ? timestamp : time.toZDT(timestamp).toInstant();

    this.#states.push([ts, state]);

    return this;

  }

As you can see in both the log and here, each state is an array with the first element being the timestamp and the second one being the actual state.

So a[i][1] should be second element of the array which is the i’th element of array a.

Similarly, s should be [timestamp, state] so s[1] should be the state of the element.

Without the error :person_shrugging:

Sorry, the error I get didn’t really tell anything. It a warning and then the rule stops…

20:50:01.271	WARN	org.openhab.core.internal.scheduler.SchedulerImpl	Scheduled job 'org.openhab.automation.script.ui.MEB_discharge_optimizer' failed and stopped```

Sorry, I messed up. Via console.log, I logged the timeseries before and after the foreach and indeed it adjust the states. As you told they would.

console.log(timeseries.states);

The error is due to another reason!

It seems the issue is created by trying to persist the timeseries.

This works without warming, but the data is not saved:

  var timeseries = optimizer.getControlPoints();
  console.log(timeseries);
  timeseries.states.forEach((s, i, a) => a[i][1] = (s[1] == 0) ? 1 : 0);
  console.log(timeseries);

  //controlItem.persistence.persist(timeseries);

This works without warning, but the data is not “inverted”

  var timeseries = optimizer.getControlPoints();
  console.log(timeseries);
  // timeseries.states.forEach((s, i, a) => a[i][1] = (s[1] == 0) ? 1 : 0);
  console.log(timeseries);

  controlItem.persistence.persist(timeseries);

Even when changing a 1 for a 1 and 0 for a 0… it fails to persist…

The time series before and after looks exaclty the same… I am lost :slight_smile:

|22:54:31.166|INFO|org.openhab.automation.script.ui.MEB_discharge_optimizer|TimeSeries (Begin=2025-05-14T10:00:00Z, End=2025-05-14T21:45:00Z, Size=48, States=[2025-05-14T10:00:00Z -> 1], [2025-05-14T10:15:00Z -> 1], [2025-05-14T10:30:00Z -> 1], [2025-05-14T10:45:00Z -> 1], [2025-05-14T11:00:00Z -> 1], [2025-05-14T11:15:00Z -> 1], [2025-05-14T11:30:00Z -> 1], [2025-05-14T11:45:00Z -> 1], [2025-05-14T12:00:00Z -> 1], [2025-05-14T12:15:00Z -> 1], [2025-05-14T12:30:00Z -> 1], [2025-05-14T12:45:00Z -> 1], [2025-05-14T13:00:00Z -> 1], [2025-05-14T13:15:00Z -> 1], [2025-05-14T13:30:00Z -> 1], [2025-05-14T13:45:00Z -> 1], [2025-05-14T14:00:00Z -> 1], [2025-05-14T14:15:00Z -> 1], [2025-05-14T14:30:00Z -> 1], [2025-05-14T14:45:00Z -> 1], [2025-05-14T15:00:00Z -> 1], [2025-05-14T15:15:00Z -> 1], [2025-05-14T15:30:00Z -> 1], [2025-05-14T15:45:00Z -> 1], [2025-05-14T16:00:00Z -> 1], [2025-05-14T16:15:00Z -> 1], [2025-05-14T16:30:00Z -> 1], [2025-05-14T16:45:00Z -> 1], [2025-05-14T17:00:00Z -> 1], [2025-05-14T17:15:00Z -> 1], [2025-05-14T17:30:00Z -> 1], [2025-05-14T17:45:00Z -> 1], [2025-05-14T18:00:00Z -> 0], [2025-05-14T18:15:00Z -> 0], [2025-05-14T18:30:00Z -> 0], [2025-05-14T18:45:00Z -> 0], [2025-05-14T19:00:00Z -> 0], [2025-05-14T19:15:00Z -> 0], [2025-05-14T19:30:00Z -> 0], [2025-05-14T19:45:00Z -> 0], [2025-05-14T20:00:00Z -> 1], [2025-05-14T20:15:00Z -> 1], [2025-05-14T20:30:00Z -> 1], [2025-05-14T20:45:00Z -> 1], [2025-05-14T21:00:00Z -> 1], [2025-05-14T21:15:00Z -> 1], [2025-05-14T21:30:00Z -> 1], [2025-05-14T21:45:00Z -> 1])|
| --- | --- | --- | --- |
|22:54:31.181|INFO|org.openhab.automation.script.ui.MEB_discharge_optimizer|TimeSeries (Begin=2025-05-14T10:00:00Z, End=2025-05-14T21:45:00Z, Size=48, States=[2025-05-14T10:00:00Z -> 1], [2025-05-14T10:15:00Z -> 1], [2025-05-14T10:30:00Z -> 1], [2025-05-14T10:45:00Z -> 1], [2025-05-14T11:00:00Z -> 1], [2025-05-14T11:15:00Z -> 1], [2025-05-14T11:30:00Z -> 1], [2025-05-14T11:45:00Z -> 1], [2025-05-14T12:00:00Z -> 1], [2025-05-14T12:15:00Z -> 1], [2025-05-14T12:30:00Z -> 1], [2025-05-14T12:45:00Z -> 1], [2025-05-14T13:00:00Z -> 1], [2025-05-14T13:15:00Z -> 1], [2025-05-14T13:30:00Z -> 1], [2025-05-14T13:45:00Z -> 1], [2025-05-14T14:00:00Z -> 1], [2025-05-14T14:15:00Z -> 1], [2025-05-14T14:30:00Z -> 1], [2025-05-14T14:45:00Z -> 1], [2025-05-14T15:00:00Z -> 1], [2025-05-14T15:15:00Z -> 1], [2025-05-14T15:30:00Z -> 1], [2025-05-14T15:45:00Z -> 1], [2025-05-14T16:00:00Z -> 1], [2025-05-14T16:15:00Z -> 1], [2025-05-14T16:30:00Z -> 1], [2025-05-14T16:45:00Z -> 1], [2025-05-14T17:00:00Z -> 1], [2025-05-14T17:15:00Z -> 1], [2025-05-14T17:30:00Z -> 1], [2025-05-14T17:45:00Z -> 1], [2025-05-14T18:00:00Z -> 0], [2025-05-14T18:15:00Z -> 0], [2025-05-14T18:30:00Z -> 0], [2025-05-14T18:45:00Z -> 0], [2025-05-14T19:00:00Z -> 0], [2025-05-14T19:15:00Z -> 0], [2025-05-14T19:30:00Z -> 0], [2025-05-14T19:45:00Z -> 0], [2025-05-14T20:00:00Z -> 1], [2025-05-14T20:15:00Z -> 1], [2025-05-14T20:30:00Z -> 1], [2025-05-14T20:45:00Z -> 1], [2025-05-14T21:00:00Z -> 1], [2025-05-14T21:15:00Z -> 1], [2025-05-14T21:30:00Z -> 1], [2025-05-14T21:45:00Z -> 1])|

Unfortunately I don’t know much about timeseries so I can’t begin to guess why the persist part fails. These aren’t carrying units so that complexity isn’t in play. I think someone who knows more about this stuff would need to chime in. I’m out of ideas.

I also solved the last issue… the control points should be in String format!

1 Like