Premise Occupancy and Lighting control

Motorola Premise

kzboray

Member
I've installed a couple of occupancy sensors and would like to control lighting with them. To start off I added the SmartRooms Class from the Premise help. I quickly found it had errors in the code that didn't allow it to work. I then tried writing my own code (I have no experience writing code). I managed to setup a OnChangeMotionDetected script that kinda works.

Code:
If Home.House.Second_Floor.Master_Bathroom.Occupancy = True Then
	 If system.times.sysTime > system.times.sysSunset(system.times.sysDate) Then
		  Home.House.Second_Floor.Master_Bathroom.RecessedLight.PowerState = True
		  addTimer 180,"Home.House.Second_Floor.Master_Bathroom.RecessedLight.PowerState = False",1,this.Name
	 End If
End If

This works as long as it is before midnight. I assume that at midnight sysSunset move to the next day and therefore the check is no longer true, and it falls through the logic check.

I also tried:

Code:
If Home.House.Second_Floor.Master_Bathroom.Occupancy = True Then
	 If system.times.sysTime > system.times.sysSunset(system.times.sysDate) And _
	 system.times.sysTime < system.times.sysSunRise(system.times.sysDate)
		  Home.House.Second_Floor.Master_Bathroom.RecessedLight.PowerState = True
		  addTimer 180,"Home.House.Second_Floor.Master_Bathroom.RecessedLight.PowerState = False",1,this.Name
	 End If
End If


This causes a impending overflow error. Again I am assuming this is due to the sysSunset and sysSunrise potentially being different days.

So..............

How do you all have your occupancy sensors setup?

Ultimately I would like to be able to have multiple brightnesses depending on the time of day and the state of my alarm panel. Any examples would be much appreciated.

Kaz
 
Kaz, search for "sysSunset method" in Premise's help file. Notice how the example checks if the current time is between Sunset and Sunrise.

So if we apply the same thinking to your first code example:

Code:
With Home.House.Second_Floor.Master_Bathroom
   If .Occupancy Then
	  If times.sysTime > times.sysSunset(times.sysDate) Or _
		times.sysTime < times.sysSunrise(times.sysDate) Then
		.RecessedLight.PowerState = True
		addTimer 180,"Home.House.Second_Floor.Master_Bathroom.RecessedLight.PowerState = False",1,this.Name
	  End If
   End If
End With

You can use a little shorthand by simply stating "If Variable Then" provided the Variable is Boolean (or a positive Integer). I also used the "With ... End With" statement to help prevent Carpal Tunnel Syndrome as a result of typing Premise's long-winded object names! :rolleyes:

PS
You can also try House.IsDark ... a neat Module that tells you if the house is Dark/Light/SomewhatDark.
 
I looked at the linked module. Does this work as presented? I cant seem to get it to work. Shouldnt the input be a DATETIME block instead of a TIME block? When I use as is, the sunset/sunrise times are incorrect but are corrected when I add the Date.

Kaz, search for "sysSunset method" in Premise's help file. Notice how the example checks if the current time is between Sunset and Sunrise.

So if we apply the same thinking to your first code example:

Code:
With Home.House.Second_Floor.Master_Bathroom
   If .Occupancy Then
	  If times.sysTime > times.sysSunset(times.sysDate) Or _
		times.sysTime < times.sysSunrise(times.sysDate) Then
		.RecessedLight.PowerState = True
		addTimer 180,"Home.House.Second_Floor.Master_Bathroom.RecessedLight.PowerState = False",1,this.Name
	  End If
   End If
End With

You can use a little shorthand by simply stating "If Variable Then" provided the Variable is Boolean (or a positive Integer). I also used the "With ... End With" statement to help prevent Carpal Tunnel Syndrome as a result of typing Premise's long-winded object names! :)

PS
You can also try House.IsDark ... a neat Module that tells you if the house is Dark/Light/SomewhatDark.
 
ABC,

The code block that 123 supplied works wonderfully. I am hesitant to answer your question in that I am just learning myself, but I'll give it a try. 123 feel free to jump in and correct me where I screw up.

This code block is designed to be used in an OnEvent not in a logic diagram.

To use this code you would first create in Home a House by right clicking on Home and selecting New/Location/Building/House. Using the same technique you would then create off of House, Second_Floor New/Location/Building SubArea/Floor. Continue on and create Master_bathroom off of Second_Floor. Now in the Master_Bathroom create a RecessedLight New/Lighting/RecessedLight and a MotionDetector New/Security/MotionDetector. With the above you should have created all of the objects the code block requires to work.

