[SOLVED] Energy Consumption calculation with Shelly devices

Has anyone actively using or has some advice on how to use properly the /energy topic, used by some of the Shelly devices?

The docs says:

shellies/shellyswitch-<deviceid>/relay/<i>/energy reports amount of energy consumed in Watt-minute

So I made a little transform which should do the calculation (correctly?) to kWh:

(function(i) {
     var kwh = (i * 17) / 1000000;
     var kwh_tofixed = kwh.toFixed(2)
     return kwh_tofixed + " kWh"
})(input)

Hope someone can confirm that this is correct.
Based on this, it seems correct:

http://convert-to.com/conversion/energy/convert-wmin-to-kwh.html

So here comes my problems:

  • Somewhere I read in the docs (which I can’t find now) that this counter will reset at some point (you can’t reset it and probably you don’t know when it will reset!? Maybe when updating, restarting the device). So I would need some rule that will persist the new data (and will always add up to maybe a proxy item?). Hope you get the problem here… And a simple persisted Item will not solve this I think.
  • What is the best way to calculate the costs for each device and summed up in a rule? Calculate it for each device and add up that later for the sum?

Thanks!

1 Like

Create a proxy number that holds the total value.

Have a Rule that triggers when the Shelly reports the energy consumption that triggers with a changed trigger. This gives you access to a previousState implicit variable.

if the new value is greater than the previous value add the difference between the two to the proxy Item.

if the new value is less than the previous value, add the current value to the proxy Item.

from core.rules import rule
from core.triggers import when

@rule("Total usage")
@when("Item Shelly_Energy changed")
def total_usage(event):
    delta = 0
    if event.itemState > event.oldItemState:
        delta = items[event.itemState.floatValue - event.oldItemState.floatValue

    elif event.itemState < event.oldItemState:
        delta = event.itemState.floatValue

    events.postUpdate("Shelly_Event_Proxy", str(items["Shelly_Event_Proxy"].floatValue + delta))
1 Like

Thank you that seems a really good solution!

I have multiple devices with an appropriate group and I’m already using Jython so your example is really good for me.
However can I somehow if one of the members triggered (I mean this is the obvious part) and then dinamically search for the Proxy Item? Like each proxy item will be named the same as the Energy item but with a _Proxy postfix. Can this somehow achiveable in the NGRE engine?

In Python this is just a matter of building the name

items["{}_Proxy".format(event.itemName)]

That gives you the state of the Associated Proxy Item (assuming the naming convention used in my code above).

events.postUpdate("{}_Proxy".format(event.itemName), str(...

That will post update to the associated proxy Item.

All you need is the name and you have access to everything.

Will this work even after a restart?
I have persisted and set restoreOnStartup on these calculated Energy values. It is enough for this to work? I mean the previousState implicit variable works just as it uses the items previous state before the change?

events.itemOldState (previousState in Rules DSL) is independent from persistence. It will always work.

But you will want to persist and restoreOnStartup your Proxy Item that keeps the running sum so you don’t lose the running total on an OH restart.

You will have to check, but you also might need to do a check to see if event.itemOldState is UnDefType (see https://openhab-scripters.github.io/openhab-helper-libraries/Guides/But%20How%20Do%20I.html#stop-a-rule-if-the-triggering-item-s-state-is-null-or-undef) just in case your Rule get’s triggered when restoreOnStartup initially populates the Proxy Item.

There also might be an edge case here. If the following occurs you will lose one or more readings:

  1. OH goes down
  2. The shelly published one or more updates
  3. The shelly resets the energy total back to zero

When OH comes back up it will have missed those values published in step 2 with no way to get them back.

Yes after thinking through I also found this case… However I rarely stop OH so that wouldn’t be a big problem for me… I just want an approxmiate reading to know the power usage…

I think it is not absolutely incorrect, but inaccurate. to go from Wm to kWh, you have to divide by the number of minutes per hour (60) and transfer from W to kW which means divide by 1000. I use the following JS transformation:

(function(value) {
    return value / 60000.0; // Divide by minutes per hour and divide by 1000 to get kilos
})(input);

At first, I also used this approach, but now I use the units of measurement which is more flexible when you want to use different units at different places in the UI. So the Wm value is converted to basic unit for energy: J (Joule or Ws). This means that the value reported should be divided by sixty (and I also round off to three decimals) with divideBySixty.js:

(function(value) {
    return Math.round(1000 * value / 60.0) / 1000;
})(input);

You can use this transformation in the following Thing/channel definition:

Thing topic shellyplug-s-XXXXXX "Plug XXXXXX" {
  Channels:
    Type number : energy "Energy" [ stateTopic="shellies/shellyplug-s-XXXXXX/relay/0/energy", transformationPattern="JS:divideBySixty.js" ]
}

To get kWh reading for you Item, I define it as:

Number:Energy PlugXXXXXX_Energy  "Consumption [%.1f kWh]" (gHistory) channel="mqtt:topic:mosquitto:shellyplug-s-XXXXXX:energy"}

Hi guys

I read through your comments but I don`t get it to work

I have the following items which are persistet everyminute, everychange and restored on sturtup

Number    Shelly_Hauptstromzaehler_energy       "Hauptstromzähler Energie [%.1f kWh]"        (gDB_influx, rrd4j_ec)                         {channel="shelly:shellyem3:c82b961167d7:device#accumulatedWTotal"}
Number    Shelly_Hauptstromzaehler_energy_sum       "Hauptstromzähler Energie Summe [%.1f kWh]" (gDB_influx, rrd4j_ec)    //                     {channel="shelly:shellyem3:c82b961167d7:device#accumulatedWTotal"}

_energy comes from a Shelly. After a reset or update from the shelly, the counter starts from 0. Because of this behaviour, I created the item energy_sum which should only add the difference.

but i dont get it to work as suggested whith the following rule.

rule "Energy"
when
    Item Shelly_Hauptstromzaehler_energy changed
    //Time cron "0/5 * * * * ? *" 
then
    logInfo("Summe Rechner 2", "Summe Hauptstromzaehler berechnet")
    var Number currentkwh = 0
    if(Shelly_Hauptstromzaehler_energy.state instanceof Number)
        currentkwh = (Shelly_Hauptstromzaehler_energy.state as Number).floatValue
    var Number previouskwh = 0
    if(Shelly_Hauptstromzaehler_energy.previousState.state instanceof Number)
        previouskwh = (Shelly_Hauptstromzaehler_energy.previousState.state as Number).floatValue
    var Number energy = 0
    if(Shelly_Hauptstromzaehler_energy_sum.state instanceof Number)
        energy = (Shelly_Hauptstromzaehler_energy_sum.state as Number).floatValue
    energy = energy + currentkwh
    if((currentkwh - previouskwh) >= 0)  //Wenn das Delta größer 0 ist
        energy = energy - previouskwh

    Shelly_Hauptstromzaehler_energy_sum.postUpdate(energy)
end

and I dont understand your rule, so I cant test this one either. Maybe you can help me

THX