Вашему вниманию предлагается программа для контроля и ограничения времени, проведённого за компьютером, например ребёнком.

Движущих факторов для создания первой версии было два:

  1. Собственно проблема. Учебный год, доступные компьютеры, которые вроде бы нужны для учёбы, но при неограниченном доступе к ним времени ни на что другое уже не оставалось.

  2. Самообразование и тренировка навыков написания скриптов на Python.

  3. Ну и надежда, что подобные ограничения будут мотивировать ребенка на «взлом» системы и как следствие изучение чего‑то полезного.:)

Сразу скажу: с одной стороны, никаких эксклюзивных решений и ноу‑хау в программе нет. С другой стороны, имеющиеся на рынке и в свободном доступе решения по разным критериям меня не устраивали. Поэтому я решил попробовать написать своё.

Первую версию я писал сам, на Python. Поддерживалась одна платформа: Windows 10/11.

Со временем парк компьютеров и операционных систем дома вырос, а вместе с ним выросло и решение. Сейчас дома есть рабочая станция с тремя ОС (Windows, Linux и macOS, выбор при загрузке) и ноутбук. А ребёнок, разумеется, быстро понял: если время в одной системе закончилось, можно перезагрузиться в другую.

Текущая версия:

  • поддерживает несколько компьютеров и операционных систем с едиными политиками доступа и общим дневным лимитом: минуты, потраченные на Windows, Linux и macOS, складываются;

  • работает в домашней сети, а вне её (например, ноутбук в поездке) продолжает работать автономно: применяет более строгие лимиты и досылает статистику, когда снова видит сеть;

  • поддерживает алиасы имён пользователей, если логин одного и того же человека в разных системах пишется по‑разному;

  • имеет статистику: сколько минут каждый ребёнок провёл на каждом компьютере за любой день, плюс общую ленту событий со всех компьютеров с выгрузкой в CSV;

  • выдает системное уведомление, почему вход не разрешён, а не просто молча выкидывает из системы.

Преимущества для меня:

  1. Единые политики для разных платформ (Windows, macOS, Linux) и физических устройств.

  2. Всё написано на Python, то есть можно поменять под себя. Было легко поменять. По мере роста функциональности и, как следствие, объёма кода это стало уже не так просто. К тому же последующие версии писались с помощью ИИ (Claude Code). Архитектуру мы обсуждали и решали вместе, но код писал он, поэтому я хуже знаю, что и где реализовано. Об этом опыте ниже.

  3. Данные не уходят «в облако производителя»: статистика хранится на моём собственном NAS.

Как это устроено

Решение состоит из двух частей.

Конфигуратор — графическое приложение (customtkinter). В нём мы добавляем профили детей, задаём политики доступа, настраиваем подключение к хранилищу и смотрим статистику. Его можно запустить на любом из компьютеров.

Для каждого человека задаются три параметра: максимум минут в день, самое раннее и самое позднее время входа. Отдельно задаются будни и выходные, плюс исключения по дням недели (например, в пятницу можно дольше). Каждое значение наследуется независимо: от исключения дня к будням/выходным ребёнка, а от них к общим значениям по умолчанию. Пустое поле означает «как по умолчанию».

Трекер — фоновая программа, которая отслеживает активные сеансы и проверяет их на соответствие политикам. На каждом компьютере и в каждой ОС работает свой экземпляр.

Трекер

Трекер запускается при старте системы от имени SYSTEM (Windows) или root (Linux, macOS) и работает постоянно, циклами. Раз в 5 минут (настраивается) он:

  1. Получает список сеансов. В каждой ОС для этого используется свой механизм:

    • Windows: Terminal Services API (WTSEnumerateSessions); заблокированный экран определяется по процессу LogonUI.exe в сеансе;

    • Linux: loginctl (systemd‑logind). Учитываются только локальные графические сеансы, SSH и текстовые консоли не считаются; блокировка определяется по LockedHint;

    • macOS: ioreg, ключ IOConsoleUsers: кто на экране, кто «в фоне» из‑за быстрого переключения пользователей, у кого заблокирован экран.

  2. Сопоставляет логин с человеком (с учётом алиасов). Чужие учётные записи (например, родительские) не учитываются и не записываются.

  3. Начисляет время только активным и незаблокированным сеансам. Время измеряется монотонными часами процесса и ограничивается интервалом проверки. Поэтому ни перевод часов, ни сон компьютера в использованное время не попадают.

  4. Складывает минуты ребёнка со всех компьютеров и при достижении лимита завершает сеанс.

