Заливка своей прошивки (ESPHome и т.п.) в умную розетку ELTEX-SW-PLG01 (Realtek RTL8720CF / AmebaZ2) по воздуху — без программатора и вскрытия корпуса.
По духу — как tuya-cloudcutter: заводская прошивка сама умеет ходить за
обновлением по HTTP, инструмент подсовывает ей свой сервер.
Проверено на живой розетке: заводская ELTEX-SW-PLG01 (HW 3v0, прошивка 2.3.0) переведена в ESPHome по воздуху; реле, кнопка и измеритель U/I/P работают.
Назначение — совместимость: инструмент нужен, чтобы устройство, которым вы владеете, работало с независимым ПО (например, Home Assistant) в рамках личного использования. Он не обходит защиту и не вскрывает чужие устройства — только переключает вашу розетку на прошивку с открытым протоколом.
Совместимое железо — см. docs/compatibility.md; подробности по устройству — в docs/hardware/.
Инструмент опирается на три особенности штатной прошивки.
-
Провижининг. В режиме настройки розетка поднимает свою точку доступа и слушает TCP:56684. Кадр = 4 байта длины (big-endian) + protobuf. Обмен: устройство шлёт
HELLO, инструмент отвечаетCONFIG, устройство —GOODBY.message Config { bytes ssid=1; bytes bssid=2; string password=3; string mqtt_broker_url=4; string mqtt_login=5; string mqtt_password=6; string node_id=7; }
-
TLS отключается портом. Поле
mqtt_broker_urlимеет видhost:port. При порте 1883 соединение идёт поtcp://открытым текстом, при любом другом — поssl://с проверкой сертификата. Значит с портом 1883 вшитый сертификат «Eltex.IoT» не задействуется и розетку можно увести на свой брокер. -
OTA — команда по MQTT. Розетка подписывается на
sys/cmd/<node_id>(а такжеsys/cmd/redirect,sys/cmd/<node_id>/redirect,dev/cmd/<node_id>/#) и принимает командуdevice_upgrade, после чего качает образ по обычному HTTP и пишет во второй OTA-слот. Загрузчик принимает образ, собранный LibreTiny.В
sys/event/<node_id>розетка публикует события сама — команды туда слать бесполезно. Рабочий payload:device_upgrade 0|<url>.
Зависимостей нет — только Python 3.8+ (для --ap/--scan нужен nmcli;
для чтения QR — опционально pyzbar/zxing-cpp/opencv).
# 1) найти точку доступа устройства (по профилям)
./eltex_cutter.py --scan
# 2) перепрошить. Пароль точки берётся автоматически: сначала перебор регистра
# серийника (--serial), потом QR наклейки (--qr); можно и напрямую --ap-password.
./eltex_cutter.py --profile eltex-sw-plg01 \
--ap ELTEX-SW-PLG01-XXXX \
--serial FC00000000 --qr label.jpg \
--ssid ДОМАШНЯЯ_СЕТЬ --password ПАРОЛЬ \
--host-ip 192.168.4.33 \
--fw firmware/image_firmware_is.0x00C000.bin --try-variantsПрофиль (profiles/*.json) описывает всё, что специфично для устройства: порт и
magic провижининга, командные топики, форматы OTA, плату и сигнатуры образа.
Новое устройство добавляется файлом профиля, без правки кода — см.
profiles/_schema.md и раздел «Новые устройства».
--host-ip — адрес компьютера в домашней сети: туда розетка пойдёт за MQTT и за
образом. Скрипт подключается к точке розетки, отдаёт ей настройки, поднимает
локальный MQTT-брокер (1883) и HTTP-раздачу, дожидается розетки и отправляет
команду OTA.
Полезные флаги:
| флаг | зачем |
|---|---|
--skip-provision |
розетка уже смотрит на ваш брокер — только OTA |
--try-variants |
перебрать форматы команды device_upgrade |
--device-ip |
адрес розетки в её AP (по умолчанию берётся из профиля) |
--bind |
интерфейс брокера/HTTP; для сухих тестов 127.0.0.1 |
--wait |
таймауты ожидания |
Нужен образ FW-слота AmebaZ2 из сборки ESPHome/LibreTiny — файл
image_firmware_is.0x0?????.bin (например image_firmware_is.0x00C000.bin) в
.esphome/build/<имя>/.pioenvs/<имя>/. Для RTL8720CF это один файл и для ota1, и
для ota2 (раздельных *.ota1.bin/*.ota2.bin у ambz2 нет).
Не подходят:
firmware.uf2— UF2-контейнер;firmware.bin— тоже UF2-контейнер (начинается с сигнатурыUF2), лишь с расширением.bin; побайтово равенfirmware.uf2;image_flash_is.0x000000.bin— полный образ флеша (таблица разделов AmebaZ2).
imgcheck отсеивает все три.
Плата для сборки — generic-rtl8720cf-2mb-992k. У RTL8720CF в LibreTiny две
раскладки: 896k («Tuya default», шаг слотов 0xE0000) и 992k («SDK default»,
шаг 0xF8000). При OTA заводская таблица разделов не переписывается, поэтому
образ должен лечь в заводской FW2. Прошивка Eltex — сток Realtek SDK с раскладкой
992k, под неё и собирают (готовый eltexplug-ota.yaml). Образ, собранный так,
принимается заводским загрузчиком; при неверном формате загрузчик откатывается на
прежний слот (Invalid FW Image Signature! в UART), кирпича не будет.
| деталь | значение |
|---|---|
| топик команд | sys/cmd/<node_id> (в sys/event/<node_id> устройство публикует события) |
| payload OTA | `device_upgrade 0 |
| формат образа | image_firmware_is.0x00C000.bin из сборки LibreTiny (~631 КБ) |
| точка доступа | WPA2, SSID ELTEX-SW-PLG01-<MAC[-3:]> |
| пароль точки | в QR-коде на корпусе: WIFI:T:WPA;ELTXMAC:...;S:...;P:<S/N>;; — S/N в смешанном регистре (Fc00000000) |
| адрес устройства в его AP | 10.24.83.55 |
| порт 1883 | соединение с брокером открытым текстом |
| подпись образа | заводской загрузчик принимает ключи LibreTiny по умолчанию |
Пароль точки — серийный номер в смешанном регистре (Fc00000000), поэтому
вручную его не угадать. Два источника, порядок задаётся --ap-order:
- перебор регистра S/N (
--serial FC00000000) — дёшев, когда букв в серийнике мало (уFC…их две → 4 варианта). Порядок по умолчанию — сначала это; - QR-код наклейки (
--qr label.jpgили--qr "WIFI:...;P:...;;") — однозначен;qrtool.pyчитает пароль даже с неидеального фото.
python3 qrtool.py label.jpg # показать содержимое QR
python3 apcreds.py --serial FC00000000 # показать кандидатов перебора| устройство | чип | статус |
|---|---|---|
| ELTEX SW-PLG01 | RTL8720CF (AmebaZ2) | проверено |
Полная таблица и страницы по железу — docs/compatibility.md.
Добавление устройства — новый profiles/<имя>.json, без правки кода
(схема — profiles/_schema.md). Проверка: python3 device.py <имя>.
Профиль задаёт порт/magic провижининга, командные топики MQTT, форматы OTA,
плату LibreTiny и сигнатуры непригодных файлов образа. Пока семейство одно
(Eltex/AmebaZ2), всё описывается данными; принципиально иной протокол потребует
кода.
docker compose build
docker compose run --rm eltex-cutter --scan
docker compose run --rm eltex-cutter \
--profile eltex-sw-plg01 --ap ELTEX-SW-PLG01-XXXX \
--serial FC00000000 --qr /firmware/label.jpg \
--ssid ДОМ --password ПАРОЛЬ --host-ip 192.168.4.33 \
--fw /firmware/image_firmware_is.0x00C000.bin --try-variantsОбразы и наклейки кладите в firmware/ (монтируется как /firmware).
Пользуйтесь docker compose — он монтирует пути правильно. При сыром
docker run -v ... из Git Bash на Windows пути ломает MSYS: нужен
MSYS_NO_PATHCONV=1 и абсолютный путь.
Управление точкой (--ap через nmcli) работает только на Linux-хосте с реальным
Wi-Fi-адаптером и с --network host + NET_ADMIN (в compose уже прописано). На
Docker Desktop (Windows/macOS) контейнер Wi-Fi не видит: подключайтесь к точке
сами, а контейнер запускайте с --skip-provision для фазы брокер+HTTP+OTA.
Если по воздуху не пойдёт, в прошивке есть AT-команда в UART-консоли:
ATOTA=http://192.168.1.50:8000/firmware.bin
Программатор и режим загрузчика не нужны — только USB-UART на TX/RX/GND.
| файл | что делает |
|---|---|
eltex_cutter.py |
оркестратор: провижининг → брокер → HTTP → OTA |
device.py |
загрузчик и валидатор профилей устройств |
profiles/*.json |
описания устройств (протокол, топики, образ) |
apcreds.py |
кандидаты пароля точки: перебор регистра S/N и QR |
apjoin.py |
подключение к точке (nmcli/netsh) с перебором паролей |
qrtool.py |
чтение пароля из QR-кода наклейки |
imgcheck.py |
проверка образа по профилю |
proto.py |
протокол провижининга и мини-кодек protobuf |
mqtt.py |
минимальный MQTT-брокер (3.1.1 и 5.0) |
test_e2e.py |
эмулятор устройства для сквозного теста |
Dockerfile, docker-compose.yml |
запуск в контейнере |
Сквозной тест без железа:
python3 test_e2e.py 56684 1883 5 &
./eltex_cutter.py --fw образ.bin --ssid Home --host-ip 127.0.0.1 \
--device-ip 127.0.0.1 --bind 127.0.0.1 --node-id plug1