#!/usr/bin/env python3 # For controlling a RUN display based on Stranger Things # (c) 2018 Bradley Knockel # Using a motion detector (PIR sensor) is optional. # Detects infrared, so is not fooled by shadows, # but it does not work through windows. # I'm using an HC-SR501. # With the HC-SR501 facing away from you, # and the 3 pins at the bottom... # left pin --> 5V # middle pin --> GPIO 25 # right pin --> GND # HC-SR501 requires nearly a minute to initialize. # During this period, it can and often will output # false detection signals. # Perhaps using a photocell (LDR) is better? # Sees through glass, so you can have a sign having # people put their finger over the LDR as if it were # a button that works through glass! # Use a resistor and LDR to create a "potentiometer"... # Photocell -> 3.3V # Photocell and resistor -> ADC pin1 (channel 0) # resistor -> GND # Using a larger fixed resistor uses less # power and is necessary if very dark, # but it gives less resolution for # measuring bright things. # Using a smaller fixed resistor gives less # resolution for measuring dark things, but # is needed for very bright situations. # 10,000 ohms is reasonable. # For safety, do not use less than 220 ohms. # In a very dark room, use at least 100,000 ohms. # My LDR is model KLS6-3537. # # If using a photocell, here are the ADC (MCP3008) pins... # VDD (16) to 3.3V # VREF (15) to 3.3V # AGND (14) to GND # CLK (13) to GPIO 11 (sclk) (must be at least 10 kHz) # DOUT (12) to GPIO 9 (miso) # DIN (11) to GPIO 10 (mosi) # CS/SHDN (10) to GPIO 8 (ce0) (must be pulled HIGH/off between conversions) # DGND (9) to GND # # If using hardware SPI, make sure you've enabled SPI using # sudo raspi-config (in Interface Options) # Then reboot the Pi. # # To install the Adafruit modules for ADC... # sudo apt-get install python3-pip # sudo pip3 install adafruit-mcp3008 # Are you using a motion detector? motionDetector = False pirPin = 25 # Are you using a light detector? # This will override motionDetector if True. lightDetector = True # seconds between sampling brightness waitTime = 0.4 # higher is harder to activate, but lower is susceptible to electrical noise thresholdFraction = 0.2 # set pins pinR = 21 pinU = 20 pinN = 16 pinRemaining = 12 import time import random random.seed() import RPi.GPIO as IO IO.setmode(IO.BCM) IO.setup(pinR, IO.OUT) IO.setup(pinU, IO.OUT) IO.setup(pinN, IO.OUT) IO.setup(pinRemaining, IO.OUT) if lightDetector: motionDetector = False import Adafruit_MCP3008 ## Software SPI configuration: #CLK = 11 #MISO = 9 #MOSI = 10 #CS = 8 #mcp = Adafruit_MCP3008.MCP3008(clk=CLK, cs=CS, miso=MISO, mosi=MOSI) ## Hardware SPI configuration: import Adafruit_GPIO.SPI as SPI # Adafruit's spidev module mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(0,0)) def getBrightness(): val = mcp.read_adc(0) print(val) # add 0.5 to prevent getting 0 voltsR = (val+0.5)/1024.0 # ratio of (volts / 3.3V) across fixed resistor return voltsR/(1-voltsR) if motionDetector: IO.setup(pirPin, IO.IN) def turnOff(): IO.output(pinR, 0) IO.output(pinU, 0) IO.output(pinN, 0) IO.output(pinRemaining, 0) def turnOn(): IO.output(pinR, 1) IO.output(pinU, 1) IO.output(pinN, 1) IO.output(pinRemaining, 1) turnOff() def getAttention(): turnOn() time.sleep(0.1) turnOff() time.sleep(0.1) turnOn() time.sleep(0.1) turnOff() def go(): IO.output(pinR, 1) time.sleep(1.5) IO.output(pinR, 0) time.sleep(0.5) IO.output(pinU, 1) time.sleep(2) IO.output(pinU, 0) time.sleep(0.5) IO.output(pinN, 1) time.sleep(3) IO.output(pinN, 0) time.sleep(0.5) # flicker all the lights t = time.time() while time.time() < t + 5.0: if random.randrange(2) == 1: turnOff() else: turnOn() time.sleep(0.04) turnOff() justWent = False try: while 1: if motionDetector: if IO.input(pirPin): if not justWent: getAttention() time.sleep(1) justWent = True go() time.sleep(1) else: justWent = False elif lightDetector: val1 = getBrightness() time.sleep(waitTime) val2 = getBrightness() #print(val1*100000, val2*100000) if abs(val1-val2)*2/(val1+val2) > thresholdFraction: if not justWent: getAttention() time.sleep(1) justWent = True go() time.sleep( max(1.0 - waitTime, 0.01) ) else: justWent = False else: go() time.sleep(5) except: pass # cleanup turnOff() IO.cleanup()