Мой трекер продуктивности — это «волшебное зеркало», но вместо времени, погоды и мотивационных цитат оно показывает:

  • Сколько времени я сегодня потратил на рабочие задачи за компьютером и в смартфоне (RescueTime).
  • Мой список дел из Trello.
  • «Радарный график», отображающий мои затраты времени на разные категории приложений по сравнению со вчерашним днём (RescueTime).
  • Недельные итоги (RescueTime).

Если вы потратили больше 50 % времени на рабочие задачи, вокруг зеркала будет яркая зелёная подсветка. Если меньше 50 % — подсветка будет красной, сигнализируя вам, что нужно повысить продуктивность! Впрочем, распределение вы можете задать самостоятельно.





Сначала я объясню суть трекера продуктивности. Затем приведу два разных списка инструментов и компонентов, так что вы сможете сделать полную или базовую (без светодиодной подсветки) версию трекера, не требующую умения паять. Дальше покажу, как делал прототип своего проекта, чтобы вам было ��егче прототипировать свой. Вы узнаете, как адаптировать код под свои нужды, и в конце рассмотрим отладку устройства.

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

Идея




Я несколько месяцев собирался написать эту статью. Но мне этого не позволял мой старый друг по имени «Прокрастинация». Я постоянно откладывал написание, заполняя своё время просмотром видео из тёмных глубин YouTube.

Однажды я читал статью о прокрастинации и узнал про сервисы, которые могли бы помочь в решении моей проблемы: диспетчер задач Trello и планировщик времени RescueTime. Оба прекрасно подошли под мои нужды, но через какое-то время я перестал заходить на их страницы и начал игнорировать уведомления. И тогда я пришёл к идее своего проекта: хочу отображать данные из приложений на зеркало, висящее на стене. Тогда я точно не спрячусь от своих обязанностей.

Первый набросок проекта был простым: буду использовать API RescueTime API для отображения моей продуктивной/отвлекающей деятельности, а API Trello API — для отображения списка задач на день. Но позднее я добавил и другие возможности, но об этом ниже.

Инструменты и компоненты


Эти инструменты я использовал для создания своего трекера, ваш набор может быть другим!

Для рамы:

  • 4 метра фанеры 7 x 15 см — зависит от размера вашего монитора.
  • Одностороннее зеркало 30 x 40 см — зависит от размера вашего монитора.
  • Монитор 25 x 35 см — нашёл на блошином рынке. Можете использовать любой.
  • Raspberry Pi 3 Model B — подойдёт и Raspberry Pi 2, но придётся найти Wi-Fi-модуль.
  • Кабель HDMI.

Для светодиодной подсветки:

  • Двухметровая RGB-светодиодная лента smd5050 — нужна именно smd5050, причину объясню ниже.
  • Три N-канальных мосфета (например, IRLZ34N).
  • Блок питания 12 В — 2 A.
  • Макетная плата.

Инструменты:

  • Пила по дереву.
  • Клей для дерева.
  • Паяльные принадлежности (для светодиодной подсветки).

Код




Эта глава состоит из трёх частей, вам не нужны все перечисленные выше компоненты, пока достаточно лишь Raspberry Pi и монитора.

Настройка Raspberry Pi


Если вы ещё не настроили Raspberry Pi, сделайте это. Для проекта вам понадобится установить веб-сервер Apache и PHP-LED-контроллер.

Руководство по установке Apache: https://www.raspberrypi.org/documentation/remote-access/web-server/apache.md.

Руководство по установке PHP-LED-контроллера: https://github.com/k1sul1/Raspberry-Pi-PHP-LED-controller.

Теперь из репозитория проекта скачайте на вашу Raspberry Pi файл index.php и положите его сюда: /var/www/html/

Если не знаете, как перемещать файлы с помощью терминала Linux, почитайте здесь: https://www.linux.com/learn/how-move-files-using-linux-commands-or-file-managers.

Адаптация кода


Здесь потребуются небольшие знания HTML/CSS.

