import RPi.GPIO as gpio
import random # For randomizing sound files
import time # To delay sound playing
<<setup logging>>
<<sound-playing logic>>
<<process management>>
<<handle exit logic>>
if __name__ == '__main__':
log.info('Execution started.')
play_sound('system/welcome.wav')
<<define state>>
<<define pins>>
<<define sounds>>
log.info('Beginning main loop.')
try:
while True:
<<run loop>>
time.sleep(2)
except KeyboardInterrupt:
log.info('Process ended with C-c.')
log.info('Program exit.')
import atexit
atexit.register(kill_child_processes)
atexit.register(logging.shutdown)
atexit.register(gpio.cleanup)
atexit.register(lambda:subprocess.call(['mplayer',
'--volume=100',
'sounds/system/deactivate.wav'],
stdout=open('/dev/null'),
stderr=open('/dev/null')))
import subprocess
global child_processes
child_processes = set()
def start_process(cmd, purpose=None):
child = subprocess.Popen(cmd)
child.snort_purpose = purpose
child_processes.add(child)
return child
def gc_processes():
for child in list(child_processes):
child.poll()
if child.returncode is not None:
log.debug('Removing process %d from the set.', child.pid)
child_processes.remove(child)
if child.returncode is not 0:
log.error('Process %d ended abnormally; exit code %d; purpose: %s',
child.pid,
child.returncode,
child.snort_purpose)
def kill_child_processes():
gc_processes()
for child in child_processes:
try:
log.info('Forcing process %d to exit', child.pid)
child.terminate()
except:
log.error('Unable to kill child process %d', pid)
<<choose a random sound file to play>>
log.debug('Playing the random sound file')
play_sound(state.current_recording)
log.debug('Choosing a random sound file')
choices = ['recordings/'+key for key in snorts if bool(snorts[key][0])]
state.current_recording = random.choice(choices)
I seem to remember a requirement being the ability to play certain
sounds. I’m not sure of the details of this requirement, but lambdas
can be used here (using the [i for i in [...] if f(i)]
construction).
log.debug('Setting up GPIO')
gpio.setmode(gpio.BOARD)
pin_led = 7
pin_pir = 12
pin_btn_no = 24
pin_btn_nc = 26
gpio.setup(pin_led , gpio.OUT, initial=gpio.LOW)
gpio.setup(pin_pir , gpio.IN)
gpio.setup(pin_btn_no, gpio.IN , gpio.PUD_DOWN)
gpio.setup(pin_btn_no, gpio.IN , gpio.PUD_DOWN)
for p in [pin_led, pin_pir, pin_btn_no, pin_btn_nc]:
log.debug('Setup pin %d for function %s', p, gpio.gpio_function(p))
snorts = {'record2snort2.wav': ('some criterion'),
'record3snort1.wav': ('some criterion'),
'record3snort2.wav': ('some criterion'),
'record4snort1.wav': ('some criterion'),
'record4snort2.wav': ('some criterion'),
'recorded snort1-3.wav': ('some criterion'),
'recorded snort1.wav': ('some criterion'),
'recorded snort2.wav': ('some criterion')}
The actual sound files aren’t included in the project as they are decently large and won’t benefit from version control.
log.log(0, 'Executing loop')
First, we need to update the internal state so we know we have current
information. This will intelligently update properties such as
button_depressed
and motion_detected
so we can use them later.
<<update state>>
It should be noted that the device won’t actually turn off; it will merely stop looking for motion.
When testing a new wiring, it’s good to just get a few tests of the LEDs and the speakers in. (I’ll probably be adding more tests later, but that’s beside the point.) If we are not testing, then check to see if we’ve detected motion. If we have, choose a random sound file to play and then play it.
if state.testing:
<<testing logic>>
state.testing = False
elif gpio.input(pin_led):
if state.motion_detected is True:
state.motion_detected = time.time()
elif 40 < time.time() - state.motion_detected and state.current_recording is not None:
state.current_recording = None
gc_processes()
elif 20 < time.time() - state.motion_detected and state.current_recording is None:
<<play a random sound file>>
elif not gpio.input(pin_led):
gc_processes()
log.info('Running diagnostic...')
for i in range(4):
log.debug('Toggling LED on pin {}'.format(pin_led))
gpio.output(pin_led, not gpio.input(pin_led))
time.sleep(1)
play_sound('system/diagnostic.wav')
log.info('Running diagnostic... Done')
def play_sound(relative_path):
log = logging.getLogger('sounds')
log.info('Playing sound: "%s"', relative_path)
return start_process(['mplayer',
'-msglevel',
'all=-1',
'sounds/{!s}'\
.format(relative_path)],
'Play sound {}'\
.format(relative_path))
class State: pass
state=State()
state.testing = False
state.button_depressed = False
state.button_depressed_old = True
state.motion_detected = False
state.current_recording = None
log.log(0, 'Updating state...')
Check for changes in button state. This logic should allow the system to manage a toggle on/off button for the system state using the momentary latch provided by the button.
state.button_depressed = gpio.input(pin_btn_no)
if state.button_depressed is not state.button_depressed_old:
state.button_depressed_old = state.button_depressed
if state.button_depressed:
<<toggle state>>
Check for any input from the PIR. If motion is detected, set the appropriate flag.
log.debug(state.motion_detected)
if gpio.input(pin_pir) and state.motion_detected is False:
log.debug('Motion detected')
state.motion_detected = True
if time.time() - state.motion_detected > 60:
log.debug('Motion terminated')
state.motion_detected = False
log.log(0, 'Updating state... Done.')
log.debug('Toggling state...')
if gpio.input(pin_led):
log.debug('Turning LED OFF')
play_sound('system/deactivate.wav')
else:
log.debug('Turning LED ON')
play_sound('system/activate.wav')
gpio.output(pin_led, not gpio.input(pin_led))
log.debug('Toggling state... Done.')
import logging
logging.basicConfig(
filename='log',
format='%(asctime)s (%(name)s) [%(funcName)s] %(levelname)s: %(message)s'
)
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
console.setFormatter(logging.Formatter('%(levelname)-8s: %(message)s'))
log = logging.getLogger('')
log.addHandler(console)
log.setLevel(logging.DEBUG)
- Resources
- recordings under
/sounds/recordings/
The recordings under /sounds/recordings/
were released by the
Macauley Library of Cornell University and are released under the
following terms. Refer to the website for the definitive license.
- CommonName
- Coyote
- Genus
- Canis
- Species
- latrans
- VocType
- barks
- RecordingCount
- 125888
- Comments
- Waller, Sara
- CommonName
- Eastern Gray Squirrel
- Genus
- Sciurus
- Species
- carolinensis
- VocType
- call
- RecordingCount
- 127048
- Comments
- Little, Randolph S.
- CommonName
- Woodchuck
- Genus
- Marmota
- Species
- monax
- VocType
- alarm call
- RecordingCount
- 55370
- Comments
- Gunn, William W. H.
- CommonName
- Coyote
- Genus
- Canis
- Species
- latrans
- VocType
- barks
- RecordingCount
- 50261
- Comments
- Keller, Geoffrey A.
- CommonName
- White-tailed deer
- Genus
- Odocoileus
- Species
- virginianus
- VocType
- snort
- RecordingCount
- 131198
- Comments
- Keller, Geoffrey A.
- CommonName
- White-tailed deer
- Genus
- Odocoileus
- Species
- virginianus
- VocType
- snort
- RecordingCount
- 120460
- Comments
- Fischer, Martha J.
- CommonName
- Gray Wolf
- Genus
- Canis
- Species
- lupus
- VocType
- call
- RecordingCount
- 128377
- Comments
- MacDonald, Stewart D.
- CommonName
- White-tailed deer
- Genus
- Odocoileus
- Species
- virginianus
- VocType
- snort
- RecordingCount
- 41832
- Comments
- Evans, William R.
- CommonName
- White-tailed deer
- Genus
- Odocoileus
- Species
- virginianus
- VocType
- snort
- RecordingCount
- 52604
- Comments
- Langtimm, Catherine A.
- CommonName
- Woodchuck
- Genus
- Marmota
- Species
- monax
- VocType
- alarm call
- RecordingCount
- 172798
- Comments
- McGowan, Jay
- CommonName
- Cougar
- Genus
- Puma
- Species
- concolor
- VocType
- call
- RecordingCount
- 126382
- Comments
- Priori, Andrea L.
- CommonName
- Eastern Gray Squirrel
- Genus
- Sciurus
- Species
- carolinensis
- VocType
- call
- RecordingCount
- 94227
- Comments
- Hershberger, Wilbur L
By visiting, viewing and/or using this website, you are agreeing to these Terms of Use.
This website (herein the “Website”) and all materials displayed or accessible through it, including but not limited to, text, photographs, images, illustrations, audio and video, computer software and code (herein called the “Content”) are protected by copyright and are owned by Cornell University, which includes the Macaulay Library (ML) and the Cornell Lab of Ornithology, its licensors or the party credited as the content provider.
Subject to the provisions listed in this Terms of Use Agreement, visitors to the Website are permitted to:
- View Content online.
- Print Website pages for non-commercial, personal, educational, and research uses provided that ML is properly cited as the source.
- Retain copies of specimen record data in digital form for non-commercial, personal, educational and research purposes provided that ML is properly cited as the source.
- Link to and share Website pages from third-party websites for non-commercial, personal, educational and research purposes only provided that ML is properly cited as the source.
- Share Content for non-commercial, personal, educational and research purposes provided that ML is properly cited as the source.
Any other uses (including but not limited to commercial, promotional, or administrative uses), reproduction, alteration, modification, public performance or display, uploading or posting onto the internet, transmission, redistribution or any other exploitation of the Website or the Content, whether in whole or in part, are prohibited without prior written permission.
Content from the specimen database accessible through the Website must not be regarded as definitive or published. Distributional, ecological, taxonomic and other such data should be verified in consultation with ML curatorial staff. Sensitive data (e.g. locality data for threatened or endangered species) and some data records may be restricted from public access through the Website. Access to these data records may be requested in writing from appropriate curatorial staff.
You may create links to this website for non-commercial (personal, educational and research) purposes only. If you wish to solicit a business relationship with the ML or the Cornell Lab of Ornithology, you need explicit written permission. While ML encourages links to the Website [link to “how to cite/link” page], it reserves the right to prohibit or refuse to accept any link to the Website at any time. You agree to remove any link you may have to the Website upon the request of ML.
This website contains links to third-party sites (Third-Party Websites). ML provides these links only as a service and convenience to our visitors. We take no responsibility for the content at Third-Party Websites including, without limitation, any representation or warranty regarding the legality, accuracy, reliability, completeness, timeliness, or suitability of any content on any Third-Party Website. The link to them in no way implies an endorsement or recommendation of the products, services or information found there. ML reserves the right to regularly review and re-evaluate any and all links originating from within the Website and reserves the right to terminate any link to Third-Party Websites without prior notification.
- By using the embed code to display audio and video Content from the Website the Embeddable Content on Third-Party Websites, you agree to be bound by the following terms:
- Subject to the Terms of Use for the Website, ML grants you a non-exclusive, non-transferable license to use the embeddable computer code to display the Embeddable Content on Third-Party Websites. You may not copy, re-publish, edit, alter, add to or use the Embeddable Content, embed code or embeddable player in any other way.
- All title, ownership rights and intellectual property rights in and to the Embeddable Content, and any code made available by ML to embed the Embeddable Content and the embeddable player shall remain the property of ML and/or its licensors.
- The Embeddable Content is subject to same terms and conditions described in the “Links to the Website” section above.
- The Embeddable Content is for personal use only and cannot be used in any commercial way. You may not charge visitors any fee for accessing the Embeddable Content, use the Embeddable Content as means to secure advertising, or commercialize the Embeddable Content or embeddable player in any other way.
- You must properly attribute and create a link back to the ML website on the pages of the Third-Party Websites where the Embeddable Content is displayed.
- You may not directly or indirectly suggest any endorsement or approval by ML of the Third-Party Sites displaying the Embeddable Content or any non-ML entity, product or content or any views expressed within Third-Party Sites without the ML’s prior written approval.
- You may not use the Embeddable Content in any way that could bring the ML into disrepute or otherwise cause any loss or damage to the ML.
- You acknowledge that ML has sole editorial control over the Embeddable Content at all times and it may change or restrict, suspend or terminate any or all Embeddable Content or your access to the Embeddable Content at any time at its sole discretion without liability.
- You acknowledge that the Embeddable Content is made available by ML on an “as is” and “as available” basis and ML gives no warranty of any kind in relation to the Embeddable Content, embed code or the embeddable player.
- The Website and all Content are provided “as is” for informational purposes only. By accessing and using the Website you acknowledge and agree that use of the Website and Content is entirely at your own risk. Where use of the Content is critical to scientific investigation, scholarly publication, or policy decisions, you are responsible for verifying the Content against primary data sources. Although ML applies the highest standards to Website performance, security, and data quality, ML makes no representations or warranties regarding the Website and Content, including, without limitation, no representation or warranty that:
- the Website and/or content will be accurate, complete, reliable, suitable or timely;
- any the Content, software, product or service made available through the Website will be of suitable for any particular purpose;
- the operation of the Website will be uninterrupted or error free;
- defects or errors in the Website will be corrected;
- the Website will be free from viruses or harmful components; and that
- communications to or from the Website will be secure or not intercepted.
ML reserves the right to modify the content of these terms of use at any time and it is your responsibility to consult the terms of use on a regular basis to determine whether any modifications have been made. By using the Website, you agree to all terms and conditions. Use of the Website after such changes are posted will signify your agreement to these revised terms.
You agree to indemnify, defend, and hold harmless Cornell University; its officers, directors, employees, agents, licensors, and third party providers to the Website from and against all losses, expenses, damages, and costs, including reasonable attorneys’ fees, resulting from any violation of these Terms. Cornell University reserves the right to assume the exclusive defense and control of any matter subject to indemnification by you, in which event you will fully cooperate with Cornell University in asserting and available defenses.