To get you started with how to program your Pico in CircuitPython, especially for those who may have started out with the official MicroPython setup, we've 'ported' the Getting Started with MicroPython on Pico book examples to CircuitPython. The book is awesome, please download/purchase it to support Raspberry Pi Press!
Another common use of microcontrollers is in alarm systems, including home security systems. While they can get complex with a significant number of sensors, a basic motion sensing alarm is quite easy to build with a microcontroller and a few components.
This section will show you how to use your Raspberry Pi Pico board to build a basic motion sensor, and then turn it into a burglar alarm by adding lights and sound.

The first step is to connect the PIR sensor to your board. Wire them up as shown below. If your PIR sensor comes with a cable, you can connect the cable and push the ends of the wires directly into the breadboard. If your PIR sensor does not have a cable, use male-to-female jumper wires to connect from the header on the sensor to the breadboard.
Programming the Basic Motion Sensor
Now that you've wired up your motion sensor, you can begin programming it.
Update your code.py to the following and save.
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries # # SPDX-License-Identifier: MIT """ Simple motion sensor example for Pico. Prints to serial console when PIR sensor is triggered. REQUIRED HARDWARE: * PIR sensor on pin GP28. """ import board import digitalio pir = digitalio.DigitalInOut(board.GP28) pir.direction = digitalio.Direction.INPUT while True: if pir.value: print("ALARM! Motion detected!") while pir.value: pass
Now open the serial console and wave your hand in front of the sensor. Motion detected!
If you sit still and wait a bit before waving your hand in front of the sensor, you'll see ALARM! Motion detected!
printed to the serial console again. However, you'll notice that if you keep waving your hand in front of the sensor, it takes a while for it to print another message. There is no delay in the code, so what's causing this behavior? The PIR sensor has a delay built in. The sensor sends a signal to your Pico board's GPIO pin when motion is detected, and maintains that signal for a period of time before stopping it. Until the signal stops, it cannot detect further motion, and therefore cannot trigger your motion detection code. Many PIR sensors have a potentiometer on them you can use to adjust the length of this delay, though there is always a minimum delay. Here is a detailed explanation.
Now, a more detailed look at the code. First import the two necessary modules.
import board import digitalio
Next, you set up the PIR sensor using digitalio
. You create the object, provide it a pin, and set the pin direction to input.
pir = digitalio.DigitalInOut(board.GP28) pir.direction = digitalio.Direction.INPUT
pir.value
returns True
when there is motion detected, and False
when no motion is detected. Inside your loop, you check whether pir.value
is True
. If it is, you print ALARM! Motion detected!
. Then there is a second loop checking pir.value
, which runs continuously as long as the condition is True
, which is a way to say "wait until pir.value
is False
" and then move on. When you have a loop inside of another loop, they are referred to as nested loops.
while True: if pir.value: print("ALARM! Motion detected!") while pir.value: pass
This code sequence helps the code only react to the initial change in signal from the PIR sensor, instead of reporting motion detected for the entire time the signal is sent. It means ALARM! Motion detected!
is only printed once instead of being spammed to the serial console for the entire duration of the signal event.
Printing to the serial console is enough to test that your PIR sensor is working, but it doesn't amount to a useful alarm. Actual burglar alarms have lights and sirens that notify everyone within range that something is wrong. With a few more components, you can add the same functionality to your setup.
Burglar Alarm
Alarms are only useful if they have some way to notify you that they have been triggered. A blinking LED is a simple way to see when the motion sensor has been triggered. So, the first thing you'll do is add an LED to your motion sensing setup.
Wiring the Burglar Alarm with Light
This example builds on the previous. For this example, you'll need your current wiring setup, an LED of any color, a resistor, and a number of male-to-male jumper wires. A 220Ω-1.0KΩ resistor will work; a 220Ω resistor is shown in the diagram.
Connect the LED to your current setup as shown below. You'll need to modify your current setup slightly by moving the PIR sensor GND. PIR signal and power do not need to be moved.
- Board GND to breadboard ground rail (using a jumper wire)
- Board GP13 to 220Ω resistor
- LED+ to 220Ω resistor
- LED- to breadboard ground rail (using a jumper wire)
- PIR sensor GND to breadboard ground rail (using a jumper wire)
Programming the Burglar Alarm with Light
Now that you've wired up your burglar alarm with light, it's time to program it.
Update your code.py to the following and save.
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries # # SPDX-License-Identifier: MIT """ A burglar alarm example for Pico. Quick flashing LED indicates alarm has been triggered. REQUIRED HARDWARE: * PIR sensor on pin GP28. * LED on pin GP13. """ import time import board import digitalio pir = digitalio.DigitalInOut(board.GP28) pir.direction = digitalio.Direction.INPUT led = digitalio.DigitalInOut(board.GP13) led.direction = digitalio.Direction.OUTPUT motion_detected = False while True: if pir.value and not motion_detected: print("ALARM! Motion detected!") motion_detected = True if pir.value: led.value = True time.sleep(0.1) led.value = False time.sleep(0.1) motion_detected = pir.value
Now when you save your hand in front of the sensor, as well as printing the message to the serial console, the LED will blink quickly to let you know motion has been detected! Once the sensor signal stops, the LED will stop blinking.
Now, a more detailed look at the code. First you import the same modules as before, but now you include time
as well.
import time import board import digitalio
Then, in addition to the PIR sensor setup, you set up the LED.
pir = digitalio.DigitalInOut(board.GP28) pir.direction = digitalio.Direction.INPUT led = digitalio.DigitalInOut(board.GP13) led.direction = digitalio.Direction.OUTPUT
You create a variable called motion_detected
and set it to False
before the loop.
motion_detected = False
Inside the loop, you first check to see if pir.value
is True
AND motion_detected
is False
. If BOTH of these conditions are valid, you print ALARM! Motion detected!
to the serial console and set motion_detected
to True
. Next, you check if pir.value
is True
, and if so, you blink the LED on and off every 0.1 seconds. Finally, you set motion_detected
equal to pir.value
. This resets motion_detected
to False
once motion is no longer detected, and allows for motion to be detected again.
while True: if pir.value and not motion_detected: print("ALARM! Motion detected!") motion_detected = True if pir.value: led.value = True time.sleep(0.1) led.value = False time.sleep(0.1) motion_detected = pir.value
To make your alarm even more effective, you could warn intruders that the alarm is active by making the LED flash slowly when there is no motion detected. To do this, simply replace the last line of the example with an else
block that includes code similar to the if pir.value:
block, except with a longer time.sleep()
.
[...] else: motion_detected = False led.value = True time.sleep(0.5) led.value = False time.sleep(0.5)
With the above update, your code.py file should look like the following.
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries # # SPDX-License-Identifier: MIT """ A burglar alarm example for Pico. Slow flashing LED indicates alarm is ready. Quick flashing LED indicates alarm has been triggered. REQUIRED HARDWARE: * PIR sensor on pin GP28. * LED on pin GP13. """ import time import board import digitalio pir = digitalio.DigitalInOut(board.GP28) pir.direction = digitalio.Direction.INPUT led = digitalio.DigitalInOut(board.GP13) led.direction = digitalio.Direction.OUTPUT motion_detected = False while True: if pir.value and not motion_detected: print("ALARM! Motion detected!") motion_detected = True if pir.value: led.value = True time.sleep(0.1) led.value = False time.sleep(0.1) else: motion_detected = False led.value = True time.sleep(0.5) led.value = False time.sleep(0.5)
Your alarm system notifies everyone visually that it's running and lets you know when motion is detected. Now it needs sound!
Wiring the Burglar Alarm with Light and Sound
This example builds on the previous. For this example, you'll need your current wiring setup, and a piezo buzzer.
Connect the piezo buzzer to your current setup as shown below. Direction for the piezo buzzer does not matter.
Programming the Burglar Alarm with Light and Sound
Now that you've wired up your burglar alarm with light and sound, it's time to program it.
Update your code.py to the following and save.
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries # # SPDX-License-Identifier: MIT """ A burglar alarm example for Pico. Slow flashing LED indicates alarm is ready. Quick flashing LED and beeping buzzer indicate alarm has been triggered. REQUIRED HARDWARE: * PIR sensor on pin GP28. * LED on pin GP13. * Piezo buzzer on pin GP14. """ import time import board import digitalio import pwmio pir = digitalio.DigitalInOut(board.GP28) pir.direction = digitalio.Direction.INPUT led = digitalio.DigitalInOut(board.GP13) led.direction = digitalio.Direction.OUTPUT buzzer = pwmio.PWMOut(board.GP14, frequency=660, duty_cycle=0, variable_frequency=True) motion_detected = False while True: if pir.value and not motion_detected: print("ALARM! Motion detected!") motion_detected = True if pir.value: led.value = True buzzer.duty_cycle = 2 ** 15 time.sleep(0.1) led.value = False buzzer.duty_cycle = 0 time.sleep(0.1) else: motion_detected = False led.value = True time.sleep(0.5) led.value = False time.sleep(0.5)
Now wave your hand in front of the sensor. Motion detected, the LED blinks rapidly, and now it beeps along with the blinking for an auditory indicator that it's been triggered!
This code will look very similar to the previous example with a few modifications. First you import the necessary modules, this time including pwmio
.
import time import board import digitalio import pwmio
Next, in addition to the PIR sensor and LED setup, you set up the piezo buzzer.
pir = digitalio.DigitalInOut(board.GP28) pir.direction = digitalio.Direction.INPUT led = digitalio.DigitalInOut(board.GP13) led.direction = digitalio.Direction.OUTPUT buzzer = pwmio.PWMOut(board.GP14, frequency=660, duty_cycle=0, variable_frequency=True)
Finally, you add two lines of code into the if block of the loop to turn the buzzer on and off along with the LED.
while True: if pir.value and not motion_detected: print("ALARM! Motion detected!") motion_detected = True if pir.value: led.value = True buzzer.duty_cycle = 2 ** 15 time.sleep(0.1) led.value = False buzzer.duty_cycle = 0 time.sleep(0.1)
The rest of the loop remains the same. That's all there is to creating a burglar alarm with light and sound!
Home security systems rarely cover only one room or area. They are often made up of a network of many sensors connected to a single alarm system. You can easily add more sensors to your setup to monitor multiple areas at the same time.
Wiring the Extended Burglar Alarm with Light and Sound
For this example, you'll need your current wiring setup and a second PIR sensor.
Connect the second PIR sensor as shown below. Since the VBUS connection is already being used by the first PIR sensor, you'll need to make a slight modification. Move both the Pico board's VBUS connection to the breadboard power rail, and the 5V pin on the first PIR sensor to the breadboard power rail.
- Board VBUS to breadboard power rail
- First PIR sensor 5V to breadboard power rail
- Second PIR sensor GND to breadboard ground rail
-
Second PIR sensor 5V to breadboard power rail
- Board GP22 to second PIR sensor data pin
Programming the Extended Burglar Alarm
Now that you've added another sensor to your setup, it's time to program it.
Update your code.py to the following, and save.
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries # # SPDX-License-Identifier: MIT """ A burglar alarm with two motion sensors example for Pico. Slow flashing LED indicates alarm is ready. Quick flashing LED and beeping buzzer indicate alarm has been triggered. REQUIRED HARDWARE: * PIR sensor on pin GP28. * PIR sensor on pin GP22. * LED on pin GP13. * Piezo buzzer on pin GP14. """ import time import board import digitalio import pwmio pir_one = digitalio.DigitalInOut(board.GP28) pir_one.direction = digitalio.Direction.INPUT pir_two = digitalio.DigitalInOut(board.GP22) pir_two.direction = digitalio.Direction.INPUT led = digitalio.DigitalInOut(board.GP13) led.direction = digitalio.Direction.OUTPUT buzzer = pwmio.PWMOut(board.GP14, frequency=660, duty_cycle=0, variable_frequency=True) motion_detected_one = False motion_detected_two = False while True: if pir_one.value and not motion_detected_one: print("ALARM! Motion detected in bedroom!") motion_detected_one = True if pir_two.value and not motion_detected_two: print("ALARM! Motion detected in living room!") motion_detected_two = True if pir_one.value or pir_two.value: led.value = True buzzer.duty_cycle = 2 ** 15 time.sleep(0.1) led.value = False buzzer.duty_cycle = 0 time.sleep(0.1) else: motion_detected_one = False motion_detected_two = False led.value = True time.sleep(0.5) led.value = False time.sleep(0.5)
Wave your hand over the first sensor to see motion reported in the bedroom. Wave your hand over the second sensor to see motion reported in the living room. Multi-area coverage!
Now a look at the code. The code will look very similar, but a number of modifications are needed to make it both work properly and be easily understood. Imports remain the same.
Setup now includes two PIR sensors, so it makes sense to update the variable names to indicate the presence of two sensors. Below the first PIR sensor, include another two lines of setup for the second one, with the appropriate pins. LED and buzzer setup remain the same.
pir_one = digitalio.DigitalInOut(board.GP28) pir_one.direction = digitalio.Direction.INPUT pir_two = digitalio.DigitalInOut(board.GP22) pir_two.direction = digitalio.Direction.INPUT
Before the loop, you create two variables to track whether motion has been detected, and set them to False
initially.
motion_detected_one = False motion_detected_two = False
The loop begins with two if blocks. They each check a sensor value and the respective motion detected variable. If the sensor value is returning True
and the motion_detected
variable is False
, then it prints the appropriate ALARM!
message to the serial console and sets the respective motion_detected
variable to True
.
while True: if pir_one.value and not motion_detected_one: print("ALARM! Motion detected in bedroom!") motion_detected_one = True if pir_two.value and not motion_detected_two: print("ALARM! +Motion detected in living room!") motion_detected_two = True
Then, the code checks whether the sensors are returning True, and if they are blink the LED and beep the buzzer on and off every 0.1 seconds.
[...] if pir_one.value or pir_two.value: led.value = True buzzer.duty_cycle = 2 ** 15 time.sleep(0.1) led.value = False buzzer.duty_cycle = 0 time.sleep(0.1)
Finally, once motion is no longer detected, the motion_detected variables are set to False, and the LED blinks on and off more slowly, every 0,.5 seconds.
[...] else: motion_detected_one = False motion_detected_two = False led.value = True time.sleep(0.5) led.value = False time.sleep(0.5)
Now you know how to extend your alarm system to cover more than one area. You can add more sensors as needed!
Page last edited January 22, 2025
Text editor powered by tinymce.