OH4 Blockly Persistence Calculation error

Hi All

Current SNAPSHOT - openHAB 4.0.0 Build #3470

I had a similar Blockly Script to this working yesterday (simplified to demonstrate the issue), but now cannot get the script to work as required. (I am getting NaN as result for any calculations). I have tried all the tricks I can see to try and work out what is wrong - any assistance would be greatly appreciated.


Which generates:

var Previous_Y1, Previous_Y2, m1;


//log:set DEBUG org.openhab.automation.script.ui.Test_Persistence
Previous_Y1 = items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(0))?.state;
Previous_Y2 = items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(1))?.state;
console.error(('Previous Y1   ' + String(Previous_Y1)));
console.error(('Previous Y2   ' + String(Previous_Y2)));
m1 = Previous_Y1 * 1;
m1 = Previous_Y1 - Previous_Y2;
console.error(('M1 is ' + String(m1)));
console.error(('M1 is ' + String(m1)));

The output I get is:

10:14:56.320 [ERROR] [.openhab.automation.script.ui.Test123] - Previous Y1   27.63 V
10:14:56.321 [ERROR] [.openhab.automation.script.ui.Test123] - Previous Y2   27.63 V
10:14:56.322 [ERROR] [.openhab.automation.script.ui.Test123] - M1 is NaN
10:14:56.322 [ERROR] [.openhab.automation.script.ui.Test123] - M1 is NaN

So the values are retrieved correctly from persistence, however any calculation with those Variables fail and produce NaN, even a simple multiply by 1.

I also tried the UoM blocks and got errors.

image

var Previous_Y1, Previous_Y2, m1;


//log:set DEBUG org.openhab.automation.script.ui.Test_Persistence
Previous_Y1 = items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(0))?.state;
Previous_Y2 = items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(1))?.state;
console.error(('Previous Y1   ' + String(Previous_Y1)));
console.error(('Previous Y2   ' + String(Previous_Y2)));
m1 = 1 * 1;
m1 = Previous_Y1 - Previous_Y2;
console.error(('M1 is ' + String(m1)));
console.error(('M1 is ' + String(m1)));
m1 = (.multiply(1));
console.error(('UoM M1 is ' + String(m1)));
10:25:12.511 [ERROR] [.internal.handler.ScriptActionHandler] - Script execution of rule with UID 'Test123' failed: org.graalvm.polyglot.PolyglotException: SyntaxError: <eval>:13:6 Expected an operand but found .
m1 = (.add(1));
      ^

The only changes I can think I made was to remove RRD4j and MAPDB as persistence services. I am now using InfluxDB - but that has been my default for a few days now.

That’s not a number. As in everywhere else in JS Scripting’s helper library, the .state of an Item or HistoricItem is a String.

Furthermore, that state carries units.

You are on the right track in trying to use the UoM blocks but you need to actually have UoM values before you can use the UoM math block.

You need to wrap the result of the call to historic state inside a Qty block.

And then you need to use the UoM math block to multiply/subtract the two UoM variables.

What is really weird is that this was working…

I tried using your suggestion:

var Previous_Y1, Previous_Y2, m1;


//log:set DEBUG org.openhab.automation.script.ui.Test_Persistence
Previous_Y1 = 0;
Previous_Y2 = items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(1))?.state;
console.error(('Previous Y1   ' + String(Previous_Y1)));
console.error(('Previous Y2   ' + String(Previous_Y2)));
m1 = 1 * 1;
m1 = Previous_Y1 - Previous_Y2;
console.error(('M1 is ' + String(m1)));
console.error(('M1 is ' + String(m1)));

This however produce 0 for “Previous Y1”?

16:08:41.683 [ERROR] [.openhab.automation.script.ui.Test123] - Previous Y1   0
16:08:41.684 [ERROR] [.openhab.automation.script.ui.Test123] - Previous Y2   27.64 V
16:08:41.684 [ERROR] [.openhab.automation.script.ui.Test123] - M1 is NaN
16:08:41.684 [ERROR] [.openhab.automation.script.ui.Test123] - M1 is NaN

