IT-инфраструктура для бизнеса и творчества
Разработка
Selectel

Сделай сам: трекер, который напомнит, что пора отвлечься от дел и передохнуть

Автоматизируем напоминания о перерывах на работе.

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

В этом материале Станислав Грицинов, разработчик электронных устройств, собирает трекер, который наблюдает за пользователем во время работы и присылает уведомление в Telegram, если тот засиживается без перерыва больше трёх часов. А к сообщению прикрепляет видеотренировку — чтобы перерыв прошёл с пользой.

Список компонентов

По задумке трекер — это устройство с камерой, которая снимает сидящего за монитором человека, фиксируясь на его лице. Если лицо не пропадает из кадра больше трёх часов подряд, то трекер сигнализирует сообщением — в нашем случае в Telegram.

Устройство мы будем собирать на основе микрокомпьютера Raspberry Pi 4 (1–8 Gb RAM) с картой microSD. Карту стоит подобрать ресурсоёмкую (рассчитанную на большое количество циклов перезаписи), с объёмом больше 16 Гб. Помимо этого нам потребуются:

  • радиатор;
  • вентилятор [5V];
  • блок питания [5V, 2A];
  • кабель micro HDMI;
  • монитор;
  • USB-клавиатура;
  • USB-мышь;
  • USB-веб-камера.

Установка пакетов: Python 3, OpenCV, telegram-send, facial_recognition

После установки системы на SD-карту, запустив Terminal, вводим по очереди команды для обновления системы перед установкой пакетов:

sudo apt update sudo apt upgrade

Затем устанавливаем Python 3:

sudo apt install python3 sudo apt install python3-pip

И проверяем установленные версии:

python3 --version pip3 --version

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

Устанавливаем OpenCV, face_recognition и imutils (некоторые команды исполняются несколько минут):

sudo apt install cmake build-essential pkg-config git sudo apt install libjpeg-dev libtiff-dev libjasper-dev libpng-dev libwebp-dev libopenexr-dev sudo apt install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libxvidcore-dev libx264-dev libdc1394-22-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev sudo apt install libgtk-3-dev libqtgui4 libqtwebkit4 libqt4-test python3-pyqt5 sudo apt install libatlas-base-dev liblapacke-dev gfortran sudo apt install libhdf5-dev libhdf5-103 sudo apt install python3-dev python3-numpy

Увеличим размер swap для успешной компиляции OpenCV (если swap небольшой — возможны зависания). Правильный расчёт размера файла подкачки выглядит следующим образом: 2 × RAM. В нашем примере «малинка» имеет 1 Гб оперативной памяти, поэтому размер файла подкачки будет составлять 2 Гб, то есть 2048 Мб. Внесите это значение в конфигурационный файл.

Откройте файл подкачки:

sudo nano /etc/dphys-swapfile

Измените размер swap CONF_SWAPSIZE=100 на CONF_SWAPSIZE=2048.

Затем выйдите по комбинации клавиш Ctrl + X и в ответ на запрос программы нажмите Y + Enter (сохранить файл).

Перезапускаем демона, управляющего файлом подкачки:

sudo systemctl restart dphys-swapfile

Я буду использовать версию OpenCV: 4.5.3. Скачиваем и распаковываем архивы с исходниками:

wget -O opencv.zip https://github.com/opencv/opencv/archive/refs/tags/4.5.3.zip unzip opencv.zip wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/refs/tags/4.5.3.zip unzip opencv_contrib.zip mkdir ~/opencv-4.5.3/build cd ~/opencv-4.5.3/build

Настройка сборки, оптимизированной для Raspberry Pi:

cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib-4.5.3/modules -D ENABLE_NEON=ON -D ENABLE_VFPV3=ON -D BUILD_TESTS=OFF -D INSTALL_PYTHON_EXAMPLES=OFF -D OPENCV_ENABLE_NONFREE=ON -D CMAKE_SHARED_LINKER_FLAGS=-latomic -D BUILD_EXAMPLES=OFF ..

