Skip to content

Repository files navigation

MBPlugin + Home Assistant: Билайн, МегаФон и МТС

Полное воспроизводимое руководство по сбору баланса, тарифа и доступных пакетных/финансовых полей мобильных номеров в Home Assistant. Рабочая схема вынесена из Home Assistant на отдельный Ubuntu-хост: MBPlugin получает данные операторов, сохраняет их в SQLite, а отдельный bridge публикует проверенные поля через MQTT Discovery.

Готовая команда для системного помощника находится в ASSISTANT_PROMPT.md. Она специально требует инвентаризацию, резервную копию, ручной ввод SMS/CAPTCHA владельцем и сквозную приёмку.

Проверенный стенд: Ubuntu, Docker Compose, MBPlugin v1.00.92, системный Chromium, Playwright 1.46.0, Mosquitto и Home Assistant MQTT Discovery. Последняя сквозная проверка этой реализации — 23 сентября 2026 года. Сайты операторов меняются, поэтому перед production нужно повторить все тесты.

Что это за проект

Это независимый комплект поверх artyl/mbplugin. Модули p_beeline_sms, p_megafon_sms и p_mts_sms из этого репозитория не входят в чистый upstream MBPlugin. Одного добавления строк в phones.ini недостаточно: для воспроизводимости нужны приложенные Dockerfile, адаптеры, runtime, MQTT bridge и процедура сохранения сессии.

Комплект предназначен для владельца или уполномоченного администратора SIM. Он не обходит CAPTCHA, не перехватывает SMS и не вводит пароль. Владелец проходит защитные шаги сам в краткоживущем браузерном окне.

Архитектура

flowchart LR
    U[Владелец] -->|SMS/CAPTCHA вручную| N[Временный noVNC 20 минут]
    N --> S[(Приватные browser sessions)]
    C[MBPlugin collector] --> S
    C --> O[Кабинеты операторов]
    C --> D[(SQLite)]
    B[Read-only MQTT bridge] --> D
    B -->|retained QoS 1 + LWT| M[Mosquitto]
    M --> H[Home Assistant MQTT Discovery]
Loading

Старый Home Assistant add-on не используется. Home Assistant остаётся потребителем MQTT, а тяжёлая браузерная часть живёт в изолированном Docker Compose на Ubuntu.

Состав репозитория

runtime/                 Docker image, collector, bridge, tests, backup
runtime/carrier/         p_beeline_sms, p_megafon_sms, p_mts_sms
runtime/Dockerfile       загрузка закреплённого исходника MBPlugin v1.00.92
login-window/            временный noVNC для ручной авторизации
examples/                обезличенные phones.ini и bridge.json
ASSISTANT_PROMPT.md     готовое задание помощнику

Dockerfile загружает архив точного commit 9e7d4de2359a4f5df6c193b372f9e13085b2659b (tag v1.00.92) с SHA-256 252a6dbad7cf04241547e70d0d039213d2ab9fc94825fd47073f9a2e12973bd2. BuildKit проверяет checksum до распаковки. Upstream test fixtures удаляются из runtime image. Условия upstream приведены в THIRD_PARTY_NOTICES.md.

Что никогда не публиковать

  • реальные номера, ФИО, договоры, балансы, тарифы и даты платежей;
  • phones.ini, bridge.json, .env, SQLite, raw payload и логи;
  • cookies, JWT, localStorage, browser profiles и state-файлы;
  • SMS-коды, CAPTCHA, пароли MQTT/noVNC/HA и токены;
  • IP, частные домены, VPN-профили, временные URL и tunnel keys;
  • dashboard JSON/entity IDs, если они раскрывают номер или имя.

Каталог /data, login private/ и backup должны быть 0700; секретные файлы — 0600. Они уже исключены .gitignore, но перед каждой публикацией всё равно сканируйте рабочее дерево и историю Git.

Требования

  • Ubuntu/Debian x86_64 с актуальными security updates;
  • Docker Engine и Compose v2;
  • минимум 4 GB свободного места, 2 GB RAM для collector;
  • существующий Mosquitto или другой MQTT broker;
  • MQTT integration и Discovery в Home Assistant;
  • HTTPS/VPN/SSH-маршрут для временного noVNC, если владелец входит не с самого Ubuntu;
  • возможность получить SMS хотя бы при первичном входе или подтверждённый контактный номер у оператора.

