Project Home‎ > ‎Documentation‎ > ‎

Creating an Instance

Okay, lets go through creating an instance that you can use to model your own control situation.

Here is an example instance script, (other examples can be found in the folder pytomation/contrib/instances):

You MUST store these files in the pytomation/instances directory as they are automatically run from there by the Pytomation startup code.

First we need to import a few modules.

# import the standard python module "select"
import select
# Import all the Pytomation interfaces we are going to use.
from pytomation.interfaces import UPB, InsteonPLM, TCP, Serial, Stargate, W800rf32, \
                                    NamedPipe, StateInterface, Command

# Import all the Pytomation Devices we will use.
from pytomation.devices import Motion, Door, Light, Location, InterfaceDevice, \
                                Photocell, Generic, StateDevice, State, Attribute   

Now we configure the interfaces connected to our computer.

###################### INTERFACE CONFIG #########################
This is where we define the interfaces that we want to use with our instance.  Below we are 
using UPB, Insteon, W800rf32 and Wtdio. # Our interfaces are all connected via serial ports. Two ports are standard, which # under Linux are ttyS0 and ttyS1 and two are USB to serial converters, ttyUSB0 and # ttyUSB1

Note: Both the Insteon serial PLM and the W800RF32 have xonxoff disabled.

upb = UPB(Serial('/dev/ttyS0', 4800))
insteon = InsteonPLM(Serial('/dev/ttyS1', 19200, xonxoff=False))
w800 = W800rf32(Serial('/dev/ttyUSB0', 4800, xonxoff=False)) 
wtdio = Wtdio(Serial('/dev/ttyUSB1', 9600))
uno = Arduino(Serial('/dev/ttyACM0', 9600))

# The Weeder board has to be told which point is an INPUT or OUTPUT
# You must set the I/O channels on the WTDIO board according to the 
# command set  S = Switch, L = Output, default low
# Inputs are set according to the wtdio manual by sending the board 
# data in the following sequence.  BOARD TYPE CHANNEL
# Example:  Board 'A', Type SWITCH, Channel D  - 'ASD'
# Currently only SWITCH inputs are handled.
# Outputs are set as follows: BOARD LEVEL CHANNEL
# Example:  Board 'A', Level LOW, Channel 'M', - 'ALM'
# Set channels A, B and C as input and channel H as output

# Set the I/O on the Arduino Uno board
uno.setChannel('ADIC')	  # Pin C (2) set as digital input with pullup
uno.setChannel('ADON')  # Pin N (13) set as digital output, LED on the UNO board
uno.setChannel('AAIO')  # Pin O (A0) set as analog input

Lets add some X10 wireless remotes that talk to the W800RF32 interface.

# ______ REMOTES ____________________________________________________ 

# X10 Slimline RF wall switch in living room
sl_sofa = Generic('A1', w800)
sl_stereo = Generic('A2', w800)
sl_outside = Generic('A3', w800)
sl_hall = Generic('A0', w800)		# Special A0 address is the DIM/BRIGHT key.

# X10 Slimline RF wall switch in Recroom
sl_recroom_light = Generic('D1', w800, name='Recroom Light Switch')
sl_recroom_lamp = Generic('D2', w800, name='Recroom Lamp Switch')
sl_recroom_lamp2 = Generic('D3', w800)
sl_alloff = Generic('D0', w800)	# Special D0 address is the DIM/BRIGHT key.

Now we'll add some motion sensors, some are hardwired to the WTDIO interface and some are wireless through the W800RF32.

# ______ MOTION SENSORS _____________________________________________ m_laundry = Motion(address='AD', devices=wtdio, name='Laundry Room Motion') #The delay means it will postpone the still command for 10 secs, so once the sensor goes to STILL it will remain in the MOTION state for 10 seconds m_hallway = Motion(address='AE', devices=wtdio, delay={ Attribute.COMMAND: Command.STILL, Attribute.SECS: 10 }, name='Hallway Motion') m_stairs = Motion(address='H1', devices=w800, name='Stair Motion') m_recroom = Motion(address='I1', devices=w800, name='Recroom Motion')

I add a location device which is used for turning lights on and off at sunset and sunrise or for telling the system that it is LIGHT or DARK outside. If you find your sunset is coming on too late just move your location East by about two or thee points and try again. Mine was originally -122.8463 but I moved it.

# ______ LOCATION ______________________________________________ # ph_standard = Location('48.9008', '-119.8463', tz='America/Vancouver', mode=Location.MODE.STANDARD, is_dst=True, name='Standard Photocell')

We are now ready to start defining some lights to control. A few lights are Insteon and a few are UPB.

Hallway light is set to an initial state of OFF, It will come on full when the back door is opened AND it is dark outside. 2*60 seconds later it will revert to the previously set state. If I turn the hallway light on and dim it to a set level say 50%, when the back door opens it will come on bright but fall back to the previously set 50% after 120 seconds. It will automatically go to OFF at “10:20pm”.

The ignore statement tells the hallway light NOT to come on when it is DARK, we just want it to know the state so the light is restricted during the daylight hours, when the door opens.

# Turn on the hallway light at night when the back door is opened. # SwitchLinc 2476D V5.4 l_hallway = Light(address='17.C0.7C', devices=(insteon, ph_standard, d_back, all_lights), ignore=({Attribute.COMMAND: Command.DARK}), mapped={ Attribute.COMMAND: (Command.CLOSE), Attribute.MAPPED: (Command.PREVIOUS), Attribute.SECS: 2*60, }, time={ Attribute.TIME: '10:20pm', Attribute.COMMAND: Command.OFF }, name="Hallway Lights",

Here the Sofa lamp turns on and off with the sl_sofa switch, at 10:00pm it will automatically dim to 60% , then go off at 10:20pm. pp_sofa source will turn the light on to a level of 60%, since the pp_sofa is an ON/OFF device we need to map the ON command to a 60% level.

# LampLinc
l_sofa = Light(address='12.07.1F', 
            devices=(insteon, sl_sofa, pp_sofa, pp_sofa60),
                Attribute.COMMAND: Command.ON,
                Attribute.MAPPED:  (Command.LEVEL, 60),
                Attribute.SOURCE:  pp_sofa60,
                Attribute.TIME: '10:00pm',
                Attribute.COMMAND: (Command.LEVEL, 60)
                Attribute.TIME: '10:20pm',
                Attribute.COMMAND: Command.OFF
            name='Sofa Lamps')

The stair light is a little unique. So what happens here is, the stair light has two motion sensors attached to it, The trigger is being used because the MS16a X10 motion sensor automatically sends an ON signal and the 60 seconds later sends a STILL signal, which we want to ignore. m_stairs is at the head of the stair and comes on when you go down. m_laundry is in the room at the bottom of the stairs and motion there will keep the light on for as long as you are there. It has a delay time of 2 minutes. When you come back up the stairs, m_stairs triggers and turns the light off 15 seconds later.

#SwitchLinc 2477S V6.0
l_stair_up = Light(address='1E.39.5C', 
            devices=(insteon, m_stairs, m_laundry),
                Attribute.COMMAND: Command.ON,
                Attribute.MAPPED: Command.OFF,
                Attribute.SOURCE: m_stairs,
                Attribute.SECS: 15,
            }, {
                Attribute.COMMAND: Command.ON,
                Attribute.MAPPED: Command.OFF,
                Attribute.SOURCE: m_laundry,
                Attribute.SECS: 2*60,
                Attribute.COMMAND: Command.STILL,
            name='Stair Lights up')

These two are UPB devices

# ______ RECROOM ____________________________________________________ 
l_recroom_lamp = Light(address=(49,6), 
            devices=(upb, sl_recroom_lamp, m_recroom),
                Attribute.COMMAND: Command.STILL,
                Attribute.SECS: 60
            name='Recroom Lamp')

Turn the bathroom fan on downstairs and it will automatically go off after 10 minutes. No point in sucking all the heat out of the house for hours if it gets left on.

# ______ BATHROOM DOWN ______________________________________________ 
f_bathroom = Light(address=(49,18),
                Attribute.COMMAND: Command.ON,
		 Attribute.MAPPED: Command.OFF,
                Attribute.SECS: 10*60
            name="Downstairs Bathroom Fan")

Turn the backdoor light on at sunset or if the door opens, or if the motion sensor triggers. This door uses the idle attribute to automatically dim the light to 40% after 60 seconds. If the door opens or the motion sensor is triggered, the light comes back up to full brightness, aka ON but always falls back to 40%, once the door is closed or there is no motion on the sensor. The sensor is actually outside pointing away from the house so it will trigger when one is about 20 feet away.

# ______ OUTSIDE _______________________________________________ 
l_backdoor = Light(address='12.B8.73', 
            devices=(insteon, sl_outside, ph_standard, d_back, all_lights, m_backdoor),
            ignore=({Attribute.COMMAND: Command.CLOSE},),
                    Attribute.MAPPED:(Command.LEVEL, 40),
                    Attribute.SECS: 60,
                Attribute.TIME: '10:30pm',
                Attribute.COMMAND: Command.OFF
            name='Backdoor Light')

I add this in so it automatically polls all my Insteon lights at system startup to retrieve the status of the lights, on/off or level. Put this just before the MainLoop.

print "Updating status..."

The MainLoop is an area where you can run some of your own code in a standard python fashion.

def MainLoop(*args, **kwargs):

	# startup is true for one loop at system start and then goes false forever.
	if startup:
		print “System is starting up....”

Here is a little goodie that plays with the internal state of the hallway light. First get the current time in an integer format. Now if it is dark AND the time is less than 10:30pm make the hallway have a previous level of 40%, else give it a level of 0. I do this because at night the I only want the hallway light to come on when the door opens and it's before 10:30pm.

If you go back up a few pages you will see the code for the hallway light.

htime = time.strftime('%H%M')
if ph_standard.state == "dark" and htime <= '2230':
	l_hallway._previous_state = (State.LEVEL,40)
	l_hallway._previous_state = (State.LEVEL, 0)

# Put in a fail safe pass in case I have no code in Mainloop