Сборка и установка:

make -j$(nproc) sudo make install sudo ldconfig

Команда make -j$(nproc) при использовании всех ядер процессора будет выполняться около часа. После успешной установки OpenCV вернём размер swap к исходному (для сохранения ресурса SD-карты):

sudo nano /etc/dphys-swapfile

Меняем размер swap CONF_SWAPSIZE=2048 на CONF_SWAPSIZE=100.

Снова применяем комбинацию клавиш «Выход» — Ctrl + X, а затем сохраняем файл — Y + Enter. Перезапускаем демона:

sudo systemctl restart dphys-swapfile pip3 install face_recognition pip3 install imutils

Устанавливаем Telegram-send:

sudo pip3 install telegram-send

А затем — пакет для распознавания лиц facial_recognition:

cd && git clone https://github.com/carolinedunn/facial_recognition

Настройка облачного хранилища Selectel

Я решил не ограничиваться только уведомлениями «Вы работаете без перерыва три часа». Чтобы трекер стал полезнее, я добавил в него видео с тренировкой для глаз, массажем шеи, короткой медитацией и зарядкой — какое именно, бот будет выбирать случайным образом. Видеозаписи нашёл в сети, но для корпоративного пользования подготовил бы их самостоятельно — чтобы все ролики были с хорошей картинкой и звуком, без лишних предисловий.

Чтобы не слишком забивать роликами по 5–10 минут локальное хранилище, выношу их в облако Selectel. Регистрируюсь в панели управления, оплачиваю объектное хранилище, нахожу «Облачное хранилище» в панели управления и перехожу в пункт меню «Пользователи». Создаю нового пользователя и контейнер в хранилище Selectel. Название хранилища стоит вводить без пробелов — иначе в ссылках, которые бот отправит в Telegram, нужно будет заменять пробелы на URL-код %20.

Тип хранилища — «Публичный», класс — «Стандартное хранение». В настройках контейнера выбираем «Управление доступом» и для указанного пользователя ставим «Чтение и запись».

Ниже список видео, которые присылает мой бот (их можно скачать и использовать для вашей разработки):

Загружаем файлы в контейнер, по ссылке — описание API для работы с хранилищем Selectel.

Настройка telegram-бота

Создаём бота через BotFather — находим его через поиск и начинаем диалог с помощью /newbot. Выбираем название и пользовательское имя бота, в ответ BotFather отправит вам токен.

Вводим команду в Terminal:

telegram-send --configure

Затем вводим токен из сообщения BotFather (Use this token to access the HTTP API):

Получаем пароль — его нужно отправить боту после сообщения /start. Теперь он готов принимать сообщения-напоминания со ссылками видео.

Настройка распознавания лиц facial_recognition

Чтобы устройство отличало пользователя от кота или фикуса на окне, обучим его распознавать лицо:

  • Откройте в File Manager папку /home/pi/facial_recognition/dataset/.
  • Создайте папку с именем пользователя, время работы которого планируете отслеживать. В проекте пользователя я назвал «USER».
  • Скопируйте в папку готовый набор фото в разных ракурсах с хорошим освещением (10 снимков вполне хватит).

Вместо готового набора фото можно создать набор с помощью веб-камеры. Для этого можно использовать, например, Text Editor: меняем в строке 3 файла headshots.py: 'Caroline' — на нужное имя и запускаем файл headshots.py из папки /home/pi/facial_recognition в Terminal:

cd facial_recognition python3 headshots.py

Запускаем файл train_model.py для обучения:

python3 train_model.py

Обработанные данные сохраняются в файле encodings.pickle.

Для проверки распознавания можно запустить файл facial_req.py:

python3 facial_req.py

Нажмите Ctrl + C для остановки работы тестовой программы распознавания.

Запуск python-программы

Распаковываем архив Work_Time_Python в новую папку и открываем Thonny Python IDE. Переходим в меню системы Raspberry, затем в меню Thonny Python IDE. Открываем файл cURL_request_def.py. Вводим в строках:

