Creating Wh from an item with only instant W

Or another Item updated from the rule itself or a variable put into cache: https://next.openhab.org/addons/automation/jsscripting/#cache

Since the existing Item is updated over MQTT, you have no idea in the rule if it has the old value or the new value when the rule runs, so you can’t really rely on that Item in your rule anyway.

I’m not sure when the updates were/will be made available. You’ll almost certainly need to upgrade to at least the latest milestone, possibly the latest snapshot (or you’ll need to install the latest using npm). Then see GitHub - openhab/openhab-js: openHAB JavaScript Library for JavaScript Scripting Automation.

There is a link to this in the docs as well: Manual | js-joda

I’m trying to do some things… I’ve modified the LastUpdate to being updated from the rule. It’s working but I cannot transform back to datetime when reading the item:

var now = time.ZonedDateTime.now().withFixedOffsetZone();
var item_lu = items.getItem('InverterPV_PVPower_LastUpdate');
var lastupdate = item_lu.state.toString();
var lastupdatee = time.ZonedDateTime.parse(lastupdate);
...other code...
item_lu.postUpdate(now.toString());

I receive this error:

org.graalvm.polyglot.PolyglotException: JsJodaException: Text '2022-06-07T21:10:07.518+0200' could not be parsed at index 23: 2022-06-07T21:10:07.518+0200, at index: 23

	at <js>.parse2(webpack://openhab/./node_modules/@js-joda/core/dist/js-joda.esm.js?:7706) ~[?:?]

	at <js>.parse(webpack://openhab/./node_modules/@js-joda/core/dist/js-joda.esm.js?:7676) ~[?:?]

Why mess with Strings at all?

var lastupdate = item_lu.rawState.getZonedDateTime();

The post problem is one I’ve seen reported on the forum before. Sometimes ZDT will put the timezone in the string in a way that Joda can’t parse. But LocalDateTime doesn’t have that problem.

item_lu.postUpdate(time.LocalDateTime.now().toString());

Do that command export epoch millis?
my value is:
InverterPV_PVPower Last Update formatted 1654701425266

This resolve my problem while using historicState that before create a tons of “java heap error” with the need of restart of openhab

var previousvalue = item.history.historicState(lastupdatee);

No, that command gets a ZonedDateTime from the DateTimeType state of that Item. Since you are parsing I assumed you had a DateTimeType.

If you have epoch? I’m surprised it can parse epoch to a ZonedDateTime since it’s missing the timezone information entirely.

So it’s a strange behavior?
Can I use it for find time for now-pastupdatee?

btw is not used anymore, but I’m going crazy how to use the same factor with historical data, for example:

var previousupdate =  item.history.lastUpdate();
//var previousupdatee = time.ZonedDateTime.parse(previousupdate.toString());
//var previousupdatee = timeUtils.toDateTime(previousupdate);
var previousupdatee = item.rawState.history.lastUpdate().getZonedDateTime();

if I try item.rawState ecc I receive error

org.graalvm.polyglot.PolyglotException: TypeError: undefined has no such function "lastUpdate"

I wouldn’t say it’s strange. It’s just not something I would have expected to work. The API docs don’t mention it.

When in doubt check the docs. JavaScript Scripting - Automation | openHAB. Don’t just flail about trying stuff at random.

An Item’s state has no ‘history’ days data member so

item.rawState.history.lastUpdate().getZonedDateTime()

is never something that will work.

But the docs show that the Item has history and that lastUpdate() returns a JavaScript Date, not a ZonedDateTime.

I being crazy trying to understand difference from js-joda and java time… and how to make to work together…
I’m sorry if I use many comments but still trying to understand what happens…

var {alerting} = require('personal');
//var {timeUtils} = require('openhab_rules_tools');

var now = time.LocalDateTime.now(); //.withFixedOffsetZone(); //.toEpochMilli();
var logger = log('Watt to Wh');
//java.lang.Thread.sleep(500);

//var item = items.getItem(event.itemName);
var item = items.getItem('InverterPV_PVPower');
//var item_lu = items.getItem(event.itemName + '_LastUpdate');
var item_lu = items.getItem('InverterPV_PVPower_LastUpdate');

var pastupdate = item_lu.rawState.getZonedDateTime();
var lastvalue = item.state;
var previousvalue = item.history.historicState(pastupdate);  //var previousvalue = item.history.previousState(true);

var delta = '';
//var delta = time.Duration.between(pastupdatee, now); 
//var delta = time.now.minus(pastupdatee);

logger.info(now);
logger.info('Handling update for: ' + item.name + ' = ' + item.state);
logger.info(item.name + '  Past Update string: ' + item_lu.state.toString() + ' Now is: ' + now.toString() ); //logger.debug
logger.info(item.name + '  Past Update formatted ' + pastupdate );
logger.info(item.name + '  Last value is: -> ' + lastvalue + ' Past value is: -> ' + previousvalue );
logger.info(item.name + ' Delta: -> ' + delta.toString() );

item_lu.postUpdate(time.LocalDateTime.now().toString());  //update with new time

In general, endeavor to always convert to and only use ZonedDateTime and you will usually be fine (with that one exception with post update which is hopefully temporary). time.toZDT() will convert what ever is passed to it, of it can, to a ZonedDateTime.

I think I have another problem…
if I do
var xxx = time.toZDT(pastupdate); to transform to JS-Joda time, i receive

org.graalvm.polyglot.PolyglotException: TypeError: (intermediate value).toZDT is not a function

Got it after looking into the community…

thanks to time.Duration.between StackOverflow error with items - #2 by cinadr

var delta = time.Duration.between(time.ZonedDateTime.parse(pastupdate.toString()), now).toMillis(); 

Any way to have directly seconds? or do I have to divide by 1000?

I’ve finally fixed my code…

var {alerting} = require('personal');
var logger = log('Watt to Wh');

var now = time.ZonedDateTime.now(); 
var time_update = time.LocalDateTime.now();

//java.lang.Thread.sleep(500);

var item = items.getItem(event.itemName);
//var item = items.getItem('InverterPV_PVPower');
var item_lu = items.getItem(event.itemName + '_LastUpdate');
//var item_lu = items.getItem('InverterPV_PVPower_LastUpdate');
var item_wh = items.getItem(event.itemName + '_H');
//var item_wh = items.getItem('InverterPV_PVPower_H');
if (item_lu.state == 'NULL') {
     item_lu.postUpdate(time.LocalDateTime.now().toString());
     java.lang.Thread.sleep(500);
}

var pastupdate = item_lu.rawState.getZonedDateTime();

var lastvalue = item.state;
var previousvalue = item.history.historicState(pastupdate);  //var previousvalue = item.history.previousState(true);

var delta = '';
var delta = time.Duration.between(time.ZonedDateTime.parse(pastupdate.toString()), now).toMillis()/1000;
//var delta = time.Duration.between(time.ZonedDateTime.parse(pastupdate.toString()), now).seconds();
var updates_h = 1 / (3600/delta);
var Wh = (previousvalue * (1 / (3600/delta))).toFixed(4);
var kWh = (Wh/1000);
item_wh.postUpdate(Wh);

logger.info(now);
logger.info('Handling update for: ' + item.name + ' = ' + item.state);
logger.info(item.name + '  Past Update string: ' + item_lu.state.toString() + '          Now is: ' + now.toString() ); //logger.debug
logger.info(item.name + '  Past Update formatted ' + pastupdate );
logger.info(item.name + '  Last value is: -> ' + lastvalue + '         Past value is: -> ' + previousvalue );
logger.info(item.name + '  Delta: -> ' + delta.toString() + '           Updates/h: ' + updates_h.toString());
logger.info(item.name + '  Actual Wh: ' + Wh.toString() + '   Actual kWh: ' + kWh.toString());

item_lu.postUpdate(time_update.toString());  //update LastUpdate item with new time

Now my log looks like:

2022-06-11 00:34:59.443 [INFO ] [openhab.automation.script.watt to wh] - 2022-06-11T00:34:59.387+02:00[SYSTEM]

2022-06-11 00:34:59.446 [INFO ] [openhab.automation.script.watt to wh] - Handling update for: InverterPV_ACOutputW = 148

2022-06-11 00:34:59.449 [INFO ] [openhab.automation.script.watt to wh] - InverterPV_ACOutputW  Past Update string: 2022-06-11T00:34:54.446+0200          Now is: 2022-06-11T00:34:59.387+02:00[SYSTEM]

2022-06-11 00:34:59.451 [INFO ] [openhab.automation.script.watt to wh] - InverterPV_ACOutputW  Past Update formatted 1654900494446

2022-06-11 00:34:59.453 [INFO ] [openhab.automation.script.watt to wh] - InverterPV_ACOutputW  Last value is: -> 148         Past value is: -> 150

2022-06-11 00:34:59.455 [INFO ] [openhab.automation.script.watt to wh] - InverterPV_ACOutputW  Delta: -> 4.941           Updates/h: 0.0013725

2022-06-11 00:34:59.457 [INFO ] [openhab.automation.script.watt to wh] - InverterPV_ACOutputW  Actual Wh: 0.2059   Actual kWh: 0.0002059

But now I have my item having power consuption for the delta (usually 5sec).
Do I have to add another rule to calculate daily power consuption? Like

var {alerting} = require('personal');
var logger = log('Daily Wh calculator');

var today = time.ZonedDateTime.now().withHour(0).withMinute(0);

var item = items.getItem('InverterPV_ACOutputW_H');
var item_daily = items.getItem('[itemdaily]');

var totalpower = item.history.sumSince(today)/1000;

logger.info('Total daily power: ' + totalpower.toString() + "kWh");

And item may show Wh or kWh automatically? Or if I set Wh it will be always Wh?
My Item is:

  • Name: InverterPV_ACOutputW_H
  • Label: Used Power Wh
  • Type: Number:Energy
  • Category energy
  • Semantic Class: Measurement
  • Semantic Property: Energy

Yes.

You can choose which units you want to see regardless of the units the Item holds. For example, if you skip the divide by 1000 and update the Item using totalpower + "Wh" and set the Item’s State Description pattern to %.0f kWh it will show kWh on your UI even though the value stored by the Item is Wh.

Ok so better to work with kWh

But it’s possible that my rule, called from 2 items updated together, may interfere each other and I have wrong values?

2022-06-13 16:57:40.503 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_ACOutputW' changed from 434 to 427
2022-06-13 16:57:40.543 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_PVPowerW' changed from 500 W to 501 W
2022-06-13 16:57:40.547 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_ACOutputWh' changed from 0.2803 to 0.6027
2022-06-13 16:57:40.552 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_ACOutputW_LastUpdate' changed from 2022-06-13T16:57:35.504+0200 to 2022-06-13T16:57:40.506+0200
2022-06-13 16:57:40.590 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_PVPowerWh' changed from 0.4574 to 0.6942
2022-06-13 16:57:40.595 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_PVPowerW_LastUpdate' changed from 2022-06-13T16:57:35.558+0200 to 2022-06-13T16:57:40.557+0200
2022-06-13 16:57:49.932 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_ACOutputWh' changed from 0.6027 to 1.1088
2022-06-13 16:57:49.942 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_ACOutputW_LastUpdate' changed from 2022-06-13T16:57:40.506+0200 to 2022-06-13T16:57:49.857+0200
2022-06-13 16:57:50.025 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_PVPowerWh' changed from 0.6942 to 1.3072
2022-06-13 16:57:50.033 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_PVPowerW_LastUpdate' changed from 2022-06-13T16:57:40.557+0200 to 2022-06-13T16:57:49.952+0200
2022-06-13 16:57:54.865 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_ACOutputW' changed from 427 to 422

I call the rule for both InverterPV_ACOutputW and InverterPV_PowerW

Only one instance of a given rule can run at a time. If the rule is already running when triggered again, the second trigger will wait for the rule to exit before running the rule again.

So it’s impossible that first item value are “modified” from second item when firing the same rule? So it’s only my suggestion… Good to know. Thanks

I’m sorry if I’m opening this thread again but… The rule after update of Openhab to version 4 is not working anymore. As I understood, it is because I cannot read an item as Number:Power (instant power), calculate and then send to an item as Number: Energy.
And I I have to admit that I didn’t understand the quantity and modification of the target measurements.

Hope someone can help

It has been two years. Post your latest version of the rule.

Yes you’re right.
this is my code without any modifications:

var logger = log('Watt to Wh');

var now = time.ZonedDateTime.now(); 
var time_update = time.LocalDateTime.now();

var item = items.getItem(event.itemName);
//var item = items.getItem('InverterPV_PVPowerW');  //Testing purpose
var item_lu_meta = item.getMetadataValue('last_update') || time.LocalDateTime.now().toString();
var item_lu = items.getItem(event.itemName + '_LastUpdate');
//var item_lu = items.getItem('InverterPV_PVPowerW_LastUpdate');  //Testing purpose
var item_wh = items.getItem(event.itemName + 'h');
//var item_wh = items.getItem('InverterPV_PVPowerWh');  //Testing purpose
if (item_lu.state == 'NULL') {
     item_lu.postUpdate(time.LocalDateTime.now().toString());
     java.lang.Thread.sleep(500);
}

var pastupdate = item_lu.rawState.getZonedDateTime(); //Using last-update item
var pastupdate_meta = time.ZonedDateTime.parse(item_lu_meta);  //Using callign item metadata

var lastvalue = item.state;

var previousvalue = item.history.historicState(pastupdate_meta);

if (lastvalue !== previousvalue) {
    var delta = time.Duration.between(time.ZonedDateTime.parse(pastupdate.toString()), now).toMillis()/1000;
 
    if (delta < 30) {  //Check if last update was less than half minute, otherwise discard
      //var updates_h = 1 / (3600/delta);
      var Wh = (previousvalue * (1 / (3600/delta))).toFixed(4);
      item_wh.postUpdate(Wh);
    }
    else {
      logger.info('Update too old... Last update was: ' + delta.toString());
    }
    item_lu.postUpdate(time_update.toString());  //update LastUpdate item with new time
    item.updateMetadataValue('last_update',now.toString());
}