Creating Wh from an item with only instant W

I have a solar inverter connected with SolPipLog that send items to MQTT. That data are sent as instant W every 5 seconds and stored into some items (with persistence working).
I would like to create a total Wh made from photovoltaic system and Wh used from home. Cannot find anything in the forum so I hope it’s not a double question.

The calculation for W to Wh is

W * H = Wh

Where W is the watts, H is hours and Wh are the resultant Watt Hours.

Your inverter reports once every 5 seconds which is about 0.833 hours so every time you receive a reading you’ll multiply the reading by 0.833 and you’ll get the Wh for that five second period of time, assuming that the W remained the same over that five seconds. Put that into a new Item.

Then you just need to sum up the Wh over what ever time range you care about (hint use persistence and sumeSince to get an estimation of the Wh over that time. But note that if your W varies widely between readings, the Wh won’t be very accurate and it will become less accurate over longer periods of time.

So the best idea would be to have an Item with Wh and make a rule that every update of the W item will make the calculation and send into Wh item, right?
But as I see, if the value of W isn’t changed between updates, the W item didn’t be updated. There is a way to use the time differences between last update and old one to make calculation with real time?

Another thing I didn’t understand the value for 5 seconds to hour… I make this:
3600 sec / 5 sec every update= 720 updates/h
Then 1hour=0,0014

You can do anything in a rule.

But I think it would be unusual for the Item to not be updated even if the W didn’t changed. Note that updates to the same value do not appear in events log. Create a rule triggered by “received update” and confirm whether or not the update is occurring or not.

If it really isn’t updating, you’ll have to keep a timestamp and calculate the difference between now and that timestamp, convert that to hours and then multiply by the W. You can keep the timestamp in the rules or use lastUpdate assuming the W Item is stored in persistence.

Yes, I did it wrong. I did the calculation for Wm, not Wh.

I’m sorry was busy on business trip without access to my openhab.
Right now I’m going crazy with the rule for converting W to Wh, and I made a rules triggered on “Received update” as you say but I have some strange things in log. (btw I use your rules tools)

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

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


var item = items.getItem(event.itemName);
var item_lu = items.getItem(event.itemName + '_LastUpdate');
logger.info('Handling update for: ' + item.name + ' = ' + item.state + ' Last Update time: ' + item_lu.state); //logger.debug

var previousvalue = item.history.previousState();
var previousupdate = item.history.lastUpdate();
var delta = item_lu.state - previousupdate;
logger.info('Past value is: -> ' + previousvalue + ' Past update is: -> ' + previousupdate );

//logger.info('Delta time is -> ' + delta );

if I try to show delta it fullfill java system memory

2022-05-31 23:21:41.885 [INFO ] [openhab.automation.script.watt to wh] - Handling update for: InverterPV_PVPower = 0 Last Update time: 2022-05-31T23:21:41.860477+0200
2022-05-31 23:21:41.906 [INFO ] [org.openhab.automation.script       ] - Last Update
2022-05-31 23:21:41.924 [INFO ] [openhab.automation.script.watt to wh] - Past value is: -> 0 Past update is: -> Tue May 31 2022 20:10:44 GMT+0200 (CEST)
2022-05-31 23:21:46.694 [INFO ] [openhab.automation.script.watt to wh] - Handling update for: InverterPV_PVPower = 0 Last Update time: 2022-05-31T23:21:41.860477+0200
2022-05-31 23:21:46.724 [INFO ] [org.openhab.automation.script       ] - Last Update
2022-05-31 23:21:46.742 [INFO ] [openhab.automation.script.watt to wh] - Past value is: -> 0 Past update is: -> Tue May 31 2022 20:10:44 GMT+0200 (CEST)
2022-05-31 23:21:52.320 [INFO ] [openhab.automation.script.watt to wh] - Handling update for: InverterPV_PVPower = 0 Last Update time: 2022-05-31T23:21:52.302991+0200
2022-05-31 23:21:52.341 [INFO ] [org.openhab.automation.script       ] - Last Update
2022-05-31 23:21:52.365 [INFO ] [openhab.automation.script.watt to wh] - Past value is: -> 0 Past update is: -> Tue May 31 2022 20:10:44 GMT+0200 (CEST)
2022-05-31 23:21:57.576 [INFO ] [openhab.automation.script.watt to wh] - Handling update for: InverterPV_PVPower = 0 Last Update time: 2022-05-31T23:21:52.302991+0200
2022-05-31 23:21:57.609 [INFO ] [org.openhab.automation.script       ] - Last Update
2022-05-31 23:21:57.628 [INFO ] [openhab.automation.script.watt to wh] - Past value is: -> 0 Past update is: -> Tue May 31 2022 20:10:44 GMT+0200 (CEST)
2022-05-31 23:22:02.574 [INFO ] [openhab.automation.script.watt to wh] - Handling update for: InverterPV_PVPower = 0 Last Update time: 2022-05-31T23:22:02.564532+0200
2022-05-31 23:22:02.596 [INFO ] [org.openhab.automation.script       ] - Last Update
2022-05-31 23:22:02.614 [INFO ] [openhab.automation.script.watt to wh] - Past value is: -> 0 Past update is: -> Tue May 31 2022 20:10:44 GMT+0200 (CEST)

It seems only the last change was used… So right now I cannot understand how to move further.
And please help me find a solution for the timestamp comparison of last update and past update.

What is your persistence strategy? Which database?

Continuing the discussion from Creating Wh from an item with only instant W:

I use InfluxDB and my strategy is:

Strategies {
everyMinute  : "0 * * * * ?"
everyHour    : "0 0 * * * ?"
everyDay     : "0 0 0 * * ?"
default = everyChange

}

/* Formato group*, item, * all items*/
Items {
        gTemperature*, gHumidity*, avgTemperature*, Temp*, avgLuminosita*, sumPotenza*, sumEnergia*, gPotenza*, gEnergia* : strategy =  everyHour, everyChange, restoreOnStartup
        /* gSpeedtest*, gPresent : strategy = everyChange */
        gSetPoint* : strategy = everyChange, everyHour, restoreOnStartup
        /* gTermostatiche*      : strategy = everyChange */
        /* gHeatingMode* : strategy = everyChange, restoreOnStartup */
        *       : strategy = everyChange, restoreOnStartup
}

and that values are not grouped for now so only everychange

BTW I’ve changed my rule to make some tests and I see I called the wrong library at top, now changed the rule with:

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

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

var item = items.getItem(event.itemName);
var item_lu = items.getItem(event.itemName + '_LastUpdate');
var lastvalue = item.state;
var lastupdate = item_lu.state;
var lastupdateee = timeUtils.toDateTime(item_lu.state);

var previousvalue = item.history.previousState();
//var previousvalue = item.history.latestState();
var previousupdate = item.history.lastUpdate();
var previousupdateee = timeUtils.toDateTime(previousupdate);
//var delta = lastupdate_epoch - pastupdate_epoch;
logger.info('Handling update for: ' + item.name + ' = ' + item.state);
logger.info(item.name + '  Last Update time: ' + lastupdate + ' Past update time: ' + previousupdate); //logger.debug
logger.info(item.name + '  Last value is: -> ' + lastvalue + ' Past value is: -> ' + previousvalue );
logger.info (item.name + '  DateTime now ' + lastupdateee + ' and before ' + previousupdateee);

and receive:

2022-06-01 18:30:35.878 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_PVPower' changed from 265 to 207
2022-06-01 18:30:35.893 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'InverterPV_PVPower_LastUpdate' changed from 2022-06-01T18:30:30.499271+0200 to 2022-06-01T18:30:35.849060+0200
2022-06-01 18:30:36.954 [INFO ] [openhab.automation.script.watt to wh] - Handling update for: InverterPV_PVPower = 207
2022-06-01 18:30:36.958 [INFO ] [openhab.automation.script.watt to wh] - InverterPV_PVPower  Last Update time: 2022-06-01T18:30:35.849060+0200 Past update time: Wed Jun 01 2022 18:30:35 GMT+0200 (CEST)
2022-06-01 18:30:36.966 [INFO ] [openhab.automation.script.watt to wh] - InverterPV_PVPower  Last value is: -> 207 Past value is: -> 207
2022-06-01 18:30:36.971 [INFO ] [openhab.automation.script.watt to wh] - InverterPV_PVPower  DateTime now undefined and before 2022-06-01T18:30:35.858+02:00[SYSTEM]

There’s your problem, or at least one problem.

Your rule is running on every update but it’s only saving data on a chance. If there was an update without a change that update won’t be saved. But because you have to use updates instead of changes, you probably can’t use persistence for this anyway.

OH doesn’t wait around for your rule to run before saving the latest event to persistence. Most of the time, but the time you rule runs, it will have already updated the database. previousState() just returns the most recent entry in the database.

You are creating a timestamp though, so before updating <itemName>_LastUpdate with now, use that timestamp with a call to item.history.historicState to get the state of the Item at that time.

Note that this is now part of the core library for the most part and I will probably be removing it at some point.

This item is linked to the channel and take the update time from mqtt. That would mean I have to work with that item with a rule instead of link?

How can I do same thing with core commands? I’m trying to learn Js from my error but I understand I’m not a programmer.

Btw can you guide me with a link (or some examples) how to make math operations with datetime? Because if I fix my problem regarding last update time I have to work with time differences, scale to hours to know my Wh.

I’ve thinked was more easier than what actually is.

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?