Строка 8: номер вашего аккаунта.

Строка 9: имя пользователя с доступом к контейнеру видеофайлов.

Строка 10: пароль аккаунта Selectel.

Строка 11: название контейнера с файлами.

Сохраняем файл cURL_request_def.py (его можно закрыть).

Открываем файл Work_time_tracker.py. Запускаем его кнопкой RUN (круглая зелёная).

Появляется окно Facial Recognition, отображающее кадры с веб-камеры и прямоугольник распознавания лица с заданным именем (USER или другое выбранное вами имя).

Чтобы остановить работу программы нужно нажать красную кнопку STOP.

Во время работы программы Work_time_tracker.py (распознан продюсер vc.ru)

С появлением пользователя в кадре и его распознавания начинается отсчёт: если человек не покидает рамок камеры три часа, то получит напоминание об этом в Telegram, а ещё — случайно выбранное видео из хранилища Selectel.

Время непрерывной работы задаётся в строке 15 файла Work_time_tracker.py: detection_interval (10 800 с. = 3 часа). Если пользователь продолжает работать, второе сообщение придёт через ещё один интервал (3 часа) detection_interval, и так далее.

При этом даже если в течение интервала detection_interval пользователь отвлекался от работы на незначительное время (например, отворачивался и камера его не распознавала), отсчёт не прерывается. Для этого в строке 16 задано absent_interval, 30 секунд. Если камера теряет его больше чем на полминуты — отсчёт прерывается и возобновляется, когда пользователь найден. Количество секунд можно настроить под себя так, чтобы трекер не засчитывал за отдых, например, выходы в туалет — в примере мы считаем их как перерыв. Интервал детектирования пользователя в кадре задаётся в строке 17: detection_interval (1 секунда).

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

{ "author_name": "Selectel", "author_type": "editor", "tags": ["selecteldiy"], "comments": 26, "likes": 23, "favorites": 46, "is_advertisement": false, "subsite_label": "dev", "id": 288561, "is_wide": true, "is_ugc": false, "date": "Wed, 15 Sep 2021 10:48:53 +0300", "is_special": false }
(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ // { // name: 'camera', // url: `${cdnUrl}CameraCat`, // text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', // link: '1', // num: 3 // }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', num: 1 }, { name: 'cloud', url: `${cdnUrl}CloudCat`, text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', link: 'https://vc.ru/dev/294799-maneki-neko', num: 2 } ] let buttonCycle = document.querySelector('.button--cycle') let buttonChoose = document.querySelector('.button--choose') let buttonMobile = document.querySelector('.button--mobile') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) buttonChoose.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) buttonMobile.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { sendEvent(`Promo ${articles[currentArticleNumber].num} Right`, 'Click') if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?3' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } const sendEvent = (label, action = 'Click') => { const value = `SelectelDIY — loc: Footer — ${label} — ${action}`; if (window.dataLayer !== undefined) { window.dataLayer.push({ event: 'data_event', data_description: value, }); } }; function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите научим?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg?3`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
26 комментариев
Популярные
По порядку
Написать комментарий...

Это точно vc, а  не хабр?

а вообще есть обратная фигня которая бы помогала заняться делами и отвлечься от ерунды?

12

Хабр все, каждый день там пробив дна и неадекватная аудитория из школьников и псевдоинтеллектуальных задротов.

6

Всех адекватных забанили. Остались только жополизы, которые боятся, что им сольют анонимно карму

1

и карма там дебильная. высказываешь непопулярное мнение - держи блокировку на определенное время.

1

Ага, мне так школьники карму слили за критику васянской сборки для пентеста под виндоувс)))

1

увы, но на счет хабра и неадекватной аудитории — вы правы.

1

хабр мертв, совершенно. Аудитория уехала на VC и DTF

1

На python я уже не потяну.
Делал такого бота на геткурсе с помощью процесса.
Он тупо каждые полчаса спрашивал в телеге- чем занимаешься?
Как ни странно-помогало.

