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.

 tx

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>