Imitating the Power Consumption of Lights (and others)

Tags: #<Tag:0x00007f6ce62541f8> #<Tag:0x00007f6ce6254090>

( ) #1

In this short article, I’m going to show how to monitor most of your energy consumption without investing in special hardware. This solution is based on the fact, that most devices (prominently all your lights) have unchanging wattage only depending on their current state, which is already controlled by your openHAB system.

By the help of power consumption measuring modules, such as the Homematic HM-ES-PMSw1-Pl, Sonoff Pow or similar, we are able to monitor the consumption of dynamic consumers, be it our washing machine, fridge, TV and more. These modules are great to measure the energy these devices consume over time. The measurements can be used to graph consumption, calculate energy cost or even build higher level state machines from.

However, the mentioned devices are not the only power consumers in our home. You could continue adding these pricey consumption measurement modules to more devices but for many of these, that might not be practicable and is actually not needed. Your home is already controlled by openHAB and the chances are high, that you can derive consumption from that. Devices like light bulbs or LED stripes have a constant wattage when active. We can easily represent this information in openHAB.

Determining Wattage

There are a few ways to determine the wattage of a light/device. The first one is more than obvious: Just check the label or housing:

The second way to measure the constant power usage of a device is by using an energy meter. These devices can be bought for cheap (~20€) in most utility stores:

It’s a matter of minutes to determine and write down the wattage of most devices in your house.

Representation in openHAB

Let’s continue with an example. I have an LED stripe in my home and after connecting the energy meter in between plug and socket I found out that it is using approximately 17 Watts when turned on (and 0 Watts when turned off). We can now build a simple rule to reflect the consumption of this device in a new Number item:


// a group for all consumers
Group:Number:SUM gPower "Overall Power Usage [%.1f W]" <energy> (gAll)

//the original switch and the additional power item
Switch myLEDstrip "LED strip" {channel="......"}
Number myLEDstrip_Power "LED strip power [%.0f W]" <energy> (gPower)


