Skip to content

About

Учебный банк времени: ребёнок зарабатывает экранное время заданиями на своём сайте, сервер сам выдаёт минуты через Google Family Link. FastAPI + Home Assistant, на старом ноутбуке.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Учебный банк времени

Экранное время, которое ребёнок зарабатывает сам — а выдаёт его сервер, не родитель.

Ребёнок открывает на планшете свой учебный сайт, смотрит разбор задания ВПР или проходит короткую миссию, отвечает на вопросы. Сервер проверяет ответы, записывает награду в журнал и сам поднимает дневной лимит в Google Family Link — через минуту на планшете появляются минуты, и Roblox открывается. Никаких «папа, добавь время»: сделка работает без родителя в цикле.

Как это выглядит

Тёмная тема — потому что ребёнок занимается вечером; язык интерфейса — игровой HUD, а не школьный сайт. Дизайн-система — в docs/design-system.md.

Экран дня Миссия по карточкам
Экран дня: табло минут, ворота домашки, миссии и разборы ВПР Миссия: шаги, условие, вопросы, бесплатные подсказки
Снимок тетради Страница родителя (телефон)
Съёмка домашки с камеры планшета Родитель: снимки, сводка пилота, чек-лист, черновики

На табло — единственная валюта: минуты. Заработанное, но запертое домашкой, окрашено янтарным; выдача на планшет показывается честно, в трёх состояниях. Ошибка ребёнка не бывает красной — красный оставлен сбоям системы.

Почему это работает

  • Домашка — сначала. Отметка «сделал» принимается только со снимком тетради с камеры планшета и стоит 45 минут сразу. Пока домашка не отмечена, заработанное на сайте лежит в журнале и ждёт. В будни «не задавали» — только со снимком дневника; в воскресенье делается домашка на понедельник.
  • Доказательство — ответы, а не просмотр. Видео нельзя «досмотреть» ради минут: минуты дают вопросы по разбору, и правильные ответы никогда не уходят в браузер.
  • Честная арифметика. Квота = min(максимум, база + домашка + заработанное), ставится абсолютным значением. Одно задание — одна награда в день, две вкладки и перезапуск сервера не удваивают время. Баланс всегда пересчитывается из журнала.
  • Сервер не доверяет Google на слово. После каждой записи квота перечитывается; три состояния выдачи — подтверждено / не применено / неизвестно. Ручную правку родителя в Family Link сервер замечает, запоминает как надбавку дня и прибавляет к заработанному — обе руки уважаются, и надбавка видна родителю в сводке.
  • Ребёнок не наказан за поломку. Базовые 15 минут живут в Family Link независимо от сервера: выключенный ноутбук — это не ноль экрана.
  • Родителю — только контроль. Страница /parent со снимками тетради по дням и кнопкой «отозвать»: минуты запираются обратно, награды в журнале целы.

Что внутри

Контент 31 разбор заданий ВПР по математике (4 класс) с видео и вопросами, сверенные с ключами, в том числе 13 полных вариантов 2025 года; 23 миссии по 9 навыкам, ротация по навыку — повтор навыка приходит с новым условием
Выдача времени Home Assistant + интеграция HAFamilyLink, вызовы через REST; фоновый исполнитель с перечиткой и защитой от ручной правки
Приложение FastAPI + SQLite без ORM, Jinja2, своя дизайн-система в одном CSS без внешних запросов; 420+ тестов, включая пересчёт каждой цепочки ответов
Железо Старый ноутбук под Debian и Docker Compose; сайт виден только в домашней сети, наружу через туннель — по желанию
Стоимость Электричество и домен. Никаких платных API в ежедневном цикле

Проверено на настоящем планшете: команда доезжает до Family Link за 9 секунд, разовая надбавка истекает в полночь сама, ручная правка родителя не перезаписывается.

Честно о риске. У Family Link нет официального API. HAFamilyLink работает через неофициальные запросы Google, и его авторы предупреждают о возможной блокировке аккаунта. Решение принимается осознанно.


Документация

Дальше — инструкция по запуску: две машины, установка, этап 1.


Прочитайте до начала

Интеграция HAFamilyLink работает через неофициальные, восстановленные обратной разработкой запросы Google. Авторы проекта пишут прямо:

использование интеграции может нарушать условия использования Google и привести к блокировке аккаунта

Для одной семьи с редкими запросами риск невелик, но нулевым он не является.

Второе. Ни один сервис из этого набора нельзя открывать в интернет: через порт 8099 отдаётся полная сессия Google. В docker-compose.yml поэтому везде стоит 127.0.0.1 — трогать это не нужно.


Две машины, не одна

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

Рабочий ноутбук Сервер
Что это Windows, ваше рабочее место Samsung R428, Debian, без графики
Роль здесь пишется код, здесь браузер работает круглосуточно, держит контейнеры
Приглашение в терминале PS C:\...> aidar@agent:~$
Что здесь запускают ssh, scp, правки кода docker, python3, sudo

Признак, что вы не на той машине: команда ssh agent внутри уже открытой SSH-сессии заставит сервер подключиться сам к себе. Выглядит это как запрос пароля и жалобы «Address already in use».

Подключение к серверу:

ssh agent

Алиас настроен в ~/.ssh/config на рабочем ноутбуке. Если соединения нет — проверьте, что выключен AmneziaWG: с поднятым туннелем сервер недоступен полностью, включая ping.


Первоначальная настройка сервера

Уже проделано, подробности и результаты — в docs/etap0-checklist.md. Кратко, если придётся повторять на другой машине:

1. Сеть. У ноутбука мёртвый Ethernet, работает Wi-Fi:

sudo bash ~/child-mind/server/setup-wifi.sh

Скрипт спрашивает домашнюю сеть и запасную (хотспот телефона), настраивает wpa_supplicant и systemd-networkd. Запускать с консоли самого сервера.

2. Доступ. На сервере:

sudo apt install -y openssh-server avahi-daemon

Затем с рабочего ноутбука создаётся ключ и кладётся в ~/.ssh/authorized_keys на сервере. avahi-daemon даёт имя agent.local, чтобы не искать IP-адрес.

3. Проект на сервер. С рабочего ноутбука:

cd "D:/AI/Child Mind" && tar --exclude=.git --exclude=data --exclude=snapshots --exclude=.env --exclude=__pycache__ -czf - . | ssh agent "mkdir -p ~/child-mind && tar xzf - -C ~/child-mind"

Этой же командой обновляется проект после правок.

4. Docker. На сервере:

sudo bash ~/child-mind/server/install-docker.sh

Ставит из официального репозитория Docker: в Debian trixie нет пакета с compose v2, а старый docker-compose не понимает наш docker-compose.yml. После установки переподключитесь (exit, затем ssh agent) — иначе членство в группе docker не подействует и команды будут требовать sudo.


Этап 1: запуск стенда

Шаг 1. Настройки

На сервере создайте .env — либо скопируйте .env.example и заполните, либо сгенерируйте секреты на месте, чтобы они не проходили через переписку:

cd ~/child-mind && cp .env.example .env && chmod 600 .env

Обязательно заполнить: TZ (должен совпадать с часовым поясом Google-аккаунта ребёнка), VNC_PASSWORD, FL_AUTH_API_KEY. Остальные поля появятся на шаге 6.

Шаг 2. Контейнеры

cd ~/child-mind && docker compose up -d

Первый запуск Home Assistant занимает около минуты и грузит процессор на 100% — на машине 2010 года это нормально. Проверить:

docker compose ps

Шаг 3. Туннель до рабочего ноутбука

Порты сервера закрыты для сети, поэтому их надо перекинуть к себе. Запускать на рабочем ноутбуке, не на сервере:

ssh -N -L 8099:127.0.0.1:8099 -L 6080:127.0.0.1:6080 -L 8123:127.0.0.1:8123 agent

Окно не закрывать, пока не закончите. Пока туннель поднят, три адреса 127.0.0.1 на вашем компьютере ведут на сервер.

Шаг 4. Вход в Google — один раз

Адрес страницы должен содержать ключ API. Без него кнопка «Start Authentication» отвечает Failed to start: защита распространяется и на запуск авторизации, а интерфейс читает ключ из адресной строки.

Получите готовый адрес — на сервере:

echo "http://127.0.0.1:8099/?api_key=$(grep FL_AUTH_API_KEY ~/child-mind/.env | cut -d= -f2)"

