Умный дом
March 1

Приручаем Zigbee: история с прыгающим USB-портом

Привет всем любителям умных технологий! Сегодня я хочу поделиться своей историей, которая началась с фразы: «Купил Zigbee-свисток — теперь всё будет работать как часы!» А закончилась она тем, что я, вооружившись скриптами и терпением, боролся с устройством, которое решило стать путешественником, постоянно меняя свой USB-порт.

Вводная: Zigbee-свисток на чипе CC2652P1, популярная (на момент написания статьи) коробочка под названием "Домашний центр МТС" и операционная система OpenLumi 23.05.5 r24106-10cc5fcd00.

Всё начиналось так радужно. Свисток работал безупречно, устройства общались друг с другом через Zigbee, и казалось, что мир IoT просто идеален. Но, как говорится, не всё то золото, что блестит. Однажды я заглянул в логи системы с помощью команды `dmesg` и обнаружил настоящий хаос:

[ 4639.074555] usb 1-1: USB disconnect, device number 2
[ 4639.077916] usb 1-1: failed to send control message: -19
[ 4639.078533] ch341-uart ttyUSB0: ch341-uart converter now disconnected from ttyUSB0
[ 4639.078741] ch341 1-1:1.0: device disconnected
[ 4639.492366] usb 1-1: new full-speed USB device number 3 using ci_hdrc
[ 4639.704270] ch341 1-1:1.0: ch341-uart converter detected
[ 4639.713477] usb 1-1: ch341-uart converter now attached to ttyUSB1
[ 6976.352845] usb 1-1: USB disconnect, device number 3
[ 6976.356782] usb 1-1: failed to send control message: -19
[ 6976.357383] ch341-uart ttyUSB1: ch341-uart converter now disconnected from ttyUSB1
[ 6976.357592] ch341 1-1:1.0: device disconnected
[ 6976.766100] usb 1-1: new full-speed USB device number 4 using ci_hdrc
[ 6976.976850] ch341 1-1:1.0: ch341-uart converter detected
[ 6976.987230] usb 1-1: ch341-uart converter now attached to ttyUSB0

«Ну дела», — подумал я. Оказалось, что устройство то на ttyUSB0, то на ttyUSB1, а потом снова возвращается на ttyUSB0… Прям игра в прятки! Первым делом я обратился к сообществу. «Меняй блок питания!» — посоветовали мне. Хорошо, поменял. Не помогло. Тогда я отключил энергосбережение USB. Результат? Устройство всё равно продолжало «прыгать».

Экспериментальным путём я выяснил, что если указать новый порт в настройках homed-zigbee, то всё работает… до следующего «переселения».

И тут меня осенило: «Если безобразие нельзя прекратить, то его нужно возглавить!» Взял SSH-клиент (можно использовать знаменитый Putty, но я предпочитаю использовать MobaXterm) и начал действовать.


Шаг 1: Создаём скрипт-сторож

Создадим папку `/root/scripts` и в ней файл `find_port.sh`:

#!/bin/sh

# Получаем вывод команды dmesg и ищем строки, содержащие нужную фразу
# Затем берем последнюю такую строку
last_line=$(dmesg | grep "ch341-uart converter now attached to ttyUSB" | tail -n 1)

# Извлекаем имя порта из строки с помощью sed
port=$(echo "$last_line" | sed -n 's/.*\(ttyUSB[0-9]\+\).*/\1/p')

# Если порт не найден, выходим с ошибкой
[ -z "$port" ] && { echo "Не удалось извлечь имя порта из строки."; exit 1; }

# Читаем значение переменной port из секции [zigbee] в файле /etc/homed/homed-zigbee.conf
zigbee_port=$(sed -n '/\[zigbee\]/,/^\[/p' /etc/homed/homed-zigbee.conf | grep -m 1 '^port=' | cut -d'=' -f2 | tr -d '[:space:]')

# Если значение port не найдено, выходим с ошибкой
[ -z "$zigbee_port" ] && { echo "Значение переменной port в секции [zigbee] не найдено."; exit 1; }

# Если значения портов совпадают, завершаем скрипт
[ "$port" = "$zigbee_port" ] && exit 0

# Останавливаем службу homed-zigbee
/etc/init.d/homed-zigbee stop

# Обновляем значение порта в конфигурационном файле
sed -i "/^\[zigbee\]/,/^\[/s/^port=.*$/port=$port/" /etc/homed/homed-zigbee.conf

# Проверяем, было ли обновление успешным
updated_port=$(sed -n '/\[zigbee\]/,/^\[/p' /etc/homed/homed-zigbee.conf | grep -m 1 '^port=' | cut -d'=' -f2 | tr -d '[:space:]')

# Если обновление не удалось, выходим с ошибкой
[ "$updated_port" != "$port" ] && { echo "Не удалось обновить значение порта в конфигурационном файле."; exit 1; }

# Запускаем службу homed-zigbee
/etc/init.d/homed-zigbee startzigbee start

Что делает этот скрипт?

Он работает как внимательный наблюдатель:

  • Сканирует логи системы, чтобы отследить момент, когда свисток «переезжает» на новый порт.
  • Сравнивает текущее положение устройства с настройками HOMEd.
  • Если порт изменился, скрипт останавливает сервис, обновляет конфигурацию и запускает всё заново.

Проще говоря, это автоматический контролёр для капризного устройства.


Шаг 2: Используем hotplug для мгновенной реакции

Hotplug — это система, которая реагирует на подключение или отключение устройств. Например, когда вы вставляете флешку, hotplug может автоматически её смонтировать. В нашем случае мы научим её следить за перемещениями Zigbee-свистка:

mkdir -p /etc/hotplug.d/usb  
cp /root/scripts/find_port.sh /etc/hotplug.d/usb/22-usb-persistent

Теперь каждый раз, когда свисток решит «переехать», скрипт сработает и исправит ситуацию!


Шаг 3: Добавляем скрипт в автозагрузку

Добавим в файл `/etc/rc.local` строку `/root/scripts/find_port.sh` перед `exit 0`. Зачем это нужно?

При загрузке роутера Zigbee-свисток всегда стартует на «правильном» порту — `/dev/ttyUSB0`. Однако, если перед перезагрузкой он успел «переехать» на другой порт (например, ttyUSB1), конфиг HOMEd мог сохранить это значение. Этот шаг гарантирует, что при старте системы скрипт проверит текущее положение свистка (который всегда возвращается на ttyUSB0) и обновит конфигурацию, если это необходимо.


Финал

Теперь мой Zigbee-свисток ведёт себя как законопослушный гражданин. Больше никаких «а где мой порт?», никаких лишних перезагрузок. Помните: скрипты и юмор — ваши лучшие союзники в мире техно-хаоса.

Кстати, если вы новичок — не бойтесь экспериментировать. Даже такие «поломки» учат нас большему, чем десяток учебников.

Хочу выразить глубокую и искреннюю благодарность автору системы HOMEd, а также всем участникам этого удивительного сообщества. Благодаря вашей поддержке, терпению и профессионализму мне удалось решить возникшую проблему. Каждый совет и каждое слово стали для меня неоценимым вкладом в решение этой проблемы.

Спасибо вам за то, что делаете этот мир лучше, помогая друг другу!