Rule to monitor device status ON/OFF and calculating total usage

Hi everyone,

I still using openhab 2.3.0 at the moment, will probably wait till next weekend with upgrade but reading forum there is a lot of positive opinions so far so can`t wait for that.

In the meantine I would like to calculate usage of a device at home which is monitored using Network Binding.
My item looks like this:

Switch DeviceStatus  { channel="network:pingdevice:Device:online" }

sitemap

Text item=DeviceStatus label="Device A [%s]" valuecolor=[ON="green" ,OFF="red"]

Ideally I would like to calculate and display total usage in hour/day/week/month and one year. Will probably end up trimming this down but just want to experiment for now. What`s is the best way to achieve this. Does anyone has any proven rules available for sharing ? I will be grateful for any suggestions.

Do you have persistence set up and running: https://www.openhab.org/docs/configuration/persistence.html

And by usage do you mean that you want to count how many times the switch has flipped to ON? Or maybe see a graph indicating how long it has been ON for a period of time?

I used the search function with “calculate time” and found this generator calculation thread. It’s old but it should get you started.

Sorry if I wasn`t clear. My intention is to display total usage of the device within certain time frame - basically need to know for how long this device was switched on during hour/day/week/month & year. Lets say we are talking about a simple lamp in bedroom. I probably will be happy just displaying as text in few lines - would that be to difficult ? I could consider using chart but maybe for this purpose getting this data as a text will be easier to read.

Also just started thinking that for maintenance knowledge I could start gathering information how many times the A switch has flipped to ON position so basically count number of position changes from OFF to ON. I will look into your old post now.

I think it depends on where and how you’d like to display the value(s). IMHO, few string items in your sitemap won’t work.

For example I’m running MySQL persistence and have a graphing script written in php to calculate ON durations and average temperatures. They are then drawn to a graph and displayed as images in my sitemap.

Hi @andy31,

I’m not familiar with the network binding, but I calculated runtime on a washing machine like this. (The runtime was used for notification purposes.). It works, but I still have some tidying to do I think.

// Switch Washing_Machine_State "Washing Machine State" <switch> - Item Definition (z-wave.items)
// Number Washing_Machine_Start_Time "Washing Machine Stop Time [%d]" - Item Definition (z-wave.items) - Stores Epoch timestamp
// Number Washing_Machine_Stop_Time "Washing Machine Stop Time [%d]" - Item Definition (z-wave.items) - Stores Epoch timestamp
// Number Washing_Machine_Runtime_Minutes "Washing Machine Runtime Minutes [%d]" Item Definition (z-wave.items) - Stores runtime minutes

var Number Epoch_Time = 0
var Number Washing_Machine_Runtime = 0


rule "Washing Machine State"
when
    Item zwave_washing_machine_meter_watts changed
then
    if (zwave_washing_machine_meter_watts.state == 0) Washing_Machine_State.postUpdate(OFF)
    if (zwave_washing_machine_meter_watts.state > 0) Washing_Machine_State.postUpdate(ON)
end


rule "Calculate Washing Machine Runtime"
when
    Item Washing_Machine_State changed
then
    Epoch_Time = now.millis
    if (Washing_Machine_State.state == OFF) Washing_Machine_Stop_Time.postUpdate(Epoch_Time)
    if (Washing_Machine_State.state == ON) Washing_Machine_Start_Time.postUpdate(Epoch_Time)
    if ((Washing_Machine_Start_Time.state as DecimalType) > 0 && (Washing_Machine_Stop_Time.state as DecimalType) > 0) {
        Washing_Machine_Runtime = ((Washing_Machine_Stop_Time.state as DecimalType) - (Washing_Machine_Start_Time.state as DecimalType)) / 60000
        Washing_Machine_Runtime_Minutes.postUpdate(Washing_Machine_Runtime)
        logInfo("Washing Machine", "Washing Machine Runtime - " + Washing_Machine_Runtime)
        }
end


rule "Washing Machine Notification"
when
    Item Washing_Machine_Runtime_Minutes changed
then
    if ((Washing_Machine_State.state == OFF) && Washing_Machine_Runtime_Minutes.state >= 10) {
        var Washing_Machine_Notification = String::format("Washing machine finished load in %.0f minutes.", Washing_Machine_Runtime.floatValue)
        sendMail("3145504161@vzwpix.com", Washing_Machine_Notification, "")
        logInfo("Washing Machine", Washing_Machine_Notification)
        Washing_Machine_Start_Time.postUpdate(0)
        //postUpdate(Washing_Machine_Start_Time, 0)
    }
end

Regards,
Burzin

@Burzin_Sumariwalla

Thank you. I shall amend your sample for what I need and will test it.
I only have one feedback coming back to openhab via Network Binding for this device - status will change between ON and OFF. So really I want to capture total time when this device is switched ON over a period of time.

Text item=DeviceStatus label="Device A [%s]" valuecolor=[ON="green" ,OFF="red"]

What is your polling interval in network binding conf? With long intervals the measurement can get quite inaccurate.

At the moment is set to 60 seconds but I can reduce it down to whatever will be required. I only get one feedback from device informing me if is ON or OFF. Works well so far must say.
If I amend the sample code above do you think I can achieve the expected result ?
This is my first contact with rules so black magic at the moment :wink:

Edit: Just to add, mainly I will be planning to monitor household devices such as computers, TV`s. So generally if device is ON , it will be used for some time and there should be plenty of time to capture state change.