Дальше:

  1. Откройте напечатанный адрес в браузере на рабочем ноутбуке.
  2. Нажмите «Start Authentication».
  3. Во второй вкладке откройте http://127.0.0.1:6080/vnc.html — это окно браузера, работающего на сервере.
  4. Войдите в родительский Google-аккаунт, пройдите двухфакторное подтверждение.
  5. Дождитесь подтверждения на первой вкладке.

Пароль вводите вы, в окне на своём экране.

Проверить, что сессия сохранилась:

KEY=$(grep FL_AUTH_API_KEY ~/child-mind/.env | cut -d= -f2); wget -qO- --header="X-API-Key: $KEY" http://127.0.0.1:8099/api/cookies/check

Ответ {"exists": true} означает успех.

Шаг 5. Интеграция

На сервере:

cd ~/child-mind && python3 tools/install_familylink.py && docker compose restart homeassistant

Скрипт кладёт файлы через контейнер: каталог конфигурации создан Docker от имени root, и записать туда с диска обычный пользователь не может.

Шаг 6. Home Assistant

  1. Откройте http://127.0.0.1:8123 (через тот же туннель), создайте локальную учётную запись — она к Google отношения не имеет.
  2. Настройки → Устройства и службы → Добавить интеграцию → Family Link.
  3. Адрес сервиса авторизации: http://familylink-auth:8099 — внутреннее имя контейнера, снаружи недоступно.
  4. Ключ API — значение FL_AUTH_API_KEY из .env.
  5. Strict mode оставьте выключенным. С ним Home Assistant начнёт откатывать ваши ручные изменения в приложении Family Link, а на пилоте вы должны иметь возможность вмешаться.

Шаг 7. Токен и идентификаторы

В Home Assistant: профиль слева внизу → Безопасность → Токены долгосрочного доступа → Создать токен. Скопируйте сразу, второй раз он не покажется. Впишите в .env как HA_TOKEN.

Затем на сервере:

cd ~/child-mind && python3 tools/fl.py check && python3 tools/fl.py discover

discover покажет идентификаторы ребёнка и устройств — впишите их в .env (FL_CHILD_ID, FL_TABLET_DEVICE_ID, FL_PHONE_DEVICE_ID).

Шаг 8. Снимок — до экспериментов

cd ~/child-mind && python3 tools/fl.py snapshot

Точка отката: файл в snapshots/ покажет, как всё было настроено до нашего вмешательства.

Шаг 9. Проверки

Откройте docs/etap1-checklist.md и идите сверху вниз, записывая результаты прямо в файл. Семь проверок, каждая с готовой командой. Ответ «не сработало» — такой же полезный результат: он определяет, каким путём мы пойдём дальше.


Шпаргалка

На сервере:

docker compose ps                 # что работает
docker compose logs -f            # что происходит (выйти: Ctrl+C)
docker compose restart homeassistant
docker compose down               # остановить всё

python3 tools/fl.py check         # связь с Home Assistant
python3 tools/fl.py discover      # id ребёнка и устройств
python3 tools/fl.py snapshot      # сохранить настройки
python3 tools/fl.py show          # текущее состояние
python3 tools/fl.py set-limit --minutes 35
python3 tools/fl.py set-limit --minutes 0 --phone
python3 tools/fl.py app --package com.android.chrome --mode unlimited
python3 tools/fl.py watch --minutes 10

На рабочем ноутбуке:

ssh agent                         # подключиться к серверу
ssh -N -L 8099:127.0.0.1:8099 -L 6080:127.0.0.1:6080 -L 8123:127.0.0.1:8123 agent

Имена приложений для --package:

Приложение Имя пакета
Chrome com.android.chrome
Roblox com.roblox.client
YouTube com.google.android.youtube

Точное имя любого другого приложения видно в адресе его страницы в Google Play, в части ?id=.


Что дальше

Этап 2 — сайт с уроками, журнал наград и очередь выдачи — начинается после того, как этап 1 пройден. Если какая-то из семи проверок провалится, мы меняем исполнитель ограничений, а не переписываем всё: сайт и журнал от Family Link не зависят.

About

Учебный банк времени: ребёнок зарабатывает экранное время заданиями на своём сайте, сервер сам выдаёт минуты через Google Family Link. FastAPI + Home Assistant, на старом ноутбуке.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages