BLE-связь между Raspberry Pi и Raspberry Pi Pico W
В этом руководстве объясняется, как настроить связь по Bluetooth Low Energy (BLE) между Raspberry Pi и Pico W. Мы начнём с рассмотрения основ BLE, включая роли центрального (Central) и периферийного (Peripheral) устройств. После этого мы рассмотрим два простых примера, в которых Pico отправляет данные на Pi.
Впервые работаете с Raspberry Pi Pico? Изучите Raspberry Pi Pico/Pico W с MicroPython с помощью нашей электронной книги
Это руководство было написано Edgardo Peregrino и отредактировано Sara Santos.
Предварительные требования
Вот список предварительных требований для этого руководства.
1) Плата Raspberry Pi
Вам нужна плата Raspberry Pi с Bluetooth. Можно использовать следующие модели: Pi 3, 3B+, 3A+, 4, 400, 5, 500, Zero W, Zero 2W, CM4 и CM5. При использовании модулей CM4 и CM5 убедитесь, что они включают модуль WiFi/Bluetooth.
1.1) Raspberry Pi OS
С точки зрения программного обеспечения вы можете использовать как Raspberry Pi OS Desktop, так и Raspberry Pi OS Lite. Мы используем 64-битную версию.
Чтобы узнать, как установить операционную систему, вы можете ознакомиться с этим руководством: :doc:`Установка Raspberry Pi OS, настройка Wi-Fi, включение и подключение по SSH </raspberry/rnt/installing-raspbian-lite-enabling-and-connecting-with-ssh/index>`_.
1.2) Терминал и SSH
Вы также должны иметь некоторое представление о терминале, особенно поскольку вам потребуется включить службу Bluetooth через терминал и установить необходимые пакеты.
Мы будем использовать программу PuTTY для установки SSH-подключения к плате RPi и выполнения команд в окне терминала.
Мы рекомендуем следовать следующему руководству, если вы не знакомы с установкой Raspberry Pi OS или подключением через SSH с помощью PuTTY:
2) Плата Raspberry Pi Pico
Вам нужна плата Raspberry Pi Pico с Bluetooth. Вы можете использовать Raspberry Pi Pico W или Raspberry Pi Pico 2 W.
2.1) Thonny IDE
Для программирования Raspberry Pi Pico мы предпочитаем использовать Thonny IDE. Убедитесь, что на вашей плате установлена последняя версия прошивки MicroPython. Мы рекомендуем быстро ознакомиться со следующими руководствами, чтобы узнать, как использовать Thonny IDE, как прошить MicroPython и как запускать и загружать код на плату:
Основы BLE или Bluetooth Low Energy
Прежде чем начать, мы должны обсудить основы BLE или Bluetooth Low Energy. BLE — это протокол, который отличается от Bluetooth Classic.
Bluetooth Classic предназначен для непрерывной потоковой передачи данных, например, для воспроизведения музыки на беспроводной колонке. В отличие от него, Bluetooth Low Energy (BLE) оптимизирован для устройств и датчиков, что делает его подходящим для Pico W и моделей Raspberry Pi со встроенным Bluetooth.
BLE потребляет значительно меньше энергии, чем Bluetooth Classic, что делает его идеальным для микроконтроллеров и небольших устройств, хотя у него более короткий радиус действия. Ещё одно ключевое отличие заключается в способе подключения: Bluetooth Classic использует последовательную (Serial) связь, в то время как BLE опирается на протокол GATT (Generic Attribute Profile).
Для более полного введения в BLE и основных понятий, таких как периферийное устройство и контроллер, UUID, профили GATT и других, мы рекомендуем прочитать вводную часть этого руководства: :doc:`Raspberry Pi Pico W: Bluetooth Low Energy (BLE) с MicroPython </raspberry/pico/raspberry-pi-pico-w-bluetooth-low-energy-micropython/index>`_.
Обзор проекта
При использовании Bluetooth Low Energy (BLE) важно понимать роли BLE Peripheral и BLE Controller (также называемого Central Device — центральным устройством).
В данном случае (в примерах, рассматриваемых в этом руководстве) Raspberry Pi будет центральным устройством (Central), а Pico будет периферийным устройством (Peripheral).
Pico настраивает профиль GATT для обеспечения связи с Raspberry Pi. После подключения он «отправляет» сообщение на Pi, которое затем отображается в терминале. Такая конфигурация может быть полезна для проектов, например, использования Pico в качестве контроллера для робота на базе Raspberry Pi.
Примечание: Слово «отправляет» взято в кавычки, потому что Pico на самом деле не отправляет данные на Pi напрямую. Вместо этого Pico записывает значение в характеристику (characteristic) своего профиля GATT. Raspberry Pi, который подключён к Pico по BLE, затем считывает эту характеристику для получения данных.
Ниже приведён пример того, что мы будем делать в этом проекте.
Периферийное устройство BLE (сервер) объявляет о своём присутствии (advertise).
Центральное устройство BLE (клиент) сканирует BLE-устройства.
Когда центральное устройство находит нужное периферийное устройство, оно подключается к нему.
После подключения оно считывает профиль GATT периферийного устройства и ищет нужный сервис.
Если сервис найден, оно может взаимодействовать с характеристиками. Например, считывать значения.
В BLE каждый сервис и характеристика должны иметь UUID (Universally Unique Identifier — универсально уникальный идентификатор). Эти UUID выступают в качестве уникальных адресов, которые Raspberry Pi использует для нахождения и подключения к сервисам Pico. Например, если Pico предоставляет сервис с характеристиками чтения и записи, каждая из них будет иметь свой UUID. Pi ищет эти UUID, чтобы знать, как взаимодействовать с ними.
Для более полного введения в BLE и основных понятий, таких как периферийное устройство и контроллер, UUID, профиль GATT и других, мы рекомендуем прочитать вводную часть этого руководства: :doc:`Raspberry Pi Pico W: Bluetooth Low Energy (BLE) с MicroPython </raspberry/pico/raspberry-pi-pico-w-bluetooth-low-energy-micropython/index>`_.
Необходимые компоненты
Вот список компонентов, необходимых для этого руководства:
Raspberry Pi (мы используем Raspberry Pi 5)
1x Светодиод
1x Резистор 220 Ом (или аналогичный номинал)
Вы можете использовать приведённые выше ссылки или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!
Подготовка Raspberry Pi
После начала работы со свежей установкой Raspberry Pi OS на вашей плате RPi, вам необходимо следовать следующим инструкциям, чтобы включить Bluetooth на Pi и установить некоторые необходимые пакеты.
Включение Bluetooth на Pi
Если вы используете версию Pi OS с рабочим столом, включить Bluetooth очень просто. Перейдите к значку Bluetooth и нажмите Make Discoverable. Вот и всё, вы готовы к работе.
Если вы используете Lite-версию или находитесь в SSH-сессии, мы будем использовать команды для включения Bluetooth. Установите SSH-подключение к вашему Pi.
Введите следующую команду:
sudo systemctl start bluetooth
После этого выполните следующие команды по порядку:
sudo bluetoothctl
agent on
default-agent
Эти команды необходимы для включения Bluetooth. Когда всё будет готово, вы можете выйти, набрав exit.
exit
Установка pigpio
Поскольку мы также будем управлять GPIO Pi, нам нужен пакет для их управления. Мы будем использовать pigpio. Выполните следующие команды для его глобальной установки и включения при загрузке.
sudo apt install pigpio
sudo systemctl enable pigpiod
Создание виртуального окружения
Мы создадим виртуальное окружение, которое использует общесистемные пакеты, такие как pigpio (я делаю это таким образом вместо установки внутри виртуального окружения, потому что обнаружил некоторые проблемы с управлением GPIO при использовании Raspberry Pi 5).
Во-первых, мы рекомендуем создать отдельную директорию, чтобы ваши файлы были организованы. Если вы используете версию Desktop, в идеале вам следует перейти в директорию Documents и создать там директорию. Например, вы можете назвать её bluetooth_samples.
Если вы используете Lite-версию, вы можете создать директорию bluetooth_samples и затем перейти в неё следующим образом:
mkdir bluetooth_samples && cd bluetooth_samples
Теперь вы должны находиться в папке bluetooth_samples.
Теперь создайте виртуальное окружение с именем blue в этой директории.
python3 -m venv blue --system-site-packages
Активируйте виртуальное окружение следующим образом:
source blue/bin/activate
Вы поймёте, что оно активно, потому что имя виртуального окружения появится перед приглашением командной строки.
Установка Bleak
Для Raspberry Pi нам нужно установить BLE-библиотеку, которая будет взаимодействовать с Pico, — она называется Bleak. Установите библиотеку в виртуальном окружении:
pip install bleak
Она должна установиться через несколько секунд.
Схема подключения Raspberry Pi
В случае Raspberry Pi для нашего примера понадобится светодиод, подключённый к GPIO 17. Вы можете следовать следующей схеме подключения.
Здесь мы подключаем длинную ножку светодиода к GPIO-контакту 17 — это будет наш светодиод для проверки правильной работы кода. Короткая ножка светодиода подключается к резистору, а провод заземления — к отрицательной шине макетной платы, где расположен резистор.
Pico будет установлен на макетной плате просто из практических соображений, и на этом подключение завершено. Если хотите, вам не обязательно устанавливать Pico на макетную плату.
Отправка базового сообщения с Pico на Pi
В этом разделе мы покажем вам простой код MicroPython, который будет использоваться на Pico для «отправки» сообщений на Raspberry Pi.
Вы можете назвать его ble_sample.py. Позже вы можете загрузить его на Pico как main.py, чтобы он запускался без подключения к компьютеру.
Впервые работаете с BLE на Raspberry Pi Pico? Вы можете прочитать наше руководство для начинающих: :doc:`Raspberry Pi Pico W: Bluetooth Low Energy (BLE) с MicroPython </raspberry/pico/raspberry-pi-pico-w-bluetooth-low-energy-micropython/index>`_.
Скопируйте следующий код в Thonny IDE.
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/ble-raspberry-pi-and-pi-pico-w/
import asyncio
import aioble
import bluetooth
from machine import Pin
# Bluetooth configuration
_SERVICE_UUID = bluetooth.UUID(0x1848)
_WRITE_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6E) # Central writes here
_READ_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6F) # Peripheral writes message here
BLE_NAME = "Pico W Peripheral"
# Initialize LED
led = Pin("LED", Pin.OUT)
connected = False
# Register GATT server
ble_service = aioble.Service(_SERVICE_UUID)
read_characteristic = aioble.Characteristic(
ble_service, _READ_CHARACTERISTIC_UUID, read=True, notify=True
)
aioble.register_services(ble_service)
# Helper to encode the message
def _encode_message(message):
return message.encode('utf-8')
# Task to handle LED blinking and message sending
async def send_task():
global connected
message_count = 1
while True:
led.toggle()
blink = 1000 if connected else 250
if connected:
message = f"Hello from {BLE_NAME}! Count: {message_count}"
read_characteristic.write(_encode_message(message), send_update=True)
message_count += 1
print(f"Sent: {message}")
await asyncio.sleep_ms(blink)
# Serially wait for connections
async def peripheral_task():
global connected
# Show MAC address once at start
ble = bluetooth.BLE()
_, mac_address = ble.config('mac')
formatted_mac = ':'.join('{:02X}'.format(b) for b in mac_address)
print(f"Bluetooth MAC Address: {formatted_mac}")
while True:
try:
async with await aioble.advertise(
2000, name=BLE_NAME, services=[_SERVICE_UUID], appearance=768
) as connection:
connected = True
print("Connection from", connection.device)
await connection.disconnected()
except Exception as e:
print("Error in peripheral_task:", e)
finally:
connected = False
print(f"{BLE_NAME} disconnected")
await asyncio.sleep_ms(100)
# Run both tasks
async def main():
t1 = asyncio.create_task(send_task())
t2 = asyncio.create_task(peripheral_task())
await asyncio.gather(t1, t2)
# Run the program
asyncio.run(main())
Как работает код?
Давайте разберём этот код для лучшего понимания.
Импорт библиотек
Сначала мы импортируем библиотеки, как показано ниже.
import asyncio
import aioble
import bluetooth
from machine import Pin
Определение UUID
Далее нам нужно определить UUID для Pico. Нам нужны UUID для сервиса, характеристик записи и чтения.
# Bluetooth configuration
_SERVICE_UUID = bluetooth.UUID(0x1848)
_WRITE_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6E) # Central writes here
_READ_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6F) # Peripheral writes message here
Имя BLE
Мы определяем имя для нашего BLE-устройства Raspberry Pi Pico. Вы можете дать ему любое другое имя.
BLE_NAME = "Pico W Peripheral"
Инициализация светодиода
Следующая строка инициализирует встроенный светодиод RPi Pico как GPIO-выход с именем led.
# Initialize LED
led = Pin("LED", Pin.OUT)
Переменная connected
Переменная connected будет использоваться для отслеживания того, подключён ли Pico к другому BLE-устройству.
connected = False
Регистрация сервиса и характеристики
Затем регистрируем GATT-сервис и характеристику.
# Register GATT server
ble_service = aioble.Service(_SERVICE_UUID)
read_characteristic = aioble.Characteristic(
ble_service, _READ_CHARACTERISTIC_UUID, read=True, notify=True
)
aioble.register_services(ble_service)
Кодирование BLE-сообщения
Сообщение, отправляемое по BLE, будет закодировано в UTF-8. Следующая функция encode_message() делает именно это.
# Helper to encode the message
def _encode_message(message):
return message.encode('utf-8')
Запись в характеристику — функция send_task()
Функция send_task() «отправляет» сообщение на Raspberry Pi после подключения. Она также заставляет встроенный светодиод Raspberry Pi Pico мигать каждую секунду при подключении. Если не подключён, светодиод будет мигать быстрее — каждые 250 миллисекунд.
async def send_task():
global connected
message_count = 1
while True:
led.toggle()
blink = 1000 if connected else 250
if connected:
message = f"Hello from {BLE_NAME}! Count: {message_count}"
read_characteristic.write(_encode_message(message), send_update=True)
message_count += 1
print(f"Sent: {message}")
await asyncio.sleep_ms(blink)
Новое сообщение отправляется каждую секунду. Мы добавляем счётчик к сообщению, чтобы отслеживать, сколько сообщений было отправлено.
message = f"Hello from {BLE_NAME}! Count: {message_count}"
Это строка, которая «отправляет» новое сообщение.
read_characteristic.write(_encode_message(message), send_update=True)
Счётчик message_count увеличивается в каждом цикле.
message_count += 1
Обратите внимание, что send_task — это асинхронная функция. Для работы с BLE лучше использовать асинхронное программирование, чтобы избежать проблем с таймингом. Если вы хотите узнать больше об асинхронном программировании с Raspberry Pi Pico на MicroPython, мы рекомендуем следующее руководство:
Объявление Pico как BLE-сервиса — peripheral_task()
Помимо записи в характеристику температуры, нам также нужно объявить Raspberry Pi Pico как BLE-сервис. Для этого мы используем функцию peripheral_task(), которая настраивает Pico как периферийное устройство и начинает объявление (advertising).
Мы также получаем и выводим MAC-адрес Pico — он понадобится нам позже на стороне Raspberry Pi для подключения к Pico.
# Serially wait for connections
async def peripheral_task():
global connected
# Show MAC address once at start
ble = bluetooth.BLE()
_, mac_address = ble.config('mac')
formatted_mac = ':'.join('{:02X}'.format(b) for b in mac_address)
print(f"Bluetooth MAC Address: {formatted_mac}")
while True:
try:
async with await aioble.advertise(
2000, name=BLE_NAME, services=[_SERVICE_UUID], appearance=768
) as connection:
connected = True
print("Connection from", connection.device)
await connection.disconnected()
except Exception as e:
print("Error in peripheral_task:", e)
finally:
connected = False
print(f"{BLE_NAME} disconnected")
await asyncio.sleep_ms(100)
Главная функция
Наконец, мы создаём асинхронную функцию main(), в которой напишем основу нашего кода. Мы создаём две асинхронные задачи: одну для объявления и другую для отправки новых сообщений каждую секунду и мигания встроенного светодиода. Затем мы собираем и запускаем задачи асинхронно, вызывая функцию main().
# Run both tasks
async def main():
t1 = asyncio.create_task(send_task())
t2 = asyncio.create_task(peripheral_task())
await asyncio.gather(t1, t2)
# Run the program
asyncio.run(main())
Запуск кода
Запустите код на Pico, нажав зелёную кнопку воспроизведения в Thonny или нажав F5 на клавиатуре. После выполнения он отобразит MAC-адрес Pico.
Raspberry Pi — Приём сообщений от RPi Pico
На Raspberry Pi создайте новый файл с кодом ниже. Вы можете назвать его pi_led_receive.py. Файл должен находиться внутри папки, которую мы создали ранее, — bluetooth_samples — в том же месте, где мы создали наше виртуальное окружение.
Существует множество способов создания и запуска файлов на Pi. Мне нравится использовать :doc:`Remote-SSH в VS Code </raspberry/rnt/raspberry-pi-remote-ssh-vs-code/index>`_. Это расширение позволяет установить SSH-подключение к вашему Pi, создавать файлы, писать код и выполнять его непосредственно на вашей плате Raspberry Pi с вашего компьютера через интерфейс VS Code. Узнайте больше здесь: :doc:`Программирование Raspberry Pi удалённо с помощью VS Code (Remote-SSH) </raspberry/rnt/raspberry-pi-remote-ssh-vs-code/index>`_.
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/ble-raspberry-pi-and-pi-pico-w/
import asyncio
from bleak import BleakClient, uuids
from gpiozero import LED
connected = False
led = LED(17)
# Replace with the MAC address of your Pico
pico_address = "FF:FF:FF:FF:FF:FF"
# Service UUID (0x1848)
SERVICE_UUID = uuids.normalize_uuid_16(0x1848)
WRITE_CHARACTERISTIC_UUID = uuids.normalize_uuid_16(0x2A6E) # Central writes here
READ_CHARACTERISTIC_UUID = uuids.normalize_uuid_16(0x2A6F) # Central reads here
async def receive_data_task(client):
"""Receive data from the peripheral device."""
while True:
try:
response = await client.read_gatt_char(READ_CHARACTERISTIC_UUID)
print(f"Central received: {response.decode('utf-8')}")
await asyncio.sleep(1)
except Exception as e:
print(f"Error receiving data: {e}")
break
async def blink_task():
global connected
print("blink task started")
while True:
led.toggle()
blink = 1000 if connected else 250
await asyncio.sleep(blink / 1000)
async def connect_and_communicate(address):
global connected
"""Connect to the peripheral and manage data exchange."""
print(f"Connecting to {address}...")
async with BleakClient(address) as client:
connected = client.is_connected
print(f"Connected: {connected}")
# Create tasks for sending and receiving data
tasks = [
asyncio.create_task(receive_data_task(client)),
asyncio.create_task(blink_task())
]
await asyncio.gather(*tasks)
connected = False
# Run the connection and communication
loop = asyncio.get_event_loop()
loop.run_until_complete(connect_and_communicate(pico_address))
Перед запуском кода вам нужно изменить следующую строку, указав Bluetooth MAC-адрес Pico. Вы должны были получить его в предыдущем примере.
# Replace with the MAC address of your Pico
pico_address = "2C:CF:67:B6:D7:4C"
Как работает код?
Давайте теперь быстро рассмотрим код, чтобы понять, как он работает.
Сначала импортируем необходимые библиотеки. Мы подключаем bleak для Bluetooth-функций.
import asyncio
from bleak import BleakClient, uuids
from gpiozero import LED
У нас есть булева переменная для отслеживания того, подключены ли мы к другому Bluetooth-периферийному устройству или нет.
connected = False
Мы определяем UUID сервиса и характеристик. Это сервис и характеристики Pico, которые мы будем искать для чтения сообщения, отправленного с Pico. Поэтому они должны совпадать с UUID на Pico.
# Service UUID (0x1848)
SERVICE_UUID = uuids.normalize_uuid_16(0x1848)
WRITE_CHARACTERISTIC_UUID = uuids.normalize_uuid_16(0x2A6E) # Central writes here
READ_CHARACTERISTIC_UUID = uuids.normalize_uuid_16(0x2A6F) # Central reads here
Затем у нас есть асинхронная функция receive_data_task(), которая ожидает чтения значения характеристики периферийного устройства. Она читает характеристику каждую секунду.
async def receive_data_task(client):
"""Receive data from the peripheral device."""
while True:
try:
response = await client.read_gatt_char(READ_CHARACTERISTIC_UUID)
print(f"Central received: {response.decode('utf-8')}")
await asyncio.sleep(1)
except Exception as e:
print(f"Error receiving data: {e}")
break
У нас есть ещё одна задача — blink_task(), которая будет выполняться одновременно. Эта задача будет мигать светодиодом, подключённым к GPIO 17 на Raspberry Pi. Она будет выполняться каждую секунду, если мы подключены к периферийному устройству.
async def blink_task():
global connected
print("blink task started")
while True:
led.toggle()
blink = 1000 if connected else 250
await asyncio.sleep(blink / 1000)
Наконец, функция connect_and_communicate() пытается подключиться к периферийному устройству с MAC-адресом, который мы определили ранее. После подключения мы создаём и собираем задачи для приёма данных и мигания светодиода.
async def connect_and_communicate(address):
global connected
"""Connect to the peripheral and manage data exchange."""
print(f"Connecting to {address}...")
async with BleakClient(address) as client:
connected = client.is_connected
print(f"Connected: {connected}")
# Create tasks for sending and receiving data
tasks = [
asyncio.create_task(receive_data_task(client)),
asyncio.create_task(blink_task())
]
await asyncio.gather(*tasks)
connected = False
Наконец, мы асинхронно запускаем задачи в цикле.
# Run the connection and communication
loop = asyncio.get_event_loop()
loop.run_until_complete(connect_and_communicate(pico_address))
Запуск Python-кода
После создания файла pi_led_receive.py с кодом, которым мы поделились ранее, и указания MAC-адреса вашего Pico, вы можете запустить его на вашей плате Raspberry Pi. Мы используем :doc:`расширение Remote-SSH в VS Code </raspberry/rnt/raspberry-pi-remote-ssh-vs-code/index>`_, но вы можете просто создать новый файл с помощью команды nano.
После сохранения файла вы можете запустить его. Но сначала убедитесь, что вы находитесь в виртуальном окружении, которое мы создали ранее. Если вы вышли из виртуального окружения, вы можете активировать его снова следующим образом:
source blue/bin/activate
Наконец, вы можете запустить вашу Python-программу следующим образом:
python3 pi_led_receive.py
Демонстрация
Код начнёт выполняться, и через несколько секунд подключится к Raspberry Pi Pico (убедитесь, что RPi Pico выполняет код в Thonny IDE).
Он начнёт получать сообщения от Pico.
В то же время светодиод, подключённый к GPIO 17, начнёт мигать каждую секунду.
Вот и всё. Теперь Raspberry Pi считывает данные с Raspberry Pi Pico по BLE.
Вы также можете проверить отправленные сообщения в консоли Thonny IDE.
Отправка текущего времени с Pico на Pi
Вместо отправки бессмысленного сообщения мы можем легко изменить код для отправки показаний датчиков или команд, например. В этом разделе мы покажем вам, как можно легко изменить предыдущий пример для отправки других данных. В данном случае мы будем отправлять текущее время с Pico на Pi.
Код для Pi останется прежним. Для Pico нам нужно внести небольшие изменения. Вот код для Pico.
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/ble-raspberry-pi-and-pi-pico-w/
import asyncio
import aioble
import bluetooth
from machine import Pin
import time
# Bluetooth configuration
_SERVICE_UUID = bluetooth.UUID(0x1848)
_WRITE_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6E) # Central writes here
_READ_CHARACTERISTIC_UUID = bluetooth.UUID(0x2A6F) # Peripheral writes message here
BLE_NAME = "Pico W Peripheral"
# Initialize LED
led = Pin("LED", Pin.OUT)
connected = False
# Register GATT server
ble_service = aioble.Service(_SERVICE_UUID)
read_characteristic = aioble.Characteristic(
ble_service, _READ_CHARACTERISTIC_UUID, read=True, notify=True
)
aioble.register_services(ble_service)
# Helper to encode the message
def _encode_message(message):
return message.encode('utf-8')
# Task to handle LED blinking and message sending
async def send_task():
global connected
while True:
led.toggle()
blink = 1000 if connected else 250
if connected:
today = time.localtime() # get the current time
message = f"{today}"
read_characteristic.write(_encode_message(message), send_update=True)
print(f"Sent: {message}")
await asyncio.sleep_ms(blink)
# Serially wait for connections
async def peripheral_task():
global connected
# Show MAC address once at start
ble = bluetooth.BLE()
_, mac_address = ble.config('mac')
formatted_mac = ':'.join('{:02X}'.format(b) for b in mac_address)
print(f"Bluetooth MAC Address: {formatted_mac}")
while True:
try:
async with await aioble.advertise(
2000, name=BLE_NAME, services=[_SERVICE_UUID], appearance=768
) as connection:
connected = True
print("Connection from", connection.device)
await connection.disconnected()
except Exception as e:
print("Error in peripheral_task:", e)
finally:
connected = False
print(f"{BLE_NAME} disconnected")
await asyncio.sleep_ms(100)
# Run both tasks
async def main():
t1 = asyncio.create_task(send_task())
t2 = asyncio.create_task(peripheral_task())
await asyncio.gather(t1, t2)
# Run the program
asyncio.run(main())
Сначала нам нужно добавить библиотеку для работы со временем.
import time
Затем нам нужно изменить функцию send_task(). По сути, после подключения мы получаем текущее время и сохраняем его в переменной today.
today = time.localtime()
Текущее время будет нашим сообщением.
message = f"{today}"
Затем мы просто записываем текущее время в характеристику следующим образом:
read_characteristic.write(encode_message(message), send_update=True)
Теперь легко понять, что вы можете легко изменить код для отправки любых других полезных данных, таких как показания датчиков или команды для управления выходами, например.
Демонстрация
На стороне Raspberry Pi соединение должно было разорваться с Pico, когда вы запустили этот новый код. Вам нужно снова запустить Python-код на Raspberry Pi сразу после запуска кода на Pico.
Через некоторое время устройства подключатся и начнут отправку сообщений.
На стороне Raspberry Pi он будет получать время, отправленное с Pico. Временная метка должна отображаться в окне терминала.
Заключение
В этом руководстве мы изучили основы BLE и узнали, как настроить Pi для взаимодействия с Pico.
Мы планируем создать больше руководств на эту тему. В частности, рассмотреть двунаправленную связь, чтобы оба устройства могли отправлять и получать данные одновременно.
А пока вот несколько задач, если вы хотите развить этот пример дальше:
Организуйте чтение Pi значений :doc:`внутреннего датчика температуры Pico </raspberry/pico/raspberry-pi-pico-internal-temperature-micropython/index>`_.
Добавьте к Pico внешний датчик температуры, такой как :doc:`BME280 </raspberry/pico/raspberry-pi-pico-bme280-micropython/index>`_, и организуйте чтение Pi значений температуры.
Для дополнительного задания добавьте I2C-дисплей LCD на Pi для отображения температуры вместо простого вывода значений в терминал.
Надеемся, вы нашли это руководство полезным.
Особая благодарность нашему читателю Edgardo Peregrino, который создал и написал макет этого руководства, а также примеры кода.
Edgardo Peregrino — автор книг «Programming Raspberry Pi in 30 Days» и «Cloud Powered Robotics with Raspberry Pi», а также автор нескольких статей, особенно в журнале Servo Magazine. Вы можете ознакомиться с его работами на его странице GitHub или YouTube-канале (LinuxRobotGeek).
Узнайте больше о Raspberry Pi Pico и Raspberry Pi:
Спасибо за чтение.