├── README.md └── Code ├── Project_15 ├── max.JPG ├── background.JPG ├── style.css └── index.html ├── Project_19 └── Project_19_Scratch_Game.sb2 ├── Project_2 └── led_flashlight.py ├── Project_8 ├── sense_hat_scrolling_text.py ├── sense_hat_set_led_colors.py ├── sense_hat_display_picture.py ├── sense_hat_joystick_control.py └── pong_game.py ├── Project_14 ├── record_file.py └── surveillance_system.py ├── Project_16 ├── templates │ └── index.html ├── static │ └── style.css └── app.py ├── Part_0 ├── pick_a_fruit.py └── calculator.py ├── Project_1 └── blinking_led.py ├── Project_6 ├── character_lcd.py └── scrolling_text.py ├── Project_20 ├── Function_Node.js └── Project_20_import_Node-RED_flow.txt ├── Project_9 ├── weather_data.py └── weather_station.py ├── Project_3 └── brightness_controller.py ├── Project_11 └── smoke_detector.py ├── Project_18 └── digital_drum_set.py ├── Project_10 ├── send_email.py └── intruder_alarm.py ├── Project_13 └── burglar_detector.py ├── Project_4 └── rgb_led_controller.py ├── Project_12 └── temperature_humidity_data_logger.py ├── Project_5 └── rainbow_effect.py ├── Project_17 └── Project_17_import_Node-RED_flow.txt └── Project_7 └── weather_forecast.py /README.md: -------------------------------------------------------------------------------- 1 | # RaspberryPiProject 2 | https://nostarch.com/RaspberryPiProject 3 | -------------------------------------------------------------------------------- /Code/Project_15/max.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RuiSantosdotme/RaspberryPiProject/HEAD/Code/Project_15/max.JPG -------------------------------------------------------------------------------- /Code/Project_15/background.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RuiSantosdotme/RaspberryPiProject/HEAD/Code/Project_15/background.JPG -------------------------------------------------------------------------------- /Code/Project_19/Project_19_Scratch_Game.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RuiSantosdotme/RaspberryPiProject/HEAD/Code/Project_19/Project_19_Scratch_Game.sb2 -------------------------------------------------------------------------------- /Code/Project_2/led_flashlight.py: -------------------------------------------------------------------------------- 1 | #Project 2 - Pushbutton LED Flashlight 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | from gpiozero import LED, Button 6 | from signal import pause 7 | 8 | led = LED(25) 9 | button = Button(2) 10 | 11 | button.when_pressed = led.on 12 | button.when_released = led.off 13 | 14 | pause() 15 | -------------------------------------------------------------------------------- /Code/Project_8/sense_hat_scrolling_text.py: -------------------------------------------------------------------------------- 1 | #Project 8 - Scrolling Text 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | from sense_hat import SenseHat 6 | #uncomment the following line if you are using the emulator 7 | #from sense_emu import SenseHat 8 | sense = SenseHat() 9 | sense.show_message('Hello World!', text_colour = [0, 0, 255]) 10 | -------------------------------------------------------------------------------- /Code/Project_14/record_file.py: -------------------------------------------------------------------------------- 1 | #Project 14 - Record Video to a File 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | import picamera 6 | 7 | camera = picamera.PiCamera() 8 | 9 | camera.resolution = (640, 480) 10 | camera.start_recording('videotest.h264') 11 | camera.wait_recording(60) 12 | camera.stop_recording() 13 | 14 | print('Finished recording') 15 | -------------------------------------------------------------------------------- /Code/Project_16/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RPi Web Server 5 | 6 | 7 | 8 | 9 | 10 |

RPi Web Server

11 |

{{relay_state}}

