{"id":177129,"date":"2025-10-16T14:37:12","date_gmt":"2025-10-16T14:37:12","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=177129"},"modified":"2025-10-16T14:59:28","modified_gmt":"2025-10-16T14:59:28","slug":"ble-raspberry-pi-and-pi-pico-w","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/ble-raspberry-pi-and-pi-pico-w\/","title":{"rendered":"BLE Communication between Raspberry Pi and Raspberry Pi Pico W"},"content":{"rendered":"\n<p>This tutorial explains how to set up Bluetooth Low Energy (BLE) communication between a Raspberry Pi and a Pico W. We\u2019ll start by covering the basics of BLE, including the roles of Central and Peripheral devices. After that, we\u2019ll go through two simple examples where the  Pico sends data to the Pi.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Rpi-Pico-to-RPi-Communication-Bluetooth-Low-Energy.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"BLE Communication between Raspberry Pi and Raspberry Pi Pico W\" class=\"wp-image-179872\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Rpi-Pico-to-RPi-Communication-Bluetooth-Low-Energy.jpg?w=1920&amp;quality=100&amp;strip=all&amp;ssl=1 1920w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Rpi-Pico-to-RPi-Communication-Bluetooth-Low-Energy.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Rpi-Pico-to-RPi-Communication-Bluetooth-Low-Energy.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Rpi-Pico-to-RPi-Communication-Bluetooth-Low-Energy.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Rpi-Pico-to-RPi-Communication-Bluetooth-Low-Energy.jpg?resize=1536%2C864&amp;quality=100&amp;strip=all&amp;ssl=1 1536w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclgreen\"><strong>New to the Raspberry Pi Pico?<\/strong> <a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-w-micropython-ebook\/\" title=\"\">Learn Raspberry Pi Pico\/Pico W with MicroPython\u200b with our eBook<\/a><\/p>\n\n\n\n<p class=\"rntbox rntclgray\">This tutorial was written by <a href=\"https:\/\/github.com\/sentairanger\" target=\"_blank\" rel=\"noopener\" title=\"\">Edgardo Peregrino<\/a> and edited by Sara Santos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p>Here&#8217;s a list of prerequisites for this tutorial.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1) Raspberry Pi Board<\/h3>\n\n\n\n<p>You need a <a href=\"https:\/\/makeradvisor.com\/best-raspberry-pi-starter-kits\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Raspberry Pi board<\/a> that has Bluetooth. The following models can be used: Pi 3, 3B+, 3A+, 4, 400, 5, 500, Zero W, Zero 2W, CM4 and CM5. When using the CM4 and CM5 modules, ensure that they include the WiFi\/Bluetooth module.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"400\" height=\"301\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/Raspberry-Pi-5.png?resize=400%2C301&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Raspberry Pi 5\" class=\"wp-image-177197\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/Raspberry-Pi-5.png?w=400&amp;quality=100&amp;strip=all&amp;ssl=1 400w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/Raspberry-Pi-5.png?resize=300%2C226&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/raspberry-pi-board\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Get a Raspberry Pi 5 Board<\/a><\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">1.1) Raspberry Pi OS<\/h4>\n\n\n\n<p>In terms of software, you can use either <strong>Raspberry Pi OS Desktop<\/strong> or <strong>Raspberry Pi OS Lite<\/strong>. We use the 64-bit version.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>To learn how to install the operating system, you can check this tutorial: <a href=\"https:\/\/randomnerdtutorials.com\/installing-raspbian-lite-enabling-and-connecting-with-ssh\/\">Install Raspberry Pi OS, Set Up Wi-Fi, Enable and Connect with SSH<\/a>.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">1.2) Terminal and SSH<\/h4>\n\n\n\n<p>You should also have some understanding of the terminal, especially since you&#8217;ll need to enable the Bluetooth service using the terminal and install essential packages.<\/p>\n\n\n\n<p>We&#8217;ll use <a href=\"https:\/\/www.putty.org\/\" target=\"_blank\" rel=\"noopener\" title=\"\">PuTTY software<\/a> to establish an SSH connection with the RPi board to run the commands in the terminal window.<\/p>\n\n\n\n<p>We recommend following the next tutorial if you&#8217;re not familiar with installing the Raspberry Pi OS, or establishing a connection via SSH using PuTTY:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-raspbian-lite-enabling-and-connecting-with-ssh\/\" title=\"\">Install Raspberry Pi OS, Set Up Wi-Fi, Enable and Connect with SSH<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2) Raspberry Pi Pico Board<\/h3>\n\n\n\n<p>You need a Raspberry Pi Pico board that comes with Bluetooth. You can use a Raspberry Pi Pico W or Raspberry Pi Pico 2 W.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/raspberry-pi-pico-w\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Raspberry Pi Pico W<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/raspberry-pi-pico-2-w\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Raspberry Pi Pico 2 W<\/a><\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">2.1) Thonny IDE<\/h4>\n\n\n\n<p>To program the Raspberry Pi Pico, we like to use Thonny IDE. Make sure your board is running the latest version of MicroPython firmware. We recommend taking a quick look at the following guide to check how to use Thonny IDE, how to flash MicroPython firmware, and how to run and upload code to the board:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/getting-started-raspberry-pi-pico-w\/\" title=\"\">Getting Started with Raspberry Pi Pico (and Pico W)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/getting-started-raspberry-pi-pico-2-w\/\">Getting Started with Raspberry Pi Pico 2 and Pico 2 W<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">The Basics of BLE or Bluetooth Low Energy<\/h2>\n\n\n\n<p>Before we begin, we should discuss the basics of BLE or Bluetooth Low Energy. BLE is a protocol that is different from Bluetooth Classic. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"400\" height=\"129\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/03\/Bluetooth-low-energy.png?resize=400%2C129&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Bluetooth Smart Logo\" class=\"wp-image-95092\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/03\/Bluetooth-low-energy.png?w=400&amp;quality=100&amp;strip=all&amp;ssl=1 400w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/03\/Bluetooth-low-energy.png?resize=300%2C97&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/figure><\/div>\n\n\n<p>Bluetooth Classic is designed for continuous data streaming, such as playing music on a wireless speaker. In contrast, Bluetooth Low Energy (BLE) is optimized for devices and sensors, making it suitable for the Pico W and Raspberry Pi models with built-in Bluetooth.<\/p>\n\n\n\n<p>BLE consumes significantly less power than Bluetooth Classic, making it ideal for microcontrollers and small devices, although it has a shorter range. Another key difference is how they connect: Bluetooth Classic uses Serial communication, while BLE relies on the GATT (Generic Attribute Profile) protocol.<\/p>\n\n\n\n<p class=\"rntbox rntclgray\">For a more comprehensive introduction to BLE and basic concepts such as peripheral and controller, UUIDs, GATT profiles, and more, we recommend reading the introduction section of this tutorial: <a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-w-bluetooth-low-energy-micropython\/\" title=\"\">Raspberry Pi Pico W: Bluetooth Low Energy (BLE) with MicroPython<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Project Overview<\/h3>\n\n\n\n<p>When using Bluetooth Low Energy (BLE), it\u2019s important to understand the roles of BLE Peripheral and BLE Controller (also referred to as the Central Device).<\/p>\n\n\n\n<p>In this case (in the examples covered in this guide), the <strong>Raspberry Pi will be the Central device<\/strong> and the <strong>Pico will be the Peripheral Device<\/strong>. <\/p>\n\n\n\n<p>The Pico sets up a GATT profile to allow communication with the Raspberry Pi. Once connected, it &#8220;sends&#8221; a message to the Pi, which is then displayed in the terminal. This setup can be useful for projects like using the Pico as a controller for a Raspberry Pi\u2013powered robot.<\/p>\n\n\n\n<p class=\"rntbox rntclgray\"><strong>Note:<\/strong> I\u2019m putting \u201csends\u201d in quotes because the Pico isn\u2019t actually pushing data to the Pi. Instead, the Pico writes a value to a characteristic in its GATT profile. The Raspberry Pi, which is connected to the Pico over BLE, then reads that characteristic to get the data.<\/p>\n\n\n\n<p>Below is an example of what we will be doing in this project.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1023\" height=\"1039\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Pico-to-RPi-BLE-Communication.png?resize=1023%2C1039&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Diagram showing how the Pico as a Peripheral Device communicates with the Pi as a Central BLE Device\" class=\"wp-image-177199\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Pico-to-RPi-BLE-Communication.png?w=1023&amp;quality=100&amp;strip=all&amp;ssl=1 1023w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Pico-to-RPi-BLE-Communication.png?resize=295%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 295w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Pico-to-RPi-BLE-Communication.png?resize=1008%2C1024&amp;quality=100&amp;strip=all&amp;ssl=1 1008w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Pico-to-RPi-BLE-Communication.png?resize=768%2C780&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1023px) 100vw, 1023px\" \/><\/figure><\/div>\n\n\n<ol class=\"wp-block-list\">\n<li>The BLE Peripheral (server) advertises its existence.<\/li>\n\n\n\n<li>The BLE Central Device (client) scans for BLE devices.<\/li>\n\n\n\n<li>When the central device finds the peripheral it is looking for, it connects to it.<\/li>\n\n\n\n<li>After connecting, it reads the GATT profile of the peripheral and searches for the service it is looking.<\/li>\n\n\n\n<li>If it finds the service, it can now interact with the characteristics. For example, reading the values.<\/li>\n<\/ol>\n\n\n\n<p>In BLE, every service and characteristic must have a UUID (Universally Unique Identifier). These UUIDs act as unique addresses that the Raspberry Pi uses to find and connect to the Pico\u2019s services. For example, if the Pico provides a service with read and write characteristics, each will have its own UUID. The Pi looks for these UUIDs to know how to and to communicate with them.<\/p>\n\n\n\n<p class=\"rntbox rntclgray\">For a more comprehensive introduction to BLE and basic concepts such as peripheral and controller, UUIDs, GATT profile, and more, we recommend reading the introduction section of this tutorial: <a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-w-bluetooth-low-energy-micropython\/\" title=\"\">Raspberry Pi Pico W: Bluetooth Low Energy (BLE) with MicroPython<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Parts Required<\/h2>\n\n\n\n<p>Here&#8217;s a list of the parts required for this tutorial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Raspberry Pi (we&#8217;re using a <a href=\"https:\/\/makeradvisor.com\/tools\/raspberry-pi-board\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Raspberry Pi 5<\/a>)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/raspberry-pi-pico-w\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Raspberry Pi Pico W<\/a> or <a href=\"https:\/\/makeradvisor.com\/tools\/raspberry-pi-pico-2-w\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Raspberry Pi Pico 2 W<\/a><\/li>\n\n\n\n<li>1x <a href=\"https:\/\/makeradvisor.com\/tools\/3mm-5mm-leds-kit-storage-box\/\" target=\"_blank\" rel=\"noopener\" title=\"\">LED<\/a><\/li>\n\n\n\n<li>1x <a href=\"https:\/\/makeradvisor.com\/tools\/resistors-kits\/\" target=\"_blank\" rel=\"noopener\" title=\"\">220Ohm resistor<\/a> (or similar value)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Breadboard<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Jumper wires<\/a><\/li>\n<\/ul>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preparing the Raspberry Pi<\/h2>\n\n\n\n<p>After starting with a fresh installation of Raspberry Pi OS on your RPi board, you need to follow the next instructions to enable Bluetooth on the Pi and install some essential packages.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Enabling Bluetooth on the Pi<\/h3>\n\n\n\n<p>If you are using the desktop version of Pi OS, it&#8217;s very easy to turn on Bluetooth. Go to the Bluetooth icon and click on <em>Make Discoverable.<\/em> And that&#8217;s it<em>,<\/em> you&#8217;re ready to go. <\/p>\n\n\n\n<p>If you&#8217;re using the Lite version or if you&#8217;re in an SSH session, we will use commands to enable Bluetooth. Establish an SSH connection with your Pi.<\/p>\n\n\n\n<p>Type the following command:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo systemctl start bluetooth<\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"661\" height=\"418\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Enable-Bluetooth.png?resize=661%2C418&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Raspberry Pi Enable Bluetooth on Terminal Window\" class=\"wp-image-177135\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Enable-Bluetooth.png?w=661&amp;quality=100&amp;strip=all&amp;ssl=1 661w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Enable-Bluetooth.png?resize=300%2C190&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 661px) 100vw, 661px\" \/><\/figure><\/div>\n\n\n<p>After that, run the following commands in order:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo bluetoothctl<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">agent on<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">default-agent<\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"661\" height=\"418\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/Rpi-Enable-Bluetooth-Completed.png?resize=661%2C418&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Enabling Bluetooth on RPi Completed\" class=\"wp-image-177136\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/Rpi-Enable-Bluetooth-Completed.png?w=661&amp;quality=100&amp;strip=all&amp;ssl=1 661w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/Rpi-Enable-Bluetooth-Completed.png?resize=300%2C190&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 661px) 100vw, 661px\" \/><\/figure><\/div>\n\n\n<p>These commands are needed to enable Bluetooth. Once it&#8217;s done, you can exit by typing <span class=\"rnthl rntliteral\">exit<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">exit<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Installing pipgio<\/h3>\n\n\n\n<p>Since we&#8217;ll also be controlling the Pi&#8217;s GPIOs, we need a package to control them. We&#8217;ll use <span class=\"rnthl rntliteral\">pigpio<\/span>. Run the following commands to install it globally and enable it on boot.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo apt install pigpio<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo systemctl enable pigpiod<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating a Virtual Environment<\/h3>\n\n\n\n<p>We&#8217;ll create a virtual environment that uses the system-wide packages like the <span class=\"rnthl rntliteral\">pigpio<\/span> (I&#8217;m doing it this way instead of installing it inside the virtual environment because I found some issues with controlling the GPIOs this way when using a Raspberry Pi 5).<\/p>\n\n\n\n<p>First, we recommend creating a dedicated directory so you can keep your files organized. If you&#8217;re using the Desktop, ideally, you should go into the <em>Documents <\/em>directory and create a directory in there. For example, you can call it <span class=\"rnthl rntliteral\"><strong>bluetooth_samples<\/strong><\/span>.<\/p>\n\n\n\n<p>If you&#8217;re on the Lite version, you can create a directory called <span class=\"rnthl rntliteral\">bluetooth_samples<\/span> and then enter the directory like so:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">mkdir bluetooth_samples &amp;&amp; cd bluetooth_samples<\/pre>\n\n\n\n<p>Now, you should be in the <span class=\"rnthl rntliteral\"><strong>bluetooth_samples<\/strong><\/span> folder.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"645\" height=\"418\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/creating-bluetooth-samples-directory-RPi.jpg?resize=645%2C418&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Creating and moving to the bluetooth_samples folder on a Raspberry Pi\" class=\"wp-image-177137\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/creating-bluetooth-samples-directory-RPi.jpg?w=645&amp;quality=100&amp;strip=all&amp;ssl=1 645w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/creating-bluetooth-samples-directory-RPi.jpg?resize=300%2C194&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 645px) 100vw, 645px\" \/><\/figure><\/div>\n\n\n<p>Now, create a virtual environment called <span class=\"rnthl rntliteral\"><strong>blue<\/strong><\/span> in that directory.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">python3 -m venv blue --system-site-packages <\/pre>\n\n\n\n<p>Activate the virtual environment like so:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">source blue\/bin\/activate<\/pre>\n\n\n\n<p>You know it&#8217;s active because the name of the virtual environment will show up before the prompt.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"629\" height=\"340\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-virtual-environment-active.jpg?resize=629%2C340&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Raspberry Pi Virtual Environment Active\" class=\"wp-image-177138\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-virtual-environment-active.jpg?w=629&amp;quality=100&amp;strip=all&amp;ssl=1 629w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-virtual-environment-active.jpg?resize=300%2C162&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 629px) 100vw, 629px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Installing Bleak<\/h3>\n\n\n\n<p>For the Raspberry Pi, we will need to install a BLE library that will communicate with the Pico, which is called <a href=\"https:\/\/github.com\/hbldh\/bleak\" target=\"_blank\" rel=\"noopener\" title=\"\">Bleak<\/a>. Install the library in the virtual environment:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pip install bleak<\/pre>\n\n\n\n<p>It should be installed after a few seconds.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"669\" height=\"370\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/Installing-Bleak-Raspberry-Pi-Terminal-Window.png?resize=669%2C370&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Installing Bleak on a Raspberry Pi - Terminal Window\" class=\"wp-image-177140\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/Installing-Bleak-Raspberry-Pi-Terminal-Window.png?w=669&amp;quality=100&amp;strip=all&amp;ssl=1 669w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/Installing-Bleak-Raspberry-Pi-Terminal-Window.png?resize=300%2C166&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 669px) 100vw, 669px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Raspberry Pi Wiring Diagram<\/h3>\n\n\n\n<p>In the case of the Raspberry Pi, our example will need an LED connected to GPIO 17. You can follow the next schematic diagram.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"736\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-connected-to-LED-RPi-Pico-BLE.jpg?resize=1024%2C736&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"BLE Communication between RPi and RPi Pico\" class=\"wp-image-177202\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-connected-to-LED-RPi-Pico-BLE.jpg?resize=1024%2C736&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-connected-to-LED-RPi-Pico-BLE.jpg?resize=300%2C216&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-connected-to-LED-RPi-Pico-BLE.jpg?resize=768%2C552&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-connected-to-LED-RPi-Pico-BLE.jpg?w=1200&amp;quality=100&amp;strip=all&amp;ssl=1 1200w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<p>Here, we&#8217;re connecting the longer leg of the LED to GPIO pin 17 and this will be our LED to test if the code is working properly. The shorter lead of the LED will connect to the resistor, and we will connect the ground wire to the negative rail of the breadboard where the resistor is placed.<\/p>\n\n\n\n<p>The Pico will be mounted on the breadboard just for practical reasons, and that will be it for the wiring. If you prefer, you don&#8217;t need to mount the Pico on the breadboard.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sending a Basic message from the Pico to Pi<\/h2>\n\n\n\n<p>In this section, we&#8217;ll show you a simple MicroPython code that will be used on the Pico to &#8220;send&#8221; messages to the Raspberry Pi.<\/p>\n\n\n\n<p>You can call it <span class=\"rnthl rntliteral\">ble_sample.py<\/span>. Later, you can upload it to the Pico as <span class=\"rnthl rntliteral\">main.py<\/span> so that it runs without being connected to the computer.<\/p>\n\n\n\n<p class=\"rntbox rntclgreen\"><strong>New to BLE with the Raspberry Pi Pico? <\/strong>You can read our getting started guide: <a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-w-bluetooth-low-energy-micropython\/\">Raspberry Pi Pico W: Bluetooth Low Energy (BLE) with MicroPython<\/a>.<\/p>\n\n\n\n<p>Copy the following code to Thonny IDE.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\r\n# Complete project details at https:\/\/RandomNerdTutorials.com\/ble-raspberry-pi-and-pi-pico-w\/\r\n\r\nimport asyncio\r\nimport aioble\r\nimport bluetooth\r\nfrom machine import Pin\r\n\r\n# Bluetooth configuration\r\n_SERVICE_UUID = bluetooth.UUID(0x1848)\r\n_WRITE_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6E) # Central writes here\r\n_READ_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6F)  # Peripheral writes message here\r\n\r\nBLE_NAME = &quot;Pico W Peripheral&quot;\r\n\r\n# Initialize LED\r\nled = Pin(&quot;LED&quot;, Pin.OUT)\r\n\r\nconnected = False\r\n\r\n# Register GATT server\r\nble_service = aioble.Service(_SERVICE_UUID)\r\nread_characteristic = aioble.Characteristic(\r\n    ble_service, _READ_CHARACTERISTIC_UUID, read=True, notify=True\r\n)\r\naioble.register_services(ble_service)\r\n\r\n# Helper to encode the message\r\ndef _encode_message(message):\r\n    return message.encode('utf-8')\r\n\r\n# Task to handle LED blinking and message sending\r\nasync def send_task():\r\n    global connected\r\n    message_count = 1\r\n    while True:\r\n        led.toggle()\r\n        blink = 1000 if connected else 250\r\n        if connected:\r\n            message = f&quot;Hello from {BLE_NAME}! Count: {message_count}&quot;\r\n            read_characteristic.write(_encode_message(message), send_update=True)\r\n            message_count += 1\r\n            print(f&quot;Sent: {message}&quot;)\r\n        await asyncio.sleep_ms(blink)\r\n\r\n# Serially wait for connections\r\nasync def peripheral_task():\r\n    global connected\r\n    # Show MAC address once at start\r\n    ble = bluetooth.BLE()\r\n    _, mac_address = ble.config('mac')\r\n    formatted_mac = ':'.join('{:02X}'.format(b) for b in mac_address)\r\n    print(f&quot;Bluetooth MAC Address: {formatted_mac}&quot;)\r\n    \r\n    while True:\r\n        try:\r\n            async with await aioble.advertise(\r\n                2000, name=BLE_NAME, services=[_SERVICE_UUID], appearance=768\r\n            ) as connection:\r\n                connected = True\r\n                print(&quot;Connection from&quot;, connection.device)\r\n                await connection.disconnected()\r\n        except Exception as e:\r\n            print(&quot;Error in peripheral_task:&quot;, e)\r\n        finally:\r\n            connected = False\r\n            print(f&quot;{BLE_NAME} disconnected&quot;)\r\n            await asyncio.sleep_ms(100)\r\n\r\n# Run both tasks\r\nasync def main():\r\n    t1 = asyncio.create_task(send_task())\r\n    t2 = asyncio.create_task(peripheral_task())\r\n    await asyncio.gather(t1, t2)\r\n\r\n# Run the program\r\nasyncio.run(main())<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/Raspberry-Pi\/RPi_to_RPi_Pico\/ble_sample.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>Let\u2019s break down this code to get a better understanding. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Importing Libraries<\/h4>\n\n\n\n<p>First we import the libraries as shown below.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>import asyncio\nimport aioble\nimport bluetooth\nfrom machine import Pin<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Defining UUIDs<\/h4>\n\n\n\n<p>Next, we need to define our UUIDs for the Pico. We need UUIDs for the service, <em>write <\/em>and <em>read <\/em>characteristics.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Bluetooth configuration\n_SERVICE_UUID = bluetooth.UUID(0x1848)\n_WRITE_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6E) # Central writes here\n_READ_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6F)  # Peripheral writes message here<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">BLE Name<\/h4>\n\n\n\n<p>We define the name for our Raspberry Pi Pico BLE device. You can call it any other name.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>BLE_NAME = \"Pico W Peripheral\"<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Initializing the LED<\/h4>\n\n\n\n<p>The next line initializes the RPi Pico built-in LED as a GPIO output with the name <span class=\"rnthl rntliteral\">led<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Initialize LED\nled = Pin(\"LED\", Pin.OUT)<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">The connected variable<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">connected<\/span> variable will be used to keep track whether the Pico is connected to oher BLE device.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>connected = False<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Register the Service and Characteristic<\/h4>\n\n\n\n<p>Then, register the GATT service and characteristic.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Register GATT server\nble_service = aioble.Service(_SERVICE_UUID)\nread_characteristic = aioble.Characteristic(\n    ble_service, _READ_CHARACTERISTIC_UUID, read=True, notify=True\n)\naioble.register_services(ble_service)<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Encode the BLE Message<\/h4>\n\n\n\n<p>The message to be sent via BLE will be encoded as UTF-8. The following <span class=\"rnthl rntliteral\">encode_message()<\/span> function does that.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Helper to encode the message\ndef _encode_message(message):\n    return message.encode('utf-8')<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Writing to the characteristic &#8211; send_task() function<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">send_task()<\/span> function &#8220;sends&#8221; a message to the Raspberry Pi once connected. It will also blink the Raspberry Pi Pico built-in LED every second when connected. If not connected, the LED will blink faster, every 250 milliseconds.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>async def send_task():\n    global connected\n    message_count = 1\n    while True:\n        led.toggle()\n        blink = 1000 if connected else 250\n        if connected:\n            message = f\"Hello from {BLE_NAME}! Count: {message_count}\"\n            read_characteristic.write(_encode_message(message), send_update=True)\n            message_count += 1\n            print(f\"Sent: {message}\")\n        await asyncio.sleep_ms(blink)<\/code><\/pre>\n\n\n\n<p>A new message is sent every second. We add a counter to the message to keep track of how many messages were sent.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>message = f\"Hello from {BLE_NAME}! Count: {message_count}\"<\/code><\/pre>\n\n\n\n<p>This is the line that &#8220;sends&#8221; a new message.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>read_characteristic.write(_encode_message(message), send_update=True)<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">message_count<\/span> is incremented in each loop.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>message_count += 1<\/code><\/pre>\n\n\n\n<p>Notice that the <span class=\"rnthl rntliteral\">send_task<\/span> is an asynchronous function. For BLE handling, it&#8217;s better to use asynchronous programming to avoid timing issues. If you want to learn more about asynchronous programming with the Raspberry Pi Pico using MicroPython, we recommend the following tutorial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/micropython-raspberry-pi-pico-asynchronous-programming\/\">Raspberry Pi Pico Asynchronous Programming \u2013 Run Multiple Tasks (MicroPython)<\/a><\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Advertise the Pico as a BLE Service &#8211; peripheral_task()<\/h4>\n\n\n\n<p>Besides writing to the temperature characteristic, we also need to advertise the Raspberry Pi Pico as a BLE service. For that, we use the <span class=\"rnthl rntliteral\">peripheral_task()<\/span> function that sets up the Pico as a peripheral device and starts advertising.<\/p>\n\n\n\n<p>We also get and print the Pico MAC address\u2014we&#8217;ll need it later on the Raspberry Pi side to connect to the Pico.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Serially wait for connections\nasync def peripheral_task():\n    global connected\n    # Show MAC address once at start\n    ble = bluetooth.BLE()\n    _, mac_address = ble.config('mac')\n    formatted_mac = ':'.join('{:02X}'.format(b) for b in mac_address)\n    print(f\"Bluetooth MAC Address: {formatted_mac}\")\n    \n    while True:\n        try:\n            async with await aioble.advertise(\n                2000, name=BLE_NAME, services=&#091;_SERVICE_UUID], appearance=768\n            ) as connection:\n                connected = True\n                print(\"Connection from\", connection.device)\n                await connection.disconnected()\n        except Exception as e:\n            print(\"Error in peripheral_task:\", e)\n        finally:\n            connected = False\n            print(f\"{BLE_NAME} disconnected\")\n            await asyncio.sleep_ms(100)<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Main Function<\/h4>\n\n\n\n<p>Finally, we create an asynchronou <span class=\"rnthl rntliteral\">main()<\/span> function, where we\u2019ll write the base for our code. We create two asynchronous tasks: one for advertising and another to send new messages every second and blink the on-board LED. Then, we gather and run the tasks asynchronously by asynchronously calling the <span class=\"rnthl rntliteral\">main()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Run both tasks\nasync def main():\n    t1 = asyncio.create_task(send_task())\n    t2 = asyncio.create_task(peripheral_task())\n    await asyncio.gather(t1, t2)\n\n# Run the program\nasyncio.run(main())<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Running the Code<\/h3>\n\n\n\n<p>Run the code on the Pico by pressing the green play button on Thonny or we can press F5 on the keyboard. Once it\u2019s done, it\u2019ll display the MAC address of the Pico.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"626\" height=\"277\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Pico-Bluetooth-MAC-address.png?resize=626%2C277&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Raspberry Pi Pico . display Bluetooth MAC address\" class=\"wp-image-177148\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Pico-Bluetooth-MAC-address.png?w=626&amp;quality=100&amp;strip=all&amp;ssl=1 626w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Pico-Bluetooth-MAC-address.png?resize=300%2C133&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 626px) 100vw, 626px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Raspberry Pi &#8211; Receive the RPi Pico Messages<\/h2>\n\n\n\n<p>On the Raspberry Pi, create a new file with the code below. You can call it <span class=\"rnthl rntliteral\">pi_led_receive.py<\/span>. The file should be located inside the folder we created previously called <span class=\"rnthl rntliteral\">bluetooth_samples<\/span> \u2014 the same place where we created our virtual environment.<\/p>\n\n\n\n<p class=\"rntbox rntclgray\">There are many ways to create and run files on the Pi. I like to use<strong> <a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-remote-ssh-vs-code\/\" title=\"\">Remote-SSH on VS Code<\/a><\/strong>. This extension allows you to establish an SSH connection with your Pi, create files, write code, and execute it directly on your Raspberry Pi board from your computer using the VS Code interface. Learn more here: <a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-remote-ssh-vs-code\/\" title=\"\">Programming Raspberry Pi Remotely using VS Code (Remote-SSH)<\/a>.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n# Complete project details at https:\/\/RandomNerdTutorials.com\/ble-raspberry-pi-and-pi-pico-w\/\n\nimport asyncio\nfrom bleak import BleakClient, uuids\nfrom gpiozero import LED \n\nconnected = False   \n\nled = LED(17)\n\n# Replace with the MAC address of your Pico \npico_address = &quot;FF:FF:FF:FF:FF:FF&quot;\n\n# Service UUID (0x1848)\nSERVICE_UUID = uuids.normalize_uuid_16(0x1848)\nWRITE_CHARACTERISTIC_UUID = uuids.normalize_uuid_16(0x2A6E) # Central writes here\nREAD_CHARACTERISTIC_UUID = uuids.normalize_uuid_16(0x2A6F)  # Central reads here\n\nasync def receive_data_task(client):\n    &quot;&quot;&quot;Receive data from the peripheral device.&quot;&quot;&quot;\n    while True:\n        try:\n            response = await client.read_gatt_char(READ_CHARACTERISTIC_UUID)\n            print(f&quot;Central received: {response.decode('utf-8')}&quot;)\n            await asyncio.sleep(1)\n        except Exception as e:\n            print(f&quot;Error receiving data: {e}&quot;)\n            break\n\nasync def blink_task():\n    global connected \n    print(&quot;blink task started&quot;)\n    while True:\n        led.toggle() \n        blink = 1000  if connected else 250\n        await asyncio.sleep(blink \/ 1000)\n\nasync def connect_and_communicate(address):\n    global connected\n    &quot;&quot;&quot;Connect to the peripheral and manage data exchange.&quot;&quot;&quot;\n    print(f&quot;Connecting to {address}...&quot;)\n\n    async with BleakClient(address) as client:\n        connected = client.is_connected\n        print(f&quot;Connected: {connected}&quot;)\n\n        # Create tasks for sending and receiving data\n        tasks = [\n            asyncio.create_task(receive_data_task(client)),\n            asyncio.create_task(blink_task())\n        ]\n        await asyncio.gather(*tasks)\n    connected = False\n\n# Run the connection and communication\nloop = asyncio.get_event_loop()\nloop.run_until_complete(connect_and_communicate(pico_address))<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/Raspberry-Pi\/RPi_to_RPi_Pico\/rpi_led_receive.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Before running the code, you need to modify the following line with the Bluetooth MAC address of the Pico. You should have gotten it in the previous example.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Replace with the MAC address of your Pico \npico_address = \"2C:CF:67:B6:D7:4C\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>Let&#8217;s now take a quick look at the code to see how it works.<\/p>\n\n\n\n<p>First, import the required libraries. We&#8217;re including <span class=\"rnthl rntliteral\">bleak<\/span> for the Bluetooth functions.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>import asyncio\nfrom bleak import BleakClient, uuids\nfrom gpiozero import LED <\/code><\/pre>\n\n\n\n<p>We have a boolean variable to keep track of whether we&#8217;re connected to another Bluetooth peripheral or not.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>connected = False<\/code><\/pre>\n\n\n\n<p>We define the service and characteristics&#8217; UUIDs. These are the service and characteristics of the Pico that we&#8217;ll search for to read the message sent from the Pico. So, these must be the same of the Pico.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Service UUID (0x1848)\nSERVICE_UUID = uuids.normalize_uuid_16(0x1848)\nWRITE_CHARACTERISTIC_UUID = uuids.normalize_uuid_16(0x2A6E) # Central writes here\nREAD_CHARACTERISTIC_UUID = uuids.normalize_uuid_16(0x2A6F)  # Central reads here<\/code><\/pre>\n\n\n\n<p>Then, we have an asynchronous function called <span class=\"rnthl rntliteral\">receive_data_task()<\/span> that waits to read the characteristic value of the peripheral device. It reads the characteristic every second.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>async def receive_data_task(client):\n    \"\"\"Receive data from the peripheral device.\"\"\"\n    while True:\n        try:\n            response = await client.read_gatt_char(READ_CHARACTERISTIC_UUID)\n            print(f\"Central received: {response.decode('utf-8')}\")\n            await asyncio.sleep(1)\n        except Exception as e:\n            print(f\"Error receiving data: {e}\")\n            break<\/code><\/pre>\n\n\n\n<p>We have another task called <span class=\"rnthl rntliteral\">blink_task()<\/span> that will run at the same time. This task will blink the LED connected to GPIO 17 on the Raspberry Pi. It will run every second if we are connected to the peripheral device.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>async def blink_task():\n    global connected \n    print(\"blink task started\")\n    while True:\n        led.toggle() \n        blink = 1000  if connected else 250\n        await asyncio.sleep(blink \/ 1000)<\/code><\/pre>\n\n\n\n<p>Finally, the <span class=\"rnthl rntliteral\">connect_and_communicate()<\/span> function tries to connect to the peripheral device with the MAC address we defined earlier. Once it is connected, we create and gather the tasks to receive data and blink the LED.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>async def connect_and_communicate(address):\n    global connected\n    \"\"\"Connect to the peripheral and manage data exchange.\"\"\"\n    print(f\"Connecting to {address}...\")\n\n    async with BleakClient(address) as client:\n        connected = client.is_connected\n        print(f\"Connected: {connected}\")\n\n        # Create tasks for sending and receiving data\n        tasks = &#091;\n            asyncio.create_task(receive_data_task(client)),\n            asyncio.create_task(blink_task())\n        ]\n        await asyncio.gather(*tasks)\n    connected = False<\/code><\/pre>\n\n\n\n<p>Finally, we asynchronously run the tasks in a loop.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Run the connection and communication\nloop = asyncio.get_event_loop()\nloop.run_until_complete(connect_and_communicate(pico_address))<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Running the Python Code<\/h3>\n\n\n\n<p>After creating the <span class=\"rnthl rntliteral\">pi_led_receive.py<\/span> file with the code we&#8217;ve shared previously and inserting your Pico MAC address, you can run it on your Raspberry Pi board. We&#8217;re using the <a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-remote-ssh-vs-code\/\" title=\"\">Remote-SSH extension on VS Code<\/a>, but you can simply create a new file using the <a href=\"https:\/\/pimylifeup.com\/nano-text-editor\/\" target=\"_blank\" rel=\"noopener\" title=\"\">nano command<\/a>.<\/p>\n\n\n\n<p>After saving the file, you can run it. But first, make sure you&#8217;re in the virtual environment we created previously. If you&#8217;ve exited the virtual environment, you can activate it again like so:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted language-python\">source blue\/bin\/activate<\/pre>\n\n\n\n<p>Finally, you can run your Python program like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted language-python\">python3 pi_led_receive.py<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Demonstration<\/h2>\n\n\n\n<p>The code will start running, and after a few seconds it will connect to the Raspberry Pi Pico (make sure the RPi Pico is running the code on Thonny IDE).<\/p>\n\n\n\n<p>It will start receiving the Pico&#8217;s messages.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"644\" height=\"418\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Receive-BLE-Messages-From-Pico.png?resize=644%2C418&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Raspberry Pi Receiving BLE messages from the RPi Pico - terminal window\" class=\"wp-image-177268\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Receive-BLE-Messages-From-Pico.png?w=644&amp;quality=100&amp;strip=all&amp;ssl=1 644w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-Receive-BLE-Messages-From-Pico.png?resize=300%2C195&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 644px) 100vw, 644px\" \/><\/figure><\/div>\n\n\n<p>At the same time, the LED connected to GPIO 17 will start blinking every second.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-RPI-Pico-BLE-Communication.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"RPi to RPi Pico BLE Communication\" class=\"wp-image-177274\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-RPI-Pico-BLE-Communication.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/RPi-RPI-Pico-BLE-Communication.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>And that&#8217;s it. Now, you have the Raspberry Pi reading data from the Raspberry Pi Pico via BLE. <\/p>\n\n\n\n<p>You can also check the sent messages on the shell of Thonny IDE.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"688\" height=\"433\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/RPi-Pico-Bluetooth-Message-Sent.png?resize=688%2C433&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"RPi Pico Sending Bluetooth Message to Raspberry Pi\" class=\"wp-image-179873\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/RPi-Pico-Bluetooth-Message-Sent.png?w=688&amp;quality=100&amp;strip=all&amp;ssl=1 688w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/RPi-Pico-Bluetooth-Message-Sent.png?resize=300%2C189&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 688px) 100vw, 688px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Sending Current Time from the Pico to Pi Example<\/h2>\n\n\n\n<p>Instead of sending a message without meaning, we can easily change the code to send sensor readings or commands, for example. In this section, we&#8217;ll show you how you can easily change the previous example to send different data. In this case, we&#8217;ll send the current time from the Pico to the Pi.<\/p>\n\n\n\n<p>The code for the Pi will remain the same. For the Pico, we need to make some slight changes. This is the code for the Pico.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\r\n# Complete project details at https:\/\/RandomNerdTutorials.com\/ble-raspberry-pi-and-pi-pico-w\/\r\n\r\nimport asyncio\r\nimport aioble\r\nimport bluetooth\r\nfrom machine import Pin\r\nimport time\r\n\r\n# Bluetooth configuration\r\n_SERVICE_UUID = bluetooth.UUID(0x1848)\r\n_WRITE_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6E) # Central writes here\r\n_READ_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6F)  # Peripheral writes message here\r\n\r\nBLE_NAME = &quot;Pico W Peripheral&quot;\r\n\r\n# Initialize LED\r\nled = Pin(&quot;LED&quot;, Pin.OUT)\r\n\r\nconnected = False\r\n\r\n# Register GATT server\r\nble_service = aioble.Service(_SERVICE_UUID)\r\nread_characteristic = aioble.Characteristic(\r\n    ble_service, _READ_CHARACTERISTIC_UUID, read=True, notify=True\r\n)\r\naioble.register_services(ble_service)\r\n\r\n# Helper to encode the message\r\ndef _encode_message(message):\r\n    return message.encode('utf-8')\r\n\r\n# Task to handle LED blinking and message sending\r\nasync def send_task():\r\n    global connected\r\n    while True:\r\n        led.toggle()\r\n        blink = 1000 if connected else 250\r\n        if connected:\r\n            today = time.localtime()  # get the current time\r\n            message = f&quot;{today}&quot;\r\n            read_characteristic.write(_encode_message(message), send_update=True)\r\n            print(f&quot;Sent: {message}&quot;)\r\n        await asyncio.sleep_ms(blink)\r\n\r\n# Serially wait for connections\r\nasync def peripheral_task():\r\n    global connected\r\n    # Show MAC address once at start\r\n    ble = bluetooth.BLE()\r\n    _, mac_address = ble.config('mac')\r\n    formatted_mac = ':'.join('{:02X}'.format(b) for b in mac_address)\r\n    print(f&quot;Bluetooth MAC Address: {formatted_mac}&quot;)\r\n    \r\n    while True:\r\n        try:\r\n            async with await aioble.advertise(\r\n                2000, name=BLE_NAME, services=[_SERVICE_UUID], appearance=768\r\n            ) as connection:\r\n                connected = True\r\n                print(&quot;Connection from&quot;, connection.device)\r\n                await connection.disconnected()\r\n        except Exception as e:\r\n            print(&quot;Error in peripheral_task:&quot;, e)\r\n        finally:\r\n            connected = False\r\n            print(f&quot;{BLE_NAME} disconnected&quot;)\r\n            await asyncio.sleep_ms(100)\r\n\r\n# Run both tasks\r\nasync def main():\r\n    t1 = asyncio.create_task(send_task())\r\n    t2 = asyncio.create_task(peripheral_task())\r\n    await asyncio.gather(t1, t2)\r\n\r\n# Run the program\r\nasyncio.run(main())\r\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/Raspberry-Pi\/RPi_to_RPi_Pico\/ble_time.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>First, we will have to add the library for time.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>import time<\/code><\/pre>\n\n\n\n<p>Then, we need to modify the <span class=\"rnthl rntliteral\">send_task()<\/span> function. Basically, once connected, we get the current time and save it in the <span class=\"rnthl rntliteral\">today<\/span> message.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>today = time.localtime()<\/code><\/pre>\n\n\n\n<p>The local time will be our message.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>message = f\"{today}\"<\/code><\/pre>\n\n\n\n<p>Then, we simply need to write the current time on the characteristic like so:<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>read_characteristic.write(encode_message(message), send_update=True)<\/code><\/pre>\n\n\n\n<p>Now, it&#8217;s easy to understand that you can easily modify the code to send any other useful data like sensor readings or commands to control outputs, for example.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demonstration<\/h3>\n\n\n\n<p>On the Raspberry Pi side, it should have disconnected from the Pico when you run this new code. You need to run the Python code on the Raspberry Pi again right after running the code on the Pico.<\/p>\n\n\n\n<p>After a while, it will be connected and start sending the messages.<\/p>\n\n\n\n<p>On the Raspberry Pi side, it will receive the time sent from the Pico. The timestamp should be printed in the terminal window.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"679\" height=\"420\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/pi-receive-time-from-pico-via-ble.jpg?resize=679%2C420&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"RPi Receive Time From Pico via BLE\" class=\"wp-image-177270\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/pi-receive-time-from-pico-via-ble.jpg?w=679&amp;quality=100&amp;strip=all&amp;ssl=1 679w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/09\/pi-receive-time-from-pico-via-ble.jpg?resize=300%2C186&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 679px) 100vw, 679px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Wrapping up<\/strong><\/h2>\n\n\n\n<p>In this tutorial, we learned the basics of BLE and how to set up the Pi to interact with the Pico. <\/p>\n\n\n\n<p>We&#8217;re planning to create more tutorials about this subject. Specifically, cover bidirectional communication so that both devices can send and receive data at the same time.<\/p>\n\n\n\n<p>Meanwhile, here are some challenges if you\u2019d like to take this example further:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Have the Pi read the values of the <a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-internal-temperature-micropython\/\" title=\"\">Pico\u2019s internal temperature sensor<\/a>.<\/li>\n\n\n\n<li>Add an external temperature sensor like the <a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-bme280-micropython\/\" title=\"\">BME280<\/a> to the Pico and have the Pi read back the temperature values.<\/li>\n\n\n\n<li>For an added challenge, add an I2C-based LCD screen on the Pi to display the temperatures rather than simply printing the values in the terminal.<\/li>\n<\/ul>\n\n\n\n<p>We hope you&#8217;ve found this tutorial useful.<\/p>\n\n\n\n<p>Special thanks to our reader <a href=\"https:\/\/github.com\/sentairanger\" target=\"_blank\" rel=\"noopener\" title=\"\">Edgardo Peregrino<\/a>, who created and wrote the layout for this tutorial as well as the example codes.<\/p>\n\n\n\n<p class=\"rntbox rntclgray\"><a href=\"https:\/\/github.com\/sentairanger\" target=\"_blank\" rel=\"noopener\" title=\"\">Edgardo Peregrino<\/a> is the author of &#8220;Programming Raspberry Pi in 30 Days&#8221; and &#8220;Cloud Powered Robotics with Raspberry Pi&#8221; and writer of several articles especially in Servo Magazine. You can <a href=\"https:\/\/github.com\/sentairanger\" target=\"_blank\" rel=\"noopener\" title=\"\">check his work here on its GitHub page<\/a> or YouTube channel (<a href=\"https:\/\/www.youtube.com\/@linuxrobotgeek\" target=\"_blank\" rel=\"noopener\" title=\"\">LinuxRobotGeek<\/a>).<\/p>\n\n\n\n<p>Learn more about the Raspberry Pi Pico and the Raspberry Pi:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-raspberry-pi\/\" title=\"\">All our <strong>Raspberry Pi <\/strong>Tutorials<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-w-micropython-ebook\/\" title=\"\">Learn Raspberry Pi Pico with MicroPython eBook<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-raspberry-pi-pico\/\" title=\"\">All our <strong>Raspberry Pi Pico <\/strong>Tutorials<\/a><\/li>\n<\/ul>\n\n\n\n<p>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial explains how to set up Bluetooth Low Energy (BLE) communication between a Raspberry Pi and a Pico W. We\u2019ll start by covering the basics of BLE, including the &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"BLE Communication between Raspberry Pi and Raspberry Pi Pico W\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/ble-raspberry-pi-and-pi-pico-w\/#more-177129\" aria-label=\"Read more about BLE Communication between Raspberry Pi and Raspberry Pi Pico W\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":179872,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[301,264,190,268],"tags":[],"class_list":["post-177129","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-0-raspberrypi","category-project","category-raspberry-pi","category-raspberry-pi-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/10\/Rpi-Pico-to-RPi-Communication-Bluetooth-Low-Energy.jpg?fit=1920%2C1080&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/177129","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=177129"}],"version-history":[{"count":25,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/177129\/revisions"}],"predecessor-version":[{"id":181374,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/177129\/revisions\/181374"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/179872"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=177129"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=177129"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=177129"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}