Now let's add the script and copy in the code.

Right click on the MotionDetector and select New/Script/Property Change, In the Select Property Dialog click on MotionDetected and then click OK. This will create the OnChangeMotionDetected Script. It is blank at the moment. copy in the code block below.
Code:
With Home.House.Second_Floor.Master_Bathroom
   If .Occupancy Then
	  If times.sysTime > times.sysSunset(times.sysDate) Or _
		times.sysTime < times.sysSunrise(times.sysDate) Then
		.RecessedLight.PowerState = True
		addTimer 180,"Home.House.Second_Floor.Master_Bathroom.RecessedLight.PowerState = False",1,this.Name
	  End If
   End If
End With

The way this works is as follows. Until there is a End With assume all dot references are about the object listed. So in this case Home/House/Second_Floor/Master_Bathroom
Code:
With Home.House.Second_Floor.Master_Bathroom
This line uses the shortcut we implemented in the first line allowing us to forgo using the entire object identifier.
Code:
If .Occupancy Then
So if Occupancy is true then do whats listed below. If we were to write out this line in it's full context it would read.
Code:
 If Home.House.Second_Floor.Master_Bathroom.Occupancy = True Then
But using the short cuts 123 demonstrated it can be shortened to what you see. The following bit of code checks two things.
Code:
If times.sysTime > times.sysSunset(times.sysDate) Or _
		times.sysTime < times.sysSunrise(times.sysDate) Then
First is the current time times.sysTime > the time of sunset for todays date times.sysTime(sysDate). This requires that you have setup your location correctly in Sys. You can do this by first loading the LocationInfo module that comes with Sys. The Or _ at the end of the line indicates that it needs to check another condition before finishing up the If loop.
Code:
If times.sysTime > times.sysSunset(times.sysDate) Or _
Then pretty much the same thing, but this checks the the current time is less than SunSet. I'm still not sure why it works this way but for now it's enough to know that it works.
Code:
times.sysTime < times.sysSunrise(times.sysDate) Then
I would of assumed that the actual code should be.
Code:
If times.sysTime > times.sysSunset(times.sysDate) And _
		times.sysTime < times.sysSunrise(times.sysDate) Then
But the use of AND confuses Sys no end. So OR seems to be the right call here. I need to read up on OR, AND, XOR, etc and make sure I understand how they should be used. I'm getting off the topic but since it confused me I thought I would share it with you as well so you don't make the same mistake.
Now it's time to actually do something with the light. This turns the light on to what ever the PresetDim Value is.
Code:
 .RecessedLight.PowerState = True
This little piece of code is pretty simple it says create a timer on the fly addTimer, and set it's duration to 180 seconds. The timer is for the object Home.House.Second_Floor.Master_Bathroom.RecessedLight.PowerState, and when the timer runs out I want the value of this object to be False. I want the timer to run 1 time only and the name of the timer should be Second_Floor.Master_Bathroom.Occupancy derived from the scripts root objects name this.name.
I just learned that It's best practice to remove any existing timers before creating a new one. Since this is looking at the Occupancy property and not the Trigger property it seems to work OK. If I instead was looking at the motion detectors Trigger property it might be necessary to remove the timer each time the Trigger went true, before creating a new timer. Otherwise you could end up with a gazillion timers all for the same object. I haven't tested this theory yet but I'm fairly certain I'll need to add a check for an existing timer and then if there is one delete it first. Tomorrows project.
Code:
addTimer 180,"Home.House.Second_Floor.Master_Bathroom.RecessedLight.PowerState = False",1,this.Name
The last bits of code, simply close the loops up and ends the With block.
Code:
End If
   End If
End With

I have actually added a piece of code to this that sets the PresetDim property according to the state of the alarm.

Code:
Select Case Devices.Ademco.ApexDestiny6100.Partitions.Partition_1.SecurityState
	 Case 0 'Away Mode
		  .RecessedLight.PresetDim = 0
	 Case 1 'Disarmed
		  .RecessedLight.PresetDim = 1
	 Case 2 'Home
		  .RecessedLight.PresetDim = .15
End Select

