Calculating Heater Runtime

val long oldVal = (MainHeater_Runtime_MSec.state as Number).longValue

I’ve never used longValue in a rule and not sure if this is line 88 or not. Double check the doc’s for proper use and syntax. If everything is correct, perhaps @rlkoshak or @vzorglub could provide some assistance, their some of the best with rules.

I think I have more than that going on the rule. I had to head down there last night and take it out. It was preventing the heater from turning on. That would kinda not be good. The rule seems to be checking the heater and turning it off. I will have to walk back through it. Agreed on @rlkoshak and @vzorglub!

I will test out that line and see what it does. Will have to check on other issues in there too. Once I get this figured out I will document it so others can follow. The generator post was great but was missing some key items like how to actually structure the items that are listed in the rules.

@boilermanc
I have had a quick look at your rule and I am working on it.
I have to say that i t is a bit of a mess with locks and 45s thread sleep… Begging for failure

A bit busy right now but I should come up with something soon

1 Like

thanks for much vincent. huge help!

That’s what the little heart icon is for.:wink:

Just making a quick run through the rule and pointing out what sticks out to me.

  • Remove the import for actions.*. This is not needed for OH 2.x
  • Locks are very dangerous, do your really need the Lock?
  • org.joda.time.DateTime is already imported for you, just use var DateTime whenStarted = null
  • Avoid the use of primitives (e.g longValue) unless absolutely required.
  • Use a Timer instead of a 45 second sleep. If the Rule takes more than half a second to run, you need to be using Timers.
  • The error is almost certainly that MainHeater_Runtime_MSec is NULL. NULL indicates an Item is uninitialized. NULL is not a Number and cannot be cast to a Number.
  • Here is one reason why Locks are dangerous. Because you have a type error in “Check Main Heater and Increment Runtimes”, the finally clause never executes and your Lock never gets unlocked.

I’m sure Vincent will steer you right.

Yep

Not if we check for status at start of rule

Yep, done

Yes, @boilermanc see: (OH 1.x and OH 2.x Rules DSL only] Why have my Rules stopped running? Why Thread::sleep is a bad idea
Timer replacing sleeps, coming up waiter…

Could be, we’ll add a logInfo and a check for that

Your order coming up, young man…
Well, in the morning. Bit late now

2 Likes

Your order sir!!

Try this:
Not tested but VSCode is happy with it so far:

var DateTime whenStarted = null
var Timer MainHeater_timer = null

rule "Main Heater Started"
when
    Item MainHeater received command ON
then	
	if (MainHeater_timer === null) {  /// Check equivalent to lock
    	MainHeater_timer = createTimer(now.plusSeconds(45), [ |
            if (MainHeater.state == ON) {
                whenStarted = now // Start Clock
                MainHeater_Failed.postUpdate(OFF)
                MainHeater_Cooling.postUpdate(OFF)
                createTimer(now.plusSeconds(15), [ |
                    //sendMail("myemail@gmail.com", "MainHeater", "Main Heater Started, load at " + Buy_Total_Watts.state + " watts")
                ])
            } else {
                whenStarted = null
                MainHeater_Failed.postUpdate(ON)
                MainHeater_Override.postUpdate(OFF)
                //sendMail("myemail@gmail.com", "Main Heater", "Main Heater Failed to Start!!")
            }
    		MainHeater_timer = null
	    ])
	}
end


rule "Main Heater Stopped"
when
    Item MainHeater received command OFF
then	
    whenStarted = null //Stops clock
    MainHeater_Cooling.postUpdate(ON)
	createTimer(now.plusSeconds(90), [ |
        MainHeater_Cooling.postUpdate(OFF)
	])
end

rule "Check Main Heater and Increment Runtimes"
when
    Time cron "0 0/1 * * * ?"
then	
    // Check if MainHeater failed
    if (MainHeater_Failed.state == ON) {
        //sendMail("myemail@gmail.com", "Main Heater", "Main Heater Failed!!")
    }

    // Increment Runtimes
    if (MainHeater.state == ON && whenStarted !== null) {
        val Number nowMSec = now.millis
        val Number wsMSec = whenStarted.millis
        whenStarted = now	
        val Number timeSinceLastUpdate = nowMSec - wsMSec
        val Number oldVal = if (MainHeater_RuntimeMSec.state == UNDEF || GeneratorRuntimeMSec.state == NULL) 0 else GeneratorRuntimeMSec.state as Number
        val Number totalMSec = oldVal + timeSinceLastUpdate // calculate total runtime
        MainHeater_Runtime_MSec.postUpdate(totalMSec) // post the full runtime
        val Number hours = totalMSec / 3600000 // (1000 / 60 / 60)
        MainHeater_Runtime_Hours.postUpdate(hours)

        // Calculate runtime for today		
        val Number todayOldVal = if(Today_MainHeater_Runtime_MSec.state == UNDEF || Today_MainHeater_Runtime_MSec.state == NULL) 0 else (Today_MainHeater_Runtime_MSec.state as Number).longValue
        val Number todayTotalMSec = todayOldVal + timeSinceLastUpdate // calculate total runtime
        Today_MainHeater_Runtime_MSec.postUpdate(todayTotalMSec) // post the full runtime
        val Number todayHours = todayTotalMSec/1000.0/60.0/60.0
        Today_MainHeater_Runtime_Hours.postUpdate(todayHours)
    }
