Перейти к содержанию

Протокол прошивки и диагностика

Для установки, подключения проводов и обычной работы используйте руководство по настройке. Этот справочник описывает прошивку C3 и протокол связи с компьютером.

Индикация сопряжения и диагностика без внешних светодиодов

Таблица показывает каждый режим на трёх внешних светодиодах и на встроенном, поэтому плату можно диагностировать и без внешних светодиодов. Настроенный встроенный светодиод — одноцветный, на GPIO8, с активным низким уровнем; он кодирует цвета сессий числом импульсов, а не сменой цвета. Светодиод описан в руководстве производителя SuperMini, а справочник Apache NuttX для SuperMini описывает полярность GPIO8 и его роль при выборе режима загрузки. Варианты плат различаются: эта сборка не определяет, установлен ли светодиод. Отдельным индикатором питания прошивка не управляет. GPIO8 управляется только после обычной загрузки; не добавляйте внешнюю цепь, которая тянет этот вывод выбора режима загрузки к низкому уровню при сбросе.

Режим / условие Внешние красный/жёлтый/зелёный светодиоды Встроенный светодиод
startup: первые три секунды после инициализации прошивки Все три плавно загораются и гаснут вместе: два цикла по 1,5 секунды Такие же изменения яркости с максимумом 32/255
preview: ползунок яркости подключённой лампы Все три непрерывно светят с процентом предпросмотра; возврат к статусу через две секунды после последнего предпросмотра Тот же процент применяется к базовому уровню 32/255
identify: Identify на подключённой лампе Красный → жёлтый → зелёный три раза, по одному светодиоду, 100 мс на светодиод (всего 0,9 секунды); приложение запрашивает 100% Один импульс 40 мс на шаг при 32/255, масштабированный запрошенным процентом
connected: первая корректная запись статуса (N, R, Y или G) в каждом BLE-соединении; вспышка пропускается во время индикации запуска, после разрыва соединения со статусом или при прерывании затухания по тайм-ауту Все три включаются один раз на 250 мс Включается на те же 250 мс с яркостью 32/255
status: свежий R, Y или G Соответствующий светодиод горит постоянно Повторяющиеся группы: зелёный — один, жёлтый — два, красный — три импульса по 100 мс с интервалом 250 мс; одна группа каждые три секунды при 32/255
status: свежий N Выключены Выключен
fading: подтверждённый разрыв BLE при отображении статуса или пять секунд без корректных BLE-обновлений При разрыве сразу начинается затухание текущего цвета и яркости до нуля за три секунды. При открытом соединении: пять секунд без изменения цвета, пять секунд затухания, полностью выключено к десятой секунде. Последовательный статус гаснет за 700 мс после тайм-аута Гаснет вместе с цветом, если уже горел; новые импульсы не начинаются
pairing: окно открыто, свежего статуса нет Красный → жёлтый → зелёный, по 250 мс на шаг Один импульс 100 мс на шаг при 32/255
unpaired: на плате нет ключей сопряжения, окно закрыто, свежего статуса нет Все три одну секунду включены, одну выключены Тот же ритм при 32/255
waiting: на плате есть ключи сопряжения, BLE отключён, окно закрыто, свежего статуса нет Выключены Выключен
stale: BLE подключён, свежего статуса нет, и либо идёт восстановление после разрыва, либо подтверждённый статус просрочен, либо на плате есть ключи сопряжения и окно закрыто Выключены Выключен

Значения заполнения выше указаны при 100% яркости лампы. Сохранённая настройка масштабирует все управляемые выходы, включая индикацию запуска, подключения; предпросмотр временно использует процент ползунка, а Identify — запрошенный процент (100% из приложения). При 0% управляемые светодиоды не светятся. См. управление яркостью.

