RasPi as X10 server
Unlike all my other articles this article will be in English:
My Raspberry Pi is now an RF X10 server!
What I wanted to do is switch my X10 dimmers with my smartphone.
Hardware
Each of my switches is RF enabled, so all I needed was one of my 433.92MHz transmitters and apply it to one of the GPIO outputs of my Raspi.
The transmitter is widely and cheaply available and has three pins: 2 Power pins and one data pin. On the Raspi connector, pins 1 and 3 are used as positive and negative power pins respectively. I used pin 11 (GPIO17 on my Rev1 board) as data pin.
Maybe I should mention that my RasPi is running in standard mode @ 700MHz.
Software
Among many options, I've chosen to create a Python library to control the GPIO pins, in turn controlled by a PHP page, running on Apache2.
To enable the user running Apache2 (www-data) to execute scripts using the GPIO pins, I needed to give 'www-data' root access as well as chmod the script files.
I've given www-data sudo rights on the script in file sudoers in the /etc folder. To change this text file I edited in the terminal screen by entering 'visudo'.
After that you're presented with an editor and you can make the change to file 'sudoers'.
I added this line to sudoers:
www-data ALL= NOPASSWD:/var/www
Using Leafpad to edit 'sudoers' didn't work for me...
Python library:
I've followed the specs of X10 and tested them in practice (The RasPi is pretty accurate with the timings):
Use this script with: sudo python x10.py <zone> <unit>
Like: sudo python x10.py A ON1 or sudo python x10.py A OFF1 or sudo python x10.py K Dim or sudo python x10.py K Bri
#!/usr/bin/python
import sys
import RPi.GPIO as GPIO
import time as Time
import datetime
def high():
GPIO.output(11, GPIO.HIGH)
Time.sleep(0.00015)
GPIO.output(11,GPIO.LOW)
Time.sleep(0.002)
return;
def low():
GPIO.output(11, GPIO.HIGH)
Time.sleep(0.00015)
GPIO.output(11,GPIO.LOW)
Time.sleep(0.001)
return;
def leadin():
GPIO.output(11, GPIO.HIGH)
Time.sleep(0.009)
GPIO.output(11,GPIO.LOW)
Time.sleep(0.0045)
return;
def leadout():
GPIO.output(11, GPIO.HIGH)
Time.sleep(0.0002)
GPIO.output(11,GPIO.LOW)
Time.sleep(0.040)
return;
def sendcommand():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11,GPIO.OUT)
count=0
while count < 5:
leadin()
for c in strCmd:
if c=='1':
high()
else:
low()
leadout()
count += 1
GPIO.cleanup()
return;
#Zones
ZoneA= '01100000'
ZoneB= '01110000'
ZoneC= '01000000'
ZoneD= '01010000'
ZoneE= '10000000'
ZoneF= '10010000'
ZoneG= '10100000'
ZoneH= '10110000'
ZoneI= '11100000'
ZoneJ= '11110000'
ZoneK= '11000000'
ZoneL= '11010000'
ZoneM= '00000000'
ZoneN= '00010000'
ZoneO= '00100000'
ZoneP= '00110000'
#Units
ON1 = '00000000'
OFF1= '00100000'
ON2 = '00010000'
OFF2= '00110000'
ON3 = '00001000'
OFF3= '00101000'
ON4 = '00011000'
OFF4= '00111000'
ON5 = '01000000'
OFF5= '01100000'
ON6 = '01010000'
OFF6= '01110000'
ON7 = '01001000'
OFF7= '01101000'
ON8 = '01011000'
OFF8= '01111000'
Bri= '10001000'
Dim= '10011000'
# Get zone and unit from arguments
argZone=sys.argv[1]
argUnit=sys.argv[2]
if argZone=="A":zone=ZoneA
elif argZone=="B":zone=ZoneB
elif argZone=="C":zone=ZoneC
elif argZone=="D":zone=ZoneD
elif argZone=="E":zone=ZoneE
elif argZone=="F":zone=ZoneF
elif argZone=="G":zone=ZoneG
elif argZone=="H":zone=ZoneH
elif argZone=="I":zone=ZoneI
elif argZone=="J":zone=ZoneJ
elif argZone=="K":zone=ZoneK
elif argZone=="L":zone=ZoneL
elif argZone=="M":zone=ZoneM
elif argZone=="N":zone=ZoneN
elif argZone=="O":zone=ZoneO
elif argZone=="P":zone=ZoneP
if argUnit=="ON1" or argUnit=="ON9":unit=ON1
if argUnit=="OFF1" or argUnit=="OFF9":unit=OFF1
if argUnit=="ON2" or argUnit=="ON10":unit=ON2
if argUnit=="OFF2" or argUnit=="OFF10":unit=OFF2
if argUnit=="ON3" or argUnit=="ON11":unit=ON3
if argUnit=="OFF3" or argUnit=="OFF11":unit=OFF3
if argUnit=="ON4" or argUnit=="ON12":unit=ON4
if argUnit=="OFF4" or argUnit=="OFF12":unit=OFF4
if argUnit=="ON5" or argUnit=="ON13":unit=ON5
if argUnit=="OFF5" or argUnit=="OFF13":unit=OFF5
if argUnit=="ON6" or argUnit=="ON14":unit=ON6
if argUnit=="OFF6" or argUnit=="OFF14":unit=OFF6
if argUnit=="ON7" or argUnit=="ON15":unit=ON7
if argUnit=="OFF7" or argUnit=="OFF15":unit=OFF7
if argUnit=="ON8" or argUnit=="ON16":unit=ON8
if argUnit=="OFF8" or argUnit=="OFF16":unit=OFF8
if argUnit=="Bri":unit=Bri
if argUnit=="Dim":unit=Dim
#If argUnit number > 8 then add 100 to argZone
#First get unitNum
if argUnit[:2] == "ON": unitNum=int(argUnit[2:])
elif argUnit=="Dim" or argUnit=="Bri": unitNum=0
else:unitNum=int(argUnit[3:])
#Subsitute 0 for 1 to 5th position of the zone
if unitNum > 8:
zonelist=list(zone);
zonelist[5]='1';
zone=''.join(zonelist)
# Add complementary bytes to zone and unit
zone+=''.join('1'if x=='0' else '0'for x in zone)
unit+=''.join('1'if x=='0' else '0'for x in unit)
strCmd = zone + unit
#print( strCmd)
sendcommand()
#print ("end")
PHP script:
All the PHP does is this (buttons names on the form are 'command'; radio buttons are named 'zone'):
<!--<?php-->
if(isset( $_POST['command']))
{
exec('sudo /var/www/x10.py ' . $_POST['zone'] . ' ' . $_POST['command']);
// If you want to see some feedback from the script, use this:
//$output = shell_exec('sudo /var/www/x10.py ' . $_POST['zone'] . ' ' . $_POST['command']);
//echo $output;
}
<!--?-->
<html>
<head>
<style type="text/css">
body {width:100%;height:100%;}
.com {height:150px; width:49%;font-size:28px}
.zone {}
.coms {width:100%;}
.zones {width:100%;}
table{cellpadding:0px;cellspacing:0px;border:0px;}
</style>
</head>
<body>
<form method="post">
<table class="zones"><tr>
<td><input type="radio" name="zone" value="A" class="zone">A</input></td>
<td><input type="radio" name="zone" value="B" class="zone">B</input></td>
<td><input type="radio" name="zone" value="C" class="zone">C</input></td>
<td><input type="radio" name="zone" value="D" class="zone">D</input></td>
<td><input type="radio" name="zone" value="E" class="zone">E</input></td>
<td><input type="radio" name="zone" value="F" class="zone">F</input></td>
<td><input type="radio" name="zone" value="G" class="zone">G</input></td>
<td><input type="radio" name="zone" value="H" class="zone">H</input></td>
</tr><tr>
<td><input type="radio" name="zone" value="I" class="zone">I</input></td>
<td><input type="radio" name="zone" value="J" class="zone">J</input></td>
<td><input type="radio" name="zone" value="K" class="zone">K</input></td>
<td><input type="radio" name="zone" value="L" class="zone">L</input></td>
<td><input type="radio" name="zone" value="M" class="zone">M</input></td>
<td><input type="radio" name="zone" value="N" class="zone">N</input></td>
<td><input type="radio" name="zone" value="O" class="zone">O</input></td>
<td><input type="radio" name="zone" value="P" class="zone">P</input></td>
</tr></table>
<table class="coms">
<tr>
<td>
<button name="command" value="ON1" class="com">MySwitch ON</button>
<button name="command" value="OFF1" class="com">MySwitch OFF</button>
</td>
</tr>
<tr>
<td>
<button name="command" value="Bri" class="com">Brighten</button>
<button name="command" value="Dim" class="com">Dim</button>
</td>
</tr>
</table>
</form>
</body>
</html>