12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Code/Project_16/static/style.css: -------------------------------------------------------------------------------- 1 | h2 { 2 | font-size: 2.5rem; 3 | } 4 | p { 5 | font-size: 1.8rem; 6 | } 7 | body { 8 | display: inline-block; 9 | margin: 0px auto; 10 | text-align: center; 11 | } 12 | button { 13 | display: inline-block; 14 | margin: 0 auto; 15 | padding: 15px 25px; 16 | font-size: 3rem; 17 | border-radius: 4px; 18 | color: #fff; 19 | background-color: #009933; 20 | border: none; 21 | } 22 | .off { 23 | color: #fff; 24 | background-color: #604f43; 25 | } 26 | a { 27 | text-decoration: none; 28 | } 29 | -------------------------------------------------------------------------------- /Code/Project_8/sense_hat_set_led_colors.py: -------------------------------------------------------------------------------- 1 | #Project 8 - Set LED Colors 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | from sense_hat import SenseHat 6 | #uncomment the following line if you are using the emulator 7 | #from sense_emu import SenseHat 8 | sense = SenseHat() 9 | #set blue pixel 10 | sense.set_pixel(0, 1, 0, 0, 255) 11 | #set green pixel 12 | sense.set_pixel(7, 6, 0, 255, 0) 13 | #set pink pixel 14 | sense.set_pixel(2, 5, 255, 51, 153) 15 | -------------------------------------------------------------------------------- /Code/Part_0/pick_a_fruit.py: -------------------------------------------------------------------------------- 1 | #Part 0 - Pick a fruit 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | print('Pick a fruit:') 6 | print('strawberry, banana, or kiwi?') 7 | color = input ('Enter the color of the fruit you chose: ') 8 | if (color == 'red'): 9 | print('Your fruit is a strawberry.') 10 | elif (color == 'yellow'): 11 | print('Your fruit is a banana.') 12 | elif (color == 'green'): 13 | print('Your fruit is a kiwi.') 14 | else: 15 | print('Invalid input.') 16 | -------------------------------------------------------------------------------- /Code/Project_1/blinking_led.py: -------------------------------------------------------------------------------- 1 | #Project 1 - Blinking an LED 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #importing necessary packages 6 | from gpiozero import LED 7 | from time import sleep 8 | #create an object called led that refers to GPIO 25 9 | led = LED(25) 10 | 11 | #create a variable called delay that refers to the delay time in seconds 12 | delay = 1 13 | 14 | while True: 15 | #set led to on for the delay time 16 | led.on() 17 | print("LED set to on") 18 | sleep(delay) 19 | #set led to off for the delay time 20 | led.off() 21 | print("LED set to off") 22 | sleep(delay) 23 | -------------------------------------------------------------------------------- /Code/Project_6/character_lcd.py: -------------------------------------------------------------------------------- 1 | #Project 6 - Displaying a Character Message 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | import Adafruit_CharLCD as LCD 6 | 7 | #Raspberry Pi pin configuration 8 | lcd_rs = 27 9 | lcd_en = 22 10 | lcd_d4 = 25 11 | lcd_d5 = 24 12 | lcd_d6 = 23 13 | lcd_d7 = 18 14 | lcd_backlight = 4 15 | 16 | #define the LCD size 17 | lcd_columns = 16 18 | lcd_rows = 2 19 | 20 | #initialize the LCD 21 | lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, 22 | lcd_d7, lcd_columns, lcd_rows, lcd_backlight) 23 | #write your message 24 | lcd.message('It works\nYou rock!') 25 | -------------------------------------------------------------------------------- /Code/Project_15/style.css: -------------------------------------------------------------------------------- 1 | header { 2 | background: url(background.JPG); 3 | background-size: cover; 4 | height: 70vh; 5 | } 6 | .title { 7 | position: absolute; 8 | top: 50%; 9 | left: 50%; 10 | transform: translate(-50%, -40%); 11 | color: #fff; 12 | text-align: center; 13 | } 14 | h1 { 15 | font-size: 4rem; 16 | } 17 | h2 { 18 | font-size: 2.5rem; 19 | } 20 | p { 21 | font-size: 1.3rem; 22 | } 23 | main { 24 | max-width: 500px; 25 | margin: 20px auto; 26 | } 27 | button { 28 | display: block; 29 | margin: 0 auto; 30 | padding: 10px 20px; 31 | font-size: 1.7rem; 32 | border-radius: 4px; 33 | color: #fff; 34 | background-color: #009933; 35 | border: none; 36 | } 37 | a { 38 | text-decoration: none; 39 | } 40 | -------------------------------------------------------------------------------- /Code/Project_20/Function_Node.js: -------------------------------------------------------------------------------- 1 | var msg1 = { payload: 0 }; 2 | var msg2 = { payload: 0 }; 3 | var msg3 = { payload: 0 }; 4 | var msg4 = { payload: 0 }; 5 | var msg5 = { payload: 0 }; 6 | var msg6 = { payload: 0 }; 7 | if (msg.payload === "forward") { 8 | msg1.payload = 1; 9 | msg2.payload = 1; 10 | msg4.payload = 1; 11 | msg5.payload = 1; 12 | } 13 | else if (msg.payload === "left") { 14 | msg1.payload = 1; 15 | msg2.payload = 1; 16 | } 17 | else if (msg.payload === "right") { 18 | msg4.payload = 1; 19 | msg5.payload = 1; 20 | } 21 | else if (msg.payload === "reverse") { 22 | msg1.payload = 1; 23 | msg3.payload = 1; 24 | msg4.payload = 1; 25 | msg6.payload = 1; 26 | } 27 | return [msg1, msg2, msg3, msg4, msg5, msg6]; 28 | -------------------------------------------------------------------------------- /Code/Project_8/sense_hat_display_picture.py: -------------------------------------------------------------------------------- 1 | #Project 8 - Display Picture 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | from sense_hat import SenseHat 6 | #uncomment the following line if you are using the emulator 7 | #from sense_emu import SenseHat 8 | 9 | sense = SenseHat() 10 | 11 | #red color 12 | X = [255, 0, 0] 13 | #no color 14 | N = [0, 0, 0] 15 | 16 | #sad face array 17 | sad_face = [ 18 | N, N, X, X, X, X, N, N, 19 | N, X, N, N, N, N, X, N, 20 | X, N, X, N, N, X, N, X, 21 | X, N, N, N, N, N, N, X, 22 | X, N, N, X, X, N, N, X, 23 | X, N, X, N, N, X, N, X, 24 | N, X, N, N, N, N, X, N, 25 | N, N, X, X, X, X, N, N 26 | ] 27 | 28 | sense.set_pixels(sad_face) 29 | -------------------------------------------------------------------------------- /Code/Project_9/weather_data.py: -------------------------------------------------------------------------------- 1 | #Project 9 - Reading Temperature, Humidity, And Pressure 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | from sense_hat import SenseHat 6 | #from sense_emu import SenseHat 7 | 8 | from time import sleep 9 | 10 | #create an object called sense 11 | sense = SenseHat() 12 | 13 | while True: 14 | temperature = sense.temperature 15 | temperature = str(round(temperature, 2)) 16 | print('Temperature: ' + temperature + '*C\n') 17 | 18 | humidity = sense.humidity 19 | humidity = str(round(humidity, 2)) 20 | print ('Humidity: ' + humidity + '%\n') 21 | 22 | pressure = sense.pressure 23 | pressure = str(round(pressure, 2)) 24 | print('Pressure: ' + pressure + 'hPa\n') 25 | 26 | sleep(1) 27 | 28 | -------------------------------------------------------------------------------- /Code/Project_3/brightness_controller.py: -------------------------------------------------------------------------------- 1 | #Project 3 - LED Dimmer Switch 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #import necessary packages 6 | from gpiozero import PWMLED, MCP3008 7 | from time import sleep 8 | 9 | #create an object called pot which refers to MCP3008 channel 0 10 | pot = MCP3008(0) 11 | 12 | #create a PWMLED object called led that refers to GPIO 17 13 | led = PWMLED(17) 14 | 15 | while True: 16 | #the pot.value accesses the current pot reading 17 | if(pot.value < 0.001): 18 | #if the pot value is very small, the led is turned off 19 | led.value = 0 20 | else: 21 | #change led brightness accordingly to the pot value 22 | led.value = pot.value 23 | #print the pot value 24 | print(pot.value) 25 | #pause for 0.1 seconds 26 | sleep(0.1) 27 | -------------------------------------------------------------------------------- /Code/Project_15/index.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | Max - The Dog 10 | 11 | 12 | 13 | 14 |
15 |
16 |

MAX - THE DOG

17 |
18 |
19 | 20 |
21 |

About Max

22 |

Howdy, I'm Max. I'm an aspiring police dog living in Portugal. I enjoy barking, running, and playing catch. I like meat, bones, and leftovers.

23 |

My favorite TV series is Inspector Rex.

24 |

25 | 26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /Code/Project_8/sense_hat_joystick_control.py: -------------------------------------------------------------------------------- 1 | #Project 8 - Joystick Control 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | from signal import pause 6 | 7 | from sense_hat import SenseHat 8 | #uncomment the following line if you are using the emulator from sense_emu import SenseHat 9 | 10 | sense = SenseHat() 11 | 12 | def move_up(event): 13 | print('joystick was moved up') 14 | 15 | def move_down(event): 16 | print('joystick was moved down') 17 | 18 | def move_right(event): 19 | print('joystick was moved right') 20 | 21 | def move_left(event): 22 | print('joystick was moved left') 23 | 24 | def move_middle(event): 25 | print('joystick was pressed') 26 | 27 | sense.stick.direction_up = move_up 28 | sense.stick.direction_down = move_down 29 | sense.stick.direction_right = move_right 30 | sense.stick.direction_left = move_left 31 | sense.stick.direction_middle = move_middle 32 | 33 | pause() 34 | -------------------------------------------------------------------------------- /Code/Project_11/smoke_detector.py: -------------------------------------------------------------------------------- 1 | #Project 11 - Gas and Smoke Alarm 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #import necessary packages 6 | from gpiozero import LED, Button, Buzzer, MCP3008 7 | from time import sleep 8 | 9 | led = LED(17) 10 | button = Button(2) 11 | buzzer = Buzzer(27) 12 | gas_sensor = MCP3008(0) 13 | 14 | gas_sensor_status = False 15 | 16 | threshold = 0.1 17 | 18 | def arm_gas_sensor(): 19 | global gas_sensor_status 20 | if gas_sensor_status == True: 21 | gas_sensor_status = False 22 | led.off() 23 | else: 24 | gas_sensor_status = True 25 | led.on() 26 | 27 | button.when_pressed = arm_gas_sensor 28 | 29 | while True: 30 | #print(gas_sensor.value) 31 | #check if the gas sensor is armed and 32 | #reached the threshold value 33 | if(gas_sensor_status == True and gas_sensor.value > threshold): 34 | buzzer.beep() 35 | else: 36 | buzzer.off() 37 | sleep(2) 38 | -------------------------------------------------------------------------------- /Code/Project_18/digital_drum_set.py: -------------------------------------------------------------------------------- 1 | #Project 18 - Digital Drum Set 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #import the necessary packages 6 | import pygame.mixer 7 | from pygame.mixer import Sound 8 | from gpiozero import Button 9 | from signal import pause 10 | 11 | #create an object for the mixer module that loads and plays sounds 12 | pygame.mixer.init() 13 | 14 | #assign each button to a drum sound 15 | button_sounds = { 16 | Button(2): Sound("samples/drum_cymbal_open.wav"), 17 | Button(3): Sound("samples/drum_heavy_kick.wav"), 18 | Button(14): Sound("samples/drum_snare_hard.wav"), 19 | Button(15): Sound("samples/drum_cymbal_closed.wav"), 20 | Button(17): Sound("samples/drum_roll.wav"), 21 | Button(18): Sound("samples/perc_snap.wav"), 22 | Button(22): Sound("samples/loop_amen_full.wav"), 23 | Button(27): Sound("samples/loop_mika.wav"), 24 | } 25 | 26 | #the sound plays when the button is pressed 27 | for button, sound in button_sounds.items(): 28 | button.when_pressed = sound.play 29 | 30 | #keep the program running to detect events 31 | pause() 32 | -------------------------------------------------------------------------------- /Code/Project_10/send_email.py: -------------------------------------------------------------------------------- 1 | #Project 10 - Send Email 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | import smtplib 6 | from email.mime.multipart import MIMEMultipart 7 | from email.mime.text import MIMEText 8 | 9 | #replace the next 3 lines with your credentials 10 | from_email_addr = 'YOUR_EMAIL@gmail.com' 11 | from_email_password = 'YOUR_EMAIL_PASSWORD' 12 | to_email_addr = 'TO_YOUR_OTHER_EMAIL@gmail.com' 13 | 14 | #set your email message 15 | body = 'Motion was detected in your room' 16 | msg = MIMEText(body) 17 | 18 | #set send and recipient 19 | msg['From'] = from_email_addr 20 | msg['To'] = to_email_addr 21 | 22 | #set your email subject 23 | msg['Subject'] = 'WARNING' 24 | 25 | #connecting to server and sending email 26 | #edit the following line with your provider's SMTP server details 27 | server = smtplib.SMTP('smtp.gmail.com', 587) 28 | #comment out the next line if your email provider doesn't use TLS 29 | server.starttls() 30 | server.login(from_email_addr, from_email_password) 31 | server.sendmail(from_email_addr, to_email_addr, msg.as_string()) 32 | server.quit() 33 | print('Email Sent') 34 | -------------------------------------------------------------------------------- /Code/Project_13/burglar_detector.py: -------------------------------------------------------------------------------- 1 | #Project 13 - Burglar Detector With Photo Capture 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #import the necessary packages 6 | from gpiozero import Button, MotionSensor 7 | from picamera import PiCamera 8 | from time import sleep 9 | from signal import pause 10 | 11 | #create objects that refer to a button, 12 | #a motion sensor and the PiCamera 13 | button = Button(2) 14 | pir = MotionSensor(4) 15 | camera = PiCamera() 16 | 17 | #start the camera 18 | camera.rotation = 180 19 | camera.start_preview() 20 | 21 | #image image names 22 | i = 0 23 | 24 | #stop the camera when the pushbutton is pressed 25 | def stop_camera(): 26 | camera.stop_preview() 27 | #exit the program 28 | exit() 29 | 30 | #take photo when motion is detected 31 | def take_photo(): 32 | global i 33 | i = i + 1 34 | camera.capture('/home/pi/Desktop/image_%s.jpg' % i) 35 | print('A photo has been taken') 36 | sleep(10) 37 | 38 | #assign a function that runs when the button is pressed 39 | button.when_pressed = stop_camera 40 | #assign a function that runs when motion is detected 41 | pir.when_motion = take_photo 42 | 43 | pause() 44 | -------------------------------------------------------------------------------- /Code/Project_6/scrolling_text.py: -------------------------------------------------------------------------------- 1 | #Project 6 - An LCD Reminder 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | import Adafruit_CharLCD as LCD 6 | import time 7 | 8 | #Raspberry Pi pin configuration 9 | lcd_rs = 27 10 | lcd_en = 22 11 | lcd_d4 = 25 12 | lcd_d5 = 24 13 | lcd_d6 = 23 14 | lcd_d7 = 18 15 | lcd_backlight = 4 16 | 17 | #define the LCD size 18 | lcd_columns = 16 19 | lcd_rows = 2 20 | 21 | #initialize the LCD 22 | lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, 23 | lcd_d6, lcd_d7, lcd_columns, lcd_rows, lcd_backlight) 24 | 25 | #write your message 26 | title = "Don't forget!" 27 | reminder = "You have a doctor appointment next Monday" 28 | 29 | #set the delay for scroll 30 | delay = 0.3 31 | 32 | #write a function to scroll the message 33 | def scroll_text(reminder, delay): 34 | padding = " " * lcd_columns 35 | scroll_message = padding + reminder + " " 36 | for i in range(len(scroll_message)): 37 | lcd.set_cursor(0, 1) 38 | lcd.message(scroll_message[i:(i+lcd_columns)]) 39 | time.sleep(delay) 40 | 41 | #Scroll text in infinite loop 42 | lcd.clear() 43 | lcd.home() 44 | lcd.message(title) 45 | 46 | while(True): 47 | scroll_text(reminder, delay) 48 | -------------------------------------------------------------------------------- /Code/Part_0/calculator.py: -------------------------------------------------------------------------------- 1 | #Part 0 - Python Calculator 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | running = True 6 | welcome_message = '***Welcome to Python Calculator***' 7 | print(welcome_message) 8 | while running: 9 | print('Operations') 10 | print('1 = Addition') 11 | print('2 = Subtraction') 12 | print('3 = Multiplication') 13 | print('4 = Division') 14 | print('5 = Quit program') 15 | operation = int(input('Enter a number to choose an operation: ')) 16 | if operation == 1: 17 | print('Addition') 18 | first = int(input('Enter first number: ')) 19 | second = int(input('Enter second number: ')) 20 | print('Result = ', first + second) 21 | elif operation == 2: 22 | print('Subtraction') 23 | first = int(input('Enter first number: ')) 24 | second = int(input('Enter second number: ')) 25 | print('Result = ', first - second) 26 | elif operation == 3: 27 | print('Multiplication') 28 | first = int(input('Enter first number: ')) 29 | second = int(input('Enter second number: ')) 30 | print('Result = ', first * second) 31 | elif operation == 4: 32 | print('Division') 33 | first = int(input('Enter first number: ')) 34 | second = int(input('Enter second number: ')) 35 | print('Result = ', first / second) 36 | elif operation == 5: 37 | print('Quitting program... ') 38 | running = False 39 | -------------------------------------------------------------------------------- /Code/Project_16/app.py: -------------------------------------------------------------------------------- 1 | #Project 16 - Connecting Your Electronics to the Web 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #import necessary packages 6 | from gpiozero import LED 7 | from flask import Flask, render_template, request 8 | 9 | #create a Flask object 10 | app = Flask(__name__) 11 | 12 | #create an object that refers to a relay 13 | relay = LED(17) 14 | #set the relay off; remember the relay works with inverted logic 15 | relay.on() 16 | #save current relay state 17 | relay_state = 'Relay is off' 18 | 19 | #display the main web page 20 | @app.route('/') 21 | def main(): 22 | global relay_state 23 | # pass the relay state to the index.html and return it to the user 24 | return render_template('index.html', relay_state=relay_state) 25 | 26 | #execute control() when someone presses the on/off buttons 27 | @app.route('/') 28 | def control(action): 29 | global relay_state 30 | #if the action part of the URL is 'on', turn the relay on 31 | if action == 'on': 32 | #set the relay on 33 | relay.off() 34 | #save the relay state 35 | relay_state = 'Relay is on' 36 | if action == 'off': 37 | relay.on() 38 | relay_state = 'Relay is off' 39 | 40 | #pass the relay state to the index.html and return it to the user 41 | return render_template('index.html', relay_state=relay_state) 42 | 43 | #start the web server at localhost on port 80 44 | if __name__ == '__main__': 45 | app.run(host='0.0.0.0', port=80, debug=True) 46 | -------------------------------------------------------------------------------- /Code/Project_4/rgb_led_controller.py: -------------------------------------------------------------------------------- 1 | #Project 4 - A Graphical User Interface For A Multicolor Led 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #import necessary libraries 6 | from gpiozero import PWMLED 7 | from tkinter import * 8 | 9 | #change the RGB LED color 10 | def change_color(self): 11 | red.value = red_slider.get() 12 | green.value = green_slider.get() 13 | blue.value = blue_slider.get() 14 | print(self) 15 | 16 | #close the window 17 | def close_window(): 18 | window.destroy() 19 | 20 | #create a PWMLED object for each color 21 | red = PWMLED(23) 22 | green = PWMLED(24) 23 | blue = PWMLED(25) 24 | 25 | #create window 26 | window = Tk() 27 | window.title("RGB LED Controller") 28 | window.geometry("300x200") 29 | 30 | #create three sliders to control each RGB LED lead 31 | red_slider = Scale(window, from_=0, to=1, resolution = 0.01, orient=HORIZONTAL, 32 | label="Red", troughcolor="red", length=200, command=change_color) 33 | red_slider.pack() 34 | 35 | green_slider = Scale(window, from_=0, to=1, resolution = 0.01, orient=HORIZONTAL, 36 | label="Green", troughcolor="green", length=200, command=change_color) 37 | green_slider.pack() 38 | 39 | blue_slider = Scale(window, from_=0, to=1, resolution = 0.01, orient=HORIZONTAL, 40 | label="Blue", troughcolor="blue", length=200, command=change_color) 41 | blue_slider.pack() 42 | 43 | #create close button 44 | close_button = Button(window, text="Close", command=close_window) 45 | close_button.pack() 46 | 47 | mainloop() 48 | -------------------------------------------------------------------------------- /Code/Project_12/temperature_humidity_data_logger.py: -------------------------------------------------------------------------------- 1 | #Project 12 - Temperature and Humidity Data Logger 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #import necessary packages 6 | import Adafruit_DHT 7 | import time 8 | 9 | #comment and uncomment the line below for your sensor 10 | #sensor = Adafruit_DHT.DHT11 11 | sensor = Adafruit_DHT.DHT22 12 | #sensor = Adafruit_DHT.AM2302 13 | 14 | #DHT pin connects to GPIO 4 15 | sensor_pin = 4 16 | 17 | #create a variable to control the while loop 18 | running = True 19 | 20 | #new .txt file created with header 21 | file = open('sensor_readings.txt', 'w') 22 | file.write('time and date, temperature, humidity\n') 23 | 24 | #loop forever 25 | while running: 26 | try: 27 | #read the humidity and temperature 28 | humidity, temperature = Adafruit_DHT.read_retry(sensor, sensor_pin) 29 | 30 | #uncomment the line below to convert the temperature to Fahrenheit 31 | #temperature = temperature * 9/5.0 + 32 32 | 33 | #sometimes you won't get a reading and the results will be null 34 | #the next statement guarantees that it only saves valid readings 35 | if humidity is not None and temperature is not None: 36 | #print temperature and humidity 37 | print('Temperature = ' + str(temperature) + ', Humidity = ' + str(humidity)) 38 | #save time, date, temperature and humidity in .txt file 39 | file.write(time.strftime('%H:%M:%S %d/%m/%Y') + ', ' + 40 | str(temperature) + ', '+ str(humidity) + '\n') 41 | else: 42 | print('Failed to get reading. Try again!') 43 | #waits 10s between each sensor reading 44 | time.sleep(10) 45 | #if KeyboardInterrupt triggered: stops loop and closes .txt file 46 | except KeyboardInterrupt: 47 | print ('Program stopped') 48 | running = False 49 | file.close() 50 | -------------------------------------------------------------------------------- /Code/Project_5/rainbow_effect.py: -------------------------------------------------------------------------------- 1 | #Project 5 - Rainbow Light Strip 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #based on Tony DiCola's NeoPixel library strandtest example 6 | 7 | #import necessary libraries 8 | from neopixel import * 9 | from time import sleep 10 | from gpiozero import Button, MCP3008 11 | 12 | # LED strip configuration 13 | LED_COUNT = 14 #number of LED pixels 14 | LED_PIN = 18 #GPIO pin connected to the pixels (must support PWM!) 15 | LED_FREQ_HZ = 800000 #LED signal frequency in hertz (usually 800khz) 16 | LED_DMA = 5 #DMA channel to use for generating signal (try 5) 17 | LED_INVERT = False #set True to invert the signal 18 | LED_CHANNEL = 0 #leave channel '0' for GPIO 18 19 | 20 | #create pot objects to refer to MCP3008 channel 0 and 1 21 | pot_brightness = MCP3008(0) 22 | pot_speed = MCP3008(1) 23 | 24 | #connect pushbutton to GPIO pin 2, pull-up 25 | button_start = Button(2) 26 | 27 | #animation running control variable 28 | running_animation = False 29 | 30 | #generate rainbow colors across 0-255 positions 31 | def wheel(pos): 32 | if pos < 85: 33 | return Color(pos * 3, 255 - pos * 3, 0) 34 | elif pos < 170: 35 | pos -= 85 36 | return Color(255 - pos * 3, 0, pos * 3) 37 | else: 38 | pos -= 170 39 | return Color(0, pos * 3, 255 - pos * 3) 40 | 41 | #draw rainbow that uniformly distributes itself across all pixels 42 | def rainbowCycle(strip): 43 | for j in range(256): 44 | for i in range(strip.numPixels()): 45 | strip.setPixelColor(i, wheel((int(i * 256 / strip.numPixels()) + j) & 255)) 46 | strip.show() 47 | sleep((pot_speed.value*40)/1000.0) 48 | 49 | #function to start and stop the animation 50 | def start_animation(): 51 | global running_animation 52 | if running_animation == True: 53 | running_animation = False 54 | else: 55 | running_animation = True 56 | 57 | #assign a function that runs when the button is pressed 58 | button_start.when_pressed = start_animation 59 | 60 | #create NeoPixel object with appropriate configuration 61 | strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, int(pot_brightness.value*255), LED_CHANNEL) 62 | #initialize the strip 63 | strip.begin() 64 | while True: 65 | if running_animation == True: 66 | #set LED strip brightness 67 | strip.setBrightness(int(pot_brightness.value*255)) 68 | rainbowCycle(strip) 69 | -------------------------------------------------------------------------------- /Code/Project_9/weather_station.py: -------------------------------------------------------------------------------- 1 | #Project 9 - All-In-One Weather Sensor Station 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #import necessary packages 6 | from tkinter import * 7 | from tkinter import ttk 8 | import time 9 | from sense_hat import SenseHat 10 | #from sense_emu import SenseHat 11 | 12 | #create an object called sense 13 | sense = SenseHat() 14 | 15 | #create window 16 | window = Tk() 17 | window.title('Local Weather Station') 18 | window.geometry('200x480') 19 | 20 | #create humidity label for title and value 21 | humidity_label = Label(window, text = 'Humidity', font = ('Helvetica', 18), pady = 3) 22 | humidity_label.pack() 23 | 24 | humidity = StringVar() 25 | 26 | humidity_value=Label(window, textvariable = humidity, 27 | font = ('Courier', 20), fg = 'blue', anchor = N, width = 200) 28 | humidity_value.pack() 29 | 30 | #create humidity canvas 31 | humidity_canvas = Canvas(window, width = 200, height = 200) 32 | humidity_canvas.pack() 33 | 34 | #create humidity progress bar 35 | humidity_bar = DoubleVar() 36 | 37 | progressbar_humidity = ttk.Progressbar(humidity_canvas, variable = humidity_bar, 38 | orient = VERTICAL, length = 200, maximum = 100) 39 | progressbar_humidity.pack(fill=X, expand=1) 40 | 41 | #create temperature label for title and value 42 | temperature_label = Label(window, text = 'Temperature', font = ('Helvetica', 18), 43 | anchor = S, width = 200, height = 2) 44 | temperature_label.pack() 45 | 46 | temperature=StringVar() 47 | 48 | temperature_value = Label(window, textvariable = temperature, font = ('Courier', 20), 49 | fg = 'red', anchor = N, width = 200) 50 | temperature_value.pack() 51 | 52 | #create pressure label for title and value 53 | pressure_label = Label(window, text = 'Pressure', font = ('Helvetica', 18), 54 | anchor = S, width = 200, height = 2) 55 | pressure_label.pack() 56 | 57 | pressure = StringVar() 58 | 59 | pressure_value = Label(window, textvariable = pressure, 60 | font = ('Courier', 20), fg = 'green', anchor = N, width = 200) 61 | pressure_value.pack() 62 | 63 | def update_readings(): 64 | humidity.set(str(round(sense.humidity, 2)) + '%') 65 | humidity_bar.set(sense.humidity) 66 | temperature.set(str(round(sense.temperature, 2)) + 'ºC') 67 | #temperature.set(str(round(sense.temperature*(9/5)+32, 2)) + 'ºF') 68 | pressure.set(str(round(sense.pressure)) + 'hPa') 69 | window.update_idletasks() 70 | window.after(3000, update_readings) 71 | 72 | update_readings() 73 | window.mainloop() 74 | -------------------------------------------------------------------------------- /Code/Project_10/intruder_alarm.py: -------------------------------------------------------------------------------- 1 | #Project 10 - Intruder Alarm With Email Notifications 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #import necessary packages 6 | from gpiozero import LED, Button, MotionSensor 7 | import smtplib 8 | from email.mime.text import MIMEText 9 | from signal import pause 10 | 11 | #create objects to refer to each LED, the button, and the PIR sensorled_status = LED(17) 12 | led_status = LED(17) 13 | led_triggered = LED(18) 14 | button = Button(2) 15 | pir = MotionSensor(4) 16 | 17 | #control variables 18 | motion_sensor_status = False 19 | email_sent = False 20 | 21 | #arm or disarm the PIR sensor 22 | def arm_motion_sensor(): 23 | global email_sent 24 | global motion_sensor_status 25 | if motion_sensor_status == True: 26 | motion_sensor_status = False 27 | led_status.off() 28 | led_triggered.off() 29 | else: 30 | motion_sensor_status = True 31 | email_sent = False 32 | led_status.on() 33 | 34 | #send email when motion is detected and the PIR sensor is armed 35 | def send_email(): 36 | global email_sent 37 | global motion_sensor_status 38 | if(motion_sensor_status == True and email_sent == False): 39 | #replace the next 3 lines with your credentials 40 | from_email_addr = 'YOUR_EMAIL@gmail.com' 41 | from_email_password = 'YOUR_EMAIL_PASSWORD' 42 | to_email_addr = 'TO_YOUR_OTHER_EMAIL@gmail.com' 43 | 44 | #set your email message 45 | body = 'Motion was detected in your room' 46 | msg = MIMEText(body) 47 | 48 | #set send and recipient 49 | msg['From'] = from_email_addr 50 | msg['To'] = to_email_addr 51 | 52 | #set your email subject 53 | msg['Subject'] = 'WARNING' 54 | 55 | #connect to server and send email 56 | #edit this line with your provider's SMTP server details 57 | server = smtplib.SMTP('smtp.gmail.com', 587) 58 | #comment out this line if your provider doesn't use TLS 59 | server.starttls() 60 | server.login(from_email_addr, from_email_password) 61 | server.sendmail(from_email_addr, to_email_addr, msg.as_string()) 62 | server.quit() 63 | email_sent = True 64 | led_triggered.on() 65 | print('Email Sent') 66 | 67 | #assign a function that runs when the button is pressed 68 | button.when_pressed = arm_motion_sensor 69 | #assign a function that runs when motion is detected 70 | pir.when_motion = send_email 71 | 72 | pause() 73 | -------------------------------------------------------------------------------- /Code/Project_8/pong_game.py: -------------------------------------------------------------------------------- 1 | #Project 8 - Pong With a Sense HAT 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #based on raspberrypi.org Sense HAT Pong example 6 | 7 | #import necessary libraries 8 | from random import randint 9 | from time import sleep 10 | 11 | #use this line if you are using the Sense HAT board 12 | from sense_hat import SenseHat 13 | 14 | #uncomment the following line if you are using the emulator 15 | #from sense_emu import SenseHat 16 | 17 | #create an object called sense 18 | sense = SenseHat() 19 | 20 | #set bat position, random ball position, and velocity 21 | y = 4 22 | ball_position = [int(randint(2,6)), int(randint(1,6))] 23 | ball_velocity = [1, 1] 24 | 25 | #red color 26 | X = [255, 0, 0] 27 | #no color 28 | N = [0, 0, 0] 29 | 30 | #sad face array 31 | sad_face = [ 32 | N, N, X, X, X, X, N, N, 33 | N, X, N, N, N, N, X, N, 34 | X, N, X, N, N, X, N, X, 35 | X, N, N, X, N, N, N, X, 36 | X, N, N, X, N, N, N, X, 37 | X, N, X, N, N, X, N, X, 38 | N, X, N, N, N, N, X, N, 39 | N, N, X, X, X, X, N, N 40 | ] 41 | 42 | #draws bat at y position 43 | def draw_bat(): 44 | sense.set_pixel(0, y, 0, 255, 0) 45 | sense.set_pixel(0, y+1, 0, 255, 0) 46 | sense.set_pixel(0, y-1, 0, 255, 0) 47 | 48 | #move bat up 49 | def move_up(event): 50 | global y 51 | if y > 1 and event.action=='pressed': 52 | y -= 1 53 | 54 | #move bat down 55 | def move_down(event): 56 | global y 57 | if y < 6 and event.action=='pressed': 58 | y += 1 59 | 60 | #move ball to the next position 61 | def draw_ball(): 62 | #ball displayed on current position 63 | sense.set_pixel(ball_position[0], ball_position[1], 75, 0, 255) 64 | #next ball position 65 | ball_position[0] += ball_velocity[0] 66 | ball_position[1] += ball_velocity[1] 67 | #if ball hits ceiling, calculate next position 68 | if ball_position[0] == 7: 69 | ball_velocity[0] = -ball_velocity[0] 70 | #if ball hits wall, calculate next position 71 | if ball_position[1] == 0 or ball_position[1] == 7: 72 | ball_velocity[1] = -ball_velocity[1] 73 | #if ball reaches 0 position, player loses and quits game 74 | if ball_position[0] == 0: 75 | sleep(0.25) 76 | sense.set_pixels(sad_face) 77 | quit() 78 | #if ball hits bat, calculate next ball position 79 | if ball_position[0] == 1 and y - 1 <= ball_position[1] <= y+1: 80 | ball_velocity[0] = -ball_velocity[0] 81 | 82 | #when joystick moves up or down, trigger corresponding function 83 | sense.stick.direction_up = move_up 84 | sense.stick.direction_down = move_down 85 | 86 | #run the game 87 | while True: 88 | sense.clear() 89 | draw_bat() 90 | draw_ball() 91 | sleep(0.25) 92 | -------------------------------------------------------------------------------- /Code/Project_17/Project_17_import_Node-RED_flow.txt: -------------------------------------------------------------------------------- 1 | [{"id":"de9b231a.1a02c","type":"tab","label":"Flow 1"},{"id":"aca49001.dd1ed","type":"inject","z":"de9b231a.1a02c","name":"Off at 11PM","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"00 23 * * *","once":false,"x":200,"y":230,"wires":[["8ee3d13.d91eb3"]]},{"id":"8ee3d13.d91eb3","type":"rpi-gpio out","z":"de9b231a.1a02c","name":"LED 1 - GPIO 17","pin":"11","set":"","level":"0","out":"out","x":440,"y":230,"wires":[]},{"id":"712c2a21.fd8374","type":"ui_switch","z":"de9b231a.1a02c","name":"LED 1 - Switch","label":"LED 1","group":"3e309e92.011152","order":0,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"1","onvalueType":"num","onicon":"","oncolor":"","offvalue":"0","offvalueType":"num","officon":"","offcolor":"","x":190,"y":289,"wires":[["8ee3d13.d91eb3"]]},{"id":"39c4721f.2f451e","type":"rpi-gpio out","z":"de9b231a.1a02c","name":"LED 2 - GPIO 18","pin":"12","set":"","level":"0","out":"pwm","x":455,"y":354,"wires":[]},{"id":"4ffe4b8a.0e3224","type":"ui_slider","z":"de9b231a.1a02c","name":"LED 2 - Slider","label":"LED 2","group":"3e309e92.011152","order":0,"width":0,"height":0,"passthru":true,"topic":"","min":0,"max":"100","step":1,"x":184,"y":355,"wires":[["39c4721f.2f451e"]]},{"id":"94e9a6c9.d067e8","type":"rpi-dht22","z":"de9b231a.1a02c","name":"DHT22 - GPIO 4","topic":"","dht":22,"pintype":"0","pin":"4","x":381,"y":461,"wires":[["38bc9199.f4c8be","9e9213a6.dba38"]]},{"id":"b42f3acb.c3e228","type":"inject","z":"de9b231a.1a02c","name":"Read DHT22","topic":"","payload":"true","payloadType":"bool","repeat":"60","crontab":"","once":false,"x":198,"y":459,"wires":[["94e9a6c9.d067e8"]]},{"id":"9e9213a6.dba38","type":"function","z":"de9b231a.1a02c","name":"Get humidity","func":"msg.payload = msg.humidity;\nreturn msg;","outputs":1,"noerr":0,"x":578.25,"y":501.75,"wires":[["16c12704.519d79"]]},{"id":"38bc9199.f4c8be","type":"ui_chart","z":"de9b231a.1a02c","name":"Temperature - Chart","group":"3e309e92.011152","order":0,"width":0,"height":0,"label":"Temperature","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"x":629.5,"y":420,"wires":[[],[]]},{"id":"16c12704.519d79","type":"ui_gauge","z":"de9b231a.1a02c","name":"Humidity- Gauge","group":"3e309e92.011152","order":0,"width":0,"height":0,"gtype":"gage","title":"Humidity","label":"%","format":"{{value}}","min":0,"max":"100","colors":["#77bbff","#379bff","#004a95"],"seg1":"","seg2":"","x":756,"y":503,"wires":[]},{"id":"e66f84f2.860ea8","type":"inject","z":"de9b231a.1a02c","name":"On at 7PM","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"00 19 * * *","once":false,"x":195,"y":170.00000286102295,"wires":[["8ee3d13.d91eb3"]]},{"id":"3e309e92.011152","type":"ui_group","z":"","name":"Dashboard","tab":"e7a3e0ed.cd0ab","disp":true,"width":"6"},{"id":"e7a3e0ed.cd0ab","type":"ui_tab","z":"","name":"Home","icon":"dashboard"}] -------------------------------------------------------------------------------- /Code/Project_7/weather_forecast.py: -------------------------------------------------------------------------------- 1 | #Project 7 - Mini Weather Forecaster 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #import necessary libraries 6 | import time 7 | import Adafruit_SSD1306 8 | import requests 9 | 10 | from PIL import Image 11 | from PIL import ImageDraw 12 | from PIL import ImageFont 13 | 14 | #Raspberry Pi pin configuration 15 | RST = 24 16 | 17 | #128x32 display with hardware I2C 18 | #disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST) 19 | 20 | #128x64 display with hardware I2C 21 | disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST) 22 | 23 | #set your unique OpenWeatherMap.org URL 24 | open_weather_map_url = 'http://api.openweathermap.org/data/2.5/weather?q=Porto,PT&APPID=801d2603e9f2e1c70e042e4f5f6e0381' 25 | 26 | #initialize display 27 | disp.begin() 28 | 29 | while True: 30 | #clear display 31 | disp.clear() 32 | disp.display() 33 | 34 | #create blank image for drawing 35 | #make sure to create image with mode '1' for 1-bit color 36 | width = disp.width 37 | height = disp.height 38 | image = Image.new('1', (width, height)) 39 | 40 | #get drawing object to draw on image 41 | draw = ImageDraw.Draw(image) 42 | 43 | #draw a black filled box to clear the image 44 | draw.rectangle((0,0,width,height), outline=0, fill=0) 45 | 46 | #define constants to define drawing area 47 | padding = 2 48 | top = padding 49 | #move left to right keeping track of the current x position for drawing text 50 | x = padding 51 | 52 | #load default font 53 | font = ImageFont.load_default() 54 | 55 | #OpenWeatherMap.org weather data request 56 | weather_data = requests.get(open_weather_map_url) 57 | 58 | #display location 59 | location = weather_data.json().get('name') + ' - ' + weather_data.json().get('sys').get('country') 60 | draw.text((x, top), location, font=font, fill=255) 61 | 62 | #display description 63 | description = 'Desc ' + weather_data.json().get('weather')[0].get('main') 64 | draw.text((x, top+10), description, font=font, fill=255) 65 | 66 | #temperature 67 | raw_temperature = weather_data.json().get('main').get('temp')-273.15 68 | 69 | #temperature in Celsius 70 | temperature = 'Temp ' + str(raw_temperature) + '*C' 71 | #uncomment for temperature in Fahrenheit 72 | #temperature = 'Temp ' + str(raw_temperature*(9/5.0)+32) + '*F' 73 | draw.text((x, top+20), temperature, font=font, fill=255) 74 | 75 | #display pressure 76 | pressure = 'Pres ' + str(weather_data.json().get('main').get('pressure')) + 'hPa' 77 | draw.text((x, top+30), pressure, font=font, fill=255) 78 | 79 | #displays humidity 80 | humidity = 'Humi ' + str(weather_data.json().get('main').get('humidity')) + '%' 81 | draw.text((x, top+40), humidity, font=font, fill=255) 82 | 83 | #displays wind 84 | wind = 'Wind ' + str(weather_data.json().get('wind').get('speed')) + 'mps ' + str(weather_data.json().get('wind').get('deg')) + '*' 85 | draw.text((x, top+50), wind, font=font, fill=255) 86 | 87 | #display image 88 | disp.image(image) 89 | disp.display() 90 | time.sleep(10) 91 | -------------------------------------------------------------------------------- /Code/Project_14/surveillance_system.py: -------------------------------------------------------------------------------- 1 | #Project 14 - Home Surveillance Camera 2 | #latest code updates available at: https://github.com/RuiSantosdotme/RaspberryPiProject 3 | #project updates at: https://nostarch.com/RaspberryPiProject 4 | 5 | #based on the Web Streaming example at: http://picamera.readthedocs.io/en/latest/recipes2.html 6 | 7 | import io 8 | import picamera 9 | import logging 10 | import socketserver 11 | from threading import Condition 12 | from http import server 13 | 14 | PAGE="""\ 15 | 16 | 17 | Raspberry Pi - Surveillance Camera 18 | 19 | 20 |

Raspberry Pi - Surveillance Camera

21 |
22 | 23 | 24 | """ 25 | 26 | class StreamingOutput(object): 27 | def __init__(self): 28 | self.frame = None 29 | self.buffer = io.BytesIO() 30 | self.condition = Condition() 31 | 32 | def write(self, buf): 33 | if buf.startswith(b'\xff\xd8'): 34 | #new frame, copy the existing buffer's content and notify all 35 | #clients it's available 36 | self.buffer.truncate() 37 | with self.condition: 38 | self.frame = self.buffer.getvalue() 39 | self.condition.notify_all() 40 | self.buffer.seek(0) 41 | return self.buffer.write(buf) 42 | 43 | class StreamingHandler(server.BaseHTTPRequestHandler): 44 | def do_GET(self): 45 | if self.path == '/': 46 | self.send_response(301) 47 | self.send_header('Location', '/index.html') 48 | self.end_headers() 49 | elif self.path == '/index.html': 50 | content = PAGE.encode('utf-8') 51 | self.send_response(200) 52 | self.send_header('Content-Type', 'text/html') 53 | self.send_header('Content-Length', len(content)) 54 | self.end_headers() 55 | self.wfile.write(content) 56 | elif self.path == '/stream.mjpg': 57 | self.send_response(200) 58 | self.send_header('Age', 0) 59 | self.send_header('Cache-Control', 'no-cache, private') 60 | self.send_header('Pragma', 'no-cache') 61 | self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME') 62 | self.end_headers() 63 | try: 64 | while True: 65 | with output.condition: 66 | output.condition.wait() 67 | frame = output.frame 68 | self.wfile.write(b'--FRAME\r\n') 69 | self.send_header('Content-Type', 'image/jpeg') 70 | self.send_header('Content-Length', len(frame)) 71 | self.end_headers() 72 | self.wfile.write(frame) 73 | self.wfile.write(b'\r\n') 74 | except Exception as e: 75 | logging.warning( 76 | 'Removed streaming client %s: %s', 77 | self.client_address, str(e)) 78 | else: 79 | self.send_error(404) 80 | self.end_headers() 81 | 82 | class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer): 83 | allow_reuse_address = True 84 | daemon_threads = True 85 | 86 | with picamera.PiCamera(resolution='640x480', framerate=24) as camera: 87 | output = StreamingOutput() 88 | camera.start_recording(output, format='mjpeg') 89 | try: 90 | address = ('', 8000) 91 | server = StreamingServer(address, StreamingHandler) 92 | server.serve_forever() 93 | finally: 94 | camera.stop_recording() 95 | -------------------------------------------------------------------------------- /Code/Project_20/Project_20_import_Node-RED_flow.txt: -------------------------------------------------------------------------------- 1 | [{"id":"d65fe56.5b89418","type":"rpi-gpio out","z":"40001313.40791c","name":"Enable M1","pin":"29","set":"","level":"0","out":"out","x":878,"y":250,"wires":[]},{"id":"dbe323a8.78b4a","type":"rpi-gpio out","z":"40001313.40791c","name":"+ M1","pin":"13","set":"","level":"0","out":"out","x":856,"y":306,"wires":[]},{"id":"d335f3ef.2c8e4","type":"rpi-gpio out","z":"40001313.40791c","name":"- M1","pin":"18","set":"","level":"0","out":"out","x":858,"y":362,"wires":[]},{"id":"efbee7a8.8f9a28","type":"rpi-gpio out","z":"40001313.40791c","name":"Enable M2","pin":"11","set":"","level":"0","out":"out","x":877,"y":416,"wires":[]},{"id":"d12fe690.212908","type":"rpi-gpio out","z":"40001313.40791c","name":"+ M2","pin":"31","set":"","level":"0","out":"out","x":860,"y":463,"wires":[]},{"id":"6678d732.e82658","type":"rpi-gpio out","z":"40001313.40791c","name":"- M2","pin":"15","set":"","level":"0","out":"out","x":860,"y":517,"wires":[]},{"id":"adebbe34.43c2a","type":"ui_button","z":"40001313.40791c","name":"","group":"952ae9f1.7370e8","order":0,"width":0,"height":0,"passthru":false,"label":"Forward","color":"","bgcolor":"","icon":"fa-arrow-up","payload":"forward","payloadType":"str","topic":"","x":439,"y":293,"wires":[["80992854.6ad3c8"]]},{"id":"459cd803.a21468","type":"ui_button","z":"40001313.40791c","name":"","group":"952ae9f1.7370e8","order":0,"width":0,"height":0,"passthru":false,"label":"Left","color":"","bgcolor":"","icon":"fa-arrow-left","payload":"left","payloadType":"str","topic":"","x":430,"y":335,"wires":[["80992854.6ad3c8"]]},{"id":"f476aa35.e14b78","type":"ui_button","z":"40001313.40791c","name":"","group":"952ae9f1.7370e8","order":0,"width":0,"height":0,"passthru":false,"label":"Right","color":"","bgcolor":"","icon":"fa-arrow-right","payload":"right","payloadType":"str","topic":"","x":431,"y":378,"wires":[["80992854.6ad3c8"]]},{"id":"54f9b8c3.103248","type":"ui_button","z":"40001313.40791c","name":"","group":"952ae9f1.7370e8","order":0,"width":0,"height":0,"passthru":false,"label":"Reverse","color":"","bgcolor":"","icon":"fa-arrow-down","payload":"reverse","payloadType":"str","topic":"","x":439,"y":420,"wires":[["80992854.6ad3c8"]]},{"id":"f2acf720.9e3e88","type":"ui_button","z":"40001313.40791c","name":"","group":"952ae9f1.7370e8","order":0,"width":0,"height":0,"passthru":false,"label":"Stop","color":"","bgcolor":"","icon":"fa-hand-paper-o","payload":"stop","payloadType":"str","topic":"","x":431,"y":460,"wires":[["80992854.6ad3c8"]]},{"id":"80992854.6ad3c8","type":"function","z":"40001313.40791c","name":"","func":"var msg1 = { payload: 0 }; \nvar msg2 = { payload: 0 };\nvar msg3 = { payload: 0 }; \nvar msg4 = { payload: 0 }; \nvar msg5 = { payload: 0 }; \nvar msg6 = { payload: 0 };\nif (msg.payload === \"forward\") {\n msg1.payload = 1;\n msg2.payload = 1;\n msg4.payload = 1;\n msg5.payload = 1;\n}\nelse if (msg.payload === \"left\") {\n msg1.payload = 1;\n msg2.payload = 1;\n}\nelse if (msg.payload === \"right\") {\n msg4.payload = 1;\n msg5.payload = 1;\n}\nelse if (msg.payload === \"reverse\") {\n msg1.payload = 1;\n msg3.payload = 1;\n msg4.payload = 1;\n msg6.payload = 1;\n}\nreturn [msg1, msg2, msg3, msg4, msg5, msg6];","outputs":"6","noerr":0,"x":655,"y":370,"wires":[["d65fe56.5b89418"],["dbe323a8.78b4a"],["d335f3ef.2c8e4"],["efbee7a8.8f9a28"],["d12fe690.212908"],["6678d732.e82658"]]},{"id":"85135e7f.81d54","type":"ui_button","z":"40001313.40791c","name":"Poweroff","group":"979642d9.eabbd","order":0,"width":0,"height":0,"passthru":false,"label":"Poweroff","color":"","bgcolor":"red","icon":"fa-power-off","payload":"","payloadType":"str","topic":"","x":458,"y":605,"wires":[["ce2080f1.1c3b9"]]},{"id":"ce2080f1.1c3b9","type":"exec","z":"40001313.40791c","command":"/usr/bin/sudo","addpay":false,"append":"poweroff","useSpawn":"","timer":"","name":"Poweroff","x":642,"y":604.5,"wires":[[],[],[]]},{"id":"952ae9f1.7370e8","type":"ui_group","z":"","name":"Main","tab":"53e02181.cf324","disp":true,"width":"6"},{"id":"979642d9.eabbd","type":"ui_group","z":"","name":"Poweroff","tab":"53e02181.cf324","order":2,"disp":true,"width":"6"},{"id":"53e02181.cf324","type":"ui_tab","z":"","name":"Robot","icon":"dashboard"}] --------------------------------------------------------------------------------