TL;DR: Я ранее установил Mobian (Linux-дистрибутив, на основе Debian) на смартфон OnePlus 6. Теперь разбираюсь с потенциальным возгоранием батареи. Определил основной источник рисков. Решил защитить батарею от перезаряда, разряда и перегрева. Реализовал сервис для systemd, который реализует эту защиту на уровне управления драйвером зарядки устройства, на основе данных с батареи. Репозиторий.

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

В комментариях к предыдущей статье, где я рассказывал, как устанавливал Mobian на OnePlus 6, чтобы сделать из него домашний сервер, подняли вопрос возможности взрыва батареи на устройстве.

Первая мысль, которая меня посетила, было отключить батарею вовсе, припаять диод и питаться только от внешнего источника питания. Но это убивает один из плюсов сервера на телефоне - по сути встроенного ИБП. Учитывая, что в телефон на Mobian вполне можно вставить SIM-карту и использовать интернет с неё, то можно построить довольно защищённую от перебоев систему, которая по стабильности уже начнёт спорить с гораздо более дорогими решениями. Поэтому всё же, я решил разобраться, что можно сделать, чтобы защитить аккумулятор.

Скажу честно, когда я только установил Mobian, я вообще не думал об этой проблеме. Но после комментариев, решил озаботиться этим вопросом и как-то разобраться и в механике процесса, и в возможных решениях проблемы.

Почему батареи горят?

Для начала изучим вопрос с технической точки зрения. Почему может взорваться батарея?

Небольшой, очень простой ликбез

На самом деле, для ответа на этот вопрос придётся для начала начать с упрощённого разбора устройства самой батареи. Более подробно об этом можно почитать в тематических статьях. Но базово есть анод (отрицательно заряженный электрод), катод (положительно заряженный электрод), электролит и сепаратор.

Схематическое изображение аккумулятора. Взято из статьи об устройстве батареи на сайте Deep Review.
Схематическое изображение аккумулятора. Взято из статьи об устройстве батареи на сайте Deep Review.

Электроны из Анода (-) должны попасть в Катод (+). Но сделать это напрямую внутри аккумулятора они не могут, так как между анодом и катодом находится пористый сепаратор, пропитанный электролитом, который и пропускает через себя положительный заряд. Сепаратор отделяет положительно заряженную часть от отрицательно заряженной, чтобы не возникло короткого замыкания, которое, собственно, и может привести к возгоранию батареи.

Один из самых частых сценариев возгорания выглядит примерно так: при перегреве батареи повреждается сепаратор, возникает короткое замыкание, которое ещё больше разгоняет нагрев и закипает электролит.

Второй негативный фактор, который может привести к разрушению батареи - это образование дендритов. При перезаряде или быстрой зарядке литий осаждается на аноде в виде «иголок», прорастающих сквозь сепаратор. Сначала они дают локальные короткие замыкания, которые по тому же принципу дают нагрев, ускорение реакций в батарее и постепенное разрушение. Это не мгновенный пробой, а постепенная деградация с накоплением риска возгорания.

Третий вариант - при напряжении выше нормы: электролит окисляется на катоде, анод может насыщаться литием сверх меры, растёт давление, температура и шанс разрушения батареи

Вообще со временем (особенно при перегреве) батарея деградирует. Что происходит? Постепенно происходит разложение электродов с выделением сопутствующих веществ, которые могут ускорить горение или разогнать другие процессы разрушения. И, конечно, деградирует сам электролит, попутно выделяя газ, который и приводит к вздутию батареи.

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

В общем, путей, которые могут привести к возгоранию много. Но все они сводятся к пяти основным внешним факторам, которые повышают вероятность любого из сценариев:

  1. Возраст, а именно, количество циклов заряда/разряда (к сожалению, любая батарея при использовании даже в самых безопасных условиях, всё равно будет постепенно деградировать)

  2. Перегрев (ускорение вообще всех негативных процессов внутри батареи)

  3. Перезаряд (ускорение деградации катода)

  4. Глубокий разряд (ускорение деградации, в первую очередь анода)

  5. Механическое воздействие

