How to create a new point containing difference of 2 values?

I think it’s better if I describe exactly of what I need hoping the forum to find the best solution. The title might be misleading…

I have a inverter generating power. It gives info about currently generated power (KOSTAL_PLENTICORE_Plus_100_AC_Power) and the power being already consumed by the house (KOSTAL_PLENTICORE_Plus_100_Home_Consumption). Both are provided by KOSTAL binding. I want to create a new point showing what power is currently being fed back to the grid. That would be a simple difference of AC_Power and Home_Consumption. Both values are in watts. How can I do it?

I tried to create rule but I’m not even sure if I go in the right direction.
The code (DOESN’T WORK)

var QuantityType<Power> KOSTAL_PLENTICORE_100_Plus_Available_Power
var itemMetadata;

rule "Kostal Available Power"
  
when
    Item KOSTAL_PLENTICORE_100_Plus received update
then    
    var current_power_generated = KOSTAL_PLENTICORE_100_Plus_AC_Power
    var current_power_used = KOSTAL_PLENTICORE_100_Plus_Home_Consumption
    KOSTAL_PLENTICORE_100_Plus_Available_Power = current_power_generated - current_power_used
    
    itemMetadata = items.metadata.getMetadata('KOSTAL_PLENTICORE_100_Plus', 'Available Power');
    itemMetadata = (itemMetadata === null) ? { value: '', configuration: {} } : itemMetadata;
    itemMetadata.value = KOSTAL_PLENTICORE_100_Plus_Available_Power;
    items.metadata.replaceMetadata('KOSTAL_PLENTICORE_100_Plus', 'Available Power', itemMetadata.value, itemMetadata.configuration);
end

Just create another Number:Power Item KOSTAL_PLENTICORE_100_Plus_Available_Power (which stays unbound, no link to a channel).

Then use a rule to fill that Item:

rule "Kostal Available Power"
when
    Item KOSTAL_PLENTICORE_100_Plus_Home_Consumption changed or
    Item KOSTAL_PLENTICORE_100_Plus_AC_Power changed
then
    if(!(KOSTAL_PLENTICORE_100_Plus_Home_Consumption.state instanceof Number)) return;
    if(!(KOSTAL_PLENTICORE_100_Plus_AC_Power.state         instanceof Number)) return;

    val nAvail = (KOSTAL_PLENTICORE_100_Plus_AC_Power.state as Number)-(KOSTAL_PLENTICORE_100_Plus_Home_Consumption.state as Number)

    KOSTAL_PLENTICORE_100_Plus_Available_Power.postUpdate(nAvail)
end

The two if statements are to check whether the Item state is of type Number or not. You can’t use NULL for calculations…

It’s a bit lazy to use as Number, the “correct” way would be to cast to QuantityType<Power>

1 Like

Thank you! I don’t have it working yet (shows NULL), but at least I have a good map how to do it.

I wish more posters did this. It helps avoid XY Problems. Thank you!

You sued ChatGPT to generate this code, didn’t you.

I can tell because Rules DSL doesn’t do Item metadata.

Without going into another rant, AI chatbots are not suitable for creating rules in OH. You basically have to know enough about rule to fix the garbage they produce as you would need to just code it yourself in the first place.

In this case, there’s no reason to use Item metadata in the first place, Item metadata cannot be accessed an used in Rules DSL, and the code shown to access and set the metadata shown here is JavaScript, not Rules DSL.

If you don’t really know programming I strongly recommend using Blockly.

Let’s break the problem down.

OK, any time either one of these changes you need to recalculate the power being fed back to the grid. So like @Udo_Hartmann’s version shows, you want to trigger the rule on changes to either of these Items.

In the UI go to Settings → Rules → +, fill in the UID, name and description with something meaningful. Then click the green + next to triggers and add an Item event trigger configured for changes on the Plus_Home_Consumption Item.

Click the green + next to triggers and add another Item event trigger configured for changes on the Plus_AC_Power Item.

Again, as @Udo_Hartmann describes, create a new Item for Plus_Available_Power to store the new value. Make sure to define this Item the same way as the other two above.

Obviously you need to enter the correct Item names in place of “MyItem”. Using the “Units of Measurement” blocks preserves the units and does any conversions necessary.

Finally, because error checking is a good idea, from the rule’s page click the green + next to “add condition” and choose a “Script condition”. The code would be:

I got a little fancy here with the function to make the blocks a little more concise but it’s pretty straight forward to do it all inline if that’s what you want.

The last line/block of the script condition needs to evaluate to true or false. When true, the rule is allowed to run when triggered. When false, the rule won’t run even if it’s triggered. This condition prevents the rule from running if one or both of the Consumption and AC_Power Items have states that can’t be calculated with.

And stay off of the chatbots. Your time is better spent experimenting, looking through the docs, and asking questions here on the forum than trying to fix the crap that AI generates.

1 Like

Thank you for the warm words - I’m an admin on a technical forum, so i think I know how to avoid asking bad questions. Or I hope so. I don’t use AI… The code was sample from our forum, trimmed to my needs and ugly glued with code produced by Blocky editor. And anything I could find on the net :blush: I have enough experience with programming to try that kind of things, but without knowing the internals of OH the results are not good.

Thank you for your solution - I’m analysing it now :heart_eyes:

@rlkoshak Thank you very much for the solution! I had some problems with following it to the letter, because the trigger channel part was not showing me list of channels from the inverter. Weird - I see channels from some items, but not from all of them. I used “an item state is updated” instead.

The Blocky editor is a great tool when you´re lost with the OH internals (like me!!!), but for someone normally using vim to edit a code (like me!!!) it’s a lot of clicking to find what I need. And to understand the logic behind it. A piece of code floating in space is still messing with my mind :slight_smile: I know much more about it know and I’m sure it will help me in the future! :smiley:

The most important: the solution WORKS LIKE A CHARM! Thank you!!!


An the HABPanel showing the value:

Would it be beneficial for the future users to do snips of my implementation of your solution, or it’s a niche case and there is no need for it?

Hey guys,
Isn’t the solution something overly complex for the purpose of substracting two values? Did I miss something justifying an additional rule for it?

Anyway, I’d point out a solution, which just requires another form of the item definition of the “difference”-item. Nothing else! No rules, no script, no trigger condition…

The trick is using a group item for the “difference” of production power and load.

Sounds weird?
No it isn’t. It simplifies the task because of the built-in aggregation function feature of groups. In our case we leverage the sum function:

Then we put the inverter output power item and the house load item into that group. The aggregation will do the calculation for you without all that rule overhead:

In case your house load item is not signed negative, just link that load channel from your smartmeter/inverter using the invert-negate-profile:

1 Like

I think it’s important to have the core concepts down when working with OH and terms like Item, Thing, and Channel are technical terms of art when working with OH. That’s the main reason I always capitalize them when using them to refer to these entities.

A Channel from the inverter Thing wouldn’t show up in the list of Items you can choose from unless it’s an Event type Channel. Event type Channels are Channels which represent a momentary event (e.g. button pressed) and do not have a state (e.g. the amount of power that is being used). The vast majority of Channels you will encounter are State Channels. These Channels can only be linked to Items. To trigger your rule you would use an Item trigger.

Two things about this. There is a button at the bottom to see what JS Scripting code is generated by the Blocks. You can use them as a learning resource.

Beyond that, all of the Rules automation add-ons except for maybe Groovy have very complete, comprehensive, and complete reference documents (e.g. here’s JS Scripting’s: JavaScript Scripting - Automation | openHAB). You should be using these resources as the first place to look for how to do something.

But, if you don’t have a good grasp on the core OH concepts you will have a hard time even with these references. Therefore I cannot stress enough how important it is to read and understand the concepts section of the docs and at least review the Getting Started Tutorial. There is also built in a context aware help in MainUI in the developer sidebar (alt-shift-d).

Finally, the code isn’t “floating in space”. All managed configs are stored in $OH_USERDATA/jsondb. Rules in particular are stored in the automation_rules.json file in that folder. But you don’t have to use managed rules or really almost anything and use text files if you choose. There are compromises each way. Personally I’d probably be more comfortable using text file configs overall, but the fact that it’s really hard to mess up syntax and I rarely have to look anything up when using managed configs.more than makes up for it. And since the managed configs are saved in an ordered JSON file it’s just as easy to source control as text file configs.

It’s a pretty basic task to do in OH. A tutorial is always welcome but I don’t think that a rule like this would be worth the effort to make into a Rule tempalte. All you are really doing is adding the states of two Items whereas rule templates tend to do more suff like calculatinng the solar radiance based on the overall radiance reported by the Astro binding and the percentage of cloudiness from a weather binding, or send an alert when a temperature remains above a threshold more than 15 minutes, but not between the hours of 23:00 and 08:00.

It’s not a sum, it’s a minus (and I do see that I messed that up in my blockly code example now but @Udo_Hartmann got it right in the Rules DSL version).

To use the Group aggregation, you’d have to negate the state of KOSTAL_POLENTICORE_100_Plus_Home_Consumption which means you’d need to apply a profile to the Link and have that Item’s state always be negative, or you’d need to create a proxy Item to store the negative version for use in the Group. Either approach is viable but just about the same in terms of complexity overall.

If it were just addition though you are right, creating the Group with the aggregation function would probably be a bit simpler.

1 Like