Прошивка выбирает первый подходящий режим в таком порядке:

  1. Плавная индикация запуска: один раз при загрузке, три секунды. Обработка статуса и сопряжения продолжается в фоне.
  2. Identify или предпросмотр: при подтверждённом аутентифицированном соединении и свежем статусе. Отключение, потеря аутентификации или устаревание статуса отменяют их.
  3. Вспышка подключения: 250 мс после первой корректной записи статуса в соединении. Если эта запись пришла во время индикации запуска, вспышки нет: запуск уже показал, что питание есть. Последующие записи N/R/Y/G обновляют сохранённый статус, не отменяя и не перезапуская вспышку. Отключение, потеря аутентификации или истечение срока статуса отменяют её, поэтому даже задержанная первая запись не продлит свечение за десятисекундный срок устаревания.
  4. Затухание: подтверждённый разрыв BLE сразу запускает одно затухание текущего цвета статуса и яркости за три секунды. Диагностика уже показывает state=N. Само переподключение не восстанавливает статус и не перезапускает затухание. Свежий корректный статус отменяет затухание и показывает последний цвет с настроенной яркостью; N оставляет лампу выключенной. При восстановлении вспышка подключения пропускается, даже если затухание уже завершилось. Цвета из очереди до разрыва отбрасываются; подтверждённый N по-прежнему может выключить лампу. Если соединение не разорвано, но не получает корректных обновлений, статус сохраняется пять секунд, затем плавно гаснет ещё пять секунд до полного выключения к десятой секунде. Логический статус сохраняется до этого срока. Затухание не меняет настройку яркости и начинается с текущего уровня, ограниченного настроенной яркостью, даже если уменьшение яркости пришло одновременно с началом затухания. Выключенный статус, предпросмотр и вспышка подключения не запускают затухание. Отсчёт идёт от исходного разрыва или срока статуса, поэтому задержка основного цикла не воспроизводит завершившееся затухание заново.
  5. Свежий статус, включая команды по последовательному порту и N.
  6. stale при восстановлении без свежего статуса или подтверждённом соединении с просроченным статусом, даже если окно сопряжения ещё открыто.
  7. pairing, затем unpaired, затем stale (соединение есть), затем waiting.

Для BLE затухание по тайм-ауту занимает вторую половину срока устаревания.

Выходы используют восьмибитный PWM с частотой 2 кГц. В platformio.ini LED_RED_PIN=0, LED_YELLOW_PIN=1 и LED_GREEN_PIN=3 задают выводы внешних светодиодов (GPIO0..10, кроме 2, 8 и 9), а STATUS_TIMEOUT_MS=10000 — тайм-аут устаревания (больше 2000 мс). BUILTIN_LED_PIN=8 и BUILTIN_LED_ACTIVE_LOW=1 выбирают обычный встроенный светодиод; установите номер вывода -1, чтобы отключить этот выход на другой плате. BUILTIN_LED_BRIGHTNESS=32 задаёт обычные импульсы встроенного светодиода. В режиме ожидания все четыре выхода остаются выключенными. После изменения параметров пересоберите прошивку и запишите её на идентифицированную плату; значения PWM — заданные уровни заполнения, а не измеренная яркость.

При подключённом последовательном USB-интерфейсе прошивка выводит такие строки:

  • При загрузке: gatt_change_manual=<0|1> result=<n>, затем lamp=BroGlow C3 XXXX security=sc-bonded button=BOOT.
  • pairing=open duration_ms=60000 и pairing=closed.
  • authentication=ok reason=0 или authentication=failed reason=<n>, где n — код ошибки Bluetooth SMP.
  • bond_reset=requested count=<n> или bond_reset=error после удержания BOOT 10 секунд. requested означает, что удаление запрошено, а не подтверждено.

Запрос ?\n возвращает диагностическую строку, даже когда лампой управляет BLE.

Задайте BOARD_PORT для идентифицированной платы, как в разделе сборка и определение платы. Порт может открыть только одна программа. Если BroGlow передаёт статус на эту плату по USB, выполните broglow ble off и подождите три секунды (broglow ble on вернёт управление); закройте broglow led, запущенный вручную, и другие мониторы порта. Запускайте из каталога исходников или корня распакованного пакета:

uv run --frozen python - "$BOARD_PORT" <<'PY'
import sys
import time
import serial

with serial.Serial(sys.argv[1], 115200, timeout=0.5, write_timeout=2) as port:
    port.rts = False
    port.dtr = True
    time.sleep(0.3)
    port.reset_input_buffer()
    port.write(b"?\n")
    port.flush()
    until = time.monotonic() + 3
    while time.monotonic() < until:
        line = port.readline().decode(errors="replace").strip()
        if line:
            print(line)
        if line.startswith("state="):
            break
