- PVSM.RU - https://www.pvsm.ru -
Время — самый ценный ресурс который у нас есть. Чтобы использовать его максимально продуктивно, существуют всякого рода техники тайм-менеджмента. Если говорить о тайм-менеджменте в масштабах рабочего дня, то одна из самых популярных техник называется Pomodoro [1]. Но эта статья не про GTD, а про код (и немного про железо ^^).
Так вот, для техники Pomodoro есть инструмент Tomighty [2] и у него открытый исходный код [3] на C#, что побуждает к модификации этого самого кода с целью добавления новых возможностей и интеграции со всякими штуками.
Сегодня мы будем интегрировать клиент Tomighty с устройстовм "Большая Красная Кнопка". Нам для этого понадобится:
Зачем? Чтобы получить опыт работы с чужим кодом. В связи с грядущим Hacktoberfest [10], этот скилл будет крайне актуален.
Welcome!
С аппаратной стороны нет ничего сверхестесственного, посему подробно описывать каждый шаг не буду, всё должно работать, а код сам по себе довольно понятный.
mqtt.py
. На ESP через WebREPL [14].main.py
.Начнём с клонирования репозитория. Можно официальный [3], можно форк [18] (где в соответствующем брэнче всё уже сделано). Открываем солюшн в студии.
Для того чтобы собрать проект Tomighty.Windows, необходимо устанвоить в него пакет UWPDesktop через NuGet [19]. Это совершенно не очевидное действие, до которого мы относительно долго пытались додуматься и чуть менее долго догуглиться. Возможно это тривиально для тех кто имел дело со старомодными WinForms приложениями, зовущими новомодный UWP API, но для тех кто таким не занимался — не очень.
Таким образом, на данном этом этапе у меня получилось собираемое и запускаемое приложение, так что я приступил к поиску мест, в которые можно внедриться со своими костылями. С помощью CodeRush for Roslyn [9] это оказалось совсем не сложно.
Задачи такие:
Для начала, выясним как запустить период Pomodoro, скорее всего этот путь приведет нас к основным архитектурным элементам приложения быстрее всего. Пробный запуск показал, что, похоже, основным источником управления тут является икнока в трэе, так что попробуем найти точку входа где-нибудь в папке Tomighty.WindowsTray
. Действительно, в интерфейсе ITrayMenu
есть похожий на правду метод, посмотрим где он используется.
Нашёлся очень мясистый файлик TrayMenuController.cs
, а в нём и нужный метод
private void OnStartPomodoroClick(object sender, EventArgs e) => StartTimer(IntervalType.Pomodoro);
// ...
private void StartTimer(IntervalType intervalType) {
Task.Run(() => pomodoroEngine.StartTimer(intervalType));
}
Окей, значит за основные операции типа запуска периодов отвечает объект pomodoroEngine
. Он нам понадобится.
Название (да и содержимое) этого класса TrayMenuController
как бы намекают на то что он является одним из интерфейсов программы с человеком, и скорее всего нам надо создать что-то похожее, чтобы добавить поддержку собственного интерфейса в виде красной кнопки. Воспользуемся той же Jump to [20] менюшкой, чтобы найти где этот класс создается.
Отлично, мы нашли точку входа. Она выглядит как-то так:
internal class TomightyApplication : ApplicationContext {
public TomightyApplication() {
var eventHub = new SynchronousEventHub();
var timer = new Tomighty.Timer(eventHub);
var userPreferences = new UserPreferences();
var pomodoroEngine = new PomodoroEngine(timer, userPreferences, eventHub);
var trayMenu = new TrayMenu() as ITrayMenu;
var trayIcon = CreateTrayIcon(trayMenu);
var timerWindowPresenter = new TimerWindowPresenter(pomodoroEngine, timer, eventHub);
new TrayIconController(trayIcon, timerWindowPresenter, eventHub);
new TrayMenuController(trayMenu, this, pomodoroEngine, eventHub);
// ...
new StartupEvents(eventHub);
}
// ...
}
Время совершить небольшую интервенцию: создадим еще один объект несуществующего класса, а потом с помощью фичи Declare Class [21] добавим сам класс.
Я сразу передал еще и eventHub
, потому что заметил что в TrayMenuController
через него можно подписаться на ивенты старта и окончания таймера. Пригодится.
Сразу можно сделать два филда из автоматически сгенерированных параметров конструктора фичей Declare Field with Initializer [22]:
Чтож, теперь мы можем подписываться на ивенты и управлять таймерами. Попробуем добавить пункт меню в трэй, который будет вызывать метод RedButtonController.Connect()
.
Довольно быстро пришло осознание, что лучше всё-таки сохранить инстанс нашего контроллера и передать его в TrayMenuController
, чтобы тот мог спокойно напрямую позвать Connect()
безо всяких ивентов и усложнений.
var redButton = new RedButtonController(eventHub);
// ...
new TrayMenuController(trayMenu, this, pomodoroEngine, eventHub, redButton);
Чтобы пункт меню появился в списке, надо создать TrayMenu.redButtonConnectItem
и везде его прокинуть по аналогии с теми что рядом. В поиске таких мест хорошо поможет Tab to Next Reference [23]: Можно просто поставить курсор на любой референс, нажать Tab и перейти к следующему, при этом все референсы в поле зрения подсвечиваются.
Никаких подводных камней замечено не было, всё заработало довольно быстро. redButtonConnectItem
вызывает RedButtonController.Connect()
через хэндлер TrayMenuController.OnRedButtonConnect()
(таскбар слева экономит вертикальное пространство и круче чем таскбар снизу)
А теперь, попробуем вызвать Toast (это такие новомодные нотификации). Когда я впервые запустил приложение, один такой прилатал с предложением настроиться после первого запуска. Попробуем его отыскать. Думаю, надо начать со строчки new StartupEvents(eventHub)
в конце конструктора TomightyApplication
. Пара нажатий на F12 (перейти к декларации) приводят в файл Tomighty.WindowsEvents.cs
с двумя пустыми ивентами:
namespace Tomighty.Windows.Events {
public class FirstRun { }
public class AppUpdated { }
}
Чтож, ни один из этих нам не подходит, при чём даже формат пустого ивента не совсем подходит, хотелось бы передавать туда результат попытки подключиться. Создаём новый ивент, объявляем в нём филд и используем Smart Constructor [24] для добавления конструктора с автоматической инициализацией филда.
Далее, пришлось пройтись по всем местам где что-то происходило с ивентом FirstRun
и добавить подобные действия для нашего ивента RedButtonConnectionChanged
.
Попутно пришлось добавить XML-документ с содержанимем нотификации и прописать путь к нему в ресурсы. Но, опять же, всё завелось без единой бряки. Вот что значит хорошая архитектура!
Окей, у нас есть pomodoroEngine
, eventHub
, пункт меню и нотификации, вроде бы всё что нужно, можно соединяться с MQTT и пробывать общаться с кнопкой. Для MQTT будем использовать самый гуглящийся клиент M2Mqtt [25]:
PM> Install-Package M2Mqtt
У меня уже был простенький класс [26], для M2Mqtt, так что я его просто подключил и наслаждался ну-совсем-простым API:
public void Connect() {
mqtt = new MQTTClient("m10.cloudmqtt.com", 13633);
mqtt.Connect("%LOGIN%", "%PASSWORD%");
if (!mqtt.client.IsConnected) {
eventHub.Publish(new RedButtonConnectionChanged(false));
return;
}
eventHub.Publish(new RedButtonConnectionChanged(true));
mqtt.client.MqttMsgPublishReceived += onMsgReceived;
mqtt.Subscribe("esp");
}
Добавить хэндлер можно с помощью Declare Method [27]:
Осталось подписаться на TimerStarted
и TimerStopped
, и можно писать логику. А логика у меня в первом приближении получилась такая:
Тут можно много чего доработать, например, адекватно обработать ситуацию когда кнопка нажата во время перерыва, но это уже мелочи. А вот корпус уже куплен и скорее всего будет, осталось продырявить и скоммутировать. Дополнительной фичей получившегося девайса является то, что он сообщает коллегам когда вас можно отвлекать, а когда нельзя. А в остальном, довольно бесполезная штука :)
Автор: Himura
Источник [32]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-2/264630
Ссылки в тексте:
[1] Pomodoro: https://www.lucidchart.com/blog/5-reasons-to-use-the-pomodoro-technique-at-work
[2] Tomighty: http://tomighty.org/
[3] открытый исходный код: https://github.com/tomighty/tomighty-windows
[4] не очень большая: http://www.sci.com.tw/PRODUCTS/switch/(R13)%20PUSH%20SWITCH/R13-556.html
[5] ESP8266: https://ru.wikipedia.org/wiki/ESP8266
[6] MicroPython: https://micropython.org/
[7] MQTT: https://ru.wikipedia.org/wiki/MQTT
[8] Visual Studio: https://www.visualstudio.com/
[9] CodeRush for Roslyn: https://marketplace.visualstudio.com/items?itemName=DevExpress.CodeRushforRoslyn
[10] Hacktoberfest: https://hacktoberfest.digitalocean.com/
[11] любой: https://www.aliexpress.com/wholesale?SearchText=ESP8266
[12] по инструкции: http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html
[13] официальную реализацию MQTT: https://github.com/micropython/micropython-lib/blob/master/umqtt.simple/umqtt/simple.py
[14] WebREPL: https://github.com/micropython/webrepl
[15] Mosquitto: https://mosquitto.org/
[16] CloudMQTT: https://www.cloudmqtt.com/
[17] код для ESP8266: https://github.com/Himura2la/tomighty-windows/blob/big-red-button/RedButton-main.py
[18] форк: https://github.com/Himura2la/tomighty-windows
[19] через NuGet: https://www.nuget.org/packages/UwpDesktop/
[20] Jump to: https://documentation.devexpress.com/CodeRushForRoslyn/115798/Navigation-and-Search-Tools/Navigating-Anywhere
[21] Declare Class: https://documentation.devexpress.com/CodeRushForRoslyn/115689/Coding-Assistance/Code-Providers/Declaration-Providers/Declare-Class
[22] Declare Field with Initializer: https://documentation.devexpress.com/CodeRushForRoslyn/116325/Coding-Assistance/Code-Providers/Declaration-Providers/Declare-Field-with-Initializer
[23] Tab to Next Reference: https://documentation.devexpress.com/CodeRushForRoslyn/115799/Navigation-and-Search-Tools/Finding-References#tab
[24] Smart Constructor: https://documentation.devexpress.com/CodeRushForRoslyn/115941/Coding-Assistance/Code-Templates/Interactive-Templates
[25] M2Mqtt: https://m2mqtt.wordpress.com/
[26] класс: https://github.com/Himura2la/tomighty-windows/blob/45e016db2759d4d60e8393961891c7673a215b14/Tomighty.Windows/RedButton/MQTTClient.cs
[27] Declare Method: https://documentation.devexpress.com/CodeRushForRoslyn/115702/Coding-Assistance/Code-Providers/Declaration-Providers/Declare-Method
[28] Репозиторий с готовый кодом: https://github.com/Himura2la/tomighty-windows/tree/big-red-button/Tomighty.Windows/RedButton
[29] Купить ESP8266 быстро: https://www.chipdip.ru/catalog-show/wireless-modules?gq=esp8266
[30] Канал CNLhor: https://www.youtube.com/user/CNLohr/videos
[31] статья: https://geektimes.ru/post/272800/
[32] Источник: https://habrahabr.ru/post/338948/
Нажмите здесь для печати.