Проверяем мост Matter в Apple Home без железа: только ПК и телефон

Пока платы в пути: ПК с Windows в роли шлюза и телефон с nRF Connect в роли Bluetooth-устройства. Сопряжение, управление и обратная связь в Apple Home.

В прошлой статье я описал общий план: поставить между нашими Bluetooth-устройствами и Apple Home шлюз Matter, который переводит сообщения в обе стороны.

На бумаге планы всегда выглядят гладко. Прежде чем браться за железо, я хотел сначала проверить одну вещь: примет ли Apple Home шлюз, написанный нами самими, и сможет ли управлять Bluetooth-устройствами за ним?

Для этого вопроса железо не нужно. Отладочные платы ещё ехали по почте, поэтому я взял то, что было под рукой, — ПК на Windows и телефон — и прогнал всю цепочку от начала до конца.

Сначала софт, потом железо

В железных проектах так и тянет начать с покупки плат, пайки модулей и прошивки. Но цепочка длинная, и потом трудно понять, на каком уровне что-то сломалось: не прошло сопряжение по Matter, баг в шлюзе, последовательный канал теряет байты или просто слабый Bluetooth-сигнал?

Если сначала отладить два верхних уровня на чистом софте, то когда появится настоящее железо, область поиска ошибки сократится. А обходится это почти даром: хватит компьютера и телефона.

Кто какую роль играет

Роль В реальном продукте В этом демо
Контроллер Apple Home Apple Home (настоящий)
Шлюз Плата на Linux + Bluetooth-модуль ПК на Windows со встроенным Bluetooth
Bluetooth-устройство Выключатели и лампы Телефон с nRF Connect

Apple Home здесь настоящий, и программа шлюза — та же самая, что поедет в продукт. Телефоном подменено только Bluetooth-устройство на самом нижнем уровне.

nRF Connect — бесплатное приложение от Nordic для отладки Bluetooth на Android и iPhone. Оно умеет сканировать рекламные пакеты поблизости и рассылать свои, так что как заглушка для устройства подходит отлично.

Почему не эмулировать устройство Bluetooth Mesh напрямую?

В реальном продукте устройства и шлюз общаются по SIG Mesh. Но телефон не может выступать устройством Mesh: ни Android, ни iOS не позволяют приложениям становиться узлом сети Mesh. Приложения вроде nRF Mesh умеют только добавлять устройства в сеть и работать как пульты.

Поэтому в демо используется вариант попроще: устройство и шлюз обмениваются обычными Bluetooth-рекламными пакетами. Чтобы включить свет, шлюз рассылает «включить»; когда состояние устройства меняется, оно рассылает это обратно шлюзу.

В таком формате нет ни шифрования, ни защиты от повторной отправки. Он нужен только для проверки цепочки и в продукт не попадёт. Его ценность в том, что в шлюзе всё, кроме самого нижнего коммуникационного уровня, настоящее: сопряжение по Matter, таблица устройств, трансляция команд и синхронизация состояния.

Формат рекламного пакета в демо

Чем проще формат, тем лучше: его должно быть можно набрать руками в приложении на телефоне.

Шлюз → устройство (downlink): одна запись Manufacturer Data с Company ID 0xFFFF. Этот ID Bluetooth SIG зарезервировал для тестов, и в реальных продуктах его использовать нельзя.

Байты Содержимое Пример
1–2 Константа GW 47 57
3–4 Адрес устройства, little-endian 02 00 означает 0002
5 Состояние вкл/выкл 01 — включено, 00 — выключено
6 Порядковый номер, +1 при каждой отправке 05

Устройство → шлюз (uplink): один формат для Android, другой для iPhone.

  • Android: тоже Manufacturer Data, Company ID 0xFFFF, данные 4456020001. 4456 — это DV, 0200 — адрес 0002, а последний 01 означает «включено».
  • iPhone: iOS не позволяет приложениям класть в рекламный пакет произвольные данные производителя, можно лишь менять имя устройства. Поэтому имя задаётся как DV0002:1: адрес 0002, включено.