end

rule "Today Main Heater Runtime Reset"
when
    Time cron "50 59 23 * * ?"
then
    Today_MainHeater_Runtime_MSec.postUpdate(0)
end
2 Likes

That’s a thing of beauty. I will get over and put it in today. We have a cold day here so it will get a chance to start recording.

On the variables in the rule, anything that has a post update I can add as an item and then to the sitemap? Do I even need to create an item for them or your doing that in the rule? They can be persisted as well? Would that be done in the rule or in the item? Once we get this running I will want to create another rule that will calculate the actual propane usage that’s one reason for the ask as well as just wanting to keep this charted.

Thanks!

The two variables, whenstarted and MainHeater_timer, no item needed. You will need to create the other items such as MainHeater_Failed, MainHeater_Cooling, MainHeater_Override. Looking at the rule these items will be a Switch type (ON/OFF).

Switch MainHeater_Failed "Main Heater Failed"

Other items such as MainHeater_Runtime_Hours and Today_MainHeater_Runtime_Hours will need to be a Number item.

Number MainHeater_Runtime_Hours "Main Heater Run Hours [%d]"

After creating the item you can add all of these to your sitemap.

2 Likes

Because there was a postUpdate already in the OP’s code I assumed these were items already created

Ok, this is where I am…

I added the rule as created! Thanks!

I added this as my items:

Switch MainHeater_Failed "Main Heater Failed"
Switch MainHeater_Cooling "Main Heater Cooling"
Switch  MainHeater_Override " Main Heater Override"

			
Number MainHeater_Runtime_Hours		"Main Heater Runtime Hours [%.1f Hours]"	   <heater>
Number Today_MainHeater_Runtime_Hours		"Main Heater Runtime Hours [%.1f Hours]"	   <heater>
Number MainHeater_Runtime_MSec      "Main Heater Runtime [%.1f MSec]" 	   <heater>
Number Today_MainHeater_Runtime_MSec      "Today Main Heater Runtime_MSec [%.1f MSec]" 	   <heater>

I persisted each of those.

I added this to my sitemap:

Text item=MainHeater_Runtime_Hours
Text item=Today_MainHeater_Runtime_Hours

i get this as an error:

[ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'Check Main Heater and Increment Runtimes': The name 'MainHeater_RuntimeMSec' cannot be resolved to an item or type; line 55, column 33, length 22

also, at what point would i expect data to start showing up?

thanks!

The item name and the name in the rule is not the same. Easy fix is to change the name in the items file to MainHeater_RuntimeMSec, as this is used several time in the rule. Notice the difference of _ in the item MainHeater_Runtime_MSec vs the item in the rule?

Actually now I see a couple of different things. In the rule there is:

MainHeater_RuntimeMSec.state == UNDEF || GeneratorRuntimeMSec.state == NULL) 0 else GeneratorRuntimeMSec.state as Number

I do not have any of those setup as items.

But there is also: MainHeater_Runtime_MSec.postUpdate in the rule. That I did as an item.

My post above was a quick scan of items to create, must have missed those. Not a big deal, just add them in your items file and check that you have no errors in the logs.

Whoot Whoot!

Ok, I changed the MainHeater_RuntimeMSec to MainHeater_Runtime_MSec across the board. I added the Generator item even though I dont think i need it.

i get this in the log!

2018-11-15 14:31:00.075 [vent.ItemStateChangedEvent] - MainHeater_Runtime_MSec changed from 35650 to 60004

2018-11-15 14:31:00.100 [vent.ItemStateChangedEvent] - MainHeater_Runtime_Hours changed from 0.00990278 to 0.01666778

2018-11-15 14:31:00.133 [vent.ItemStateChangedEvent] - Today_MainHeater_Runtime_MSec changed from 35650 to 95654

2018-11-15 14:31:00.152 [vent.ItemStateChangedEvent] - Today_MainHeater_Runtime_Hours changed from 0.00990278 to 0.02657056

added the runtime hours and today hours into the sitemap. thats now showing as zero as i just did the short test but it smells like success to me!

Looks good,:+1: glad to see working. Time will tell, if anything a slight tweak may be needed to suit a particular need but nothing major. @vzorglub knows his rules.:wink:

Agreed! @vzorglub pretty much rocks. How do you do that when you cant test it? Lot’s of practice. I brag on the Openhab community all the time to my friends. Best community out there. Oh, it’s an awesome app too…

In any case, this is awesome. I was able to create another rule that takes the daily total and calculates the gallons that are being used based on the run time. That’s what I wanted to get to. Now I need to see how that works over a couple of days. I may need to make some modifications so I can track that over time effectively.

I’ll do a follow up post with the final final so others can follow along. Again, thanks for all the help. I am sure this will be useful for others.

Thanks, I don’t deserve that praise. I am just standing on the shoulder of giants.

Please tick the solution post.

@boilermanc
If you want to PM me so we can go through the rule line by line. Think of it as a personalised tutorial.
And I’ll help you put together the tutorial post.

Seems elaborate.
Online flowmeter would give a direct digital pulse or pulses per revolution.
Count the pulses to give the quantity of gas used in any period
Assuming a constant flow rate i.e. a constant heat output then calculate total period from the number of pulses