Мы будем адаптировать файл index.php, являющийся сердцем проекта. Подключите монитор к Raspberry Pi. Если попытаетесь открыть index.php, то ничего не выйдет, потому что сначала нужно вставить в код API-ключи. Для этого войдите в аккаунт на сайте RescueTime, перейдите в раздел для разработчиков и нажмите Activate This Key. Сохраните куда-нибудь этот ключ.

То же самое сделайте и для API Trello: войдите в аккаунт и на портале для разработчиков сгенерируйте API-ключ.

Теперь откройте в своём текстовом редакторе файл index.php, лежащий в /var/www/html/, и замените [API_KEY] на ключи из RescueTime и Trello. [list_number] — номер списка, который нужен для получения списка задач из Trello. Чтобы сгенерировать номер, сначала создайте в Trello свежий список и назовите «To-Do», задачи из этого списка будут отображаться на волшебном зеркале.

Теперь скопируйте из строки браузера адрес, который выглядит так:

https://trello.com/b/3hS6yyLo/board-name

добавьте в конце .json: https://trello.com/b/3hS6yyLo/board-name.json
нажмите Enter, и экран заполнится кодом. Найдите в этом хаосе имя вашего списка ''To-Do". Это должно выглядеть подобным образом: {"name":"To Do","id":"5981c123cd1b23f13907cd18"}, здесь id — идентификатор вашего списка. Вставьте его значение в [list_number] в файле index.php.

Теперь откройте браузер, в адресной строке напишите localhost и нажмите Enter. На графиках должны отобразиться ваши данные.

Примечание: местоположение графиков может отличаться из-за разрешения вашего монитора. Настроить ширину, высоту и расположение элементов можно в CSS-разделе кода.

Теперь осталось сделать рамку для монитора и подключить светодиоды.

Примечание: если вас не интересует подробное рассмотрение API, можете сразу перейти к следующей главе.

API в подробностях


В основе проекта лежат два API:


Хотя в документации есть вся нужная информация, я объясню, какие данные из API использует наш проект.

В разделе управления временем вызывается RescueTime API и запрашивается информация о сегодняшнем распределении времени:

"https://www.rescuetime.com/anapi/data?key=[API_KEY]&perspective=rank&interval=hour&restrict_begin=".date('Y-m-d')."&restrict_end=".date('Y-m-d')."&format=json"

Здесь
date('Y-m-d') — текущая дата.
perspective=rank — вид сортировки данных. В данном случае по «категории», то есть на что потрачено больше всего времени.

После выполнения вызова мы получаем файл в JSON-формате (см. код файла data.json в конце главы). Из него мы возьмём «Time Spent (seconds)» и «Productivity» (может иметь значения от -2 (отвлекаешься) до 2, (продуктивен)). На основе этих данных можно сгенерировать индекс продуктивности со значением больше 100.

Следующий вызов API RescueTime:

"https://www.rescuetime.com/anapi/daily_summary_feed?key=[API_KEY]"

Вы получите недельный отчёт (см. код файла summary.json в конце главы). Эти данные используются для построения недельного графика.

Вызов Trello API:

"https://api.trello.com/1/lists/[list_number]/cards?fields=name&key=[API_KEY]&token=[Token]"

Вы получите данные из карточек задач в Trello:

[{"id":"5a4160103bfcd14994852f59","name":"ceylan cinemagraph"},{"id":"59e8241f6aa8662a51eb7de6","name":"Learn GitHuB"},{"id":"5981c19577c732f826ad8025","name":"Publish Instructible"},{"id":"5a341dba7f17d235d7c5bbd1","name":"SPACE PROGRAM"}]

В карточках вы можете размещать текст и передавать его ещё куда-нибудь.

data.json

Код
Formatted JSON Data
{  
   "notes":"data is an array of arrays (rows), column names for rows in row_headers",
   "row_headers":[  
      "Rank",
      "Time Spent (seconds)",
      "Number of People",
      "Activity",
      "Category",
      "Productivity"
   ],
   "rows":[  
      [  
         1,
         1536,
         1,
         "en.0wikipedia.org",
         "Uncategorized",
         0
      ],
      [  
         2,
         1505,
         1,
         "youtube.com",
         "Video",
         -2
      ],
      [  
         3,
         1178,
         1,
         "OpenOffice",
         "Writing",
         2
      ],
      [  
         4,
         709,
         1,
         "moodle.bilkent.edu.tr",
         "General Reference \u0026 Learning",
         2
      ],
      [  
         5,
         602,
         1,
         "google.com.tr",
         "Search",
         2
      ],
      [  
         6,
         439,
         1,
         "reddit.com",
         "General News \u0026 Opinion",
         -2
      ],
      [  
         7,
         437,
         1,
         "tr.sharelatex.com",
         "Writing",
         2
      ],
      [  
         8,
         361,
         1,
         "yemeksepeti.com",
         "General Shopping",
         -2
      ],
      [  
         9,
         356,
         1,
         "Gmail",
         "Email",
         0
      ],
      [  
         10,
         328,
         1,
         "Google Chrome",
         "Browsers",
         0
      ],
      [  
         11,
         207,
         1,
         "stars.bilkent.edu.tr",
         "General Reference \u0026 Learning",
         2
      ],
      [  
         12,
         179,
         1,
         "whatsapp",
         "Instant Message",
         -1
      ],

summary.json

Код
[  
   {  
      "id":1515657600,
      "date":"2018-01-11",
      "productivity_pulse":54,
      "very_productive_percentage":34.2,
      "productive_percentage":10.6,
      "neutral_percentage":25.6,
      "distracting_percentage":0.0,
      "very_distracting_percentage":29.6,
      "all_productive_percentage":44.8,
      "all_distracting_percentage":29.6,
      "uncategorized_percentage":16.1,
      "business_percentage":6.0,
      "communication_and_scheduling_percentage":4.3,
      "social_networking_percentage":0.0,
      "design_and_composition_percentage":0.0,
      "entertainment_percentage":15.2,
      "news_percentage":3.3,
      "software_development_percentage":5.4,
      "reference_and_learning_percentage":22.8,
      "shopping_percentage":12.9,
      "utilities_percentage":14.1,
      "total_hours":2.51,
      "very_productive_hours":0.86,
      "productive_hours":0.27,
      "neutral_hours":0.64,
      "distracting_hours":0.0,
      "very_distracting_hours":0.74,
      "all_productive_hours":1.12,
      "all_distracting_hours":0.74,
      "uncategorized_hours":0.4,
      "business_hours":0.15,
      "communication_and_scheduling_hours":0.11,
      "social_networking_hours":0.0,
      "design_and_composition_hours":0.0,
      "entertainment_hours":0.38,
      "news_hours":0.08,
      "software_development_hours":0.13,
      "reference_and_learning_hours":0.57,
      "shopping_hours":0.32,
      "utilities_hours":0.35,
      "total_duration_formatted":"2h 30m",
      "very_productive_duration_formatted":"51m 26s",
      "productive_duration_formatted":"15m 56s",
      "neutral_duration_formatted":"38m 34s",
      "distracting_duration_formatted":"no time",
      "very_distracting_duration_formatted":"44m 30s",
      "all_productive_duration_formatted":"1h 7m",
      "all_distracting_duration_formatted":"44m 30s",
      "uncategorized_duration_formatted":"24m 11s",
      "business_duration_formatted":"9m 6s",
      "communication_and_scheduling_duration_formatted":"6m 26s",
      "social_networking_duration_formatted":"no time",
      "design_and_composition_duration_formatted":"no time",
      "entertainment_duration_formatted":"22m 49s",
      "news_duration_formatted":"4m 55s",
      "software_development_duration_formatted":"8m 3s",
      "reference_and_learning_duration_formatted":"34m 17s",
      "shopping_duration_formatted":"19m 22s",
      "utilities_duration_formatted":"21m 17s"
   },
   {  
      "id":1515571200,
      "date":"2018-01-10",
      "productivity_pulse":33,
      "very_productive_percentage":21.9,
      "productive_percentage":2.3,
      "neutral_percentage":14.4,
      "distracting_percentage":11.0,
      "very_distracting_percentage":50.3,
      "all_productive_percentage":24.2,
      "all_distracting_percentage":61.4,
      "uncategorized_percentage":0.3,
      "business_percentage":0.0,
      "communication_and_scheduling_percentage":13.5,
      "social_networking_percentage":0.0,
      "design_and_composition_percentage":6.3,
      "entertainment_percentage":44.7,
      "news_percentage":4.2,
      "software_development_percentage":0.0,
      "reference_and_learning_percentage":15.5,
      "shopping_percentage":0.0,
      "utilities_percentage":15.4,
      "total_hours":2.24,
      "very_productive_hours":0.49,
      "productive_hours":0.05,
      "neutral_hours":0.32,
      "distracting_hours":0.25,
      "very_distracting_hours":1.13,
      "all_productive_hours":0.54,
      "all_distracting_hours":1.37,
      "uncategorized_hours":0.01,
      "business_hours":0.0,
      "communication_and_scheduling_hours":0.3,
      "social_networking_hours":0.0,
      "design_and_composition_hours":0.14,
      "entertainment_hours":1.0,
      "news_hours":0.09,
      "software_development_hours":0.0,
      "reference_and_learning_hours":0.35,
      "shopping_hours":0.0,
      "utilities_hours":0.34,
      "total_duration_formatted":"2h 14m",
      "very_productive_duration_formatted":"29m 22s",
      "productive_duration_formatted":"3m 8s",
      "neutral_duration_formatted":"19m 18s",
      "distracting_duration_formatted":"14m 48s",
      "very_distracting_duration_formatted":"1h 7m",
      "all_productive_duration_formatted":"32m 30s",
      "all_distracting_duration_formatted":"1h 22m",
      "uncategorized_duration_formatted":"27s",
      "business_duration_formatted":"1s",
      "communication_and_scheduling_duration_formatted":"18m 5s",
      "social_networking_duration_formatted":"no time",
      "design_and_composition_duration_formatted":"8m 30s",
      "entertainment_duration_formatted":"59m 54s",
      "news_duration_formatted":"5m 39s",
      "software_development_duration_formatted":"no time",
      "reference_and_learning_duration_formatted":"20m 51s",
      "shopping_duration_formatted":"no time",
      "utilities_duration_formatted":"20m 39s"
   },
   {  
      "id":1515484800,
      "date":"2018-01-09",
      "productivity_pulse":68,
      "very_productive_percentage":60.4,
      "productive_percentage":0.5,
      "neutral_percentage":11.0,
      "distracting_percentage":7.1,
      "very_distracting_percentage":21.0,
      "all_productive_percentage":60.9,
      "all_distracting_percentage":28.1,
      "uncategorized_percentage":9.1,
      "business_percentage":21.9,
      "communication_and_scheduling_percentage":7.2,
      "social_networking_percentage":5.1,
      "design_and_composition_percentage":1.2,
      "entertainment_percentage":1.6,
      "news_percentage":12.5,
      "software_development_percentage":9.1,
      "reference_and_learning_percentage":28.2,
      "shopping_percentage":2.9,
      "utilities_percentage":1.2,
      "total_hours":2.78,
      "very_productive_hours":1.68,
      "productive_hours":0.01,
      "neutral_hours":0.31,
      "distracting_hours":0.2,
      "very_distracting_hours":0.58,
      "all_productive_hours":1.69,
      "all_distracting_hours":0.78,
      "uncategorized_hours":0.25,
      "business_hours":0.61,
      "communication_and_scheduling_hours":0.2,
      "social_networking_hours":0.14,
      "design_and_composition_hours":0.03,
      "entertainment_hours":0.04,
      "news_hours":0.35,
      "software_development_hours":0.25,
      "reference_and_learning_hours":0.78,
      "shopping_hours":0.08,
      "utilities_hours":0.03,
      "total_duration_formatted":"2h 46m",
      "very_productive_duration_formatted":"1h 40m",
      "productive_duration_formatted":"47s",
      "neutral_duration_formatted":"18m 23s",
      "distracting_duration_formatted":"11m 49s",
      "very_distracting_duration_formatted":"34m 57s",
      "all_productive_duration_formatted":"1h 41m",
      "all_distracting_duration_formatted":"46m 46s",
      "uncategorized_duration_formatted":"15m 7s",
      "business_duration_formatted":"36m 26s",
      "communication_and_scheduling_duration_formatted":"11m 59s",
      "social_networking_duration_formatted":"8m 28s",
      "design_and_composition_duration_formatted":"2m 4s",
      "entertainment_duration_formatted":"2m 39s",
      "news_duration_formatted":"20m 49s",
      "software_development_duration_formatted":"15m 5s",
      "reference_and_learning_duration_formatted":"46m 59s",
      "shopping_duration_formatted":"4m 51s",
      "utilities_duration_formatted":"2m 3s"
   }
  ]

Прототипирование


image





Данные теперь выводятся на монитор, пришла пора спроектировать рамку и зеркало. Здесь всё зависит от ваших предпочтений. Я взял светлую древесину, потому что она больше подходит к моему интерьеру.

Если вы хотите выбрать другую конструкцию рамы, то есть несколько отличных руководств:

https://www.instructables.com/id/Smart-Mirror-by-Raspberry-Pi/
https://www.instructables.com/id/Raspberry-Pi-Smart-Mirror/
https://www.instructables.com/id/Magic-Mirror/

Размеры заготовок для моей рамы:

Передняя сторона:

  • 2 x 40 см
  • 2 x 47 см

Задняя сторона:

  • 2 x 38 см
  • 2 x 50 см

Сборка рамы и зеркала


image





Некоторые замечания:

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

Сборка электроники


















Если делаете базовую версию без светодиодов, можете пропустить соответствующий этап.

Схемы сборки и установки светодиодов взяты из двух разных руководств:

How to control a RGB LED-Strip with a Raspberry Pi
Raspberry Pi PHP LED controller

Важные замечания:

Я использовал такие пины:

  • GPIO17 для красного провода.
  • GPIO22 для зелёного провода.
  • GPIO24 для синего провода.

Если хотите использовать другие пины, придётся изменить их номера в начале index.php.

Проверка




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

1. Запустите терминал и введите: sudo nano /home/pi/.config/lxsession/LXDE-pi/autostart
2. Затем введите: chromium-browser --kiosk --incognito "http://localhost/index.php"

Теперь можно отключить мышь и клавиатуру. Браузер должен запуститься и открыть файл index.php.

Устранение неисправностей


У меня ошибка API
У наших API есть ограничения на количество обращений. Если дёргать их слишком часто, получите ошибку. Для решения этой проблемы добавьте в index.php задержку обновления, по умолчанию стоит 360 секунд.

#Seconds to refresh the webpage<br>$sec = "360";

Браузер не открывается при загрузке
В разных ОС файл autostart находится в разных местах. Я использовал Raspbian GNU/Linux 8.0 Jessie, так что уточните, где лежит этот файл в вашей ОС.

Светодиоды светятся разным цветом
Подключение светодиодных лент может различаться, и наверняка цветовые подключения перемешаны. Исправить это можно с помощью припайки проводов к правильным контактам. Также можете подстроить цвета подсветки с помощью HEX-значений в index.php.

if ($oran<50) { $led->setHex("#FF0000"); }else { $led->setHex("#00FF00"); }

Вот вам в помощь HEX-калькулятор цветов.

Хочу использовать другие графики
Я применил JS-библиотеку chart.js. Если хотите использовать другие графики, почитайте документацию: http://www.chartjs.org/samples/latest/

Что дальше


Есть много способов улучшения этого проекта. Например:

  • Экран побольше: тогда можно выводить гораздо больше графиков, или оставить часть площади именно под зеркало.
  • Интеграция разных API: сегодня доступно огромное количество всевозможных API (Twitter, Google и множество других). Мне пришла в голову идея со Spotify API, чтобы отображать на зеркале, какая песня сейчас играется. Вот вам список для мозгового штурма: www.programmableweb.com/apis/directory
  • Голосовое управление Amazon Alexa: у меня стоит такое устройство, могу с помощью голоса управлять светом. Можно прикрутить Алексу для управления графиками на зеркале.