These blocks where recently worked on - so wonder of there is an issue in my SNAPSHOT?

When though. If in OH 3.4, well Blockly now converts to a whole new version of JavaScript. If a snapshot of OH more than a week or so ago, the way that units are managed on Items was completely reworked and now perhaps Items that didn’t have units now do.

That looks like a bug in the UoM block. All I can suggest there is to file an issue.

It should generate something that looks like

Previous_Y1 = Quantity(items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(0))?.state);

Though now that I notice it, why bother pulling anything out of persistence with a data that is effectively now? Just use the Item’s current state.

I had this working yesterday on the same 4.0.0 SNAPSHOT. All I have done in between is removed RRD4J and MAPDB. I have tried re-installing them but made no difference.

That is just a subset of what I am retrieving to demonstrate the issue. The actual rule is longer with more calculations in it. I need Now, 1 minute ago, 2 minutes ago, 3 Minutes ago.

So what’s configured as the default persistence?

InfluxDB, which it has been for about a week. I was running them together till InfluxDB had enough data for me to cut across.

And HistoricState is returning something valid?

If it worked before and doesn’t now, something changed. If all you changed was uninstalling two persistence engines you have your culprit. Something about removing those two engines changed what historic state is returning.

I am going to try reboot the server. Uninstalling MAPDB did cause OH to “crash”. I restarted and all seemed to be OK. But maybe not.

It does look like something other than persistence though:

image

var Previous_Y1, Previous_Y2, m1;


//log:set DEBUG org.openhab.automation.script.ui.Test_Persistence
Previous_Y1 = items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(1))?.state;
Previous_Y2 = items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(2))?.state;
console.error(('Previous Y1   ' + String(Previous_Y1)));
console.error(('Previous Y2   ' + String(Previous_Y2)));
m1 = 1 * 1;
m1 = (items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(0))?.state) - (items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(1))?.state);
console.error(('M1 is ' + String(m1)));
console.error(('M1 is ' + String(m1)));

Should return 1 for m1, but it is NaN:

16:53:37.092 [ERROR] [.openhab.automation.script.ui.Test123] - Previous Y1   27.6 V
16:53:37.093 [ERROR] [.openhab.automation.script.ui.Test123] - Previous Y2   27.63 V
16:53:37.116 [ERROR] [.openhab.automation.script.ui.Test123] - M1 is NaN
16:53:37.117 [ERROR] [.openhab.automation.script.ui.Test123] - M1 is NaN

No, you set m1 to 1*1 and then set m1 to (items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').... before logging m1 for the first operation. You wipe out the 1 before you get a chance to log it.

Sorry, yes, all the changes must have missed that one - thanks for pointing out.

Yes, the logs show valid values. Fails on the calulations.

Seems to be an issue with the UoM QTY blcoks?

image

Produces:

m1 = (.subtract());
m1 = Previous_Y1 - Previous_Y2;

So I am pretty sure the first calculation is wrong. Could this be the root of the problems?

And even


Produces:

Previous_Y1 = 0;
Previous_Y1 = items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(1))?.state;

And again the QTY version is incorrect.

EDIT:

Logged issue:

Yes, that’s why I said above it looks like a bug and an issue should be filed. The UoM blocks are not producing valid code. Hopefully your issue will be seen and fixed quickly.

1 Like

Thanks for the support.

So to try and get back up and running I have added inline scripts to perform the required functions.

I was expecting that once the Quantity is assigne dto a variable, that that Quantity would be carried through to the later calculations etc - But it appears that this is not the case - I end up with 0 as a result?

So I have added the following inline script to retrieve the persisted values:

PreviousY1 = Quantity(items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(0))?.state);
PreviousY2 = Quantity(items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(1))?.state);
PreviousY3 = Quantity(items.getItem('Shelly_UNI_Persist_1Min_Voltage_ADC').history.historicState(time.ZonedDateTime.now().minusMinutes(2))?.state);

And the following to perform the calulations:

m1 = (Quantity(PreviousY1).subtract(Quantity(PreviousY2)));
m2 = (Quantity(PreviousY2).subtract(Quantity(PreviousY3)));