This says that if the Alarm is set to Home mode (We set this when we go to bed) that I want the lights PresetDim value to be 15%. Otherwise if we are home but not in bed set it to 100%. If no one is home set it to 0 or off. I make this check before calling sunrise/sunset check. The final code looks like this.
Code:
With Home.House.Second_Floor.Master_Bathroom
   If .Occupancy Then
	 Select Case Devices.Ademco.ApexDestiny6100.Partitions.Partition_1.SecurityState
	 Case 0 'Away Mode
		  .RecessedLight.PresetDim = 0
	 Case 1 'Disarmed
		  .RecessedLight.PresetDim = 1
	 Case 2 'Home
		  .RecessedLight.PresetDim = .15
	 End Select
	  If times.sysTime > times.sysSunset(times.sysDate) Or _
		times.sysTime < times.sysSunrise(times.sysDate) Then
		.RecessedLight.PowerState = True
		addTimer 180,"Home.House.Second_Floor.Master_Bathroom.RecessedLight.PowerState = False",1,this.Name
	  End If
   End If
End With

I probably missed your point or gave you to much information. Either way let me know and I'll do my best to fill in any missing blanks.

Kaz
 
Kaz,
Great job of explaining the script's details!

Here are a few answers to some of your questions:

Why use OR instead of AND for the time test?
If you want something to happen when it is dark, then you need to know if the current time is between Sunset and Sunrise. You must peform two tests:
  1. Is a given hour between Sunset and Midnight?
  2. Is a given hour between Midnight and Sunset?
If Sunset is at 8:00 PM, any hour between 8:00 and midnight (8 - 12) is greater than Sunset.
If Sunrise is at 6:00 AM, any hour between midnight and 6:00 (12 - 6) is less than Sunrise.
So far so good. However, a given hour cannot be numerically greater than Sunset AND less than Sunrise. If it is 2:00 AM, 2 is less than 6 but not greater than 8. If it is 10:00 PM, 10 is greater than 8 but not less than 6. So a given hour can pass the first test OR the second test but cannot satisfy both tests.

Do I need to remove an existing timer before creating a new one?
In Premise Builder's Help, at the very bottom of the Timers page, you'll find this tip:
Resetting Timers: To reset a Timer that is currently running, you must call the system.addTimer method in Script. When calling the addTimer method to reset a Timer, use the same line of code that started the Timer. Anytime you supply the name of an existing Timer as the fourth parameter of an addTimer method call, it will reset the existing Timer.

BTW
I've read the SmartRooms example several times and I've been meaning to implement it ... but you say it's broken? What sort of error messages did you encounter?

acalbear,
I believe you are 100% ccorrect about Home.IsDark. I haven't used the Module, but its logic diagram does not display the correct Sunrise/Sunset times unless its input block, Time, is replaced by DateTime. How could it possibly know what is the correct Sunrise/Sunset times for a given date if the date is not supplied?!?
 
123,

Thanks for the explanation of OR and the tip on timers. I had kind of worked out the OR issue, but I wanted to test it. You saved me some time thank you.

As to the SmartRooms module well I've had two issues trying to get it working first I followed the directions given and I believe I successfully created the module as instructed. I then added a SmartDetector to my Master_Bathroom linking it to /devices/ademco/apex6100/zones/zone_22. Zone 22 is the motion detector in the master bathroom. Then I added a Preferences object to the Master_bathroom as well and set the PresetDim to 100%. If I then drag the Master_Bathroom into the watch window and click on the SmartDetector.Detected box. The light will turn on at the PresetDim set in preferences as indicated by the instructions in the SmartRooms example. However If I instead trigger the motion detector by walking into the room the SmartDetector never triggers. I know the problem is here.
Code:
'check first if the parent inherits from the Occupancy class
If this.Parent.IsOfExplicitType(schema.Modules.SmartRooms.Classes.SmartRoom.Path) Then
	 'if detected is set to true
	 If (sysevent.newVal = True) Then
		  'change properties on the parent room
		  With this.Parent
			   .Trigger = True
			   .LastDetection = this.Name
			   .TimeTriggered = Now()
		  End With
	 End If
End If
But I'm not sure how to correct it. I think the issue is that it is looking at the status of Occupancy and not Trigger. Secondly it's looking at the Parent.Room and not the Bound.Object.

The second issue is that you will get a impending stack overflow in line 5 of the following if you set the times in preferences to something usable. For a test try a start time of 6:00pm and an end time of 5:00am.
Code:
Sub GetPreferences(objContainer, ByRef objPreference)
	 'if no preferences are found, the function will return nothing
	 Set objPreference = Nothing
	 'cycle through the preferences created in a container
	 For Each obj In objContainer.GetObjectsByType(Modules.SmartRooms.Classes.Preferences.Path)
		  'If the current time is in between the start and end time of preference
		  If (Time >= obj.StartTime) and (Time < obj.EndTime) Then
			   'return the preference
			   Set objPreference = obj
		  End If
	 Next
	 'if a preference was not found for the current object
	 If objPreference Is Nothing Then
		  'and the parent of the current object is also a location
		  If objContainer.Parent.IsOfExplicitType("sys://Schema/Home/Location") Then
			   'make a recursive call to this sub To check the parent location for any preferences
			   GetPreferences this.Parent, objPreference
		  End If
	 End If
End Sub

I changed.
Code:
If (Time >= obj.StartTime) AND (Time < obj.EndTime) Then
to
Code:
If (Time >= obj.StartTime) OR (Time < obj.EndTime) Then

but that didn't fix the problem. So I decided to write my own script and you know where I'm at with that. Let me know if you have any ideas how to fix this. It's a good model and should be easy to extend.
 
I don't have any solid answers until I get a chance to try this out (and that may take awhile ... so much to do, so little time).

The first code snippet changes properties that are part of the Room object (which is the Parent object of the Detector). The first line mentions "Occupancy class" and I thought you'd need the Occupancy module installed but I now think this is a typo ... there is no test for the Occupancy class; it tests for the presence of the SmartRoom class.

GetPreferences does not appear to handle a time-range that spans midnight so a range of 6:00 PM to 5:00AM will not work. Changing the AND to an OR will create a problem. 11:00 PM is not in the range of 8:00 PM to 10:00PM but it will be accepted. [11 > 8 (True) OR 11< 10 (False)] = True ... oops, not good. Yet the example show a range of 8:00 AM to 5:00 PM ... hmm.
 
Not to add my two cents on this topic, but I thought I would share some code I did to handle occupancy in my family room. I have a scene called Night_Interior that turns on the lights 30 minutes before dusk and off at 1030p. I'm also using the HomeIsDarkLightSomewhatDark module from the old forum. My approach is that I expect the lights to be on in the evenings regardless of occupancy (thus the use of the Night_Interior scene); and outside of that, the lights should come on when someone walks into the family room (unless it's daylight outside). The code should be in an OnChangeOccupancy procedure.

-John

[codebox]' This should turn on the lights after someone has entered
' the room during normal off-hours mid-night to sunrise
'

' Make sure that the lights turn on only if the room is
' occupied
'
' 7/18/2004 - JMG - Baseline code
' 7/19/2004 - JMG - Added check for no occupancy to turn lights
' off between midnight and sunrise
' 8/5/2004 - JMG - Rearchitected to use the scene "Play" attribute
' and to get around wierd states at sunrise
' 2/11/2006 - JMG - Added INSTEON floor lamp as an experiment
' 2/12/2006 - JMG - Added INSTEON Table lamp and removed "Lights"
' 6/17/2006 - JMG - Using INSTEON Group 2 (All Family Room Lights) instead of the individual ligts
' 9/15/2006 - JMG - Using Insteon Group 3 (All Family Room lights). Repurposed Insteon Group 2 to all first floor lights
' 9/16/2006 - JMG - Modified to use IsLight property for the home rather than doing an explicit day-light check
'
if Home.House.FirstFloor.FamilyRoom.Occupancy then
'
' This branch gets executed when the room is occupied
'
' Check to see if the scene is active. If not process. If so
' ignore
'
if not Scenes.Night_Interior.Play then
'
' Scene is not playing. Check to see if it is day-time
'

if home.IsLight then
'
' It is daytime so just turn the lights off
'
Home.House.FirstFloor.FamilyRoom.All_Family_room_lights=false
Home.House.FirstFloor.LivingRoom.Curio_Cabinet=false

else
'
' It is night time and the scene is not playing, so turn the lights on
'
Home.House.FirstFloor.FamilyRoom.All_Family_room_lights=true
Home.House.FirstFloor.LivingRoom.Curio_Cabinet=true

end if ' Daylight check

end if ' Scene play check

else
'
' This branch gets executed if the room is not occupied
' Check to see if the scene is NOT playing. If it is not, turn the
' lights off. If so, ignore and keep going
'
if not Scenes.Night_Interior.Play then
Home.House.FirstFloor.FamilyRoom.All_Family_room_lights=false
Home.House.FirstFloor.LivingRoom.Curio_Cabinet=false


end if



end if ' Occupancy check



[/codebox]
 
Back
Top