Ecobee occupancy-based Auto-OFF for lights

I have an ecobee thermostat, which has integrated occupancy sensors. I’ve set up the ecobee binding and some rules to turn off the lights when the ecobee says there’s no one in the room. (The ecobee trips occupancy “ON” for a minimum of 30 minutes, and the ecobee binding sends status updates every minute. So this rule turns off the lights if no one has been in the room for 30 to 31 minutes, when the occupancy status updates to “OFF”)

rule "LivingRoom Lights Auto-OFF"
when
	Item LivingRoomOccu received update OFF
then
		Living_Room.sendCommand(OFF)
end

It works, but there is a small catch:
Sometimes, when I walk into the room, the occupancy sensor doesn’t trip ON until after then next OFF update goes through. I’m trying to figure out the best way to ignore that false “unoccupied” reading.

I’m considering creating a switch called “OccupancyDelay” and then using the below pair of rules. The goal being to delay the OFF command until two consecutive Occupancy OFF updates have been recieved. Is there a better way to make this happen?

rule "LivingRoom Lights Auto-OFF"
when 	Item LivingRoomOccu received update OFF
then 
	if (OccupancyDelay.state == ON) {
		Living_Room.sendCommand(OFF)
	OccupancyDelay.sendCommand(OFF)
	} 
	else {
	OccupancyDelay.sendCommand(ON)
	}
end

rule "LivingRoom Lights Occupancy reset"
when
	Item LivingRoomOccu received update ON
then
	OccupancyDelay.sendCommand(OFF)
end

Also, I’m curious about efficient use of system resources. As it is, the rule sends an “OFF” command to the lights every minute as long as the room is not occupied. To the user, this is invisible and doesn’t pose a problem. But, does it consume system resources or cause any background issue that I may not be aware of?

And, if I put an “if” clause into the rule, so that it only sends the OFF command if the lights are already on, does evaluating that “if” clause every minute cause more or less of a burden on system resources than just letting it send the OFF command every minute?

I think I understand the issue, and I think it’s the result of the very long latency between when the physical sensor trips and the time it’s reported by the API. So you want to avoid OFF commands for the maximum latency since the last ON command:

import org.joda.time.*

var DateTime lastOn = null

rule LivingRoomOccuON
when
  Item LivingRoomOccu changed to ON
then
  lastOn = now.toDateTime
  Living_Room.sendCommand(ON)
end

rule LivingRoomOccuOFF
when
  Item LivingRoomOccu received update OFF
then
  if (lastOn != null && lastOn.plusMinutes(6).isBeforeNow()) {
    Living_Room.sendCommand(OFF)
  }
end

Untested! (and updated)

Also, what binding are you using to turn the light off and on? If it’s Z-Wave, for example, I doubt there are any side effects from multiple OFF commands.

Cool, thanks. I’ll give it a shot and let you know if it works.

And, I’m talking to Hue lights through the hue binding, and to Z-wave lights on my Vera through the MiOS binding.

I don’t know of any reason why sending multiple OFF commands through those paths would be a problem.

Also, if you don’t mind, would you download and test this version of the Ecobee binding JAR that I hope to add to openHAB 1.8?

Nice. I’ve just installed the new binding JAR and I’ll let you know how it goes.

I realized any issue with the occupancy delay code, so I’ll be trying something else with that, as well: As it is, the code doesn’t set the variable until the occupancy state switches to ON… but at that point, I don’t need the delay anymore.

The lag time between occupancy triggering and the binding hearing about through the API is too long to use for turning lights ON upon entering the room. However, I hope to use this code as a backup for turning the lights OFF if we forget when we leave the room for a while, or leave the house. So, I’ve changed the code to: trigger when any light in the room is turned on, and set the variable to that time. Then, when an “Occupancy OFF” update comes in, it gets ignored if it’s still within 6 minutes of the light getting turned on.

I won’t be home during the day today to check that it works though. Hopefully I’ll have a moment tonight.

One more quick question related to this: Is there a way to access the occupancy settings for the main thermostat? I can see the remote sensor capability settings for occupancy, but I can’t seem to find any way to get the occupancy from the thermostat itself.

I can see the occupancy from the main thermostat in my ecobee portal… is it just not accessible via the API?

If your ecobee3 thermostat’s name is Dining Room, you ought to be able to get the occupancy state like this:

ecobee="<[123456789012#remoteSensors(Dining Room).capability(occupancy).value]"

Aha, I see. So it still says “remoteSensors” even though it’s not physically a remote sensor unit. That’s why I was confused. :slight_smile: Thanks!

They just grouped all the sensors that way in the API. You can also get the relative humidity at the thermostat that way:

Number humidity { ecobee="<[123456789012#remoteSensors(Dining Room).capability(humidity).value]" }

and you can get the ambient temperature at the thermostat itself, instead of the temperature averaged across all active sensors that runtime.actualTemperature returns, like this:

Number temperature { ecobee="<[123456789012#remoteSensors(Dining Room).capability(temperature).value]" }

Nice. Thanks! This info will definitely be helpful as I start making more rules and charts.

Here’s what ended up working, in the kitchen. I’m using the light getting turned on (or updated, in case it’s set to a dimmer level instead of ON) as a trigger, since the whole point of this rule is that the occupancy trigger of the ecobee sensor doesn’t report quickly enough.

rule "KitchenOccuON"
when
  Item Kitchen_Table received update
then
  if (Kitchen_Table.state != OFF){
  lastOn = now.toDateTime
  }
end

rule "KitchenOccuOFF"
when
  Item KitchenOccu received update OFF
then
  if (lastOn != null && lastOn.plusMinutes(7).isBeforeNow()) {
    Kitchen_Table.sendCommand(OFF)
  }
end

Now I intend to do the same thing in the LIving Room, using a group of lights instead of a single light. So I’ve set the rule up like this:

rule "LivingRoomOccuON"
when
  Item Living_Room received update
then
  if (Living_Room.state != OFF){
  LRlastOn = now.toDateTime
  LRRuleFired.sendCommand(ON)
  }
end

rule "LivingRoomOFF"
when
  Item LivingRoomOccu received update OFF
then
  if (LRlastOn != null && LRlastOn.plusMinutes(7).isBeforeNow()) {
    Living_Room.sendCommand(OFF)
  }
end

I added the virtual switch in there (LRRuleFired) so that I could easily see if the trigger fired. I wasn’t sure if it would work using a group instead of a single light.

The good news is that updating the status of any of the lights in the group does serve to trigger the rule. It seems to trigger four times, though. In the events.log, “LRRuleFired” gets set to “ON” four times in a row, in under one second, every time a light in the group “Living_Room” gets its status updated.

At first I thought it must be related to the number fo lights in the group, but there are actually more than 4 lights in the Living_Room group.

I suspect that this is fine for the operation of the rule, but is there a better way to trigger a rule when any one of a group of lights is updated?

Group items seem to receive lots of updates, but if you just want to know if any of the contained items was updated, it should be OK to do it that way.