Отказоустойчивость¶
Без присмотра ломается ровно то, что на глазах работает: облачная интеграция отдаёт закэшированный процент, трекер «теряет» стоящую машину, станция на секунду уходит в недоступность. Ниже — что блюпринт делает с каждым из этих отказов и почему именно так.
Достоверность данных о заряде¶
Достоверность данных о заряде проверяется по трём признакам, строго в этом порядке:
| Проверка | Что означает | Что делает блюпринт |
|---|---|---|
| Сущность недоступна | Чаще всего слетела авторизация интеграции | car_data_unavailable_check_integration_auth |
| Данные устарели | Машина давно не выходила на связь | car_data_stale |
| Процент «замёрз» | Значение не меняется, хотя ток идёт | car_data_frozen |
Замёрзший процент — худший из отказов
Третья проверка нужна потому, что многие облачные интеграции при пропаже связи
с машиной не уходят в unavailable, а продолжают отдавать последнее
закэшированное значение сколь угодно долго. Для регулятора это худший из отказов:
замёрзший процент заставил бы держать максимальный ток всю сессию.
При любом из трёх зарядка продолжается — план переключается на энергию сессии либо на резервный ток, а причина уходит в уведомление.
Если зарядка уже идёт, ток при этом не снижается: резервное значение — это ответ на вопрос «с чего начинать», а не «до чего опускаться». Уменьшать ток, которого и так могло не хватать, значит увеличивать отставание, и процент после этого растёт ещё медленнее. Поэтому берётся большее из двух: резервный ток и тот, что уже стоит на станции.
Процент, дошедший до цели, замёрзшим не считается: перестать меняться ему положено, а станция в это время ещё отдаёт мощность на балансировку ячеек. Иначе достигнутая цель выглядела бы как отказ данных, и зарядка не выключилась бы до конца окна.
Трекер, который врёт¶
Трекеры регулярно «теряют» стоящую машину, причём обычно не молчанием,
а бодрым not_home: координаты уплывают на пару сотен метров, и машина
формально выходит из зоны. Ни один из этих сбоев не должен гасить зарядку.
Различить враньё от настоящего отъезда позволяет сама станция: уехать,
не отключив кабель, невозможно. Поэтому пока станция отдаёт ток, никакой
not_home идущую сессию не прерывает — доверяем железу, а не спутникам.
Проверяется именно ток (сенсор мощности), а не статус станции: статус умеет
залипать, ток — нет. Если сенсора мощности нет, используется статус.
Настоящий отъезд — трекер вне зоны и тока нет — останавливает зарядку как
раньше, с причиной car_not_home.
Обрыв связи со станцией при этом за «тока нет» не считается. Иначе достаточно было бы совпадения двух рядовых сбоев — вравшего трекера и секундной потери связи, — чтобы блюпринт решил, что машина уехала, и погасил исправно идущую зарядку. «Не знаем» и «нет» — разные ответы.
Потеря позиции (unavailable / unknown) тоже не рвёт идущую сессию, а лишь
запрещает старт новой.
Почему для старта правило другое¶
Ток подтверждает присутствие только у идущей сессии. Пока зарядка не включена, тока нет, и подтвердить нечем — поэтому начать зарядку при машине вне зоны нельзя. Это защита от того, чтобы не начать заряжать чужую машину, если кто-то воткнёт свой автомобиль в вашу станцию.
Одной проверкой в момент начала окна дело при этом не ограничивается. Условие перепроверяется на каждом пересчёте всю сессию, поэтому сбой GPS в неудачную минуту стоит не всей сессии, а лишь задержки до ближайшего пересчёта:
| Когда трекер пришёл в себя | Что происходит |
|---|---|
| 00:20 | Старт в 00:20, цель достигнута |
| 02:00 | Старт в 02:05, цель достигнута |
| 05:00 | Старт в 05:05, дозарядка сколько успеет |
Кроме таймера есть и мгновенный триггер: переход трекера в домашнюю зону запускает пересчёт сразу, не дожидаясь очередного тика. То есть при штатном поведении GPS задержки не будет вообще.
А вот если трекер соврал уже после старта — зарядка не прервётся, как описано выше. Правила разные намеренно: начать вслепую рискованно, прервать идущую зарядку — вредно.
В пятую ночь обкатки это сработало вживую: трекер ушёл в not_home за 48 минут
до конца окна и не вернулся, машина всё это время стояла в гараже и брала
12.6 А. Зарядку не тронули, до цели дошли.
Защита действует, пока идёт ток
Подтверждает присутствие машины именно ток, поэтому после штатного выключения подтверждать нечем — и с этого момента совравший трекер начинает выглядеть как уехавшая машина. На поведение это не влияет (заряжать в этот момент уже нечего), но в журнале причина бездействия указывалась бы неверно, поэтому «машина не дома» объясняет только два случая: почему гасим идущую зарядку и почему не начинаем новую.
Станция в закрытом гараже
Если станция стоит в гараже и заряжать на ней можете только вы, проверку зоны проще выключить совсем — снимите галку «Заряжать только когда машина в зоне».
Ручная зарядка¶
Если заполнить поле «Флаг сессии», автоматизация начнёт отличать свою зарядку от начатой вручную и в чужую не вмешивается: не подбирает ток и не гасит её в конце окна. Включили сами — значит и ток выставили какой хотели.
Уважение это распространяется ровно на то, что человек действительно выбирал: на ток и на длительность. Всё остальное к его выбору отношения не имеет и останавливает зарядку независимо от того, кто её начал:
| Причина остановки | Чужая сессия |
|---|---|
| Неисправность станции | Останавливаем |
| Машина уехала (и ток не идёт) | Останавливаем |
| Кабель выдернут | Останавливаем |
| Цель достигнута | Останавливаем |
| Станция сообщила «заряжено» | Останавливаем |
| Окно кончилось | Не трогаем |
| Ток разошёлся с планом | Не трогаем |
Раньше всё это висело на одном признаке, и стоило ему ошибиться — отключались сразу все остановки. Ровно так и вышло во вторую реальную ночь (см. ниже).
Воткнутый заранее кабель при выключенной зарядке чужой сессией не считается — это обычный способ поставить машину ждать окна, и в нём она начнёт заряжаться своим порядком.
Своя остановка не превращается в чужую сессию
Останавливая зарядку, автоматизация гасит выключатель и следом опускает флаг сессии. Флаг падает мгновенно, а станция подтверждает выключение через несколько секунд — в шестую ночь через 43. Всё это время выключатель ещё включён, а флаг уже опущен, то есть выглядит это в точности как ручная зарядка.
Отличает их возраст выключателя: наша команда ушла секунды назад, а человек щёлкает выключателем задолго до пересчёта. Без этой оговорки проглоченная станцией команда выключения означала бы, что зарядка льётся до утра, а автоматизация вежливо не вмешивается в собственную сессию.
Без этого флага отличить одно от другого нечем: Home Assistant не запоминает, кто щёлкнул выключателем.
Тот же принцип применён к статусу станции. Если сенсор статуса стал нечитаемым
(unknown / unavailable), новая сессия не начинается — отличить
подключённый кабель от пустой розетки нечем, а включение вслепую вдобавок
подняло бы ложную тревогу «включено, но тока нет». Уже идущая зарядка при этом
не прерывается.
Станция, потерявшая связь¶
Дешёвые станции (Tuya и родня) регулярно отваливаются на секунду-другую. Выглядит это неприятнее, чем кажется: интеграция роняет все сущности устройства разом, а поднимает их не одновременно — в реальной ночи восстановление заняло четыре такта за две секунды.
| Такт | Что уже вернулось |
|---|---|
| +0.0 с | ничего: выключатель, статус, уставка, связь — всё недоступно |
| +0.6 с | статус (charging) |
| +1.5 с | выключатель (on) |
| +1.9 с | сенсор связи |
Опасен здесь первый такт. Выключатель в нём «не включён» — но не потому, что его выключили, а потому что его нет. Ровно на этом блюпринт однажды и погорел: уборка прочитала недоступность как ручное выключение и погасила флаг сессии, а через полторы секунды выключатель вернулся — и своя же зарядка до утра считалась чужой.
Отсюда общее правило: воздержаться от действия можно по любому сомнению, а вот разрушительный вывод — «выключили», «чужая», «сломалась» — делается только по подтверждённому состоянию. Практически это значит:
- недоступный выключатель не считается выключенным — в том числе когда по нему судят, идёт ли ток: иначе обрыв связи посреди зарядки читался бы как «машина уехала», стоило трекеру в тот же момент ошибиться;
- сенсор неисправности читается только при живой связи и читаемом статусе — иначе обрыв выглядел бы поломкой и поднимал ложную тревогу;
- нечитаемый флаг сессии означает «владелец неизвестен», а не «чужая»
(при перезапуске Home Assistant
input_booleanпроходит черезunknown); - переходы сущностей в недоступность не запускают пересчёт вовсе: считать
по ним нечего, а в режиме
restartкаждый такой прогон обрывает предыдущий.
Если флаг всё же потерялся при живой зарядке, автоматизация забирает владение обратно — но только когда уставка на станции сходится с расчётом. Это и отличает свою сессию: включая зарядку, блюпринт сначала пишет ток, и у его собственной сессии уставка совпадает с планом. Человек ставит ток по своему разумению, и попасть в плавающий расчёт может разве что случайно.
Команда, которую станция проглотила¶
Те же дешёвые станции иногда просто теряют команду. Не отвечают ошибкой,
не отваливаются — принимают и ничего не делают. На третьей ночи обкатки так
пропало включение зарядки: команда ушла в 23:06, выключатель остался off.
Коварство в том, что промах команды не порождает события. Выключатель как
был выключен, так и остался; уставка как была 11, так и осталась. Обычные
триггеры здесь бесполезны — они ждут либо часов, либо изменения состояния.
Поэтому промах жил до следующего пересчёта: зарядка началась на 24 минуты
позже, а каждая потерянная запись тока стоила получаса регулирования.
Потерянное включение лечится триггером на неизменность: выключатель,
пролежавший в off дольше паузы между командами, — это либо «мы ещё
не начинали», либо «команда пропала», и прогон разбирается сам. У исправной
станции триггер молчит: выключатель уходит в on сразу.
Приём работает потому, что off — состояние покоя: выключатель попадает
в него настоящим переходом (в конце прошлой сессии или когда станция
отключилась сама), и отсчёт уже идёт, когда команда пропадает.
Потерянную запись тока так поймать нельзя
«Неверный ток» состоянием покоя не является — лежать в нём нечему, и взводить отсчёт нечем. Триггер на состояние в Home Assistant требует смены значения, а проглоченная запись не меняет ничего: события нет.
Поэтому потерянная уставка живёт до ближайшего пересчёта — в худшем случае полный интервал. Обнаруживает её обычная проверка расхождения с планом, и следующая же команда уходит повторно. В пятую ночь обкатки так и вышло: запись 13 А в 03:30 пропала, ток полчаса стоял на 12 А, в 04:00 команда ушла снова и подействовала. Ценой были 0.2 % заряда.
Ускорить это нечем без постоянного шума: сенсор фактического тока дрожит на миллиамперы и будил бы автоматизацию на каждое обновление. Если станция теряет команды часто, помогает более короткий период пересчёта.
Отдельный триггер на принятую уставку нужен для другого — для очереди команд: уставка, простоявшая паузу, означает «станция приняла запись, можно слать следующую», и включение уходит сразу, не дожидаясь общего интервала.
Повторы при этом не превращаются в долбёж: включение по-прежнему требует
подтверждённого off и выдержанной паузы, а запись тока — расхождения с планом.
Станция, которая просто выключена вне окна, никаких команд не получает.
Два триггера, совпавшие по времени¶
Пауза между командами отсчитывается по возрасту сущности станции, и у этого есть слепое пятно: сущность меняется не мгновенно. Если два триггера сработают почти одновременно, второй прогон увидит уставку ещё не изменившейся, сочтёт паузу выдержанной и отправит ту же команду второй раз.
Случай не экзотический. Круглое время начала окна попадает на сетку пересчёта: в шестую ночь обкатки старт был выставлен на 23:30, и «начало окна» с обычным пересчётом дали два прогона с разницей 204 миллисекунды — оба успели дойти до записи тока. В станцию ушли две одинаковые команды подряд, ровно с тем интервалом, от которого пауза и защищает.
Поэтому блюпринт смотрит не только на возраст сущностей, но и на то, когда запускался он сам. Прогон, стартовавший меньше секунды после предыдущего, — это гонка триггеров, а не новая мысль, и команд он не шлёт. Порог заведомо меньше любой осмысленной паузы между командами, так что на обычную работу это не влияет; если паузу выставить в ноль, проверка отключается вместе с ней.
Ничего настраивать не нужно, и совпадающее с сеткой время старта менять тоже не нужно — это штатный случай.
Отдельно блюпринт защищён от нескольких «тихих» ошибок настройки, каждая из которых иначе навсегда и без единого сообщения отключила бы зарядку:
| Ситуация | Что было бы | Что делает блюпринт |
|---|---|---|
| Минимальный и максимальный ток перепутаны местами | Ток выше расчётного для проводки | Побеждает максимум: поднять потолок нельзя, опустить пол можно |
| В поле энергии сессии указан накопительный счётчик | «Уже залито 4500 кВт·ч» → цель считается достигнутой | Считает сенсор недоступным и заряжает по резервному плану |
| Сняты все галочки дней недели | Окно не откроется никогда | Трактует как «все дни» |
| Сенсор напряжения врёт (мВ вместо В) | Ток падает до минимума на всю сессию | Отбрасывает значения вне 175–280 В |
| У зоны нет отображаемого имени | Машина никогда не «дома» | Откатывается на идентификатор зоны |