I would however like to round the result to 1 decimal place, which also requires the Quantity again, so trying to use inline script with (and a few variants):

m1 = (Quantity(m1).toFixed(1));

But I always get an error:

09:11:44.186 [ERROR] [ab.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: TypeError: (intermediate value)(...).toFixed is not a function
        at <js>.:program(<eval>:17) ~[?:?]
        at org.graalvm.polyglot.Context.eval(Context.java:399) ~[?:?]
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:458) ~[?:?]
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:426) ~[?:?]
        at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:262) ~[java.scripting:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.DelegatingScriptEngineWithInvocableAndAutocloseable.eval(DelegatingScriptEngineWithInvocableAndAutocloseable.java:53) ~[?:?]

I am sure my syntax is wrong - But I have no idea why.

I don’t know if there is support for toFixed() on a QuantityType. Quantity is just a wrapper around the Java QuantityType. I don’t see such a function anywhere.

Why do you need to round it in the rule? You shouldn’t round numbers until the last moment (e.g. when you display it on a UI). This is particularly important if you are doing further calculations with that number because rounding errors can become huge in only a couple of operations.

If you must round/truncate here, you’re going to have to convert it to a number and then back to a Quantity. m1’s already a Quantity so it would be this convoluted path.

m1 = Quantity(String(m1.toFloat().toFixed(1)), 'V')

Thanks for the help so far Rich.

I think maybe part of my issue (besides the “broken” blocks, is my understanding of String vs Quantity vs Number and where they need /have to be used.

So from what I understand:

Having read Units Of Measurement | openHAB

An Item STATE is stored as a string, so before any “calculations” can be performed it needs to be converted to a “numerical” format being either a Quantity or a Number?

A Quantity is a number with a UoM attached, such as 100kW, 100V, etc?

A Number is a plain number with no UoM attached, such as 100, 200, 159.764 etc?

What I don’t seem to get is:

  • If a state of an item is retrieved from the item itself or from persistence and stored in a variable, it is still a string
  • Unless it is converted to a quantity? Is it then always a Quantity going forward in that variable? So in Blockly one would have to use the UoM blocks - which are currently broken (even in 4.0.0.M3)
  • The Plain Math Blocks are only used for numbers with no UoM?

So this extract:

image

Which produces (and works):

temp = (3.123).toFixed(1);

Resulting in:

3.1

Would not work for a Quantity type? It would only work for a Plain Number?

Maybe I need to back off a bit and wait for the UoM blocks to be fixed and then try again?

Not quite.

Blockly “compiles” to GraalVM JavaScript Scripting: JavaScript Scripting - Automation | openHAB

The Item class has four “state” properties:

  • .state - always a String
  • .numericState - always a JavaScript number or null if the Item’s state cannot be represented as a number
  • .quantityState - always returns a Quantity or null if the Item’s state cannot be represented as a Quantity
  • .rawState - the original Java State Object

You can get all but this last one using the “get X from Item” block.

But you can only get state from the “get the historic state of the Item…” block. So if you want to do math with it, you need to convert it to a numericState or a quantityState.

No, it’s just the .state property of the Item is always a String. And by default Blockly uses .state unless told otherwise and it doesn’t have the option to be told otherwise when getting the historic state.

Yes with the caveat that if you reassign the variable some other value, that new value might not be a Quantity.

Correct.

Correct. If you have a Quantity, you can only use the block from the Units of Measurement section to do comparisons and math.

It is a pity I have only seen this thread by chance.

When you say that the UOM blocks are broken, are you referring to the variable usage?

I have provided a fix for that yesterday

because I stumbled over it myself during documenting the latest changes.
Sorry for the inconvenience.

Update: Now I saw your filed issue on github: [blockly] Latest UoM QTY blocks with variables no longer work · Issue #1907 · openhab/openhab-webui · GitHub

Unfortunately I need to check this out again.

The problem is that blockly cannot detect the type of the content of the variables which is a pity which is why I need to make assumptions, so I went for

Blockly cannot detect the type that is contained in a variable so it expects an item object.
This allows to iterate over a group of item members which returns a list of item objects

which of course is debatable… :thinking: