Okay, lets go
through creating an instance that you can use to model your own
control situation.
Here is an
example instance script, myhouse.py (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
wtdio.setChannel('ASA')
wtdio.setChannel('ASB')
wtdio.setChannel('ASC')
wtdio.setChannel('ALH')
# 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),
send_always=True,
mapped={
Attribute.COMMAND: Command.ON,
Attribute.MAPPED: (Command.LEVEL, 60),
Attribute.SOURCE: pp_sofa60,
},
time=({
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),
trigger=({
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,
},),
ignore={
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),
delay={
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),
devices=(upb),
mapped={
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),
send_always=True,
ignore=({Attribute.COMMAND: Command.CLOSE},),
idle={
Attribute.MAPPED:(Command.LEVEL, 40),
Attribute.SECS: 60,
},
time={
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..."
insteon.update_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)
else:
l_hallway._previous_state = (State.LEVEL, 0)
# Put in a fail safe pass in case I have no code in Mainloop
pass