rule "myLEDstrip"
    Item myLEDstrip received update
    if (myLEDstrip.state == ON) {
    } else {

I’ve decided to condense this rule to make my rules file with dozens of these easier to read:

rule "myLEDstrip" when Item myLEDstrip received update
then if (myLEDstrip.state == ON) myLEDstrip_Power.postUpdate(17.0) else myLEDstrip_Power.postUpdate(0) end

Adding all further devices in this way is as simple as copy&paste. The shown code lines are working in openHAB 2.0 but should just as well work in openHAB 1.8.

On the Influence of Dimmers

Some devices have a constant usage which is related to a dimmer level or some other openHAB Number item. By taking multiple measurements it’s possible to derive the power usage of your device in relation to this item. An example could be (Dimmer percentage on the left, measured power on the right):

Afterwards you need to find the mathematical correlation between these two. You can use a curve fitting tool to do so:
Depending on your device try y=a*x, then y=m*x+c and then continue with more complex functions like y=a*x²+b*x+c till you find a good fit. The simplest form will be more than enough! It’s no rocket science.

The result for our example from above is pretty obvious:

y = 1.17 * x

Transferred to an openHAB rule:


rule "myDimmer" when Item myDimmer_Level received update
then myDimmer_Power.postUpdate((1.17 * (myDimmer_Level.state as PercentType)).intValue()) end

That’s it.

We have successfully added a Number item per device to represent the usage of these at all times. You can now do the next step. An example would be graphing all devices usage with InfluxDB+Grafana. You can also have the overall usage as a Text sitemap item. Lastly you could add logic to accumulate consumption over time and potentially decrease your energy bill :money_with_wings: Have fun!

Help, I'm ready to give up
Help with rule, power switch NS310-F
Gui to manage schedule?
General Rule help needed!
historicState-rule or "robby is fully loaded" - Experience Report from a Newbie
Calculate Energy Consumtion & Costs
(Hallo Ween) #2

Is this still work in progress or is this tutorial finished???

I´m missing the way, how to get the time how long the lights are on. If i only get the value "17" without the duration i can´t do very much with this...

( ) #3

yes it is finished but we could of course add further details.

The topic of this short tutorial was to create an item that always holds the usage of one device. By the help of the posted rule the item will be set to 0 watt when the myLEDstrip is turned off and 17 watt when it is turned on. I've just broken down the rule to multiple lines to make this better visible.

You could now for example persist these usages with InfluxDB+Grafana, that's what I am doing. You can also see the overall usage as a Text sitemap item. I'll add a summarizing sentence at the end.

That was not my intention. I guess what you are talking about is, that you want to know how much energy was consumed over time and how much this will cost you. Correct?

( ) #4

While editing the article I realized my fault. I'm talking about the consumption of a consumer the whole time but the tutorial is only covering the part, where the wattage of one light bulb or device is made known to openHAB :see_no_evil: I've updated the article.

(Hallo Ween) #5

yes, I thought I can see my daily cost for lighting.

Would be great if you could make a tutorial for this too (or expand this tutorial).

( ) #6

There are different ways we could do that.

  • Consumption per device vs. overall consumption
  • Updated at every device state change vs. timed updates (e.g. every 10 minutes)
  • Store the consumption for all time vs. per day vs. per week vs. a mixture...

How would you like to proceed?

(Hallo Ween) #7

Best thing would be a page where i can see all my lights and there i get power consumption for every device on its own.

Then i can add all devices and get the sum of all lights.

If it will be shown after state has changed or every xxx minutes - that doessnt matter and can be changed very easy.

This way i can see, where it would be a good idea to change old bulbs to new led lightings for example. Some rooms which i enter not very often, there it doesn´t make sense to change to leds - too expensive.

Storing consumption for a longer time would be great.

(Seaside) #8

I do monthly checks. I have some devices with does not support energy metering, and some (like z-wave), which have their internal kwh-counter.

Every month I send a report with usage as well as resetting all counters.

For instance I have items like:

Number ZwaveBabyDimmerEnergy            "Dimmer Baby Room [%.2f kWh]"         <energybulb2> (ZwaveBabyDimmer,KwhSum) { channel="zwave:device:xxxxxxx:node37:meter_kwh" }
Switch ZwaveBabyDimmerEnergyReset       "Dimmer Baby Room Energy Reset"       <switch>      (ZwaveBabyDimmer,gEnergyReset) { channel="zwave:device:xxxxxx:node37:meter_reset" }

I have a group kwh sum for all items with kwh.

Group:Switch:OR(ON, OFF) gEnergyReset                 "Energy Reset Items"             (gIntitalizeZero)
Group:Number:SUM KwhSum           "Total Energy [%.2f kWh]"                  <energybulb2> (gRestore)

I then do a sitemap

  Group label="Energy" icon="energyg" {
             Group item=KwhSum

Here you will be able to see all members in group

And a rule to reset:

val SimpleDateFormat df = new SimpleDateFormat("YYYY-MM-dd")
rule "ResetKwhMonthly"
  Time cron "0 0 0 1 * ?" or
  Item CostResetSwitch received update ON
  		logInfo("ResetKwhMonthly", "Begin")
    	val String message = "Resetting all kwh counters"
	    val String displayTime = df.format(new Date())
	    var String report = "<h1>Total KwhSum Before Reset " + displayTime + " " + KwhSum.state.toString + " kWh</h1>\n\n"
	    report +=   "<table><tbody><tr><td>Item</td><td>Usage (kwh)</td></tr>" 
	    KwhSum.members.forEach [ kwhMember | 
    	       report += "<tr><td>" + kwhMember.label.toString + "</td><td>" + kwhMember.state.toString + "</td></tr>"
      report += "</tbody></table>"
    	logInfo("ResetKwhMonthly", "Sending report: " + report)

(Hallo Ween) #9

You have a zwave device which gave you the kwh for each light.

But i only can count the kwh by "watt x time".

Now i can see when a light is on, there i get, how many watt the light consumes at this moment.

But i want to get kwh. I have persisted the watt to rrd4j already (every change, every minute).

How can i get kwh with this information?

(Seaside) #10

Trying to strip off a lot of specific stuff .. Also I'm not using rrd4j, only mapdb I only store the latest value.
This can probably be done in some other way with avargeSince-function if you store values in a db. I'm using a timer..

Switch ZwaveBalconyRelaySwitch             "Balcony Relay Switch"                                <light>       (ZwaveBalconyRelay)   ["Switchable"]             { channel="zwave:device:69f10e1b:node8:switch_binary" }
Switch ZwaveBalconyRelayEnergyReset        "Balcony Relay Energy Reset"             <switch>      (ZwaveBalconyRelay,gEnergyReset)     
Number ZwaveBalconyRelayEnergy             "Balcony Relay [%.2f kWh]"               <energybulb2> (ZwaveBalconyRelay,KwhSum,gRestore)       
Number ZwaveBalconyRelaySensorPower        "Balcony Relay [%.2f W]"                 <power>       (ZwaveBalconyRelay,SensorPowerSum,gRestore) 
Number ZwaveBalconyRelaySensorPowerValue   "Balcony Relay [%.2f W]"                 <power>       (ZwaveBalconyRelay,gRestore)

var Timer mUpdateKwhTimer
var double mBalconyPowerValue = 0.0
var int mEnergyInterval = 10
var String LOG = "Energy"

val Functions$Function2 updateEnergyConsumption = [ int energyInterval, double powerValue | 
        if (ZwaveBalconyRelayEnergy.state == NULL) {
        val double currentEnergyValue = (ZwaveBalconyRelayEnergy.state as DecimalType).doubleValue
        val double kwh = (powerValue *  (energyInterval / 60.0)) / 1000.0 
        val double totalUsage = currentEnergyValue + kwh
        new Double(totalUsage)

rule "UpdateKwhCostOn"
  Item ZwaveBalconyRelaySwitch changed to ON
  try {
        mBalconyPowerValue = (ZwaveBalconyRelaySensorPowerValue.state as DecimalType).doubleValue
        if (mUpdateKwhTimer == null) {
            mUpdateKwhTimer = createTimer(now.plusMinutes(mEnergyInterval), [|
                                val Double energyConsumption =  updateEnergyConsumption.apply(mEnergyInterval, mBalconyPowerValue) as Double 
                                logInfo(LOG, "Update Energy Consumption " + energyConsumption)
      } catch (Exception x) {
          logInfo(LOG, "Failed to start timer for balcony relay", x)

rule "UpdateKwhCostOff"
  Item ZwaveBalconyRelaySwitch changed to OFF
    if (mUpdateKwhTimer != null) {
        logInfo(LOG, "Turning relay off, stop to collect energy usage")
        //Adding consumption even though it not might not have been consumed for the entire time
        updateEnergyConsumption.apply(mEnergyInterval, mBalconyPowerValue)
        mUpdateKwhTimer = null

Sitemap: (So I can change the usage in watts using the basicui)

 Setpoint item=ZwaveBalconyRelaySensorPowerValue minValue=0.0 maxValue=100.0 step=0.1

( ) #11

Great script. That's probably how I would have done it.
Love the usage of a rescheduled timer and the defined function.

I fear that this script is too much for a beginner though. Would you be able to write a tutorial like description about it?

(Hallo Ween) #12

Great! Thanks a lot! I will try to edit it to my needs.

Is there a way to do this with groups or do i have to write a rule for each light?

(Seaside) #13

I agree, I can write something in the coming days.

It's not impossible, but it's more difficult for sure. I have something similar for handling my sonos-groups, but I use hashmaps where the label of item is the key. It's also possible to sort a group so you can get the most recent changed item, however, I won't display a solution of that here as it is quite messy.

(Rich Koshak) #14

Not really:


If you have Items that may not have been stored in persistence:

myGroup.members.filter[i|i.lastUpdate != null].sortBy[lastUpdate].last

(Seaside) #15

Didn't express myself very clear, was referring to the generic solution as a whole, it is possible that it can be done in a better way than what I was thinking, but my solution is messy.
I'll try to write a small guide but any improvements and or generic suggestions would be good to see.

Regards, S

( ) #16

@rlkoshak it would actually be a very nice gesture of yours, if you could write a hands-on tutorial about how to best go from items-based rules to group-based ones. I believe many users would benefit from your experiences for best practices in that area. I'm not talking about a "Design Pattern" but a step by step guide :wink:

(Rich Koshak) #17

I think it still qualifies as a Design Pattern, but I'll write it more like a tutorial than just an example.

I've already written most of it up in my own notes. I've transcribed it and beefed it up a bit here:

It ended up being difficult to provide a step by step guide as the steps are just:

  1. add your Items to groups
  2. trigger the rule on all Items (or Group updates if multiple execs of the rule per event isn't a problem)
  3. pull the triggering Item from the Group based on lastUpdate
  4. code as usual

However, I did provide examples for and description of what all of the MyGroup.members.* methods do (at least all the ones I know) including map/reduce.

( ) #18

I've only looked at it briefly but Yes, that looks great!! Thank you :tada: :wink:
I should not forget to add your design patterns tag to this or something similar:
I'm waiting for the forum restructure. That will be fun.

(Rich Koshak) #19

It can't be as painful as the eviction from Google Groups was... :slight_smile:

( ) #20

Now I have no excuse anymore, to not build a group-based rule for the above :wink: