So I have the following rule that only half works and I can’t seem to figure out my error…
rule "Energy Cost"
when
Item Energy_Watts received update
then
val hour = now.getHour()
var cost = Energy_Watts.state as DecimalType
var Number OFFrate = 0.074
var Number ONrate = 0.152
var Number MIDrate = 0.102
AnnounceStatus.sendCommand(hour)
//Off-Peak on Holidays
if (Ephemeris.isBankHoliday()) {
e_cost.sendCommand((cost)/1000 * (OFFrate))
rate.sendCommand("Holiday (7.4¢/kWh)")
}
else {
//Off-Peak on Weekend
if (Ephemeris.isWeekend()) {
e_cost.sendCommand((cost)/1000 * (OFFrate))
rate.sendCommand("Weekend (7.4¢/kWh)")
}
else{
//Off-Peak from 7PM to 7AM
if (hour >= 19 && hour < 7) {
e_cost.sendCommand((cost)/1000 * (OFFrate))
rate.sendCommand("OFF-Peak (7.4¢/kWh)")
}
//On-Peak from 11AM to 5PM
else if (hour >= 11 && hour < 17) {
e_cost.sendCommand((cost)/1000 * (ONrate))
rate.sendCommand("ON-Peak (15.2¢/kWh)")
}
//Other times are MidPeak (7AM to 11AM & 5PM to 7PM)
else if (hour >= 7 && hour < 11) {
e_cost.sendCommand((cost)/1000 * (MIDrate))
rate.sendCommand("MID-Peak (10.2¢/kWh)")
}
else if (hour >= 17 && hour < 19) {
e_cost.sendCommand((cost)/1000 * (MIDrate))
rate.sendCommand("MID-Peak (10.2¢/kWh)")
}
}
}
end
So the ON Peak and OFF peak is working correctly, but for whatever reason the MID peak rate never seems to fire. (7AM to 11 AM & 5PM to 7PM) It just keeps showing as ON-Peak during this time window.
I’ve tried several combinations, like changing the AND to OR conditions (&& to ||) and nothing seems to work.
I also originally just tried multiple IF conditions and not ELSE IF, which also didn’t work.
I know this is just a stupid syntax error but I’ve been struggling with this all week and I’m hoping a smarter mind will be able to catch my stupid error.
The first thing I notice, there’s not logging. You have a bunch of variables and calls out to stuff like Ephemeris and Item states and such and you don’t know what any of it is.
Log out everything used in the rule, particularly hour. When it doesn’t work, using pen and paper and run down the code line by line and see what it actually did.
One thing I notice, hour >= 19 && hour < 7 will never be true. You’ll never have a number that is both larger than 19 and less than 7. That’s an impossibility so it can never be true.
rule "Energy Cost"
when
Item Energy_Watts received update
then
// Constants
val COST = Energy_Watts.state as DecimalType
val OFF_RATE = 0.074
val ON_RATE = 0.152
val MID_RATE = 0.102
val HOUR = now.getHour()
// 1. Determine if the rule needs to run at all
// always run the rule
// 2. Calculate what needs to be done.
var currRate = OFF_RATE; // initialize to OFF
var rateMessage = "OFF_Peak (7.4¢/kWh)"
if(Ephemeris.isBankHoliday()) rateMessage = "Holiday (7.4¢/kWh)"
else if(Ephemeris.isWeekend()) rateMessage = " Weekend (7.4¢/kWh)"
else {
switch(HOUR) {
// Mid peak
case HOUR >= 7 && HOUR < 11,
case HOUR >= 17 && HOUR < 19: {
currRate = MID_RATE
rateMessage = "MID-Peak (10.2¢/kWh)"
}
// On peak
case HOUR >= 11 && HOUR < 17: {
currRate = ON_RATE
rateMessage = "ON-Peak (15.2¢/kWh)"
}
}
}
// 3. Do it
val totalCost = (COST)/1000 * (currRate)
logInfo('Energy Cost', rateMessage + ' ' + totalCost + ' at hour ' + HOUR)
e_cost.sendCommand(totalCost)
rate.sendCommand(rateMessage)
end
Note, the switch is a way to make a more compact set of if/else statements. But the general approach is to set some variables to a default. The OFF_RATE is the most common and dealing with figuring out if now is between two times that cross midnight is harder, so we choose that. That way we don’t need to explicitly test for OFF_RATE any more. Only if it’s ON_RATE or MID_RATE do we need to test. That completely gets rid of one case and reduces two states to a one liner.
I don’t know why you command rate with a different message for weekend and holiday but I preserved that in the first two if, else if statements. In both cases the rate is OFF_RATE so we don’t need to do anything there.
That leaves the else which includes a switch. The first two cases fall through and set the variables based on the midrate. Then we have the case for the ON_RATE.
We don’t actually send the commands to the two Items until the end where we log out all the important stuff which will tell you what the rule did and why.
Note, I just typed in the above, it could have errors.