├── 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"}]
--------------------------------------------------------------------------------