Между циклами трекер каждые 20 секунд проверяет новые входы. Если ребёнок входит, когда время на сегодня уже закончилось или вход в это время не разрешён, он видит сообщение с настоящей причиной. Через 15 секунд сеанс завершается.

Сообщение показывается средствами самой ОС: на Windows это WTSSendMessage (окно в сеансе пользователя из службы SYSTEM), на Linux уведомление через notify-send или D‑Bus от имени пользователя, на macOS диалог через osascript.

Запуск: Windows, Linux, macOS

Трекер упаковывается с помощью PyInstaller. Это не компиляция в машинный код: PyInstaller собирает в одну папку небольшой нативный запускатель, собственную копию интерпретатора Python, все библиотеки и байт‑код программы. На целевом компьютере Python не нужен, и обновление системного Python ничего не сломает. Отдельно собирать приходится под каждую ОС: под Windows получается tracker.exe, под Linux исполняемый ELF‑файл, под macOS — Mach‑O.

Запускает эту программу штатный механизм ОС:

  • Windows: задача планировщика (Task Scheduler) при старте, от SYSTEM, без ограничения времени работы и с перезапуском при сбое. В комплекте есть PowerShell‑скрипт, который создаёт задачу с нужными настройками, но её можно создать и вручную;

  • Linux: systemd‑служба (Restart=always);

  • macOS: LaunchDaemon (KeepAlive).

Установщика нет: папка копируется в защищённое место (Program Files, /opt, /usr/local). Права проверяет и при необходимости исправляет сам конфигуратор.

Общее хранилище: как подружить несколько компьютеров

Самое интересное архитектурное решение — как делить одно «время» между компьютерами, которые могут работать одновременно, а могут и не видеть друг друга.

Хранилище — обычный WebDAV по HTTPS с паролем. У меня это приложение WebDAV на TrueNAS Scale в домашней сети, но подойдёт и облачный WebDAV. Протокол выбран намеренно простой: от хранилища нужны только «прочитать файл», «записать файл целиком», «список файлов», «удалить». Ни дозаписи, ни блокировок.

Отсюда главное правило: каждый компьютер пишет только свои файлы.

config/limits.toml                      общие лимиты (пишет только конфигуратор)
records/<компьютер>/<дата>.json         минуты за день по каждому логину
events/<компьютер>/<дата>.jsonl         лента событий за день
writers/<компьютер>.json                имя компьютера, ОС, версия

Общее время ребёнка за день — это сумма его записей со всех компьютеров. Два компьютера никогда не пишут в один файл, поэтому конфликтов нет в принципе, и блокировки не нужны.

Каждый цикл трекер сначала пишет локально, потом отправляет файлы на NAS. Если NAS недоступен (ноутбук вне дома, NAS выключен), трекер:

  • продолжает считать время локально;

  • применяет более строгие лимиты: из личных лимитов ребёнка и общих значений по умолчанию для каждого параметра берётся строжайший. Так отключение Wi‑Fi не даёт лишнего времени;

  • отправляет накопленное, когда хранилище снова доступно.

Конфигурация (limits.toml) лежит на NAS. Каждый трекер скачивает её в каждом цикле, проверяет и только потом заменяет свою локальную копию. Поэтому ошибка в файле никогда не отключает контроль: трекер просто продолжает работать с последней корректной версией. Номер ревизии в файле не даёт двум конфигураторам незаметно перезаписать изменения друг друга.

Статистика

На вкладке Activity за любой день видно, сколько минут каждый ребёнок провёл на каждом компьютере, общий итог и лимит. Ниже — общая лента событий со всех компьютеров: вход, блокировка экрана, предупреждение о скором окончании времени, выход и его причина, потеря и восстановление связи с хранилищем. Обе таблицы можно выгрузить в CSV.

Безопасность

Модель угроз — любопытный ребёнок с обычной (не административной) учётной записью. От неё и строится защита:

  • трекер работает от SYSTEM/root, и обычный пользователь не может его остановить;

  • папка программы защищена от записи: иначе можно было бы подменить программу, которая работает от SYSTEM;

  • файл с паролем к хранилищу читают только администраторы и SYSTEM (root);

  • соединение с NAS идёт только по HTTPS с проверкой сертификата. Для самоподписанного сертификата указывается файл сертификата, а verify=False не используется никогда;

  • всё, что пришло из хранилища, проверяется (размер, схема, типы). Программа только читает данные и никогда их не исполняет.

