# Touchless lightswitch with Raspberry Pi

I am currently developing a touchless lightswitch via a Raspberry Pi, an ultrasonic module and a nice radio module.

However, I am quite a beginner in Python and it was a hard time (at least for me) to accomplish my goal. Whenever the measured distance is falling below the limit the switch is triggered "on" (1) and after that if the distance is falling short again the switch is triggered "off" (0).

#!/usr/bin/env python

import os
import sys
import time
import RPi.GPIO as GPIO

GPIOTrigger = 23
GPIOEcho    = 24

def wait(sec):
while sec > 0:
sys.stdout.write(str(sec) + '     \r')
sec -= 1
time.sleep(1)

def MeasureDistance():
GPIO.output(GPIOTrigger, True)
time.sleep(0.00001)
GPIO.output(GPIOTrigger, False)
StartTime = time.time()
while GPIO.input(GPIOEcho) == 0:
StartTime = time.time()
while GPIO.input(GPIOEcho) == 1:
StopTime = time.time()
TimeElapsed = StopTime - StartTime
Distance = (TimeElapsed * 34300) / 2
return Distance
def main():
STATUS = 0
try:
while True:
Distance = MeasureDistance()
if Distance > 10.0:
time.sleep(0.01)
else:
if STATUS != 1:
print("Passing by (%.1f cm)" % Distance)
import subprocess
subprocess.call(["/root/rcswitch-pi/send", "10000", "1", "1"])
wait(5)
STATUS = 1
else:
subprocess.call(["/root/rcswitch-pi/send", "10000", "1", "0"])
wait(5)
STATUS = 0

except KeyboardInterrupt:
print("Stopped by user")
GPIO.cleanup()
if __name__ == '__main__':
# use GPIO pin numbering convention
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIOTrigger, GPIO.OUT)
GPIO.setup(GPIOEcho, GPIO.IN)
GPIO.output(GPIOTrigger, False)
main()


This works but I am unsure whether there is a nicer way of determining the last status of STATUS or if there are some pitfalls I might not see.

MeasureDistance. The way it is written, sometimes it measures the duration of the signal, sometimes the (desired) time for the echo to arrive (consider what happens if you enter the first while loop). Suggestion:

def MeasureDistance():
StartTime = time.time()
GPIO.output(GPIOTrigger, True)
while GPIO.input(GPIOEcho) == 0:
pass
# Found the raising front
StopTime = time.time()
GPIO.output(GPIOTrigger, False)


Of course, if the echo arrives faster than the code executes (and Python is slow), you'd get the elapsed time 0. I suppose there's nothing you can do about that, other than resorting to interrupts. Also, you may want to put some safeguards (a timer maybe) in case the raising front never arrives.

main. I don't see the need to import subprocess in the middle of the code. Also, state variables tend to create an unmaintainable code. Suggestion:

    try:
Distance = MeasureDistance()
while True:
while Distance > 10.0:
Distance = MeasureDistance()
wait(5)
switch_on()
while Distance < 10.0:
Distance = MeasureDistance()
wait(5)
switch_off()
except KeyboardInterrupt:


PS: a magic 34300 constant must go. Give it a nice symbolic name (yes we all know it has something to do with the speed of sound).

Update. Usually in the situations like yours you may have a funny behaviour at the breaking distance. Due to random factors (like the code execution time, and many more others) the distance is measured with a certain error, and the switch will go on and off unpredictably. To deal with it, allow for a hysteresis:

            while Distance > breaking_distance - tolerance:
Distance = MeasureDistance()
wait(5)
switch_on()
while Distance < breaking_distance + tolerance:
Distance = MeasureDistance()
wait(5)
switch_off()