Перед началом зафиксируйте версии Docker/Compose, состояние HA/MQTT, существующие MBPlugin, topic prefix и entity IDs. Не перезапускайте весь Home Assistant, MQTT или хост без доказанной необходимости.

1. Подготовка и резервная копия

Выберите приватный каталог, например /srv/mbplugin. Не копируйте этот путь вслепую: проверьте диск, права и резервное хранилище.

sudo install -d -m 0700 -o 10001 -g 10001 /srv/mbplugin/data
sudo install -d -m 0700 /srv/mbplugin-backups
cp -a runtime /srv/mbplugin/app
cp -a login-window /srv/mbplugin/login-window
cd /srv/mbplugin/app

Если MBPlugin уже существует, сначала сохраните image digest, Compose/INI и полный /data. Приложенный backup останавливает только collector, создаёт tar.gz, SHA-256 и проверяет читаемость:

sudo ./backup.sh /srv/mbplugin-backups

Не считайте backup пригодным, пока не прошли sha256sum -c и tar -tzf. Не создавайте архив внутри копируемого каталога: одна из реальных попыток дала гонку, когда проверочный файл попал в tar во время упаковки.

2. Сборка из закреплённого исходника

cd /srv/mbplugin/app
MBPLUGIN_DATA=/srv/mbplugin/data docker compose build --pull mbplugin
MBPLUGIN_DATA=/srv/mbplugin/data docker compose config >/dev/null

Контейнер работает как UID/GID 10001, с read-only rootfs, dropped capabilities, no-new-privileges, полным seccomp-профилем и loopback-портом 127.0.0.1:19777. Docker socket, privileged и host network не нужны.

В upstream Playwright 1.46.0 использовал удалённый Chromium-флаг --headless=old; hardening заменяет его на --headless=new, включает Chromium sandbox, TLS verification, отключает изменяющие HTTP endpoints и закрепляет data root. Если сборка перестала находить точку patch, остановитесь: upstream изменился, и слепое продолжение небезопасно.

3. Первый запуск без опроса

sudo chown -R 10001:10001 /srv/mbplugin/data
sudo chmod 0700 /srv/mbplugin/data
MBPLUGIN_DATA=/srv/mbplugin/data docker compose up -d mbplugin
docker compose ps
docker compose exec mbplugin python /data/mbplugin/plugin/util.py -v version
docker compose exec mbplugin python /data/mbplugin/plugin/util.py check-import
docker compose exec mbplugin python /data/mbplugin/plugin/util.py check-ini
docker compose exec mbplugin python /data/mbplugin/plugin/util.py check-playwright

POLL_ENABLED=0 оставляют до подключения аккаунтов. HTTP-отчёт доступен только с хоста или через SSH tunnel:

ssh -L 19777:127.0.0.1:19777 <ubuntu-host>

Проверьте, что /report читается, а POST, query-команды и изменяющие endpoints возвращают 403.

4. Настройка phones.ini

Скопируйте структуру из examples/phones.example.ini в приватный /srv/mbplugin/data/phones.ini. Number — десять цифр без +7/8. Каждый связанный номер получает отдельную секцию, но использует общую сохранённую сессию своего оператора.

[Phone] #1
Region = p_beeline_sms
Monitor = TRUE
Alias = mobile_beeline_1
Number = <TEN_DIGIT_NUMBER>
Password2 = session-only-never-used

Password2 здесь — служебная непустая строка для формата MBPlugin; адаптеры не используют её для входа. Не помещайте реальный пароль в файл.

sudo chown 10001:10001 /srv/mbplugin/data/phones.ini
sudo chmod 0600 /srv/mbplugin/data/phones.ini
docker compose exec mbplugin python /data/mbplugin/plugin/util.py check-ini

5. Временное защищённое окно входа

Остановите collector, чтобы два Chromium не открыли один профиль, и сделайте backup. Затем создайте пароль Basic Auth без вывода его в историю/чат:

cd /srv/mbplugin/app/../login-window
install -d -m 0700 private
htpasswd -B -c private/login.htpasswd operator
sudo chown -R 10001:10001 private
chmod 0600 private/login.htpasswd

Скопируйте login-window рядом с runtime либо скорректируйте относительный seccomp path. Запустите один оператор:

docker compose -f /srv/mbplugin/app/compose.yaml stop mbplugin
cd /srv/mbplugin/login-window
OPERATOR=beeline MBPLUGIN_DATA=/srv/mbplugin/data docker compose up -d --build

Окно на хосте:

http://127.0.0.1:16080/vnc.html?autoconnect=true&resize=scale

Для другого компьютера используйте SSH tunnel. Для телефона создайте отдельный краткоживущий HTTPS route с аутентификацией к 127.0.0.1:16080, не публикуя backend напрямую. Проверьте 401 без Basic Auth и WebSocket 101 после входа. Route должен иметь auto-close не более 20 минут.

Владелец сам вводит номер, CAPTCHA и SMS. После появления кабинета сохраните сессию, пока окно ещё работает:

OPERATOR=beeline MBPLUGIN_DATA=/srv/mbplugin/data \
  docker compose exec -e OPERATOR=beeline login python /app/save-session.py

Ожидаемый ответ: session_saved. Затем остановите окно, удалите временный внешний route и снаружи убедитесь, что URL больше не открывается:

OPERATOR=beeline MBPLUGIN_DATA=/srv/mbplugin/data docker compose down
docker compose -f /srv/mbplugin/app/compose.yaml start mbplugin

Повторите для megafon и mts. Не используйте одновременно два login-window для одного /data.

6. Особенности Билайна

  • Для постоплаты API-поле balance.balance оказалось текущими расходами, а баланс договора — минус debt.balance. Адаптер публикует их раздельно вместе с лимитом и доступным кредитом.
  • Связанные мобильные номера читаются из одной SSO-сессии. Домашний интернет имеет userType=Fttb и намеренно отклоняется.
  • Переключение разрешено только на номер из актуального списка аккаунтов; проверяются путь, query target и итоговый profileSummary.ctn.
  • Кабинет может перевести сессию на региональный поддомен *.beeline.ru.
  • Одного Chromium profile было недостаточно: сессионные cookies исчезали после перезапуска. Поэтому используется приватный .beeline-sso-cookies.json.
  • --restore-last-session оказался нестабилен и не используется.
  • Остатки пакетов берутся из Accumulators. Если поле отсутствует, противоречиво или похоже на служебный sentinel, оно остаётся unavailable/неоднозначным.

Порядок проверки: основной номер → каждый связанный мобильный → снова основной → новый запуск Chromium → повтор всех целей.

7. Особенности МегаФона

  • Проверяются sessionCheck.authenticated и номер сессии.
  • Разрешённые связанные номера берутся из multiaccount/summary; результат multiaccount/change обязан совпасть с целью.
  • После switch старая вкладка и response listener закрываются, данные читаются в новой вкладке. Иначе задержанный ответ прежнего аккаунта можно ошибочно принять за новый.
  • Cookie jar добавляет только отсутствующие cookies и не затирает более свежий профиль.
  • Несколько параллельных копий авторизованного профиля недопустимы.
  • unlim: true важнее числового остатка. Огромный sentinel не публикуется как реальные гигабайты.

Если первое переключение сбросило authenticated, снова выполните ручной вход, сохраните обновлённую сессию и повторите основной → связанные → основной.

8. Особенности МТС

  • Прямой вход в кабинет на серверном Chromium давал 403/QRATOR. Смена VPN-маршрута не устранила причину.
  • Рабочий вход начинается через официальный MTS ID. Возможна ручная проверка человека.
  • Для модемной, smart-device или бизнес-SIM появляется отдельный экран: устройство не может принять код, и владелец должен нажать «Получить SMS с кодом» либо использовать заранее добавленный контактный номер.
  • CAPTCHA и SMS проходит только владелец. Автоматизация не должна нажимать защитные шаги или запрашивать код сама.
  • save_session.py сохраняет только cookies/origins доменов MTS в .mts-state.json.
  • Адаптер сверяет номер по user-info и counters. После успешного входа сессия должна работать без VPN и нового SMS.
  • Баланс обрезается до копеек так же, как в кабинете; интернет конвертируется из KByte. Отсутствующие минуты/SMS остаются unavailable.