PY

Строка сообщает сохранённое состояние сессии state, заданные флаги включения red/yellow/green, owner, connected, authenticated, pairing, bonds, age_ms (время с последнего принятого статуса; до первого — время работы платы) и число принятых корректных статусов accepted. Она также сообщает mode, red_pwm, yellow_pwm, green_pwm, builtin_pwm, builtin_pin и brightness (текущий процент; не сохраняется и после перезагрузки снова равен 100). Последние четыре поля — gatt_change_manual, gatt_change_requests, gatt_change_request и gatt_change_result — относятся к проверке кеша GATT. При mode=preview или mode=identify заполнение использует временный запрошенный процент; поле brightness и сохранённое состояние сессии state продолжают описывать основные настройки.

Флаги включения означают ненулевое заданное заполнение PWM, а не чтение состояния вывода. Значения PWM — заполнение 0..255 после масштабирования яркости и до инверсии активного низкого уровня встроенного светодиода, поэтому state=N может сочетаться с ненулевым заполнением при запуске, предпросмотре, Identify, настройке или вспышке подключения. authenticated=1 означает, что BLE-соединение получило зашифрованный доступ; age_ms и accepted помогают проверить доставку обновлений раз в две секунды. Ни одно из этих полей не подтверждает проводку, ток или видимый свет. После диагностики перейдите на питание только от блока, если проверяете работу без USB-соединения для данных.

Для настройки точная команда INFO\n (или CRLF) возвращает идентификатор, не меняя сопряжение, светодиоды или состояние тайм-аута. PAIR\n открывает или продлевает окно и возвращает тот же идентификатор; она не удаляет ключи сопряжения и не отключает текущее центральное устройство. CLI отправляет INFO перед PAIR. Пример ответа (идентификатор зависит от платы):

broglow_pair identity=001122334455 service=7d2ea28a-f7bd-485a-bd9d-92ad6ecfe93e

Эти команды настройки работают и при управлении светодиодами через BLE. Объявляемый идентификатор — шесть байтов базового MAC, а не потенциально меняющийся приватный Bluetooth-адрес в эфире.

Контракт BLE и поведение прошивки

Параметр Значение
Имя BroGlow <label> после переименования; иначе BroGlow C3 и суффикс платы из четырёх шестнадцатеричных цифр
Объявление Полный UUID сервиса и данные производителя: 0xffff, затем шесть байтов базового MAC (тот же идентификатор, что в INFO)
UUID сервиса 7d2ea28a-f7bd-485a-bd9d-92ad6ecfe93e
Характеристика записи статуса 7d2ea28b-f7bd-485a-bd9d-92ad6ecfe93e
Характеристика записи яркости 7d2ea28c-f7bd-485a-bd9d-92ad6ecfe93e
Характеристика записи имени 7d2ea28d-f7bd-485a-bd9d-92ad6ecfe93e
Операция GATT Запись с ответом
Данные статуса Ровно один ASCII-байт: R, Y, G или N; без перевода строки
Данные яркости Ровно один бинарный байт, процент 0..100; не ASCII-цифры. По умолчанию на плате 100; значение сбрасывается при перезапуске.
Данные предпросмотра В той же зашифрованной характеристике яркости: два бинарных байта [percent, 1], где percent — 0..100. Временно переопределяет все управляемые источники света на две секунды с момента получения; сохранённую яркость не меняет.
Данные Identify В той же зашифрованной характеристике яркости: два бинарных байта [percent, 2], где percent — 0..100. Три прохода красный → жёлтый → зелёный по 100 мс на светодиод (0,9 секунды с момента получения), затем возврат последнего статуса и сохранённой яркости. Приложение отправляет [100, 2]; настройки не меняются.
Данные имени 1..21 байт UTF-8 метки без префикса BroGlow и управляющих символов; один байт 0x00 возвращает заводское имя. Полное Bluetooth-имя помещается в поле имени scan response размером 29 байт.
Период обновлений компьютера Две секунды
Тайм-аут устаревания платы Десять секунд с последнего корректного статуса; BLE сохраняет цвет пять секунд и плавно гасит его следующие пять, достигая полного выключения и логического состояния N к десятой секунде. Последовательный статус гаснет за 700 мс после десяти секунд. Затем индикация следует состоянию соединения и сопряжений
Подтверждённый разрыв BLE Сразу сбрасывает BLE-статус в N и плавно гасит текущий цвет статуса и яркость до нуля за три секунды; для восстановления нужен свежий корректный статус, вспышка подключения пропускается
Владение управлением Подключённый BLE-клиент; последовательный порт — только при отключённом BLE
Безопасность Сопряжение LE Secure Connections Just Works; все характеристики записи требуют шифрования. Новое сопряжение допускается только при открытом окне сопряжения.
Окно сопряжения 60 секунд. Открывается при загрузке, если на плате нет ключей сопряжения, командой PAIR по последовательному порту или удержанием BOOT (GPIO9) три секунды после обычной загрузки. Удержание BOOT десять секунд запрашивает удаление всех ключей сопряжения и снова открывает окно. См. сопряжение без USB-кабеля для данных.