Yes you can. Just start coding and you’ll get familiar with rules. Create virtual items as needed and persist the final calculation in a number item. I’m not good when it comes to Rules DSL but I think that after above steps, you can use “persistence extensions” (don’t know what’s the proper name) to get historical states from that item and do further min/max/avg calculations.

Good luck and let us know how it goes. We’ll help you to get further.

Amended code but don’t think it works. As I said I`m learning rules on this challenge. This is what I done so far with this.

// Switch LGTVStatus "TV State" <switch> - Item Definition (items) 
// Number LGTVStatus_Start_Time "TV Start Time [%d]" - Item Definition (items) - Stores Epoch timestamp 
// Number LGTVStatus_Stop_Time "TV Stop Time [%d]" - Item Definition (items) - Stores Epoch timestamp 
// Number LGTVStatus_Runtime_Minutes "TV Runtime Minutes [%d]" Item Definition (items) - Stores runtime minutes 

var Number Epoch_Time = 0 
var Number LGTVStatus_Runtime = 0 

rule "TV State" 
when 
    Item LGTVStatus changed 
then
    if (LGTVStatus.state = 0FF) LGTVStatus.postUpdate(OFF) 
    if (LGTVStatus.state = 0N) LGTVStatus.postUpdate(ON) 
end

rule "Calculate TV Runtime" 
when
    Item LGTVStatus changed
	then Epoch_Time = now.millis
	if (LGTVStatus.state == OFF) LGTVStatus_Stop_Time.postUpdate(Epoch_Time)
	if (LGTVStatus.state == ON) LGTVStatus_Start_Time.postUpdate(Epoch_Time)
	if ((LGTVStatus_Start_Time.state as DecimalType) > 0 && (LGTVStatus_Stop_Time.state as DecimalType) > 0) { 
	     LGTVStatus_Runtime = ((LGTVStatus_Stop_Time.state as DecimalType) - (LGTVStatus_Start_Time.state as DecimalType)) / 60000
         LGTVStatus_Runtime_Minutes.postUpdate(LGTVStatus_Runtime)
         logInfo("LGTV", "LGTV Runtime - " + LGTVStatus_Runtime)
		 }
end

My sitemap looks like this

Text item=LGTVStatus label="Status [%s]" valuecolor=[ON="green" ,OFF="red"]
Text item=LGTVStatus_Runtime_Minutes label="Runtime Time [%d]"

And items:

Switch LGTVStatus <screen> { channel="network:pingdevice:LGTV:online" }
Number LGTVStatus_Runtime_Minutes "TV Runtime Minutes"

What am I doing wrong ? Where should I be looking to check if the this rule produces anything. I would really appreciate some help with this issue.

First thing I noticed that the first rule “TV State” then block has only two if statements. It just checks them and then does nothing.

To see what is happening you have to see logs. Do you have frontail running? Always when I’m doing something with rules or oh itself, I have frontail open in a browser tab.

And if logs aren’t telling you enough you add more logging statements to your rule starting from the top.

To speed up your debugging and developing I suggest that you create virtual items and use them in your rule and sitemap:

Switch TVStatus_test
Number TVStatus_runtime_test

This way you don’t have to wait for the real item to switch on and off. After the rule is running properly, you replace those with real items.

HI,

It looks like you have a typos in your rules

if (LGTVStatus.state = 0FF) LGTVStatus.postUpdate(OFF) 
    if (LGTVStatus.state = 0N) LGTVStatus.postUpdate(ON)

LGTVStatus.state = OFF and LGTVStatus.state = ON have zeros instead of a letter.

I changed typos but this didnt make any difference. Checking event log, but cant find any evidence this rule works. Just to make it clear I only have one feedback from device informing me if the unit is in ON or OFF state.
Not sure what is the function of this line

var Number Epoch_Time = 0

This is my current rule:

// Switch LGTVStatus "TV State" <switch> - Item Definition (items) 
// Number LGTVStatus_Start_Time "TV Start Time [%d]" - Item Definition (items) - Stores Epoch timestamp 
// Number LGTVStatus_Stop_Time "TV Stop Time [%d]" - Item Definition (items) - Stores Epoch timestamp 
// Number LGTVStatus_Runtime_Minutes "TV Runtime Minutes [%d]" Item Definition (items) - Stores runtime minutes 

var Number Epoch_Time = 0 
var Number LGTVStatus_Runtime = 0 

rule "TV State" 
when 
    Item LGTVStatus changed 
then
    if (LGTVStatus.state == 0) LGTVStatus.postUpdate(OFF) 
    if (LGTVStatus.state > 0) LGTVStatus.postUpdate(ON) 
end

rule "Calculate TV Runtime" 
when
    Item LGTVStatus changed
	then Epoch_Time = now.millis
	if (LGTVStatus.state == OFF) LGTVStatus_Stop_Time.postUpdate(Epoch_Time)
	if (LGTVStatus.state == ON) LGTVStatus_Start_Time.postUpdate(Epoch_Time)
	if ((LGTVStatus_Start_Time.state as DecimalType) > 0 && (LGTVStatus_Stop_Time.state as DecimalType) > 0) { 
	     LGTVStatus_Runtime = ((LGTVStatus_Stop_Time.state as DecimalType) - (LGTVStatus_Start_Time.state as DecimalType)) / 60000
         LGTVStatus_Runtime_Minutes.postUpdate(LGTVStatus_Runtime)
         logInfo("LGTV", "LGTV Runtime - " + LGTVStatus_Runtime)
		 }
end

Epoch_time holds current time in milliseconds. It is used for runtime calculation.

In Burzins code snippet the first rule is used to convert a power meters readings to ON/OFF state. As you already have your item as switch, you don’t need the first rule.

Add more logging into your rule to see what it does and what not.

I removed the first rule as advised (commented out for now). Still no getting any values out of this rule.
As it stands my rule looks like follow at the moment.

// Switch LGTVStatus "TV State" <switch> - Item Definition (items) 
// Number LGTVStatus_Start_Time "TV Start Time [%d]" - Item Definition (items) - Stores Epoch timestamp 
// Number LGTVStatus_Stop_Time "TV Stop Time [%d]" - Item Definition (items) - Stores Epoch timestamp 
// Number LGTVStatus_Runtime_Minutes "TV Runtime Minutes [%d]" Item Definition (items) - Stores runtime minutes 

var Number Epoch_Time = 0 
var Number LGTVStatus_Runtime = 0 

// rule "TV State" 
// when 
//    Item LGTVStatus changed 
// then
//    if (LGTVStatus.state == 0) LGTVStatus.postUpdate(OFF) 
//    if (LGTVStatus.state > 0) LGTVStatus.postUpdate(ON) 
// end

rule "Calculate TV Runtime" 
when
    Item LGTVStatus changed
	then Epoch_Time = now.millis
	if (LGTVStatus.state == OFF) LGTVStatus_Stop_Time.postUpdate(Epoch_Time)
	if (LGTVStatus.state == ON) LGTVStatus_Start_Time.postUpdate(Epoch_Time)
	if ((LGTVStatus_Start_Time.state as DecimalType) > 0 && (LGTVStatus_Stop_Time.state as DecimalType) > 0) { 
	     LGTVStatus_Runtime = ((LGTVStatus_Stop_Time.state as DecimalType) - (LGTVStatus_Start_Time.state as DecimalType)) / 60000
         LGTVStatus_Runtime_Minutes.postUpdate(LGTVStatus_Runtime)
         logInfo("LGTV", "LGTV Runtime - " + LGTVStatus_Runtime)
		 }
end


Sitemap


```csv
Text item=LGTVStatus_Runtime_Minutes label="Runtime Time [%d]"

Items


```csv
Number LGTVStatus_Runtime_Minutes "TV Runtime Minutes"

Looking at the openhab log can see the following error.

2018-12-24 22:47:20.782 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'home.rules' has errors, therefore ignoring it: [77,1]: missing EOF at 'var'

What else is missing ?

Looks like you may have eberything firgued out, but here are some useful threads…

Is this a copy paste error? If not, check indentation.

Something is wrong at line 77 as that error says. Is that the only rule in that file?

I have other rules in that file. Other rules are from demo house I believe.
I will check line 77 .

If I’m not mistaken it could be a missing bracket or end statement in the previous rule in that file.

I removed extra gap between last and previous rule and warning now moved down to line 85

2018-12-25 14:32:17.409 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'home.rules' has errors, therefore ignoring it: [85,1]: missing EOF at 'var'

I think I must to have fundamental issue with this rule. Do I need to setup anything in persistence - rrd4j ?