От чего программа не защищает: загрузка с флешки, вход под администратором, отсутствие трекера в одной из ОС. Это закрывается настройками самой системы: пароль на BIOS/UEFI, запрет загрузки с USB, пароль загрузчика, у детей только обычные учётные записи. Отдельный нюанс Windows: обычный пользователь по умолчанию может сменить часовой пояс и так «сдвинуть» полночь и разрешённые часы. Это право стоит отобрать через secpol.msc. Собственно варианты как «вломать» систему при желании есть. На это и расчет.:)

Грабли, на которые я наступил

Версия 1.x: ошибки, которых не было видно

  • Задача планировщика «умирала» через трое суток. Трекер у меня был одним долгим циклом, а задача создавалась без параметра -ExecutionTimeLimit. По умолчанию Windows останавливает задачу через 72 часа. Перезапускать её было нечему до следующей перезагрузки, так что контроль просто тихо выключался. Лечение: -ExecutionTimeLimit ([TimeSpan]::Zero) и перезапуск при сбое.

  • Пользователь из конфигурации игнорировался. Функция возвращала None для «чужого» пользователя и пустой словарь для «своего, но без личных лимитов». А проверка была if user_config:, и пустой словарь давал False. В логе ни слова, трекер исправно работал и ничего не ограничивал. Лечение: сравнение с None, а пустой профиль наследует лимиты по умолчанию.

  • Исключения по дням недели не работали вообще. Конфигуратор сохранял их с ключами mon, tue…, а трекер искал monday. Нашлось только при переписывании на 2.0; старые файлы теперь конвертируются автоматически.

  • Трекер падал на каждой проверке лимита. Функция возвращала кортеж (минуты, время), а его сравнивали с числом. Пока исключение перехватывалось где‑то выше, этого никто не видел.

  • Одна битая строка в файле статистики отключала учёт. Ошибка разбора при чтении означала, что запись перестаёт работать до ручной правки файла. Хуже того, при ошибке чтения функция возвращала {}, и следующая запись сохраняла только одного пользователя, стирая историю остальных. В 2.0 запись атомарная (временный файл → fsync → os.replace), а повреждённый файл не затирается, а откладывается в сторону.

  • Заблокированный экран считался игрой. Сеанс на экране блокировки для Windows остаётся «активным». Определяю его по процессу LogonUI.exe в этом сеансе.

  • Перерасход времени. Проверка раз в 5 минут означает до 5 лишних минут на каждом компьютере. Особенно если войти снова после того, как выкинуло: у меня набегало 415 минут при лимите 400. В 2.1 появилась быстрая проверка новых входов раз в 20 секунд.

  • Мультизагрузка и часы. Windows хранит в аппаратных часах местное время, Linux и macOS — UTC. После каждой перезагрузки в другую ОС часы «уезжают» на величину часового пояса. Лечится ключом RealTimeIsUniversal в реестре Windows. Сам трекер от этого защищён: время считается по монотонным часам процесса.

  • Забытый порт. URL без :30036 вёл на тот же NAS с тем же сертификатом, но на веб‑интерфейс TrueNAS. Вместо файла лимитов приходила HTML‑страница. Теперь проверка подключения прямо говорит: «этот адрес отвечает без пароля, это не WebDAV‑ресурс, проверьте порт».

Опыт разработки с ИИ

Вторая версия писалась уже с Claude Code. Схема работы получилась такая: я выступал архитектором и админом, ИИ — разработчиком. Архитектуру обсуждали по пунктам, примерно как на ревью: хранилище, идентичность пользователей, время и часы, надёжность записи, безопасность. Решения фиксировались в журнале, а код и тесты (около 70) писал ИИ. Я ставил и проверял всё на реальных машинах и приносил логи.

Что понравилось: скорость, внимание к краевым случаям (сон, перевод часов, повреждённые файлы, офлайн) и тесты. Что стоит учитывать: я хуже знаю код изнутри. А часть проблем (масштабирование на Linux, сертификаты на Mac, групповая политика) нашлась только при реальной установке: ни ИИ, ни тесты их заранее не увидели.

Исходный код, сборки и инструкции по установке для всех трёх систем

Буду рад замечаниям и предложениям в комментариях.