После обнаружения компьютер записывает яркость до начальной записи N или статуса, поэтому прошивка использует сохранённый уровень для первой индикации подключения. Последующие изменения процента передаются через существующее соединение.

Характеристика имени получает сохранённую метку при подключении и изменении, без отключения лампы. Прошивка обновляет GAP-имя устройства и имя в scan response, сохраняет изменённую метку в NVS; повторное имя не записывает флеш-память. Пустая запись игнорируется; только 0x00 очищает имя. Неверный UTF-8, управляющие символы и слишком длинные метки игнорируются. Запросы старого соединения отбрасываются; подтверждённый запрос текущего поколения переживает отключение. Имя не продлевает статус сессии и не меняет ключи сопряжения или идентификатор производителя. Ошибка хранения выводит name=save_failed в последовательный порт, ошибка GAP-имени — name=apply_failed. Ответ GATT на запись сам по себе не доказывает сохранение или обновление настроек macOS. Для обновления кешированного имени на Mac может потребоваться переподключение.

Интерфейс ограничивает частоту изменений предпросмотра примерно одним за 80 мс и обновляет удерживаемый указатель каждые 500 мс. Identify отправляет один запрос для выбранной подключённой лампы. Компьютер хранит только последнее событие для конкретной лампы (или запроса ко всем лампам) в течение двух секунд как для предпросмотра, так и для Identify. Каждое соединение использует более новое подходящее событие для конкретной лампы или всех ламп; адресный запрос не может повлиять на другую лампу. Обычные обновления статуса не продлевают ни один из режимов. Прошивка отбрасывает просроченный запрос или запрос от предыдущего соединения.

Пустые и многобайтовые данные статуса, неизвестные байты статуса, яркость выше 100 и данные яркости, отличные от одного байта, [percent, 1] или [percent, 2], игнорируются. Яркость, предпросмотр и Identify не обновляют тайм-аут статуса. Ответ GATT на запись подтверждает только получение. Все изменения GPIO и решения о тайм-аутах выполняются в основном цикле. Отключение возобновляет BLE-объявления.

Кеш GATT после обновления прошивки

После обновления прошивки, меняющего сервисы GATT, сопряжённый Mac может использовать их кеш. Прошивка запрашивает индикацию Service Changed для подключающегося устройства из ESP_GATTS_CONNECT_EVT через BLEDevice::setCustomGattsHandler и публичный API esp_ble_gatts_send_service_change_indication(gatts_if, remote_bda) (см. API Espressif GATTS и отправку индикации и установку режима в IDF 4.4.7). Это должно вызвать повторное обнаружение с сохранением существующего сопряжения.

Как проверить: gatt_change_manual=1 при загрузке и в ответе ? подтверждает, что прошивка может отправить индикацию; gatt_change_requests — число подключений, запросивших индикацию; gatt_change_request=0 означает, что индикация поставлена в очередь; gatt_change_result — статус отправки от стека (-1, пока его нет). Ни одно из этих полей не доказывает, что macOS обновила кеш. Не удаляйте ключи сопряжения как обычный шаг обновления.