Сделай сам: котик манеки-неко, который сделает бэкап в облако
Сопровождаем сохранение резервных копий протяжным «мяу».
В серии DIY-статей «Пространство для изобретений» мы пробуем в домашних условиях разработать необычные гаджеты и оставляем все необходимые инструкции, чтобы любой желающий мог повторить наш опыт. Серию статей поддерживает Selectel — провайдер ИТ-инфраструктуры, которая помогает в решении рабочих задач и разработке личных проектов. Посмотреть, что интересного есть у провайдера, и выбрать для себя подходящие решения можно на сайте.
В этом материале Сергей Исмулин, разработчик электронных устройств, собирает фигурку котика манеки-неко — если дать котику «пять», он сделает бэкап выбранного файла в облачное хранилище.
Для тех, кто хочет автоматизировать бэкапы, но не готов к полноценной сборке фигурки, Selectel предлагает протестировать бета-версию новой услуги «Бэкапы по расписанию». Она позволит настроить автоматические бэкапы для сетевых дисков виртуальных машин.
Данные будут защищены от сбоев и человеческих ошибок, а клиент сможет в любой момент восстановить диск и откатиться на момент до возникновения проблем. Правила бэкапирования настраиваются один раз, дальше сервис автоматически создаёт бэкапы и удаляет ранние версии.
Многим знакома ситуация: важный проект существует в одной-единственной версии и возможности откатить изменения нет. Новички не всегда осознают, насколько важен бэкап, а понимание в этом вопросе прямо пропорционально количеству набитых шишек. Вот и я созрел, чтобы использовать облачные сервисы для сохранения проделанной работы. Итак, задача: создать инструмент «в железе», который поможет в конце работы сохранять все данные на облаке.
Моя кнопка будет в виде японского кота манэки-нэко — это талисман, который приманивает деньги. Для создания бэкапа ему нужно будет «дать пять». Мой кот выглядит вот так.
В задней части у него встроен солнечный элемент, который питает небольшую схему с электромагнитной катушкой — она и заставляет кота махать лапкой на свету. Эта часть нам не важна, а значит, подробно на ней останавливаться не будем. Зато важна подвижная лапка — она будет физической кнопкой сохранения.
Для связи кота с компьютером используем плату Arduino. Плата подойдёт любая, но из-за небольшого размера фигурки мы имплантируем Arduino Nano. Заливать бэкапы будем в облако Selectel.
Помимо компонентов устройства понадобятся отвёртки, термоклей, пружинка, алюминиевый скотч, Arduino IDE, Visual Studio.
Собираем «железную» кнопку
Логика работы следующая: при нажатии на лапку срабатывает кнопка, и Arduino, подключённая к компьютеру, отправляет уведомление программе (её мы напишем) — и та отсылает на сервер указанный в настройках файл. В самого кота достаточно встроить кнопку с Arduino и вывести USB-вход. Красная подушка, на которой восседает кот, — полая, и туда отлично помещается Arduino Nano. Для этого нужно выкрутить четыре винта в нижней части.
Зачем нужен динамик с усилителем, расскажу позже, а пока обращу внимание, что USB-порт Nano я вывел наружу, прорезав отверстие в боксе.
Провода для подключения к кнопке я вывел в тело кота через отверстие в коврике.
А вот схема с «кнопкой» в деталях.
Кнопка представляет собой два куска фольги: один закреплён на корпусе кота (фиолетовый квадрат), другой — на конце качалки (фиолетовый шарик). Когда мы «даём пять» коту, лапка замыкает между собой два кусочка фольги, которые проводами соединены с Arduino Nano. Схема устройства:
Кнопка подключена между пином D4 (серый провод) и землёй (синий провод). При нажатии на входе будет установлен низкий уровень. С пина D11 (жёлтый провод) снимается аудиосигнал, но, если подключить телефонный динамик напрямую, звук будет недостаточно громким, потому я дополнительно подключил монофонический усилитель на микросхеме TDA7052.
Это мостовой усилитель с напряжением питания от 3 вольт и минимальным набором внешних компонентов. Схема его подключения выглядит так:
Теперь напишем микропрограмму и прошьём плату — для этого необходимо установить и настроить Arduino IDE. Процесс повторять не буду, поделюсь каноничной ссылкой, где это описано подробно.
Итак, IDE установлена, плата подключена, blink прошит. Возвращаемся к нашей задаче. В самом простом варианте скетч выглядит так:
В цикле слушаем вход D4, к которому подключили кнопку. При её нажатии отправляем в serial port цифру 2 (0 и 1 займём чуть позже).
Банальная отправка программе сообщения о необходимости сделать бэкап — это скучно. Добавим немного интерактива: при успешной отправке сообщения наш кот будет довольно мяукать, а если что-то пошло не так — издавать звук ошибки.
Для этого и понадобится динамик. Помимо приёма Arduino сообщения об успешной или неудачной отправке, нам нужно заставить плату воспроизводить звук. Первое, что приходит на ум, — использовать шилд mp3-плеера, но места в коте не так много. Поскольку ЦАПа (цифро-аналогового преобразователя, который превращает нули и единицы в сигнал, пригодный для воспроизведения) на борту Arduino Nanо нет, будем жёстко зашивать в исходный код звуки природы ШИМом (широтно-импульсной модуляцией, которая позволяет с помощью цифрового устройства «эмулировать» аналоговый сигнал). Чтобы не изобретать велосипед, воспользуемся готовой инструкцией.
Если коротко, нужно подготовить аудиофайл в формате wav со следующими настройками: битрейт 8 бит, частота дискретизации 8 кГц (сконвертировать можно онлайн). Далее при помощи конвертера преобразуем wav в двоичный формат, задав такие параметры:
После чего программа выдаст нам C-файл примерно такого вида:
С этими данными Arduino уже может работать. Файл представляет собой простой массив сэмплов. Дискретизация 8 кГц означает, что аудиофайл длиною в секунду будет поделён на 8 тысяч частей, где каждая часть представлена в виде уровня в восьмибитном разрешении. При воспроизведении на один из выводов Arduino будет подана последовательность этих сэмплов в виде изменяющегося ШИМ-сигнала, где ширина каждого импульса будет пропорциональна уровню семпла.
После конвертации звуков я вынес их в отдельные файлы и переименовал расширение в заголовочное – «.h». Точно так же в функцию воспроизведения
я передаю массив и размер массива sizeof(myau) — нам не нужно указывать размер, как в примере по ссылке.
Теперь наш кот может не только отправлять цифру 2 после того, как ему «дали пять», но и реагировать на пришедшее в порт сообщение. Если пришла единица — говорить «мяу»:
А на ноль — ругаться:
Проверяем, верно ли выполнили действия:
- Загружаем скетч в Arduino.
- Подключаем динамик одним концом к земле, а другим — к порту D11.
- Открываем «Монитор порта» в Arduino IDE, выбираем скорость 9600 бод.
- Отправляем 1 или 0 — получаем либо мяуканье, либо звук ошибки.
Подготовим облако и десктоп к бэкапам
И вот, когда «железо» у нас уже есть, стоит разобраться, куда и как отсылать бэкап. В разработке я буду использовать облачное хранилище Selectel, регистрируюсь и выбираю тариф. Техподдержка рассказала, что для бэкапов стоит использовать холодное хранилище. Документация для начала работы с сервисом понятна и новичку: первым делом нужно создать контейнер, присвоить ему имя, тип (приватный, открытый), выбрать «холодное хранилище» (заточенное под бэкапы). И всё готово — можно перетягивать файлы вот сюда:
Но процесс можно и автоматизировать:
Раздел «Работа с API Облачного хранилища» — то, что нам нужно. Выбираю способ передачи файлов через протокол FTP, довольно предсказуемые входные данные:
Итак, нам ясна архитектура приложения по части работы с COM-портом — отсылаем и принимаем цифры. Также ясно, что приложение должно отправлять на сервер указанный нами файл. А если у нас проект состоит из множества файлов? Логично было бы отправить папку с проектом целиком, ещё логичнее перед этим её заархивировать.
Также было бы неплохо иметь возможность выбора: заменять старый файл новым или создать его копию, добавив к имени текущие дату и время. Приложение будет использовать Windows Forms в качестве оболочки. Вот, что получилось после некоторых раздумий:
- В левом верхнем углу расположен выпадающий список портов. Кота нужно подключить к компьютеру и, выбрав соответствующий порт, нажать кнопку «Подключиться». В случае успеха кот довольно мяукнет.
- Чекбокс «Заменять файл» отвечает за то, будет ли файл перезаписан или создан заново с датой и временем в имени файла.
- Если нажать «Папка целиком», то указанная папка будет отправлена целиком со всем её содержимым в виде zip-архива.
- Текстовое поле «Путь к файлу» указывает на файл или папку для отправки. Можно не вводить адрес вручную, достаточно кликнуть по текстовому полю — и откроется диалоговое окно, где можно будет выбрать файл или папку.
- Строки ниже: «Сервер», «Пользователь», «Пароль» и «Контейнер» содержат нужные для входа и авторизации данные. Сервер указан в документации, пароль выбираете вы сами, а пользователь присваивается автоматически, найти его можно тут:
Строка «Контейнер» содержит имя контейнера, который вы создаёте сами на сервере и куда будут сохраняться файлы.
Справа указаны служебные данные: имя файла, размер, расширение (если указана папка — будет .zip) и количество файлов в папке, если отправляется папка целиком.
- Внизу строка состояния. После закрытия программы введённые данные сохраняются в настройках приложения (в том числе состояния чекбоксов и указанные пути). Утилита прячется в трей (область уведомлений) при сворачивании, чтобы она не мешала на панели задач и работала всегда в фоновом режиме.
Инициализация программы происходит так:
Сразу отправляем программу в трей и скрываем её иконку, если программа развёрнута. Если свёрнута — иконка висит в трее. Получаем записанные значения из настроек для всех вводимых нами данных, а именно: сервер, имя пользователя, пароль, контейнер, путь и так далее.
Дальше — магия подключения к Arduino.
Выбор порта
Указываем в настройках ту же скорость порта 9600, что и в скетче Arduino. При подключении надпись на кнопке «Подключить» меняется на «Отключиться», как и её функция. Также меняется надпись в статусной строке. Код ниже реализует приём сообщения через COM-порт и его обработку.
Приём сообщения
Ключевая строка:
В самом начале в коде Arduino мы прописали отправку символа 2 по нажатию на лапку. В этой строке мы его принимаем и реагируем вызовом функции sendFTP(), которая будет ниже.
Формируем строку (string uri), в которой будет содержаться хост, имя папки и имя отправляемого файла. Затем эту строку мы передаём в функцию
которая создаёт FTP-запрос. После чего открываем соединение
с аргументами в виде имени пользователя и пароля и запускаем отправку файла потоком FileStream, передав аргументом путь к файлу.
Отправка файла
Если в качестве отправляемого файла выбрана папка, а не документ, то здесь же мы её предварительно архивируем:
В качестве аргумента указывается папка для архивирования и путь, куда сохранить архив. После отправки архив будет автоматически удалён с диска. Исходник программы подробным образом прокомментирован — можно ознакомиться с полной функциональностью приложения.
Тестируем
Для компиляции и запуска приложения нажмём F5 или зелёную стрелочку в Visual Studio. Если мы не совершили ошибок, программа запустится, и нужно будет выбрать порт, к которому подключён кот, и нажать «Подключиться». Кот должен мяукнуть. Если звука нет — выбран неверный порт.
Теперь настроим подключение к серверу, введя необходимые данные. Не забываем выбрать файл или папку для отправки. Для начала рекомендую выбрать файл размером поменьше. «Даём пять», и кот говорит: «Мяу». Если звука нет, то дело может быть в качестве интернет-соединения.
С каждыми ударом по лапке на сервере прибавляется по одному новому файлу:
К оригинальному имени прибавляется время отправки. Если в программе мы поставим галочку «Заменять файл», то появится файл, как на скриншоте ниже. При каждом новом ударе он будет заменяться свежей версией:
Укажем в настройках «Папку целиком», и вот что будет с разными вариантами галочки «Заменять файл»:
Добавились новые файлы с расширением .zip, как с версией без даты (а значит, она заменяема), так и уникальные — с датами.
Вот как выглядит этот процесс со звуком:
Исходники клиента и прошивки Arduino — на GitHub. В исходниках добавлены различные варианты исключений, которые можно обрабатывать по своему усмотрению. Например, можно заставить кота озвучивать случай неподключённого приложения.