Разбор на стороне шлюза занимает всего несколько строк и понимает оба формата:

pub fn uplink(sections: &[(u8, Vec<u8>)]) -> Option<(u16, bool)> {
    sections.iter().find_map(|(t, d)| match (*t, d.as_slice()) {
        // Android: данные производителя FF FF 'D' 'V' адрес состояние
        (0xFF, [0xFF, 0xFF, b'D', b'V', a0, a1, on, ..]) => {
            Some((u16::from_le_bytes([*a0, *a1]), *on != 0))
        }
        // iPhone: имя устройства DV0002:1
        (0x08 | 0x09, name) => {
            let s = std::str::from_utf8(name).ok()?.strip_prefix("DV")?;
            let (addr, on) = s.split_once(':')?;
            Some((u16::from_str_radix(addr, 16).ok()?, match on {
                "1" => true,
                "0" => false,
                _ => return None,
            }))
        }
        _ => None,
    })
}

Программа шлюза

Шлюз написан на Rust, а для Matter используется открытая библиотека rs-matter. Bluetooth на ПК работает через встроенные API Windows, так что дополнительные драйверы не нужны.

После запуска программа делает три вещи:

  1. Работает как шлюз Matter: объявляет себя в локальной сети и ждёт, пока Apple Home выполнит сопряжение. Если сопряжения ещё не было, QR-код для него печатается прямо в терминале.
  2. Ведёт таблицу устройств: команда add 0002 Свет в гостиной в терминале добавляет лампу. Каждое устройство отображается в Matter как отдельное устройство за мостом.
  3. Отправляет и принимает рекламные пакеты: команды из Apple Home превращаются в downlink-пакеты; uplink-пакеты с телефона обновляют состояние, которое синхронизируется обратно в Apple Home.

Таблица устройств и данные сопряжения сохраняются в локальные файлы, поэтому после перезапуска программы сопрягать заново не нужно.

Добавляем в Apple Home

Отсканируйте QR-код из терминала приложением «Дом» на iPhone. На что стоит обратить внимание:

  • Вы увидите предупреждение «Несертифицированный аксессуар». На время разработки шлюз использует официальные тестовые сертификаты Matter, которые не прошли сертификацию, поэтому iOS и предупреждает. Выберите «Все равно добавить». Серийным устройствам нужны настоящие сертификаты, выдаваемые после сертификации.
  • ПК и iPhone должны быть в одной локальной сети, а брандмауэр Windows должен разрешать программе принимать и отправлять сетевой трафик. Если сопряжение завершается по таймауту, проверьте это в первую очередь.
  • Нужен домашний хаб. Чтобы управлять аксессуарами Matter, Apple Home требуется HomePod или Apple TV в роли домашнего хаба.

После добавления Apple Home покажет шлюз, за которым стоят «Свет в гостиной» и «Свет в кабинете»; каждый из них можно отнести к своей комнате, как любую другую лампу.

  1. Откройте на телефоне nRF Connect и перейдите на вкладку Scanner.
  2. Нажмите «Свет в гостиной» в Apple Home.
  3. В терминале на ПК появится BLE TX -> 0002, и шлюз в течение секунды будет рассылать команду.
  4. В списке сканирования nRF Connect появится новое устройство с данными производителя 0xFFFF и 4757 0200 01 xx, что читается как «шлюз сообщает: устройство 0002, включить».

ПК может использовать для каждого рекламного пакета новый Bluetooth-адрес. Если в списке его трудно заметить, отфильтруйте по данным производителя или по уровню сигнала.

  1. В nRF Connect создайте новый рекламный пакет (Advertiser). На Android введите данные производителя 0xFFFF / 4456020001; на iPhone задайте имя устройства DV0002:1.
  2. Запустите рассылку.
  3. В терминале на ПК появится BLE RX <- 0002 (Свет в гостиной): ON.
  4. В Apple Home лампа «Свет в гостиной» отображается как включённая.

Так имитируется нажатие выключателя на стене. Это даже важнее, чем downlink: если состояние устройства не может вернуться обратно, то картина в Apple Home не будет соответствовать реальности.

Грабли по дороге

Ничего сложного тут нет, но на некоторых местах с первого раза легко застрять.

1. Рекламный пакет с телефона снова включал свет. Телефон без конца повторяет один и тот же пакет. Сначала шлюз обновлял состояние при каждом принятом пакете, так что после выключения лампы в Apple Home «включено» от телефона через секунду возвращало её обратно. Решение: засчитывать отчёт, только если его содержимое изменилось. Настоящим устройствам нужно то же самое: повторяющиеся сообщения необходимо отсеивать.

2. iPhone кладёт имя устройства в scan response. Когда iPhone рассылает рекламу, имя устройства находится не в первом рекламном пакете, а в scan response. Пассивное сканирование, которое ПК использует по умолчанию, его не видит; нужно сканировать активно.

3. Устройства нельзя различать по Bluetooth-адресу. Телефоны и ПК рекламируются со случайными адресами, которые периодически меняются. Поэтому идентификатор устройства переносится внутрь рекламного пакета, в те самые два байта адреса. Это согласуется с тем, как устроен Mesh: устройства Mesh опознаются по назначенному unicast-адресу, а не по MAC.

4. Несколько рекламных пакетов одновременно мешают друг другу в Windows. Если нажать несколько ламп подряд, рассылки запускались одновременно и перезаписывали друг друга. Помогла очередь: пакеты отправляются по одному.

5. Рассылка блокировала Matter. Каждая рекламная рассылка в Windows должна какое-то время работать. Если вызывать её прямо в цикле обработки Matter, все остальные команды от Apple Home всё это время ждут. Поэтому рассылку вынесли в отдельный поток.

6. Смена производителя и модели шлюза не требует повторного сопряжения. Apple Home считывает эти данные со шлюза и подхватывает новые значения после перезапуска. Но он их кэширует, и когда именно обновит — неизвестно. Если изменение нужно увидеть сразу, удалите шлюз и добавьте заново, но помните: вместе со шлюзом удаляются и все устройства за ним.

Кстати, свежесобранная программа поначалу получилась довольно крупной. С оптимизацией по размеру и без отладочных символов релизная сборка занимает около 2,3 МБ, что легко помещается на плату шлюза.

Что доказывает демо

Доказано:

  • Написанный нами шлюз распознаётся и сопрягается в Apple Home.
  • Устройства за мостом можно по отдельности включать и выключать в Apple Home.
  • Работают и команды downlink, и состояние uplink.
  • После добавления или удаления устройств, а также после перезапуска при обрыве связи Apple Home остаётся синхронизированным.

Пока не доказано:

  • Настоящее добавление в сеть, шифрование и работа сети Bluetooth Mesh.
  • Совместная работа модуля Silicon Labs и устройств Telink.
  • Работа на плате шлюза с Linux.
  • Поведение, когда одновременно в сети десятки или сотни устройств.

Иными словами, половина Matter проверена; половина Bluetooth Mesh должна дождаться настоящего железа. Следующий шаг — заменить обычные рекламные пакеты на ПК Bluetooth-модулем, подключённым по последовательному порту. В программе шлюза это просто другой адаптерный слой.

Напоследок

Главный выигрыш этого шага в том, что до трат на железо подтвердилось самое важное: Apple Home принимает этот шлюз. Что бы ни пошло не так дальше, уровень Matter хотя бы больше не под подозрением.

Если вы делаете похожий шлюз или хотите заставить Matter работать ещё до появления железа, буду рад пообщаться. Подробности кода и набитые шишки — всё можно обсуждать: linktr.ee/weiyii

Сейчас я довожу демо-код до небольшой версии, которую выложу в открытый доступ. Как только она появится, добавлю ссылку в эту статью.

Чтение и отправка через WeChat

QR-код статьи

Отсканируйте и поделитесь через меню WeChat.