А вот упражнения для глаз это хорошая идея. Доработаю своего.

0

Пиздатый бот
Остался доступ?

0

Нет

0

 а вообще есть обратная фигня которая бы помогала заняться делами и отвлечься от ерунды?

Есть способы:
1. Кофе
2. Музыка

Если эти способы не помогают, значит нужно идти к врачу и лечить здоровье.

0

Нет, потому что читая VC ты уже занимаешься ерундой, был бы парадокс

0

Если лицо не пропадает из кадра более 3 часов, то подаем ток на баттплаг. ред.

5

Вы бы ещё завод построили для такой задачи. 

3

можно начать курить, например ;-)

1

А купить дешёвый китайский браслет и сделать под него прошивку не вариант?

0

это слишком скучно, речь-то про diy.

1

Вы так надуетесь писать прошивку что посинеете от китайской документации 🥲

1

Вот это мой diy дозиметр, даже чип от TI, но это очень плохой ble чип cc2541  ред.

2

Почему на сбм 20 а не бета-1, или бета-2?

0

Так они огромные)

0

За то с них толку больше.
СБМ20 и медленный и не чувствительный по сравнению с бетами. Хотя там вроде сборки на сбм20 когда их 4или 8шт разом неплохие. 

0

Неее, мы же говорим, чтоб с удовольствием что-то собрать, а не задолбаться от такой дичи)))

0
Зарубежный Слава

Комментарий удален по просьбе пользователя ред.

0

Кому-то однозначно полезно будет, но лично мне удобнее интуитивно управлять временем работы и отдыха, чем по напоминалкам  

0

Комментарий удален

Зарубежный Слава

Комментарий удален по просьбе пользователя

0
Читать все 26 комментариев
«Российский рынок акций был и остаётся одним из самых привлекательных в мире»

Виталий Исаков, директор по инвестициям УК «Открытие» («Открытие Инвестиции»).

"Ситидрайв" оштрафовал за чужой косяк

Давно уже пользовался "YouDrive" (ныне "Ситидрайв"). В целом, меня всё устраивало. Ровно до 2 октября. Пришло уведомление о том, что пришёл штраф (мой первый штраф в данной компании, за три года). Полез смотреть, и очень удивился. Однако, на фото, 25 сентября, 8 утра, адрес - Ферганский проезд.

Будущее наступит во вторник на OneRetailConf
Дефицит цифровых кадров в России и их подготовка

Весь мир переходит в цифровую среду. Пока в ежегодном глобальном рейтинге конкурентоспособности Россия занимает 43-е место, но задерживаться на нем не намерена. Для этого правительство запустило программу «Цифровая экономика РФ», которая будет поддерживать цифровую экономику в стране и подготовку необходимых кадров.

«Spotify: История продукта». Как мы разработали алгоритмы музыкальных рекомендаций

Из онлайн-библиотеки — в сервис персонализированных рекомендаций.

Прокрастинация: как перестать откладывать на потом и 4 способа которые мне помогли

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

IKEA не может доставить оплаченный товар

Обожаю товары из IKEA. Простые, стильные, иногда дешевые. Но вот с её доставкой у меня не заладилось c самого начала. Пользовался ей раза три и каждый раз проблема. То не довезут позицию, то перенесут. Но в этот раз всё зашло слишком далеко.

Netflix оценил выгоду от «Игры в кальмара» почти в $900 млн Статьи редакции

В 40 раз больше суммы, которую онлайн-кинотеатр заплатил за сериал.

Объявлены победители Finlanding
«Ситидрайв» выставил штраф в семь тысяч за свой поломанный Smart

Люблю каршеринг всей душой, даже если дорого и даже если Smart. История такая: в пт (15.10.21) вечером арендовала у «Ситидрайва» на сутки Smart м267но799 (других авто рядом не было), чтобы съездить в Конаково к бабушке.

Ростелеком. Бардак во всем

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

null