Если бы была возможность убрать все эти факторы, батарея бы работала вечно. Но, к сожалению, ничего вечного не существует, однако 4 из 5 факторов вполне себе поддаются контролю и могут быть "убраны из уравнения". Возраст победить не удастся, но батарею поменять в устройстве гораздо проще, чем многие другие комплектующие.

Что же можно сделать?

Для начала разберёмся с самым простым - механическим воздействием. Я планирую использовать сервер на Mobian в стационарном формате и после окончательной настройки положить его где-то в районе роутеров и оставить там лежать без всяких внешних воздействий, пусть пылится. То есть механическое воздействие исключается сразу

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

Перезаряд и разряд - в современных телефонах практически исключены BMS-контроллерами (BMS - Battery Management System), но крайние значения заряда всё же раздвинуты довольно широко, чтобы батареи могли работать дольше чем несколько часов. Поэтому, если бы была возможность держать телефон всегда заряженным в пределах 40-80% заряда, это бы практически исключило данный фактор.

Соответственно, ответ напрашивается сам собой. Необходимо какое-то решение, которое бы держало батарею заряженной в пределах 40-80% и при этом не допускало бы перегрева выше 45 градусов по Цельсию.

Данное решение не исключит возможность возгорания батареи и не остановит деградацию. Но сведёт их к возможному минимуму, который будет сравним или даже ниже, чем у повседневно используемых устройств, которые заряжаются быстрыми зарядками и нередко часами лежат подключенными на 100%.

Конкретно мной было придумано три основных подхода:

  1. Балансировать питание в режиме online, чтобы батарея держалась в заданном диапазоне, а основное потребление шло по проводу. Но я быстро понял, что это необоснованно сложное решение, которое, скорее, может оказаться даже хуже, более простых

  2. Управлять питанием на уровне телефона, ограничивая зарядку через драйвера в пределах 40-80% заряда с одновременным контролем температуры для защиты от перегрева.

  3. То же самое, что пункт 2, но управлять не драйверами телефона, а умной розеткой, которая будет физически размыкать соединение.

В конце концов я остановился на втором варианте. Как показала практика, он имеет пару проблем, но всё же достаточен для создания условий питания батареи. Но всё же я его реализовал. Ссылка на репозиторий - https://github.com/FA72/battery-limiter.

Реализация программной защиты

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

Если устройство заряжается, оно может заряжаться до 80%, как только заряд равен или выше 80%, мы пытаемся передать драйверу сигнал о том, что ему нужно переставать подавать заряд батарее. Это аппаратно выключает зарядку, и батарея переходит в режим разряда. Если устройство разряжается, то, как только заряд равен или ниже 40%, мы для начала пытаемся пробудить драйвер и затем выставить минимальное, но достаточное питание, чтобы устройство не садилось дальше. Это делается циклическим подбором зарядки в диапазоне 500 - 1000 милливольт. Если питания в 1000 милливольт недостаточно, я возвращаю управление драйверу (питание у меня идёт от 10-Ваттной качественной зарядки, поэтому перегрева или быстрой зарядки из-за этого не произойдёт в любом случае).

При реализации цикла управления я столкнулся с проблемой

Пробудить драйвер оказалось не так легко. Простое выставление current_max в 500 милливольт не приводило к ожидаемому результату. Выяснилось, что для пробуждения драйвера требуется передать несколько сигналов, ещё и с разными значениями тока. Есть предположение, что текущая реализация неоптимальна и не на 100% надёжна, но два дня тестов показали, что пока что всё работает, как нужно. В случае если обнаружу какие-то проблемы, это будет поправлено и отражено в репозитории.

На всякий случай всё же реализована защита от перегрева. На случай, если всё же что-то пойдёт не так. Если температура достигает на очередной проверке 45 градусов, то это приводит к остановке заряда и не допускает запуска заряда, даже если заряд опустился ниже 40%. При этом восстановление работы стандартного цикла происходит только после того, как температура опустится до 40 градусов.

Основные минусы такого формата - это отсутствие контроля фактического наличия питания от провода, так как драйвер зарядки при внешнем управлении питанием не умеет определять, есть ли фактическое подключение. К тому же нет никакой сигнализации о перегреве. Логично, что можно добавить дополнительные защиты, которые будут, например, выключать устройство при ещё большем перегреве или хотя бы сигнализировать об этом куда-то. Но в данном случае эта задача не решалась (потому что я в целом сделал отдельную систему мониторинга для данного сервера и контроль температуры настроен там, а в последующем планируется добавить сигнализацию на краевые случаи, типа полного разряда или тотального перегрева).

Для тех, кому интересно, как это всё управляется, немного напишу про код

Решение публикуется через systemd (система инициализации и управления службами в Linux) и написано на bash-скрипте.

Для публикации написан (нейросетью) отдельный power-shell скрипт, который позволяет "в одну команду" накатить сервис на устройство.

Сервис из себя представляет следующее:

Код сервиса
[Unit]
Description=Battery charge limiter (40%%-80%%)
After=multi-user.target

[Service]
Type=simple
EnvironmentFile=-/etc/default/battery-limiter
Environment=STOP_CURRENT_MAX=4800000
ExecStart=/usr/local/bin/battery-limiter.sh
# Return full driver control on stop so phone doesn't stay limited
ExecStopPost=/bin/sh -c 'path="${CHARGER_CURRENT_MAX_PATH:-${SYS_CMAX:-}}"; if [ -z "$path" ]; then for candidate in /sys/class/power_supply/*/current_max; do [ -e "$candidate" ] || continue; path="$candidate"; break; done; fi; [ -n "$path" ] && echo "${STOP_CURRENT_MAX:-4800000}" > "$path" || true'
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

[Unit] в котором определяется, когда запускается сервис - после загрузки системы до обычного пользовательского режима.

Сам [Service], где описывается запуск самого bash-скрипта с переменными окружения и параметрами запуска и журнала. А самое главное, вызывает ExecStopPost для восстановления управления питанием драйвером в случае остановки сервиса.

И [Install], описывающий, что сервис будет запускаться при каждой загрузке.

Принцип работы bash-скрипта я описал выше. Сам код, доступен в репозитории. Из примечаний скажу, что для публикации постарался сделать решение более универсальным, чтобы не упираться в конкретные драйвера устройства. Но всё же проверить я это мог только на своём устройстве (OnePlus 6 на Mobian). И настройки Sysfs-путей стоит под себя настраивать отдельно:

# --- Sysfs paths ---
BATTERY_GAUGE_BASE_PATH="${BATTERY_GAUGE_BASE_PATH:-}"
SYS_CAP="${SYS_CAP:-}"
SYS_TEMP="${SYS_TEMP:-}"
SYS_BQST="${SYS_BQST:-}"
SYS_CUR="${SYS_CUR:-}"
SYS_CMAX="${SYS_CMAX:-${CHARGER_CURRENT_MAX_PATH:-}}"

Что в итоге?

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

Комментарии (4)


  1. 13werwolf13
    21.04.2026 15:29

    Environment=STOP_CURRENT_MAX=4800000

    не совсем по теме статьи, но почему у вас эта конкретная переменная вынесена из EnvironmentFile в Environment?


    1. FA72 Автор
      21.04.2026 15:29

      В ходе подбора максимального тока на котором происходил запуск драйвера, в какой-то момент на этом значении заработало, так и осталось. Скорее, исторически. Учитывая, что у меня 10Вт зарядник, такой ток никогда не достигнется, конечно.


      1. 13werwolf13
        21.04.2026 15:29

        Да я в общем-то не про содержимое переменной спрашивал..


        1. FA72 Автор
          21.04.2026 15:29

          А. Собственно, потому что подбирал разные значения. Да, пожалуй, это не имело смысла оставлять в таком виде. Спасибо, сейчас оставлю только в env. Заодно запушу изменения от воскресенья, которые тестировались, собственно, до сегодня. И подтвердили стабильность