├── .gitattributes ├── 9781484237687.jpg ├── README.md ├── Contributing.md ├── Chapter10 ├── kml.py └── plane.py ├── Chapter9 └── cat_toy.py ├── LICENSE.txt ├── Chapter11 └── balloon.py ├── Chapter5 └── webbot.py ├── Chapter8 └── home_security.py ├── Chapter12 └── sub.py └── Chapter6 └── weather.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /9781484237687.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/Learn-Rasp-Pi-Program-Python/HEAD/9781484237687.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*Learn Raspberry Pi Programming with Python: Learn to Program on the World's Most Popular Tiny Computerhttps://www.apress.com/9781484237687) by Wolf Donet (Apress, 2018). 4 | 5 | [comment]: #cover 6 | ![Cover image](9781484237687.jpg) 7 | 8 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 9 | 10 | ## Releases 11 | 12 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 13 | 14 | ## Contributions 15 | 16 | See the file Contributing.md for more information on how you can contribute to this repository. -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Apress Source Code 2 | 3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. 4 | 5 | ## How to Contribute 6 | 7 | 1. Make sure you have a GitHub account. 8 | 2. Fork the repository for the relevant book. 9 | 3. Create a new branch on which to make your change, e.g. 10 | `git checkout -b my_code_contribution` 11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. 12 | 5. Submit a pull request. 13 | 14 | Thank you for your contribution! -------------------------------------------------------------------------------- /Chapter10/kml.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | #open files for reading and writing 4 | gps = open('locations.log', 'r') 5 | kml = open('plane.kml', 'w') 6 | 7 | kml.write('\n') 8 | kml.write('\n') 9 | kml.write('\n') 10 | kml.write('Plane Path\n') 11 | kml.write('Path taken by plane\n') 12 | kml.write('\n') 16 | kml.write('Placemark>Plane Path\n') 17 | kml.write('#yellowLineGreenPoly\n') 18 | kml.write('\n') 19 | kml.write('11\n') 20 | kml.write('relative\n') 21 | kml.write('\n') 22 | 23 | for line in gps: 24 | #separate string by spaces 25 | coordinate = string.split(line) 26 | longitude = coordinate[0] 27 | latitude = coordinate[1] 28 | altitude = coordinate[2] 29 | kml.write(longitude + "," + latitude + "," + altitude + "\n") 30 | 31 | kml.write('<\coordinates>\n') 32 | kml.write('\n') 33 | kml.write('\n') 34 | kml.write('\n') 35 | kml.write('\n') 36 | 37 | -------------------------------------------------------------------------------- /Chapter9/cat_toy.py: -------------------------------------------------------------------------------- 1 | import RPi.GPIO as GPIO 2 | import time 3 | import random 4 | random.seed() 5 | 6 | #set pins 7 | GPIO.setmode (GPIO.BOARD) 8 | GPIO.setwarnings (False) 9 | GPIO.setup (11, GPIO.OUT) #laser power 10 | GPIO.setup (13, GPIO.OUT) #X-servo 11 | GPIO.setup (15, GPIO.OUT) #Y-servo 12 | GPIO.setup (19, GPIO.IN, pull_up_down=GPIO.PUD_UP) #in from IR 13 | 14 | #setup servo pwm 15 | p = GPIO.PWM (13, 50) 16 | q = GPIO.PWM (15, 50) 17 | 18 | #set both servos to center to start 19 | p.start (7.5) 20 | q.start (7.5) 21 | 22 | def moveServos(): 23 | "Turns on laser and moves X- and Y-servos randomly" 24 | lightLaser () 25 | 26 | p.ChangeDutyCycle (random.randint (8, 12)) 27 | time.sleep (random.random()) 28 | q.ChangeDutyCycle (random.randint (8, 12)) 29 | time.sleep (random.random()) 30 | 31 | p.ChangeDutyCycle (random.randint (3, 5)) 32 | time.sleep (random.random()) 33 | q.ChangeDutyCycle (random.randint (3, 5)) 34 | time.sleep (random.random()) 35 | 36 | dimLaser () 37 | 38 | def lightLaser(): 39 | GPIO.output (11, 1) 40 | 41 | def dimLaser(): 42 | GPIO.output (11, 0) 43 | 44 | #main loop 45 | while True: 46 | #check for input from sensor 47 | if GPIO.input (19): 48 | moveServos() 49 | time.sleep (0.5) #wait a half sec before polling sensor 50 | else: 51 | dimLaser() 52 | time.sleep (0.5) 53 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Freeware License, some rights reserved 2 | 3 | Copyright (c) 2018 Wolf Donet 4 | 5 | Permission is hereby granted, free of charge, to anyone obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to work with the Software within the limits of freeware distribution and fair use. 8 | This includes the rights to use, copy, and modify the Software for personal use. 9 | Users are also allowed and encouraged to submit corrections and modifications 10 | to the Software for the benefit of other users. 11 | 12 | It is not allowed to reuse, modify, or redistribute the Software for 13 | commercial use in any way, or for a user’s educational materials such as books 14 | or blog articles without prior permission from the copyright holder. 15 | 16 | The above copyright notice and this permission notice need to be included 17 | in all copies or substantial portions of the software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | 27 | 28 | -------------------------------------------------------------------------------- /Chapter10/plane.py: -------------------------------------------------------------------------------- 1 | import os 2 | from gps import * 3 | from time import * 4 | import time 5 | import threading 6 | import logging 7 | from picamera import PiCamera 8 | 9 | #set up logfile 10 | logging.basicConfig(filename='locations.log', level=logging.DEBUG, 11 | format='%(message)s') 12 | 13 | camera = PiCamera() 14 | 15 | picnum = 0 16 | gpsd = None 17 | 18 | class GpsPoller(threading.Thread): 19 | def __init__(self): #initializes thread 20 | threading.Thread.__init__(self) 21 | global gpsd 22 | gpsd = gps(mode=WATCH_ENABLE) 23 | self.current_value = None 24 | self.running = True 25 | 26 | def run(self): #actions taken by thread 27 | global gpsd 28 | while gpsp.running: 29 | gpsd.next() 30 | 31 | if __name__ == '__main__': #if in the main program section, 32 | gpsp = GpsPoller() #start a thread and start logging 33 | try: #and taking pictures 34 | gpsp.start() 35 | while True: 36 | #log location from GPS 37 | logging.info(str(gpsd.fix.longitude) + " " + str(gpsd.fix.latitude) + " " + 38 | str(gpsd.fix.altitude)) 39 | 40 | #save numbered image in correct directory 41 | camera.capture("/home/pi/Documents/plane/image" + str(picnum) + ".jpg") 42 | picnum = picnum + 1 #increment picture number 43 | time.sleep(3) 44 | except (KeyboardInterrupt, SystemExit): 45 | gpsp.running = False 46 | gpsp.join() 47 | -------------------------------------------------------------------------------- /Chapter11/balloon.py: -------------------------------------------------------------------------------- 1 | import os 2 | from gps import * 3 | import time 4 | import threading 5 | import subprocess 6 | 7 | #set up variables 8 | picnum = 0 9 | gpsd = None 10 | 11 | class GpsPoller(threading.Thread): 12 | def __init__(self): 13 | threading.Thread.__init__(self) 14 | global gpsd 15 | global picnum 16 | gpsd = gps(mode=WATCH_ENABLE) 17 | self.current_value = None 18 | self.running = True 19 | def run(self): 20 | global gpsd 21 | while gpsp.running: 22 | gpsd.next() 23 | 24 | if __name__ == '__main__': 25 | gpsp = GpsPoller() 26 | try: 27 | gpsp.start() 28 | while True: 29 | f = open('position.txt', 'w') 30 | curAlt = gpsd.fix.altitude 31 | curLong = gpsd.fix.longitude 32 | curLat = gpsd.fix.latitude 33 | f.write( str(curAlt) + " feet altitude, " + str(curLong) + " degrees longitude, " + str(curLat) + 34 | " degrees latitude") 35 | f.close() 36 | subprocess.call(["text2wave position.txt -o position.wav"], shell = True) 37 | subprocess.call(['ffmpeg -i "position.wav" -y -ar 22050 "position.wav"'], shell = True) 38 | subprocess.call(["sudo ./pifm position.wav 103.5 22050"], shell = True) 39 | subprocess.call(["raspistill -o /home/pi/Documents/balloon/image" + str(picnum) + ".jpg"], shell=True) 40 | picnum = picnum + 1 41 | time.sleep(15) 42 | except (KeyboardInterrupt, SystemExit): 43 | gpsp.running = False 44 | gpsp.join() 45 | -------------------------------------------------------------------------------- /Chapter5/webbot.py: -------------------------------------------------------------------------------- 1 | import mechanize 2 | import time 3 | from bs4 import BeautifulSoup 4 | import re 5 | import urllib 6 | import string 7 | import os 8 | 9 | def downloadProcess(html, base, filetype, linkList): 10 | “This does the actual file downloading” 11 | Soup = BeautifulSoup(html) 12 | For link in soup.find(‘a’): 13 | linkText = str(link.get(‘href’)) 14 | if filetype in linkText: 15 | slashList = [i for i, ind in enumerate(linkText) if ind == ‘/’] 16 | directoryName = linkText[(slashList[0] + 1) : slashList[1]] 17 | if not os.path.exists(directoryName): 18 | os.makedirs(directoryName) 19 | 20 | image = urllib.URLopener() 21 | linkGet = base + linkText 22 | filesave = string.lstrip(linkText, “/”) 23 | image.retrieve(linkGet, filesave) 24 | elif “htm” in linkText: # Covers both “html” and “htm” 25 | linkList.append(link) 26 | 27 | start = "http://" + raw_input ("Where would you like to start searching?\n") 28 | filetype = raw_input ("What file type are you looking for?\n") 29 | 30 | numSlash = start.count('/') #number of slashes in start—need to remove everything after third slash 31 | slashList = [i for i, ind in enumerate(start) if ind == '/'] #list of indices of slashes 32 | 33 | if (len(slashList) >= 3): #if there are 3 or more slashes, cut after 3 34 | third = slashList[2] 35 | base = start[:third] #base is everything up to third slash 36 | else: 37 | base = start 38 | 39 | br = mechanize.Browser() 40 | r = br.open(start) 41 | html = r.read() 42 | linkList = [] #empty list of links 43 | 44 | print "Parsing " + start 45 | downloadProcess(html, base, filetype, linkList) 46 | 47 | for leftover in linkList: 48 | time.sleep(0.1) #wait 0.1 seconds to avoid overloading server 49 | linkText = str(leftover.get('href')) 50 | print "Parsing " + base + linkText 51 | br = mechanize.Browser() 52 | r = br.open(base + linkText) 53 | html = r.read() 54 | linkList = [] 55 | downloadProcess(html, base, filetype, linkList) 56 | 57 | -------------------------------------------------------------------------------- /Chapter8/home_security.py: -------------------------------------------------------------------------------- 1 | import time 2 | import RPi.GPIO as GPIO 3 | from picamera import PiCamera 4 | import string 5 | import smtplib 6 | 7 | GPIO.setwarnings (False) 8 | GPIO.setmode (GPIO.BOARD) 9 | time_stamp = time.time() #for debouncing 10 | camera = PiCamera() 11 | 12 | #set pins 13 | #pin 11 = motion sensor 14 | GPIO.setup (11, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 15 | 16 | #pin 13 = magnetic sensor 17 | GPIO.setup (13, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 18 | 19 | #pin 15 = limit switch 20 | GPIO.setup (15, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 21 | 22 | #pin 19 = pressure switch 23 | GPIO.setup (19, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 24 | 25 | def take_pic(sensor): 26 | camera.capture(sensor + “.jpg”) 27 | time.sleep(0.5) #wait 1/2 second for pic to be taken before continuing 28 | 29 | def send_text(details): 30 | HOST = “smtp.gmail.com” 31 | SUBJECT = “Break-in!” 32 | TO = “xxxxxxxxxx@txt.att.net” 33 | FROM = “python@mydomain.com” 34 | text = details 35 | BODY = string.join(("From: %s" % FROM, "To: %s" % TO, "Subject: %s" % SUBJECT, "", text), "\r\n") 36 | s = smtplib.SMTP(‘smtp.gmail.com’,587) 37 | s.set_debuglevel(1) 38 | s.ehlo() 39 | s.starttls() 40 | s.login(“username@gmail.com”, “mypassword”) 41 | s.sendmail(FROM, [TO], BODY) 42 | s.quit() 43 | 44 | def motion_callback(channel): 45 | global time_stamp 46 | time_now = time.time() 47 | if (time_now - time_stamp) >= 0.3: #check for debouncing 48 | print "Motion detector detected." 49 | send_text(“Motion detector”) 50 | take_pic(“motion”) 51 | time_stamp = time_now 52 | 53 | def limit_callback(channel): 54 | global time_stamp 55 | time_now = time.time() 56 | if (time_now - time_stamp) >= 0.3: #check for debouncing 57 | print "Limit switch pressed." 58 | send_text(“Limit switch”) 59 | take_pic(“limit”) 60 | time_stamp = time_now 61 | 62 | def magnet_callback(channel): 63 | global time_stamp 64 | time_now = time.time() 65 | if (time_now - time_stamp) >= 0.3: #check for debouncing 66 | print "Magnetic sensor tripped." 67 | send_text(“Magnetic sensor”) 68 | take_pic(“magnet”) 69 | time_stamp = time_now 70 | 71 | #main body 72 | raw_input("Press enter to start program\n") 73 | 74 | GPIO.add_event_detect(11, GPIO.RISING, callback=motion_callback) 75 | GPIO.add_event_detect(13, GPIO.RISING, callback=magnet_callback) 76 | GPIO.add_event_detect(15, GPIO.RISING, callback=limit_callback) 77 | 78 | # pressure switch ends the program 79 | # you could easily add a unique callback for the pressure switch 80 | # and add another switch just to turn off the network 81 | try: 82 | print "Waiting for sensors..." 83 | GPIO.wait_for_edge(19, GPIO.RISING) 84 | except KeyboardInterrupt: 85 | GPIO.cleanup() 86 | 87 | GPIO.cleanup() 88 | -------------------------------------------------------------------------------- /Chapter12/sub.py: -------------------------------------------------------------------------------- 1 | import time 2 | import smbus 3 | from picamera import PiCamera 4 | import RPi.GPIO as GPIO 5 | GPIO.setwarnings (False) 6 | GPIO.setmode (GPIO.BOARD) 7 | 8 | camera = PiCamera() 9 | 10 | def take_stillpic(num): 11 | camera.capture("image" + str(num) + "jpg") 12 | 13 | def go_forward(): 14 | GPIO.output (19, 1) #IN1 on 15 | GPIO.output (23, 0) #IN2 off 16 | GPIO.output (11, 1) #IN3 on 17 | GPIO.output (15, 0) #IN4 off 18 | 19 | def go_backward(): 20 | GPIO.output (19, 0) #IN1 off 21 | GPIO.output (23, 1) #IN2 on 22 | GPIO.output (11, 0) #IN3 off 23 | GPIO.output (15, 1) #IN4 on 24 | 25 | def go_right(): 26 | GPIO.output (19, 1) #IN1 on 27 | GPIO.output (23, 0) #IN2 off 28 | GPIO.output (11, 0) #IN3 off 29 | GPIO.output (15, 1) #IN4 on 30 | 31 | def go_left(): 32 | GPIO.output (19, 0) #IN1 off 33 | GPIO.output (23, 1) #IN2 on 34 | GPIO.output (11, 1) #IN3 on 35 | GPIO.output (15, 0) #IN4 off 36 | 37 | 38 | #set motor control pins 39 | #left motor 40 | # 11 = IN3 41 | # 13 = enableB 42 | # 15 = IN4 43 | GPIO.setup (11, GPIO.OUT) 44 | GPIO.setup (13, GPIO.OUT) 45 | GPIO.setup (15, GPIO.OUT) 46 | 47 | #right motor 48 | # 19 = IN1 49 | # 21 = enableA 50 | # 23 = IN2 51 | GPIO.setup (19, GPIO.OUT) 52 | GPIO.setup (21, GPIO.OUT) 53 | GPIO.setup (23, GPIO.OUT) 54 | 55 | #enable both motors 56 | GPIO.output (13, 1) 57 | GPIO.output (21, 1) 58 | 59 | #setup nunchuk read 60 | bus = smbus.SMBus(0) # or a (1) if you needed used y -1 in the i2cdetect command 61 | bus.write_byte_data (0x52, 0x40, 0x00) 62 | time.sleep (0.5) 63 | 64 | x = 1 65 | 66 | while True: 67 | try: 68 | bus.write_byte (0x52, 0x00) 69 | time.sleep (0.1) 70 | data0 = bus.read_byte (0x52) 71 | data1 = bus.read_byte (0x52) 72 | data2 = bus.read_byte (0x52) 73 | data3 = bus.read_byte (0x52) 74 | data4 = bus.read_byte (0x52) 75 | data5 = bus.read_byte (0x52) 76 | joy_x = data0 77 | joy_y = data1 78 | accel_x = (data2 << 2) + ((data5 & 0x0c) >> 2) 79 | accel_y = (data3 << 2) + ((data5 & 0x30) >> 4) 80 | accel_z = (data4 << 2) + ((data5 & 0xc0) >> 6) 81 | buttons = data5 & 0x03 82 | button_c = (buttons == 1) or (buttons == 2) 83 | button_z = (buttons == 0) or (buttons == 2) 84 | 85 | if joy_x > 200: #joystick right 86 | go_right() 87 | elif joy_x < 35: #joystick left 88 | go_left() 89 | elif joy_y > 200: #joystick forward 90 | go_forward() 91 | elif joy_y < 35: #joystick back 92 | go_backward() 93 | elif button_c == True: 94 | x = x+1 95 | take_stillpic(x) 96 | elif button_z == True: 97 | print ‘button z! \n” 98 | else: #joystick at neutral, no buttons 99 | GPIO.output (19, 0) 100 | GPIO.output (23, 0) 101 | GPIO.output (11, 0) 102 | GPIO.output (15, 0) 103 | 104 | except IOError as e: 105 | print e 106 | -------------------------------------------------------------------------------- /Chapter6/weather.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | from sht1x.Sht1x import Sht1x as SHT1x 4 | import Rpi.GPIO as GPIO 5 | from Adafruit_BMP085 import BMP085 6 | import smbus 7 | import math 8 | 9 | GPIO.setmode(GPIO.BOARD) 10 | GPIO.setup(8, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 11 | 12 | bus = smbus.SMBus(0) 13 | address = 0x1e 14 | 15 | def read_byte(adr): 16 | return bus.read_byte_data(address,adr) 17 | 18 | def read_word(adr): 19 | high = bus.read_byte_data(address, adr) 20 | low = bus.read_byte_data(address, adr) 21 | val = (high << 8) + low 22 | return val 23 | 24 | def read_word_2c(adr): 25 | val = read_word(adr) 26 | if (val >= 0x8000): 27 | return -((65535 - val) + 1) 28 | else: 29 | return val 30 | 31 | def write_byte(adr, value): 32 | bus.write_byte_data(address, adr, value) 33 | 34 | def checkTemp(): 35 | dataPin = 11 36 | clkPin = 7 37 | sht1x = SHT1x(dataPin, clkPin, SHT1x.GPIO_BOARD) 38 | temp = sht1x.read_temperature_C() 39 | temp = temp*9/5 + 32 #if you want degrees F 40 | return temp 41 | 42 | def checkHumidity(): 43 | dataPin = 11 44 | clkPin = 7 45 | sht1x = SHT1x(dataPin, clkPin, SHT1x.GPIO_BOARD) 46 | humidity = sht1x.read_humidity() 47 | return humidity 48 | 49 | def checkBarometer(): 50 | bmp = BMP085(0x77) 51 | pressure = bmp.readPressure() 52 | pressure = pressure/100.0 53 | return pressure 54 | 55 | def checkWindSpeed() 56 | prev_input = 0 57 | total = 0 58 | totalSpeed = 0 59 | current = time.time() 60 | for i in range(0, 900): 61 | input = GPIO.input(8) 62 | if ((not prev_input) and input): 63 | total = total + 1 64 | prev_input = input 65 | if total == 90: 66 | rps = (1/ (time.time()-current)) 67 | speed = math.exp((rps + 0.95)/4.3) 68 | totalSpeed = totalSpeed + speed 69 | total = 0 70 | current = time.time() 71 | speed = totalSpeed / 10 #average speed out of ten turns 72 | return speed 73 | 74 | def checkWindDirection() 75 | write_byte(0, 0b01110000) 76 | write_byte(0, 0b00100000) 77 | write_byte(0, 0b00000000) 78 | scale = 0.92 79 | x_offset = 106 #use the offsets you computed 80 | yoffset = -175 #use the offsets you computed 81 | x_out = (read_word_2c(3) - x_offset) * scale 82 | y_out = (read_word_2c(7) - y_offset) * scale 83 | direction = math.atan2(y_out, x_out) 84 | if (direction < 0): 85 | direction += 2 * math.pi 86 | direction = math.degrees(direction) 87 | return direction 88 | 89 | # Main program loop 90 | while True: 91 | temp = checkTemp() 92 | humidity = checkHumidity() 93 | pressure = checkBarometer() 94 | speed = checkWindSpeed() 95 | direction = checkWindDirection() 96 | 97 | os.system("clear") 98 | print "Current Conditions" 99 | print "----------------------------------------" 100 | print "Temperature: ", str(temp) 101 | print "Humidity: ", str(humidity) 102 | print "Pressure: ", str(pressure) 103 | print "Wind Speed: ", str(speed) 104 | print "Wind Direction: ", str(direction) 105 | 106 | time.sleep(30) 107 | --------------------------------------------------------------------------------