Если после успешного входа другие аккаунты показывают старый error, выполните один полный свежий poll всех аккаунтов: не редактируйте Flags вручную.

9. Первый реальный опрос

cd /srv/mbplugin/app
MBPLUGIN_DATA=/srv/mbplugin/data docker compose exec mbplugin python /app/runtime.py poll

Runtime не разрешает параллельные опросы, сохраняет cooldown минимум 30 минут и прерывает зависший poll через 15 минут. Код 75 означает занято/cooldown, а не поломку оператора.

Проверьте без копирования персональных данных в терминальный отчёт:

  1. у каждого аккаунта свежая строка в SQLite;
  2. identity ответа совпадает с запрошенным номером;
  3. баланс совпадает с кабинетом;
  4. 0, отсутствие, безлимит, некорректность и противоречие различаются;
  5. отрицательный баланс не превращается в «заблокирован» без явного статуса оператора.

Только после успешного ручного poll измените в runtime/compose.yaml POLL_ENABLED на 1 и пересоздайте collector. Рекомендуемый интервал — 3600 секунд; разрешённый диапазон — 1800–86400.

10. MQTT bridge

Создайте отдельного MQTT-пользователя с доступом только к mbplugin/#, homeassistant/+/mbplugin_+/+/config и чтением homeassistant/status в соответствии с синтаксисом ACL вашего broker. Не используйте администраторские credentials.

cd /srv/mbplugin/app
install -d -m 0700 secrets
cp /path/to/reviewed/bridge.json secrets/bridge.json
install -m 0600 /path/to/mqtt-password secrets/mqtt_password
sudo chown -R 10001:10001 secrets

Возьмите схему из examples/bridge.example.json. id и alias не должны содержать номер. Укажите абсолютный database path внутри контейнера /data/store/mbplugin.db.

python -m json.tool secrets/bridge.json >/dev/null
MBPLUGIN_DATA=/srv/mbplugin/data docker compose --profile mqtt config >/dev/null
MBPLUGIN_DATA=/srv/mbplugin/data docker compose --profile mqtt up -d bridge

Bridge читает SQLite в read-only transaction, публикует retained QoS 1, LWT, HA birth refresh и выполняет порядок: state → availability поля → availability аккаунта. Raw exception, номер, cookie и URL не уходят в MQTT.

Состояния диагностики ограничены: ok, stale, worker_offline, database_error, auth_required, captcha_required, parse_error, operator_error.

11. Проверка Home Assistant

Для каждого аккаунта проверьте цепочку:

кабинет оператора → adapter result → SQLite → MQTT retained state → HA entity

Обязательная приёмка:

  • все старые device/entity IDs сохранены;
  • добавились только ожидаемые поля;
  • значения MQTT и HA совпадают;
  • неизменившиеся значения перепубликуются раньше expire_after;
  • restart и --force-recreate не требуют нового SMS;
  • HA restart/birth снова получает Discovery и states;
  • остановка collector/bridge переводит данные в unavailable;
  • запуск и свежий poll возвращают online;
  • временный noVNC URL закрыт;
  • связанные номера повторно проверены после нового browser process.

Не считать успешными только healthy, зелёный контейнер или unit tests.

12. Тесты

cd runtime
PYTHONPATH=carrier python3 -m unittest discover -s carrier
PYTHONPATH=carrier python3 -m unittest discover -s bridge
python3 -m unittest discover -s tests
python3 -m py_compile runtime.py harden_upstream.py bridge/bridge.py carrier/*.py
docker compose config >/dev/null

Тестовые номера синтетические. Перед публикацией дополнительно выполните secret/PII scan всего Git history.

13. Ошибки, которые уже встретились

Симптом Причина Исправление Как проверить
Supervisor build долго висит тяжёлая сборка в HA; точная job-причина не доказана отдельный Ubuntu Compose HA healthy, Compose работает независимо
После прерванного старта нет Python package runtime bootstrap принял частичную установку зависимости только в image build check-import, force-recreate
Данные пишутся рядом с кодом upstream вычислил root по module path явный /data SQLite/INI/profile переживают recreate
Chromium не стартует удалён --headless=old --headless=new реальный browser smoke
Sandbox падает использован неполный seccomp fragment полный профиль Playwright non-root Chromium без --no-sandbox
Профиль занят после crash lock/hostname Chromium стабильный hostname; сначала исключить живой процесс restart/recreate, не удаляя cookies
HTTP опасно выставлен наружу upstream имеет mutating endpoints без общей auth loopback + read-only allowlist GET отчёта 200, изменения 403
Телефон не видит LAN noVNC нет маршрута к домашней сети временный HTTPS/VPN/SSH route до входа 401, после закрытия недоступен
Билайн показывает расходы как баланс postpaid API semantics debt/spend/credit раздельно сверка с кабинетом
Связанный Билайн снова просит вход session cookies не пережили browser restart приватный cookie jar все цели после нового browser start
После switch данные другого номера задержанный response или target не проверен точная identity до parse requested = actual
МегаФон теряет auth после switch конфликт свежих токенов/профилей один профиль, merge только отсутствующих cookies основной → связанные → основной
МегаФон показывает огромные GB unlimited sentinel unlim: true → «Безлимит» числовой sensor unavailable
Билайн без минут/SMS adapter не запросил Accumulators запрос и parser пакетов operator → DB → MQTT → HA
Нет поля превращается в ноль ошибочный fallback unavailable/status вместо 0 fixtures missing/invalid
Минусовой баланс = блокировка неверный вывод только explicit operator status Active остаётся не blocked
Прошлая дата самовольно перенесена догадка вместо source fidelity хранить исходную дату значение совпадает с ответом
МТС отвечает 403 неподходящий direct login route официальный MTS ID SSO появляется human check/login
МТС не шлёт код автоматически interstitial для modem/business SIM владелец нажимает кнопку кабинет открыт, state сохранён
После МТС другие аккаунты error старый неудачный poll оставил Flags полный свежий poll все аккаунты снова ok
Backup повреждён гонкой архив писался внутри копируемого дерева внешний каталог + tar/SHA check sha256sum -c, tar -tzf

14. Обновление и rollback

Автообновление отключено. Для обновления:

  1. сохранить image digest и проверенный backup;
  2. прочитать upstream changelog;
  3. обновить tag/hash только в отдельной ветке;
  4. убедиться, что fail-closed patches применились ровно один раз;
  5. повторить unit, browser, каждого оператора, MQTT и HA acceptance;
  6. только затем заменить production image.

Никогда не выполняйте docker compose down -v, docker system prune или очистку browser profiles в рамках обычного обновления.

Rollback: остановить только новый collector/bridge, вернуть прежний image/Compose и указать отдельную восстановленную копию /data. Не распаковывать backup поверх действующего data и не открывать новую SQLite старой версией без проверки совместимости. Retained Discovery новых сущностей удаляется отдельным точечным списком topics.

15. Границы и эксплуатация

  • Сессии операторов истекают; auth_required означает новый ручной вход.
  • CAPTCHA может появиться повторно; её нельзя обходить автоматизацией.
  • Сайт оператора способен изменить selectors/API. При несовпадении identity адаптер обязан завершиться ошибкой, а не публиковать чужие данные.
  • Финансовые поля информационные. Этот проект не выполняет платежи и не включает услуги.
  • Для нового оператора нужен отдельный adapter и отдельная приёмка.
  • Alerting/автоматические платежные уведомления — отдельная задача; их нельзя молча добавлять при сборе данных.

Лицензия

Собственные материалы и код этого репозитория доступны по MIT License. Bundled upstream MBPlugin также MIT и сохраняет оригинальный copyright/license. См. LICENSE и THIRD_PARTY_NOTICES.md.

About

Безопасное подключение Билайн, МегаФон и МТС к Home Assistant через MBPlugin, Docker и MQTT

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages