ESP32 Bluetooth Classic: связь со смартфоном без WiFi
ESP32 редкий чип, у которого WiFi и Bluetooth живут в одном корпусе. Bluetooth Classic даёт профиль SPP, то есть прозрачный серийный канал, и по сути заменяет модуль HC-05 вместе с проводами. Дальность по классу 2 составляет примерно 10-15 метров.
Приложение на телефоне не нужно: достаточно любого Bluetooth-терминала. На стороне ESP32 ставится библиотека BluetoothSerial, а на стороне Arduino скетч читает символы из SerialBT точно так же, как из обычного Serial.
Bluetooth-радио в симуляторе не работает, это эфир, а не пины. Каркас с проверкой SerialBT.available и SerialBT.read отрабатывается через Serial Monitor: код тот же, источник данных только подменяется.
Какие платы ESP32 поддерживают Classic
Поддержка Bluetooth Classic есть не у всех плат ESP32. У оригинального ESP32 с модулем ESP-WROOM-32 есть и Classic, и BLE. У ESP32-S3 есть оба режима. У ESP32-S2 Bluetooth нет вообще, только WiFi. У ESP32-C3 и ESP32-H2 есть только BLE. Это не настройка, а разница в кремнии, и перед покупкой платы стоит проверить datasheet именно вашей модели.
Библиотека BluetoothSerial.h входит в стандартный пакет поддержки ESP32 для Arduino IDE, отдельно её ставить не нужно. Имя устройства задаётся в SerialBT.begin("ESP32_Arsenal"), пин-код по умолчанию 1234, при необходимости его можно задать вторым аргументом. Подробнее про ESP32 и его пины — в лендинге распиновки.
Простейший Bluetooth-терминал
#include "BluetoothSerial.h"BluetoothSerial SerialBT;void setup() { Serial.begin(115200); SerialBT.begin("ESP32_Arsenal"); Serial.println("Готово. Подключитесь через Bluetooth Terminal");}void loop() { if (SerialBT.available()) { char c = SerialBT.read(); Serial.print("Получено: "); Serial.println(c); if (c == '1') digitalWrite(2, HIGH); else if (c == '0') digitalWrite(2, LOW); } delay(20);}Со смартфона в приложении Bluetooth Terminal отправляем символы «1» и «0», и встроенный светодиод на пине 2 зажигается. Тот же приём символов через программный UART разобран в каркасе SoftwareSerial для Uno.
Грабль с парным сопряжением: если телефон уже спарен с другим ESP32, новое сопряжение может не пройти, и устройство не появится в списке. Лечится удалением старой пары в настройках Bluetooth телефона и перезагрузкой платы. Вторая частая проблема: приложение подключается, но ничего не приходит, потому что в коде забыли SerialBT.begin, и Bluetooth вообще не поднят.
Третий момент: Bluetooth и WiFi на ESP32 умеют работать одновременно, но делят антенну и полосу 2.4 ГГц. Если в проекте постоянно гоняется поток по WiFi, задержки в Bluetooth-связи вырастают. Для проекта, где важна предсказуемая задержка в командах, лучше держать что-то одно.
BLE это другой протокол, с Bluetooth Classic они несовместимы. В BLE обмен идёт через GATT-сервисы и характеристики, и обычный телефонный терминал с ними не работает, нужно специальное приложение. Для управления платой с телефона Classic заметно проще, а для датчиков на батарейке BLE экономнее. На ESP32 доступны оба режима одновременно, но стек BLE занимает десятки килобайт ОЗУ, что важно при сборке тяжёлых проектов.
| Параметр | ESP32 BT Classic | HC-05 модуль |
|---|---|---|
| Чип | Встроенный в ESP32 | Внешний модуль BC417 |
| Профиль | SPP (Serial) | SPP (Serial) |
| Дальность | 10-15 м (Class 2) | 10 м (Class 2) |
| Парные | 1 активное | 1 активное |
| BLE | + одновременно с Classic | Нет |
Что сначала не получилось
Первый заход с телефоном закончился ничем: в списке Bluetooth устройство не появлялось. Я переустанавливал приложение, перезагружал плату и даже менял телефон. Причина была в том, что я держал кнопку EN на плате, и она постоянно сбрасывала ESP32, так что Bluetooth просто не успевал подняться.
Второй раз устройство появилось, но не подключалось. Тогда выяснилось, что на плате уже стоял Classic, но приложение пыталось подключиться по BLE: в списке BLE-устройств ESP32 не было, и я поставил галку в поиске Bluetooth рядом, а не в поиске BLE. Третий затык был с пин-кодом: телефон помнил старый пин-код от прошлой прошивки, где я его менял, и pairing падал.
Личный опыт: выключатель света с телефона
Первое устройство на ESP32 Bluetooth Classic было выключателем света: плата в коридоре, реле на лампе, а с телефона я включал и выключал свет. Связь держалась через одну бетонную стену и была устойчивой, задержка от нажатия до срабатывания реле получалась в пределах сотни миллисекунд и глазом не замечалась.
Состояние я держал в памяти RTC и дублировал его ответом в Serial, поэтому каждый переход можно было проверить по журналу. Именно так я поймал свою ошибку: команда «0» иногда срабатывала дважды, потому что приложение отправляло символ и по нажатию, и по отпусканию. В скетче я добавил учёт последней команды, чтобы игнорировать повтор, и после этого ложных срабатываний не осталось.
SerialBT и Serial в одном скетче
Отладка Bluetooth-проекта становится спокойнее, если в одном скетче живут сразу два канала. Serial остаётся подключённым к USB и печатает всё, что пришло из Bluetooth, а сам Bluetooth обслуживает отдельные команды. Так вы видите, что именно прилетело с телефона, и можете слать в телефон ответы через SerialBT.print. Для управления выключателем этого достаточно: телефон отправляет символ, плата отвечает строкой с текущим состоянием, и приложение сразу показывает, что команда прошла.
Держите в скетче счётчик команд и печатайте его раз в минуту. Он показывает, живёт ли связь на самом деле: если счётчик перестал расти, значит пакеты перестали доходить, и это видно раньше, чем пользователь пожалуется, что «ничего не работает». Для проектов, где важна отзывчивость, добавьте в SerialBT команду ping и ответ pong: задержка ответа будет точно измерена в миллисекундах.
Что ещё важно знать про BluetoothSerial
Внутри BluetoothSerial работает кольцевой буфер, и это объясняет две особенности. Первая: если приложение отправляет пачку символов быстрее, чем скетч успевает читать, часть данных теряется. Лечится чтением всех доступных байтов подряд и проверкой available() в цикле, а не по одному символу за проход. Вторая: у BluetoothSerial есть свой таймаут, и если в SerialBT буфер никто не читает, соединение может закрыться. Для проектов, где телефон молчит долго, вызывайте SerialBT.setTimeout с большим значением, иначе плата будет периодически терять сопряжение.
Второе ограничение касается скорости. Bluetooth Classic даёт по радио до 2-3 Мбит/с, но полезная скорость через BluetoothSerial на ESP32 ограничена самой платформой и объёмом данных в одном пакете. На практике для команд это десятки байт в секунду, а для потока с датчиков лучше уходить на WiFi или MQTT, а Bluetooth оставить для управления и настройки.
Авторская позиция: что взять новичку
Если проект умещается в один ESP32, берите ESP32 и не покупайте HC-05: отдельный модуль, провода, SoftwareSerial и лишние грабли с TX и RX исчезают сами. Новичку стоит начать с примера из библиотеки BluetoothSerial и убедиться, что телефон видит устройство, а уже потом писать свой протокол. Если задача про энергопотребление, смотрите в сторону BLE, а если про универсальность, то в сторону WiFi и MQTT. И всегда удаляйте старые пары перед проверкой новой прошивки: это снимает половину вопросов, почему устройство не подключается.