connecting-to-the-internet-with-pico-w
connecting-to-the-internet-with-pico-w
Colophon
© 2022-2024 Raspberry Pi Ltd
This documentation is licensed under a Creative Commons Attribution-NoDerivatives 4.0 International (CC BY-ND).
build-date: 2024-11-25
build-version: 8da33d3-clean
RPL reserves the right to make any enhancements, improvements, corrections or any other modifications to the
RESOURCES or any products described in them at any time and without further notice.
The RESOURCES are intended for skilled users with suitable levels of design knowledge. Users are solely responsible for
their selection and use of the RESOURCES and any application of the products described in them. User agrees to
indemnify and hold RPL harmless against all liabilities, costs, damages or other losses arising out of their use of the
RESOURCES.
RPL grants users permission to use the RESOURCES solely in conjunction with the Raspberry Pi products. All other use
of the RESOURCES is prohibited. No licence is granted to any other RPL or other third party intellectual property right.
HIGH RISK ACTIVITIES. Raspberry Pi products are not designed, manufactured or intended for use in hazardous
environments requiring fail safe performance, such as in the operation of nuclear facilities, aircraft navigation or
communication systems, air traffic control, weapons systems or safety-critical applications (including life support
systems and other medical devices), in which the failure of the products could lead directly to death, personal injury or
severe physical or environmental damage ("High Risk Activities"). RPL specifically disclaims any express or implied
warranty of fitness for High Risk Activities and accepts no liability for use or inclusions of Raspberry Pi products in High
Risk Activities.
Raspberry Pi products are provided subject to RPL’s Standard Terms. RPL’s provision of the RESOURCES does not
expand or otherwise modify RPL’s Standard Terms including but not limited to the disclaimers and warranties
expressed in them.
Table of contents
Colophon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Legal disclaimer notice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1. About Pico W-series devices. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2. Getting on the internet with the C SDK. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1. Installing the SDK and examples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2. Building an SDK example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3. Creating your own project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3.1. Going further. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4. Which hardware am I running on?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3. Getting on the internet with MicroPython . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1. Getting MicroPython for Pico W-series devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2. Installing MicroPython on Pico W-series devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.3. Connecting from a Raspberry Pi over USB. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.3.1. Using an integrated development environment (IDE) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.3.2. Remote access via serial port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.4. The on-board LED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.5. Installing modules. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.6. Connecting to a wireless network. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.6.1. Connection status codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.6.2. Setting the country. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.6.3. Power-saving mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.7. The MAC address . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.8. Making HTTP requests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.8.1. HTTP with sockets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.8.2. HTTP with urequests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.8.3. Ensuring robust connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.9. Building HTTP servers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.9.1. A simple server for static pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.9.2. Controlling an LED via a web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.9.3. An asynchronous web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.10. Running iperf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.11. Which hardware am I running on? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4. About Bluetooth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.1. More about Bluetooth LE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.1.1. Protocols and profiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.1.2. The GAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.1.3. The GATT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.1.4. Services and characteristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.1.5. UUIDs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5. Working with Bluetooth and the C SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.1. An example Bluetooth service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.1.1. Creating a temperature service peripheral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.2. Availability of other example code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
6. Working with Bluetooth in MicroPython . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.1. Advertising a Bluetooth service. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.2. An example Bluetooth service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.2.1. Creating a temperature service peripheral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.2.2. Implementing a central device . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Appendix A: Building MicroPython from source. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Appendix H: Documentation Release History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
25 November 2024. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
02 Feb 2024 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
14 Jun 2023 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
03 Mar 2023 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
01 Dec 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Table of contents 2
Connecting to the Internet with Raspberry Pi Pico W-series.
30 Jun 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Table of contents 3
Connecting to the Internet with Raspberry Pi Pico W-series.
Figure 1. The
Raspberry Pi Pico W
Rev3 board.
Figure 2. The
Raspberry Pi Pico 2 W
board.
Pico W-series is a low cost yet flexible development platform for RP-series microcontroller, combining a 2.4GHz
wireless interface with the following key Pico-series features:
NOTE
Full details of the Pico W-series can be found in Raspberry Pi Pico W Datasheet and Raspberry Pi Pico 2 W
Datasheet.
NOTE
By default libcyw43 is licensed for non-commercial use, but Pico W users, and anyone else who builds their product
around RP2040 and CYW43439, benefit from a free commercial-use license.
NOTE
If you have not previously used an RP-series microcontroller-based board you can get started by reading Getting
started with Raspberry Pi Pico-series, while further details about the SDK along with API-level documentation can be
found in the Raspberry Pi Pico-series C/C++ SDK book.
WARNING
If you have not initialised the tinyusb submodule in your pico-sdk checkout, then USB CDC serial, and other USB
functions and example code, will not work as the SDK will contain no USB functionality. Similarly, if you have not
initialised the cyw43-driver and lwip submodules in your checkout, then network-related functionality will not be
enabled.
$ cd pico-examples
$ mkdir build
$ cd build
$ export PICO_SDK_PATH=../../pico-sdk
$ cmake -DPICO_BOARD=pico_w -DWIFI_SSID="Your Network" -DWIFI_PASSWORD="Your Password" ..
Using PICO_SDK_PATH from environment ('../../pico-sdk')
PICO_SDK_PATH is /home/pi/pico/pico-sdk
.
.
.
-- Build files have been written to: /home/pi/pico/pico-examples/build
$
NOTE
The command line flags -DWIFI_SSID="Your Network" -DWIFI_PASSWORD="Your Password" are used by the pico-examples to
set the SSID and password to the call to cyw43_arch_wifi_connect_xxx() to connect to your wireless network.
To then build a basic example for a Pico W-series device that will scan for nearby wireless networks, you can do:
$ cd pico-examples/pico_w/wifi/wifi_scan
$ make
PICO_SDK_PATH is /home/pi/pico-sdk
PICO platform is rp2040.
Build type is Release
PICO target board is pico_w.
.
.
.
[100%] Built target picow_scan_test_background
$
Along with other targets, we have now built a binary called picow_scan_test_background.uf2, which can be dragged onto the
RP-series microcontroller USB mass storage device.
This binary will scan for wireless networks using the Pico W-series device’s wireless chip.
The fastest method to load software onto a RP-series microcontroller-based board for the first time is by mounting it as
a USB mass storage device. Doing this allows you to drag a file onto the board to program the flash. Go ahead and
connect the Pico W-series device to your Raspberry Pi using a micro-USB cable, making sure that you hold down the
BOOTSEL button as you do so, to force it into USB mass storage mode.
If you are running the Raspberry Pi Desktop the Pico W-series device should automatically mount as a USB mass
storage device. From here, you can drag-and-drop the UF2 file onto the mass storage device. RP-series microcontroller
will reboot, unmounting itself as a mass storage device, and start to run the flashed code.
By default the code will report its results via serial UART.
IMPORTANT
The default UART pins are configured on a per-board basis using board configuration files. The default Pico W-series
UART TX pin (out) is pin GP0, and the UART RX pin (in) is pin GP1.
To see the text, you will need to enable UART serial communications on the Raspberry Pi host. To do so, run raspi-
config:
$ sudo raspi-config
When asked "Would you like a login shell to be accessible over serial?", select "No".
When asked "Would you like the serial port hardware to be enabled?", select "Yes".
Figure 3. Enabling a
serial UART using
raspi-config on the
Raspberry Pi.
Leaving raspi-config, choose "Yes" and reboot your Raspberry Pi to enable the serial port.
Then, wire the Raspberry Pi and the Pico W-series device together with the following mapping:
See Figure 4.
Figure 4. A Raspberry
Pi 4 and the Raspberry
Pi Pico with UART0
connected together.
Once the two boards are wired together you should install minicom if you have not already done so:
You should see the results of our wireless scanning being printed to the console, see Figure 5:
TIP
Figure 5. Results of
our wireless scanning
in the console
$ ls -la
total 16
drwxr-xr-x 7 aa staff 224 6 Apr 10:41 ./
drwx------@ 27 aa staff 864 6 Apr 10:41 ../
drwxr-xr-x 10 aa staff 320 6 Apr 09:29 pico-examples/
drwxr-xr-x 13 aa staff 416 6 Apr 09:22 pico-sdk/
$ mkdir test
$ cd test
Then, create a test.c file in that directory with the following contents:
1 #include <stdio.h>
2
3 #include "pico/stdlib.h"
4 #include "pico/cyw43_arch.h"
5
6 char ssid[] = "A Network";①
7 char pass[] = "A Password";②
8
9 int main() {
10 stdio_init_all();
11
12 if (cyw43_arch_init_with_country(CYW43_COUNTRY_UK)) {
13 printf("failed to initialise\n");
14 return 1;
15 }
16 printf("initialised\n");
17
18 cyw43_arch_enable_sta_mode();
19
20 if (cyw43_arch_wifi_connect_timeout_ms(ssid, pass, CYW43_AUTH_WPA2_AES_PSK, 10000)) {
21 printf("failed to connect\n");
22 return 1;
23 }
24 printf("connected\n");
25 }
cmake_minimum_required(VERSION 3.13)
include(pico_sdk_import.cmake)
add_executable(test
test.c
)
pico_enable_stdio_usb(test 1)
pico_enable_stdio_uart(test 1)
pico_add_extra_outputs(test)
Copy the pico_sdk_import.cmake file from the external folder in your pico-sdk installation to your test project folder:
$ cp ../pico-sdk/external/pico_sdk_import.cmake .
$ cp ../pico-examples/pico_w/wifi/lwipopts_examples_common.h lwipopts.h
$ ls -la
total 32
drwxr-xr-x 6 aa staff 192B 29 Jun 18:11 ./
drwxr-xr-x 7 aa staff 224B 29 Jun 16:57 ../
-rw-r--r--@ 1 aa staff 379B 29 Jun 18:10 CMakeLists.txt
-rw-rw-r--@ 1 aa staff 3.3K 15 Jun 00:34 lwipopts.h
-rw-rw-r--@ 1 aa staff 3.1K 15 Jun 00:34 pico_sdk_import.cmake
-rw-r--r--@ 1 aa staff 427B 29 Jun 17:03 test.c
and can build it as we did before with our previous example in the last section.
$ mkdir build
$ cd build
$ export PICO_SDK_PATH=../../pico-sdk
$ cmake -DPICO_BOARD=pico_w ..
$ make
Finally, unplug your Pico W-series device from your computer if it is plugged in already. Then push and hold the
BOOTSEL button while plugging it back into your computer. Then, drag and drop the test.uf2 binary onto the RPI-RP2
mass storage volume which will mount on your desktop.
You should see the a message indicating that the Pico W-series device has connected to your wireless network.
1 #include <stdio.h>
2
3 #include "pico/stdlib.h"
4 #include "hardware/gpio.h"
5 #include "hardware/adc.h"
6
7 int main() {
8 stdio_init_all();
9
10 adc_init();
11 adc_gpio_init(29);
12 adc_select_input(3);
13 const float conversion_factor = 3.3f / (1 << 12);
14 uint16_t result = adc_read();
15 printf("ADC3 value: 0x%03x, voltage: %f V\n", result, result * conversion_factor);
16
17 gpio_init(25);
18 gpio_set_dir(25, GPIO_IN);
19 uint value = gpio_get(25);
20 printf("GP25 value: %i", value);
21 }
cmake_minimum_required(VERSION 3.13)
include(pico_sdk_import.cmake)
add_executable(test
test.c
)
pico_enable_stdio_usb(test 1)
pico_enable_stdio_uart(test 1)
pico_add_extra_outputs(test)
NOTE
If you have not previously used an RP-series microcontroller-based board you can get started by reading Raspberry
Pi Pico-series Python SDK book.
A pre-built binary of the latest MicroPython firmware is available from the MicroPython section of the
documentation site.
The fastest way to get MicroPython is to download the pre-built release binary from the Documentation pages. If you
can’t or don’t want to use the pre-built release — for example, if you want to develop a C module for MicroPython — you
can follow the instructions in Appendix A> to get the source code for MicroPython, which you can use to build your own
MicroPython firmware binary.
A drive called RPI-RP2 should pop up. Go ahead and drag the MicroPython firmware.uf2 file onto this drive. This
programs the MicroPython firmware onto the flash memory on your Pico W-series device.
It should take a few seconds to program the UF2 file into the flash. The board will automatically reboot when finished,
causing the RPI-RP2 drive to disappear, and boot into MicroPython.
When MicroPython boots for the first time, it will sit and wait for you to connect and tell it what to do. You can load a .py
file from your computer onto the board, but a more immediate way to interact with it is through what is called the read-
evaluate-print loop, or REPL.
There are two ways to connect to this REPL; so you can communicate with the MicroPython firmware on your board
over USB, or over the UART serial port on Pico W-series GPIOs.
NOTE
The MicroPython port for RP-series microcontroller does not expose a REPL over a UART port by default, please see
Raspberry Pi Pico-series Python SDK for more details of how to configure MicroPython to allow you to connect to
the REPL over UART.
TIP
You can run ls /dev/tty* to list your serial ports. There may be quite a few, but MicroPython’s USB serial will start
with /dev/ttyACM. If in doubt, unplug the micro USB connector and see which one disappears. If you don’t see
anything, you can try rebooting your Raspberry Pi.
$ minicom -o -D /dev/ttyACM0
Where the -D /dev/ttyACM0 is pointing minicom at MicroPython’s USB serial port, and the -o flag essentially means "just do
it". There’s no need to worry about baud rate, since this is a virtual serial port.
Press the enter key a few times in the terminal where you opened minicom. You should see this:
>>>
This is a prompt. MicroPython wants you to type something in, and tell it what to do.
If you press CTRL-D on your keyboard whilst the minicom terminal is focused, you should see a message similar to this:
This key combination tells MicroPython to reboot. You can do this at any time. When it reboots, MicroPython will print
out a message saying exactly what firmware version it is running, and when it was built. Your version number will be
different from the one shown here.
NOTE
If you are working on an Apple Mac, so long as you’re using a recent version of macOS like Catalina, drivers should
already be loaded. Otherwise, see the manufacturers' website for FTDI Chip Drivers. Then you should use a Terminal
program to connect to Serial-over-USB (USB CDC). The serial port will show up as /dev/tty.usbmodem with a number
appended to the end.
If you don’t already have a Terminal program installed you can install minicom using Homebrew:
For full details on how to use the Thonny editor, see the section on using a development environment in the Raspberry
Pi Pico-series Python SDK book.
With this you can run a script from your local machine directly on Pico W-series devices.
NOTE
or even:
>>> led.toggle()
to change the current state. However, if you now look at the led object:
>>> led
Pin(WL_GPIO0, mode=OUT)
>>>
which will configure the led object, associate it with the on-board LED and turn the LED on.
NOTE
Full details of the Pico W-series can be found in the Raspberry Pi Pico W Datasheet and Raspberry Pi Pico 2 W
Datasheet. WL_GPIO1 is connected to the PS/SYNC pin on the RT6154A to allow selection of different operating modes,
while WL_GPIO2 can be used to monitor USB VBUS.
1 import network
2 import time
3
4 wlan = network.WLAN(network.STA_IF)
5 wlan.active(True)
6 wlan.connect('Wireless Network', 'The Password')
7
8 while not wlan.isconnected() and wlan.status() >= 0:
9 print("Waiting to connect:")
10 time.sleep(1)
11
12 print(wlan.ifconfig())
although more correctly, you should wait for the connection to succeed or fail in your code, and handle any connection
errors that might occur.
1 import time
2 import network
3
4 ssid = 'Wireless Network'
5 password = 'The Password'
6
7 wlan = network.WLAN(network.STA_IF)
8 wlan.active(True)
9 wlan.connect(ssid, password)
10
11 # Wait for connect or fail
12 max_wait = 10
13 while max_wait > 0:
14 if wlan.status() < 0 or wlan.status() >= 3:
15 break
16 max_wait -= 1
17 print('waiting for connection...')
18 time.sleep(1)
19
20 # Handle connection error
21 if wlan.status() != 3:
22 raise RuntimeError('network connection failed')
23 else:
24 print('connected')
25 status = wlan.ifconfig()
26 print( 'ip = ' + status[0] )
You can also disconnect and then connect to a different wireless network.
For more information on the network.WLAN library see the library documentation.
This can cause problems on some wireless networks. If you find that your Pico W-series device does not connect to
your wireless network you may want to try setting the country code, e.g.
>>> rp2.country('GB')
1 import network
2
3 wlan = network.WLAN(network.STA_IF)
4 wlan.active(True)
5 wlan.config(pm = 0xa11140)
1 import network
2 import ubinascii
3
4 wlan = network.WLAN(network.STA_IF)
5 wlan.active(True)
6 mac = ubinascii.hexlify(network.WLAN().config('mac'),':').decode()
7 print(mac)
8
9 # Other things you can query
10 print(wlan.config('channel'))
11 print(wlan.config('essid'))
12 print(wlan.config('txpower'))
NOTE
We have to set the wireless active (which loads the firmware) before we can get the MAC address.
1 # Connect to network
2 import network
3
4 wlan = network.WLAN(network.STA_IF)
5 wlan.active(True)
6 wlan.connect('Wireless Network', 'The Password')
7
8 # Should be connected and have an IP address
9 wlan.status() # 3 == success
10 wlan.ifconfig()
11
12 # Get IP address for google.com
13 import socket
14 ai = socket.getaddrinfo("google.com", 80)
15 addr = ai[0][-1]
16
17 # Create a socket and make a HTTP request
18 s = socket.socket()
19 s.connect(addr)
20 s.send(b"GET / HTTP/1.0\r\n\r\n")
21
22 # Print the response
23 print(s.recv(512))
1 # Connect to network
2 import network
3 wlan = network.WLAN(network.STA_IF)
4 wlan.active(True)
5 wlan.connect('Wireless Network', 'The Password')
6
7 # Make GET request
8 import urequests
9 r = urequests.get("http://www.google.com")
10 print(r.content)
11 r.close()
1 import urequests
2 r = urequests.get("http://www.raspberrypi.com")
3 print(r.status_code) # redirects to https
4 r.close()
NOTE
HTTPS works, but you should be aware that SSL verification is currently disabled.
>>> r = urequests.get("http://date.jsontest.com")
>>> r.json()
{'milliseconds_since_epoch': 1652188199441, 'date': '05-10-2022', 'time': '01:09:59 PM'}
>>>>
IMPORTANT
You must close the returned response object after making a request using the urequests library using
response.close(). If you do not, the object will not be garbage-collected, and if the request is being made inside a loop
this will quickly lead to a crash.
1 import time
2 import network
3 import urequests as requests
4
5 ssid = 'A Network'
6 password = 'The Password'
7
8 wlan = network.WLAN(network.STA_IF)
9 wlan.active(True)
10 wlan.connect(ssid, password)
11
12 # Wait for connect or fail
13 max_wait = 10
14 while max_wait > 0:
15 if wlan.status() < 0 or wlan.status() >= 3:
16 break
17 max_wait -= 1
18 print('waiting for connection...')
19 time.sleep(1)
20
21 # Handle connection error
22 if wlan.status() != 3:
23 raise RuntimeError('network connection failed')
24 else:
25 print('connected')
26 status = wlan.ifconfig()
27 print( 'ip = ' + status[0] )
28
29 while True:
30
31 # Do things here, perhaps measure something using a sensor?
32
33 # ...and then define the headers and payloads
34 headers = ...
35 payload = ...
36
37 # Then send it in a try/except block
38 try:
39 print("sending...")
40 response = requests.post("A REMOTE END POINT", headers=headers, data=payload)
41 print("sent (" + str(response.status_code) + "), status = " + str(wlan.status()) )
42 response.close()
43 except:
44 print("could not connect (status =" + str(wlan.status()) + ")")
45 if wlan.status() < 0 or wlan.status() >= 3:
46 print("trying to reconnect...")
47 wlan.disconnect()
48 wlan.connect(ssid, password)
49 if wlan.status() == 3:
50 print('connected')
51 else:
52 print('failed')
53
54 time.sleep(5)
Here we handle the possibility that we lose connection to our wireless network and then will seek to reconnect.
1 import network
2 import socket
3 import time
4
5 from machine import Pin
6
7 led = Pin(15, Pin.OUT)
8
9 ssid = 'A Network'
10 password = 'A Password'
11
12 wlan = network.WLAN(network.STA_IF)
13 wlan.active(True)
14 wlan.connect(ssid, password)
15
16 html = """<!DOCTYPE html>
17 <html>
18 <head> <title>Pico W</title> </head>
19 <body> <h1>Pico W</h1>
20 <p>Hello World</p>
21 </body>
22 </html>
23 """
24
25 # Wait for connect or fail
26 max_wait = 10
27 while max_wait > 0:
28 if wlan.status() < 0 or wlan.status() >= 3:
29 break
30 max_wait -= 1
31 print('waiting for connection...')
32 time.sleep(1)
33
34 # Handle connection error
35 if wlan.status() != 3:
36 raise RuntimeError('network connection failed')
37 else:
38 print('connected')
39 status = wlan.ifconfig()
40 print( 'ip = ' + status[0] )
41
42 # Open socket
43 addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
44
45 s = socket.socket()
46 s.bind(addr)
47 s.listen(1)
48
49 print('listening on', addr)
50
51 # Listen for connections
52 while True:
53 try:
54 cl, addr = s.accept()
55 print('client connected from', addr)
56 cl_file = cl.makefile('rwb', 0)
57 while True:
58 line = cl_file.readline()
NOTE
This example is synchronous, for more robust request handling you should implement the server to handle requests
asynchronously.
Figure 6. The
Raspberry Pi Pico W
with an LED on GP15.
Connecting an LED to GP15 we can turn the LED on and off by using HTTP GET. We can do this by going to
http://192.168.1.X/light/on to turn the LED on, and http://192.168.1.X/light/off to turn the LED off, in our web browser;
where 192.168.1.X is the IP address of our Pico W-series device, which will be printed in the console after it connects to
the network.
1 import network
2 import socket
3 import time
4
5 from machine import Pin
6
7 led = Pin(15, Pin.OUT)
8
9 ssid = 'A Network'
10 password = 'A Password'
11
12 wlan = network.WLAN(network.STA_IF)
13 wlan.active(True)
14 wlan.connect(ssid, password)
15
16 html = """<!DOCTYPE html>
17 <html>
18 <head> <title>Pico W</title> </head>
19 <body> <h1>Pico W</h1>
20 <p>%s</p>
21 </body>
22 </html>
23 """
24
25 # Wait for connect or fail
26 max_wait = 10
27 while max_wait > 0:
28 if wlan.status() < 0 or wlan.status() >= 3:
29 break
30 max_wait -= 1
31 print('waiting for connection...')
32 time.sleep(1)
33
34 # Handle connection error
35 if wlan.status() != 3:
36 raise RuntimeError('network connection failed')
37 else:
38 print('connected')
39 status = wlan.ifconfig()
40 print( 'ip = ' + status[0] )
41
42 # Open socket
43 addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
44
45 s = socket.socket()
46 s.bind(addr)
47 s.listen(1)
48
49 print('listening on', addr)
50
51 # Listen for connections
52 while True:
53 try:
54 cl, addr = s.accept()
55 print('client connected from', addr)
56 request = cl.recv(1024)
57 print(request)
58
59 request = str(request)
60 led_on = request.find('/light/on')
61 led_off = request.find('/light/off')
62 print( 'led on = ' + str(led_on))
63 print( 'led off = ' + str(led_off))
64
65 if led_on == 6:
66 print("led on")
67 led.value(1)
68 stateis = "LED is ON"
69
70 if led_off == 6:
71 print("led off")
72 led.value(0)
73 stateis = "LED is OFF"
74
75 response = html % stateis
76
1 import network
2 import socket
3 import time
4
5 from machine import Pin
6 import uasyncio as asyncio
7
8 led = Pin(15, Pin.OUT)
9 onboard = Pin("LED", Pin.OUT, value=0)
10
11 ssid = 'A Network'
12 password = 'A Password'
13
14 html = """<!DOCTYPE html>
15 <html>
16 <head> <title>Pico W</title> </head>
17 <body> <h1>Pico W</h1>
18 <p>%s</p>
19 </body>
20 </html>
21 """
22
23 wlan = network.WLAN(network.STA_IF)
24
25 def connect_to_network():
26 wlan.active(True)
27 wlan.config(pm = 0xa11140) # Disable power-save mode
28 wlan.connect(ssid, password)
29
30 max_wait = 10
31 while max_wait > 0:
32 if wlan.status() < 0 or wlan.status() >= 3:
33 break
34 max_wait -= 1
35 print('waiting for connection...')
36 time.sleep(1)
37
38 if wlan.status() != 3:
39 raise RuntimeError('network connection failed')
40 else:
41 print('connected')
42 status = wlan.ifconfig()
43 print('ip = ' + status[0])
44
45 async def serve_client(reader, writer):
46 print("Client connected")
47 request_line = await reader.readline()
48 print("Request:", request_line)
49 # We are not interested in HTTP request headers, skip them
50 while await reader.readline() != b"\r\n":
51 pass
52
53 request = str(request_line)
54 led_on = request.find('/light/on')
55 led_off = request.find('/light/off')
56 print( 'led on = ' + str(led_on))
57 print( 'led off = ' + str(led_off))
58
59 stateis = ""
60 if led_on == 6:
61 print("led on")
62 led.value(1)
63 stateis = "LED is ON"
64
65 if led_off == 6:
66 print("led off")
67 led.value(0)
68 stateis = "LED is OFF"
69
70 response = html % stateis
71 writer.write('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
72 writer.write(response)
73
74 await writer.drain()
75 await writer.wait_closed()
76 print("Client disconnected")
77
78 async def main():
79 print('Connecting to Network...')
80 connect_to_network()
81
82 print('Setting up webserver...')
83 asyncio.create_task(asyncio.start_server(serve_client, "0.0.0.0", 80))
84 while True:
85 onboard.on()
86 print("heartbeat")
87 await asyncio.sleep(0.25)
88 onboard.off()
89 await asyncio.sleep(5)
90
91 try:
92 asyncio.run(main())
93 finally:
94 asyncio.new_event_loop()
NOTE
1 import network
2 if hasattr(network, "WLAN"):
3 # the board has WLAN capabilities
Alternatively, you can inspect the MicroPython firmware version to check whether it was compiled for Pico-series or for
Pico W-series using the sys module.
So if 'Pico W' in sys.implementation._machine can be used to detect whether your firmware was compiled for Pico W-
series.
NOTE
Full details of supported Bluetooth protocols and profiles are available on the Blue Kitchen BTStack Github
repository. In addition to the standard BTstack licensing terms, a supplemental licence which covers commercial
use of BTstack with Raspberry Pi Pico W or Raspberry Pi Pico WH is provided.
NOTE
The Bluetooth LE specification is a sprawling mess of interlocking documents that runs to thousands of pages; the
core standards document is over 2,700 pages just on its own. Proceed with caution.
Peripherals can operate in two modes: either by broadcasting, or when directly connected to a central device. The
broadcast mechanism is one of the big differences between Bluetooth LE and "classic" Bluetooth. Using it, data can be
sent out by the peripheral to any device within range.
This means that a Bluetooth LE peripheral device doesn’t necessarily need to be paired — in Bluetooth LE we’d speak of
it as "connected", rather than "paired" as we did with Bluetooth 2.1 — to a central device to transfer data. In broadcast
mode, the peripheral will periodically send out advertising packets, available to anyone that’s looking for them, for
devices that are acting as "observers".
The standard advertising packet describes the broadcasting device and its capabilities, but it is also capable of
including custom information — sensor data for instance — that you might want to broadcast.
Broadcasting data from your peripheral is a good choice if you’re building something like a weather station, where the
data isn’t sensitive. There is, however, no provision for security when broadcasting, so for personal data, the central
device should connect to the peripheral.
Connections are exclusive. This means that a peripheral cannot be connected to more than one central device at a time.
When a central device connects to a peripheral, the peripheral will stop advertising itself. Other devices will not be able
to see it, or connect to it, until the first connection is terminated. While a peripheral can only be connected to one central
device, a central device can be connected to more than peripheral at the same time.
If you need to exchange data between the peripheral and the central device, then you need to establish a connection
between the two devices.
There are two ways to advertise data using GAP: advertising data and scan response packets. While both packets use
the same payload format, and consist of up to 31 bytes of data, only the advertising data packet is mandatory. It is sent
out at a preset advertising interval; the longer the interval, the less power is used. On receipt, listening devices can
request the scan response packet with additional data if it exists. For instance, using custom advertisement data in the
broadcast packets is how Bluetooth beacon standards are implemented.
Once a connection with the peripheral has been made, you will use GATT services and characteristics to communicate
with the peripheral device, and advertising will stop until the connection is terminated.
Roles change when moving from GAP to GATT. GATT defines two roles: client and server.
It may seem counterintuitive, but peripheral devices are known as GATT Servers, while the (generally more powerful)
central devices are GATT Clients. Think of it this way. The server has data, and the client wants data. All connections
between the devices are started by the client.
After connecting the client, we can get a list of services offered by the server. Before connecting, the central device has
a potentially incomplete list of services from the advertising data.
Characteristics contain at least two attributes: a characteristic declaration which contains metadata about the data, and
the characteristic value which contains the data itself. The characteristic can also contain additional descriptors to
expand on the metadata. Together, the declaration, value and any optional descriptors form a bundle than make up a
characteristic.
Characteristics can be defined as read or write. Characteristics are read by the client using a read request, with the
returned value of the request being the characteristic value. Characteristic values can be written using a write request.
The server returns a confirmation after the value is written. There is an additional write property called write command.
When a characteristic value is written with a write command, the server does not send any response back to the client.
Write command is sometimes called write without response.
Two additional properties are notify and indicate. Both of these are server-initiated communication. A client subscribes
to be notified when a characteristic’s value changes. When a change occurs, the server notifies the client by sending the
new value. An indication is similar to a notification, except that the client must acknowledge the receipt of the
indication.
Characteristics can have multiple properties. For example one characteristic could allow read, write, write command,
and notify.
4.1.5. UUIDs
Bluetooth uses Universally Unique Identifiers (UUIDs) for many things including services and characteristics. Bluetooth
services that have been approved by the Bluetooth Special Interest Group are assigned 16-bit UUIDs. All other services
and characteristics must use 128-bit UUIDs. 128-bit UUIDs can be generated with tools such as uuidgen, e.g.
$ uuidgen
437121E5-A6F0-43F9-8F8F-4AB73D6CC3EB
It’s fine to reuse UUIDs if there are services and characteristics that meet your needs. If you’re making your own
services, use 128-bit UUIDs. See the Bluetooth developer site for more information.
Abbreviated instructions for installing the SDK and examples can be found in Section 2.1. For full instructions on how to
get started with the SDK, see the Getting started with Raspberry Pi Pico-series book.
NOTE
If you have not previously used an RP-series microcontroller-based board you can get started by reading Getting
started with Raspberry Pi Pico-series, while further details about the SDK, along with API-level documentation, can be
found in the Raspberry Pi Pico-series C/C++ SDK book.
WARNING
If you have not initialised the tinyusb submodule in your pico-sdk checkout, then USB CDC serial, and other USB
functions and example code, will not work, as the SDK will contain no USB functionality. Similarly, if you have not
initialised the cyw43-driver and lwip submodules in your checkout, then network- and bluetooth-related functionality
will not be enabled.
NOTE
Full details of supported Bluetooth protocols and profiles are Blue Kitchen BTStack Github repository.
1 PRIMARY_SERVICE, GAP_SERVICE
2 CHARACTERISTIC, GAP_DEVICE_NAME, READ, "picow_temp"
3
4 PRIMARY_SERVICE, GATT_SERVICE
5 CHARACTERISTIC, GATT_DATABASE_HASH, READ,
6
7 PRIMARY_SERVICE, ORG_BLUETOOTH_SERVICE_ENVIRONMENTAL_SENSING
8 CHARACTERISTIC, ORG_BLUETOOTH_CHARACTERISTIC_TEMPERATURE, READ | NOTIFY | INDICATE | DYNAMIC,
Along with other targets, we have now built two binaries called picow_ble_temp_sensor.uf2 and picow_ble_temp_reader.uf2,
which can be dragged onto the RP-series microcontroller USB mass-storage device.
The fastest method to load software onto an RP-series microcontroller-based board for the first time is by mounting it
as a USB mass-storage device. Doing this allows you to drag a file onto the board to program the flash memory. Go
ahead and connect the Pico W-series device to your Raspberry Pi using a micro-USB cable, making sure that you hold
down the BOOTSEL button as you do so, to force it into USB mass-storage mode.
If you are running the Raspberry Pi Desktop, the Pico W-series device should automatically mount as a USB mass-
storage device. From here, you can drag and drop the UF2 file onto the mass-storage device. RP-series microcontroller
will reboot, unmount itself as a mass-storage device, and start to run the flashed code.
If you connect to the Bluetooth device using a scanner application on your phone (see Figure 8), you should see a
service entry in the "Environmental Sensing" section. Beneath this, you’ll find a temperature section. You should be able
to read the temperature or subscribe for notifications when the temperature value changes.
Figure 8. The
picow_temp peripheral
in the Punch Through
LightBlue app;
advertising data (left),
services (middle), and
temperature service
(right).
The temperature will show up as a hexadecimal number, e.g. 0x4B0B. This number is a two-byte little-endian
representation of the temperature multiplied by 100. To get the value back in centigrade, you will need to flip this
representation to big-endian (e.g. 0x4B0B becomes 0x0B4B), convert the value to decimal (e.g. 0x0B4B becomes 2891), and
then divide by 100 to get the value in centigrade (here it would be 28.91°C).
NOTE
The examples in the pico-examples repository are taken from the Blue Kitchen Bluetooth stack examples.
By default, the Bluetooth examples are only built in one "mode" only (background, poll, or freertos), with the default being
background. This can be changed by passing a mode to CMake when building on the command line, e.g.
-DBTSTACK_EXAMPLE_TYPE=poll.
NOTE
Make sure you have the latest version of MicroPython installed, with Bluetooth support enabled. Until Bluetooth
functionality has been upstreamed, a pre-built binary will be available from the MicroPython section of the
documentation site.
MicroPython includes Bluetooth support for Pico W-series devices. A pre-built binary, which can be downloaded from
the MicroPython section of this documentation website, should serve most use cases and comes with micropython-lib
pre-integrated into the binary.
Pre-built Binary
A pre-built binary of the latest MicroPython firmware is available from the MicroPython section of the
Raspberry Pi documentation site. See Section 3.2 for instruction on installation.
NOTE
If you have not previously used an RP-series microcontroller-based board, begin by reading the Raspberry Pi Pico-
series Python SDK book.
NOTE
More information on using Bluetooth from MicroPython can be found online in the MicroPython documentation.
20 _ADV_TYPE_APPEARANCE = const(0x19)
21
22
23 # Generate a payload to be passed to gap_advertise(adv_data=...).
24 def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None,
appearance=0):
25 payload = bytearray()
26
27 def _append(adv_type, value):
28 nonlocal payload
29 payload += struct.pack("BB", len(value) + 1, adv_type) + value
30
31 _append(
32 _ADV_TYPE_FLAGS,
33 struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)),
34 )
35
36 if name:
37 _append(_ADV_TYPE_NAME, name)
38
39 if services:
40 for uuid in services:
41 b = bytes(uuid)
42 if len(b) == 2:
43 _append(_ADV_TYPE_UUID16_COMPLETE, b)
44 elif len(b) == 4:
45 _append(_ADV_TYPE_UUID32_COMPLETE, b)
46 elif len(b) == 16:
47 _append(_ADV_TYPE_UUID128_COMPLETE, b)
48
49 # See org.bluetooth.characteristic.gap.appearance.xml
50 if appearance:
51 _append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))
52
53 return payload
54
55
56 def decode_field(payload, adv_type):
57 i = 0
58 result = []
59 while i + 1 < len(payload):
60 if payload[i + 1] == adv_type:
61 result.append(payload[i + 2 : i + payload[i] + 1])
62 i += 1 + payload[i]
63 return result
64
65
66 def decode_name(payload):
67 n = decode_field(payload, _ADV_TYPE_NAME)
68 return str(n[0], "utf-8") if n else ""
69
70
71 def decode_services(payload):
72 services = []
73 for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE):
74 services.append(bluetooth.UUID(struct.unpack("<h", u)[0]))
75 for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE):
76 services.append(bluetooth.UUID(struct.unpack("<d", u)[0]))
77 for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE):
78 services.append(bluetooth.UUID(u))
79 return services
80
81
82 def demo():
83 payload = advertising_payload(
84 name="micropython",
85 services=[bluetooth.UUID(0x181A), bluetooth.UUID("6E400001-B5A3-F393-E0A9-
E50E24DCCA9E")],
86 )
87 print(payload)
88 print(decode_name(payload))
89 print(decode_services(payload))
90
91
92 if __name__ == "__main__":
93 demo()
Full details of supported Bluetooth protocols and profiles are Blue Kitchen BTStack GitHub repository.
32 _ENV_SENSE_UUID,
33 (_TEMP_CHAR,),
34 )
35
36 # org.bluetooth.characteristic.gap.appearance.xml
37 _ADV_APPEARANCE_GENERIC_THERMOMETER = const(768)
38
39 class BLETemperature:
40 def __init__(self, ble, name=""):
41 self._sensor_temp = machine.ADC(4)
42 self._ble = ble
43 self._ble.active(True)
44 self._ble.irq(self._irq)
45 ((self._handle,),) = self._ble.gatts_register_services((_ENV_SENSE_SERVICE,))
46 self._connections = set()
47 if len(name) == 0:
48 name = 'Pico %s' % ubinascii.hexlify(self._ble.config('mac')[1],':').decode
().upper()
49 print('Sensor name %s' % name)
50 self._payload = advertising_payload(
51 name=name, services=[_ENV_SENSE_UUID]
52 )
53 self._advertise()
54
55 def _irq(self, event, data):
56 # Track connections so we can send notifications.
57 if event == _IRQ_CENTRAL_CONNECT:
58 conn_handle, _, _ = data
59 self._connections.add(conn_handle)
60 elif event == _IRQ_CENTRAL_DISCONNECT:
61 conn_handle, _, _ = data
62 self._connections.remove(conn_handle)
63 # Start advertising again to allow a new connection.
64 self._advertise()
65 elif event == _IRQ_GATTS_INDICATE_DONE:
66 conn_handle, value_handle, status = data
67
68 def update_temperature(self, notify=False, indicate=False):
69 # Write the local value, ready for a central to read.
70 temp_deg_c = self._get_temp()
71 print("write temp %.2f degc" % temp_deg_c);
72 self._ble.gatts_write(self._handle, struct.pack("<h", int(temp_deg_c * 100)))
73 if notify or indicate:
74 for conn_handle in self._connections:
75 if notify:
76 # Notify connected centrals.
77 self._ble.gatts_notify(conn_handle, self._handle)
78 if indicate:
79 # Indicate connected centrals.
80 self._ble.gatts_indicate(conn_handle, self._handle)
81
82 def _advertise(self, interval_us=500000):
83 self._ble.gap_advertise(interval_us, adv_data=self._payload)
84
85 # ref https://github.com/raspberrypi/pico-micropython-
examples/blob/master/adc/temperature.py
86 def _get_temp(self):
87 conversion_factor = 3.3 / (65535)
88 reading = self._sensor_temp.read_u16() * conversion_factor
89
90 # The temperature sensor measures the Vbe voltage of a biased bipolar diode, connected
to the fifth ADC channel
91 # Typically, Vbe = 0.706V at 27 degrees C, with a slope of -1.721mV (0.001721) per
degree.
NOTE
The RP2040 temperature sensor measures the Vbe voltage of a biased bipolar diode, connected to the fifth ADC
channel. Typically, Vbe = 0.706V at 27°C, with a slope of -1.721mV (0.001721) per degree.
NOTE
If you connect to the Bluetooth device using a scanner application on your phone (see Figure 9) you should see a
service entry in the “Environmental sensing” section. Beneath this, there’s a temperature section. You should be able to
read the temperature or subscribe for notifications when the temperature value changes.
The temperature will show up as a hexadecimal number, e.g. 0x4B0B. This number is a two-byte, little-endian
representation of the temperature multiplied by 100. To get the value back in centigrade, you will need flip this
representation to big-endian (e.g. 0x4B0B becomes 0x0B4B), convert the value to decimal (e.g. 0x0B4B becomes 2891),
and then divide by 100 to get the value in centigrade (here it would be 28.91°C).
1 # This example finds and connects to a BLE temperature sensor (e.g. the one in
ble_temperature.py).
2
3 import bluetooth
4 import random
5 import struct
6 import time
7 import micropython
8 from ble_advertising import decode_services, decode_name
9 from micropython import const
10 from machine import Pin
11
12 _IRQ_CENTRAL_CONNECT = const(1)
13 _IRQ_CENTRAL_DISCONNECT = const(2)
14 _IRQ_GATTS_WRITE = const(3)
15 _IRQ_GATTS_READ_REQUEST = const(4)
16 _IRQ_SCAN_RESULT = const(5)
17 _IRQ_SCAN_DONE = const(6)
18 _IRQ_PERIPHERAL_CONNECT = const(7)
19 _IRQ_PERIPHERAL_DISCONNECT = const(8)
20 _IRQ_GATTC_SERVICE_RESULT = const(9)
21 _IRQ_GATTC_SERVICE_DONE = const(10)
22 _IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
23 _IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
24 _IRQ_GATTC_DESCRIPTOR_RESULT = const(13)
25 _IRQ_GATTC_DESCRIPTOR_DONE = const(14)
26 _IRQ_GATTC_READ_RESULT = const(15)
27 _IRQ_GATTC_READ_DONE = const(16)
28 _IRQ_GATTC_WRITE_DONE = const(17)
29 _IRQ_GATTC_NOTIFY = const(18)
30 _IRQ_GATTC_INDICATE = const(19)
31
32 _ADV_IND = const(0x00)
33 _ADV_DIRECT_IND = const(0x01)
34 _ADV_SCAN_IND = const(0x02)
35 _ADV_NONCONN_IND = const(0x03)
36
37 # org.bluetooth.service.environmental_sensing
38 _ENV_SENSE_UUID = bluetooth.UUID(0x181A)
39 # org.bluetooth.characteristic.temperature
40 _TEMP_UUID = bluetooth.UUID(0x2A6E)
41 _TEMP_CHAR = (
42 _TEMP_UUID,
43 bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,
44 )
45 _ENV_SENSE_SERVICE = (
46 _ENV_SENSE_UUID,
47 (_TEMP_CHAR,),
48 )
49
50 class BLETemperatureCentral:
51 def __init__(self, ble):
52 self._ble = ble
53 self._ble.active(True)
54 self._ble.irq(self._irq)
55 self._reset()
56 self._led = Pin('LED', Pin.OUT)
57
58 def _reset(self):
59 # Cached name and address from a successful scan.
60 self._name = None
61 self._addr_type = None
62 self._addr = None
63
64 # Cached value (if we have one)
65 self._value = None
66
67 # Callbacks for completion of various operations.
68 # These reset back to None after being invoked.
69 self._scan_callback = None
70 self._conn_callback = None
71 self._read_callback = None
72
73 # Persistent callback for when new data is notified from the device.
74 self._notify_callback = None
75
76 # Connected device.
77 self._conn_handle = None
78 self._start_handle = None
79 self._end_handle = None
80 self._value_handle = None
81
82 def _irq(self, event, data):
83 if event == _IRQ_SCAN_RESULT:
84 addr_type, addr, adv_type, rssi, adv_data = data
85 if adv_type in (_ADV_IND, _ADV_DIRECT_IND):
86 type_list = decode_services(adv_data)
87 if _ENV_SENSE_UUID in type_list:
88 # Found a potential device, remember it and stop scanning.
89 self._addr_type = addr_type
90 self._addr = bytes(addr) # Note: addr buffer is owned by caller so need
to copy it.
91 self._name = decode_name(adv_data) or "?"
92 self._ble.gap_scan(None)
93
94 elif event == _IRQ_SCAN_DONE:
95 if self._scan_callback:
96 if self._addr:
97 # Found a device during the scan (and the scan was explicitly stopped).
98 self._scan_callback(self._addr_type, self._addr, self._name)
99 self._scan_callback = None
100 else:
101 # Scan timed out.
102 self._scan_callback(None, None, None)
103
104 elif event == _IRQ_PERIPHERAL_CONNECT:
105 # Connect successful.
106 conn_handle, addr_type, addr = data
107 if addr_type == self._addr_type and addr == self._addr:
108 self._conn_handle = conn_handle
109 self._ble.gattc_discover_services(self._conn_handle)
110
111 elif event == _IRQ_PERIPHERAL_DISCONNECT:
112 # Disconnect (either initiated by us or the remote end).
113 conn_handle, _, _ = data
114 if conn_handle == self._conn_handle:
115 # If it was initiated by us, it'll already be reset.
116 self._reset()
117
NOTE
Copy ble_advertising.py and picow_ble_temp_reader.py to a second Raspberry Pi Pico W. It should start running, and the
on-board LED will flash briefly once repeatedly if it can’t find a device to connect to. Once it finds another device running
the picow_ble_temp_sensor.py, it will repeatedly flash twice, quickly, when it is connected and reading the temperature over
Bluetooth.
$ mkdir pico_w
$ cd pico_w
$ git clone https://github.com/micropython/micropython.git --branch master
$ git clone https://github.com/micropython/micropython-lib.git --branch master
NOTE
Putting micropython-lib side-by-side with your MicroPython checkout will mean that it is automatically pulled into
your MicroPython build, and libraries in micropython-lib will be "pre-added" to the list of modules available by default
on your Pico W-series device.
$ cd micropython
$ make -C ports/rp2 BOARD=PICO_W submodules
$ make -C mpy-cross
$ cd ports/rp2
$ make BOARD=PICO_W
If everything went well, there will be a new directory called build-PICO_W (that’s ports/rp2/build-PICO_W relative to the top-
level micropython directory), which contains the new firmware binaries. Drag and drop the firmware.uf2 onto the RPI-RP2
drive that pops up once your Pico W-series device enters BOOTSEL mode.
25 November 2024
• Added support for Pico 2 W.
• Switched back to separate release histories per PDF.
02 Feb 2024
• Corrected minor typos and formatting issues.
• Updated ROSC register information.
14 Jun 2023
• Corrected minor typos and formatting issues.
• Updated for the 1.5.1 release of the Raspberry Pi Pico C SDK.
• Added Pico W Bluetooth usage instructions.
03 Mar 2023
• Corrected even more typos and formatting issues.
• Updated for the 1.5.0 release of the Raspberry Pi Pico C SDK.
• Added a wireless networking example to the Python documentation.
01 Dec 2022
• Corrected various typos and formatting issues.
• Replaced SDK library documentation with links to the online version.
30 Jun 2022
• Initial release.
25 November 2024 46
Connecting to the Internet with Raspberry Pi Pico W-series.
30 Jun 2022 47
Connecting to the Internet with Raspberry Pi Pico W-series.
30 Jun 2022 48