Youtube оповещатель на Raspberry Pi

Описание

В этом проекте мы сделаем оповещатель YouTube для Raspberry Pi, и подключим сервопривод для поднятия флажка, если на YouTube канале появились новые видео. При этом мы будем использовать Google developer API key, что означает что нашему приложению не придётся проходить проверку на безопасность в Google.

Словарик:

  • stdout - стандартный вывод. В нашем случае (если не переадресован) это экран эмулятора терминала пользователя. Простыми словами — данные, которые программа выведет текстом на экран. 
  • stderr - стандартный вывод ошибок. Почти то же самое, что и stdout, но имеет отличный дескриптор файла (для stdout это 1, для stderr это 2), для удобства перенаправления вывода. 
  • Команда 2>&1 - отправить stderr в stdout.

    Видео

    Нам понадобится

    Установка модулей в виртуальную среду

    Для работы сценария необходимо установить модули расширения Python (библиотеки). В данном случае мы установим их в виртуальную среду Python. Виртуальная среда — это очень полезный (и иногда незаменимый) инструмент работы с Python. Зачем он нужен? Предположим у вас есть два сценария: один использует версию 1.0.1 какой-либо библиотеки, второй — версию 2.0.0 этой же библиотеки. Если вы установите обе версии библиотеки в путь по умолчанию, то, скорее всего, один из ваших сценариев перестанет работать.

    В этом случае на помощь приходит менеджер виртуальных сред Python. Для его установки необходимо открыть эмулятор терминала и набрать:

    sudo apt update && sudo apt install virtualenv

    Нажимаем клавишу Enter (или return), даём положительный ответ нажав на клавишу Y и дождаемся завершения установки. Можно приступать к установке виртуальной среды.

    Не выходя из эмулятора терминала вводим

    cd ~ && dir=.notify_virtualenv && mkdir $dir && virtualenv -p python3 $dir && source $dir/bin/activate && pip install RPi.GPIO google-api-python-client && deactivate
    

    Нажимаем Enter. Начнётся процесс создания виртуальной среды. 

    Объяснение команд:

    • cd ~ - сменить директорию в домашний каталог (на всякий случай).
    • && - логическое "И", следующая команда выполнится только если предыдущая была успешна.
    • dir=.notify_virtualenv - присваиваем локальной переменной dir значение.
    • mkdir $dir - создаём директорию (папку) с названием, которое хранится в переменной dir.
    • virtualenv -p python3 $dir - создаём виртуальную среду в директории, название которой хранится в переменной dir. Команда virtualenv выполнена с флагом -p python3 для того, чтобы убедиться, что будет установлен Python версии 3+.
    • source $dir/bin/activate - активируем среду сразу после установки.
    • pip install RPi.GPIO google-api-python-client - для работы сценария проекта необходимо два модуля Python: google-api-python-client и RPi.GPIO, устанавливаем.
    • deactivate - выходим из виртуальной среды.

    Все эти команды можно выполнить последовательно, нажимая enter в конце ввода каждой команды, тогда в && нет необходимости. Если Вы хотите узнать что делает каждая команда на практике — такой способ ввода является рекомендуемым. Также почти каждая команда (программа) имеет руководство пользователя, которое может быть вызвано командой man. Например: man mkdir . На экране появится описание работы с программой. Для выхода из man нажмите 'q'.

    Файлы проекта

    Клонирование файлов Github

    Теперь можно приступать к самому проекту. Не выходя из терминала вводим следующую строку 

    cd ~ && mkdir -p Github && cd Github && git clone "https://github.com/tremaru-file/getUploads.git" 

    Нажимаем enter. Файлы сценария теперь находятся в директории "/home/pi/Github/getUploads/"

    Листинг сценария проекта:

    import getUploads as gu
    import RPi.GPIO as GPIO
    from time import sleep
    import sys
    
    # установки
    filename = "vids.txt"
    channelname = str(sys.argv[1])
    
    # вывод сервопривода
    servopin = 12
    # ШИМ верхнего и нижнего положения
    servodown = 5   # % - эти значения необходимо откалибровать
    servoup = 10    # % - экспериментальным путём в зависимости от используемого серво
    
    # устанавливаем выводы
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(servopin, GPIO.OUT)
    
    # создаём объект сервопривода
    servo = GPIO.PWM(servopin, 50)
    
    # узнаём количество загруженных видео на канале
    vidsnumber = gu.getUploadsNumber(channelname)
    
    # функция перезаписи файла
    def rewrite(name):
        f = open(name, 'w')
        f.write(str(vidsnumber))
        f.close()
    
    # основной код
    try:
    
        # пробуем открыт файл
        myfile = open(filename, 'r')
    
    # если файл не найден
    except FileNotFoundError:
    
        # записываем данные в файл
        rewrite(filename)
        # cерво вниз
        servo.start(servodown)
        servo.stop()
        GPIO.cleanup()
        # выходим из сценария
        exit()
    
    # если файл найден
    else:
    
        try:
    
            # пробуем преобразовать данные в файле
            storednumber = int(myfile.read()) 
    
        # если в файле не цифры
        # закрываем, перезаписываем файл
        except ValueError:
    
            myfile.close()
            rewrite(filename)
            exit()
    
        # если количество загрузок не изменилось
        # со вермени последнего запроса
        # опускаем серво
        if storednumber == vidsnumber:
    
            myfile.close()
            servo.start(servodown)
    
        # если количество загрузок меньше
        # чем в прошлый раз (другой канал или видео были удалены)
        # перезаписываем файл
        elif vidsnumber < storednumber:
    
            myfile.close()
            rewrite(filename)
    
        # если ничего из вышеперечисленного,
        # значит новое видео!
        # поднимаем серво, перезаписываем файл
        else:
    
            myfile.close()
            rewrite(filename)
            servo.start(servoup)
        
        # прибираемся за собой
        sleep(.5)
        servo.stop()
        GPIO.cleanup()

    Получения Google API Key

    Для получения ключа API Key необходимо иметь учётную запись Google. Если Вы пользуетесь учётной записью YouTube, значит она у вас уже есть. Для получения ключа пройдите по ссылке console.developer.google.com. Вам потребуется войти в свою учётную запись и создать проект.

    Нажимаем создать проект:

    Вводим название и нажимаем создать:

    Нажимаем включить API и сервисы:

    Находим YouTube Data API v3:

    Нажимаем включить:

    Создаём учётные данные. Нажимаем создать:

    Выбираем YouTube Data API v3 из списка, выбираем Другое, без интерфейса пользователя, выбираем Общедоступные данные, нажимаем Выбрать тип учётных данных:

    Ключ создан, можно его скопировать и вставить в файл dev.key в директории проекта. Можно сделать это прямо в терминале командой:

    cd /home/pi/Github/getUploads && echo ваш_ключ_API > dev.key

    Первый запуск сценария

    На этом этапе можно проверить работу сценария. Он должен создать файл vids.txt в своей директории, в файле будет количество загруженных видео на указанном канале. Для работы сценария необходимо указать название канала в качестве аргумента, например python project.py iarduino. Аргумент в данном случае iarduino. Для запуска сценария необходимо пользоваться интерпретатором Python виртуальной среды, созданной ранее. Запустим сценарий:

     /home/pi/.notify_virtualenv/bin/python /home/pi/Github/getUploads/project.py iarduino

    Внимание! С каждым выполнением сценария выполняются запросы google API, что списывает очки ежедневной квоты с вашего API ключа. Допустимая квота 10000 очков в день. Если ваш сценарий будет выполняться раз в минуту, то квота иссякнет за несколько часов. В нашем примере мы будем делать запросы два раза в день — утром и вечером. В данных условиях квоты более чем достаточно. Очки квоты сбрасываются в 00:00 по тихоокеанскому времени (GMT-8), 10:00 по московскому времени.

    Установка таймера

    Для простоты работы с crontab создадим bash-сценарий в папке Scripts. Вводим в терминал следующую строку:

    cd ~ && mkdir -p Scripts && cd Scripts && echo "pushd /home/pi/Github/getUploads && /home/pi/.notify_virtualenv/bin/python project.py iarduino; popd;" > notify.sh && chmod +x notify.sh
    

    Объяснение команд:

      • cd ~ - сменить директорию в домашний каталог.
      • && - логическое "И", следующая команда выполнится только если предыдущая была успешна.
      • mkdir -p Scripts - создать директорию Scripts. Флаг -p - завершить команду успешно, даже если директория уже существует
      • echo - вывод в stdout. В данном случае выводится всё, что заключено в кавычки и выводится не в stdout, а в файл notify.sh. Объяснение команд в кавычках, записываемых в файл:
        • pushd - поместить текущую директорию в стек и сменить директорию на указанный аргумент. В нашем случае /home/pi/Github/getUploads
        • /home/pi/.notify_virtualenv/bin/python project.py iarduino - запустить исполняемый файл python из виртуальной среды, файл сценария project.py, аргумент сценария iarduino (название канала)
        • ; - конец выражения.
        • popd - сменить директорию на предыдущую из стека и перейти в неё. Текущая директория убирается из стека.
      • > - переадресация stdout. В данном случае в  файл notify.sh (если файла нет, он будет создан).
      • chmod +x - смена флагов (разрешений) файла. +x - сделать файл исполняемым.

    Для установки таймера мы воспользуемся утилитой crontab. В эмуляторе терминала введём crontab -e. Нам предложат выбрать программу редактор. Для новичков рекомендуется использовать nano, она самая простая. Так что выбираем №1 из списка и в nano откроется наш сrontab файл. Добавляем в него строку в самый низ:

    0 10,17 * * * /home/Scripts/notify.sh >> cronlog.txt 2>&1
    

    Нажимаем ctrl+x для выхода и отвечаем 'yes', чтобы сохранить буфер в файл.

    Файл crontab имеет следующую структуру: каждая новая строка — задача для выполнения. Формат строки: Минута Час День_месяца Месяц День_недели Команда. Выражения разделены пробелами. Например, следующая строка будет каждую минуту записывать в файл "who.txt" имена пользователей вошедших в систему: * * * * * w >> who.txt. Астериск [*] означает любое число.

    Объяснение команд:

    • 0 - в ноль минут указанного ниже часа, дня, месяца, дня недели
    • 10,17 - в десять утра и в пять вечера указанного ниже дня, месяца, дня недели
    • * - каждый день указанного ниже месяца
    • * - каждый месяц
    • * - каждый день недели
    • /home/Scripts/notify.sh - сценарий для выполнения
    • >> - переадресация stdout (стандартный вывод), в нашем случае в файл cronlog.txt
    • 2>&1 - дополнение к предыдущей команде, переадресовывать так же и stderr (ошибки)

    Для быстрых вычислений подходящих вам таймеров можно воспользоваться онлайн калькулятором для cron'а: crontab.guru

    Если всё прошло успешно, то в домашней директории пользователя pi (/home/pi) через минуту (или меньше) появится файл cronlog.txt. Туда будут перенаправлены все сообщения и ошибки сценария. Можно всегда зайти в него и посмотреть что произошло, если по какой-либо причине сценарий не работает должным образом.

    Подключение сервопривода

    Подключаем сервопривод к выводу 12 Trema+Expander Hat.

    Принцип работы

    1. На ЭВМ (в нашем случае Raspberry Pi) подключённой к интернету запущен таймер, который два раза в сутки запускает сценарий Python. Сценарий делает запрос Google API для получения:

      • идентификатора указанного канала,
      • идентификатора списка загрузок канала по полученному ранее идентификатору канала,
      • количества загрузок на канале по полученному ранее идентификатору списка.
    2. Если отсутствует файл "vids.txt" в директории запуска сценария, файл будет создан, в него будет записано полученное количество загруженных видео на канале, сценарий завершён.

    3. Если найден файл "vids.txt" и он содержит достоверную информацию (он не пуст и в нём записаны только цифры), то

      • Если число полученных видео больше чем то, что записано в файле — подаётся сигнал 90° на сервопривод, файл перезаписывается новым, сценарий завершён.
      • Если полученное и записанное количество загрузок совпадают — подаётся сигнал 0° на сервопривод, сценарий завершён.
      • Если полученное число меньше записанного или файл пуст — файл перезаписывается с полученным числом, сценарий завершён

    Ссылки

    Wiki - Установка и настройка микрокомпьютера Raspberry Pi

    Wiki - Raspberry Pi, настройка для работы в режиме Headless

    Shop - Raspberry Pi

    Shop - Trema+Expander Hat

    Shop - Сервопривод

    Обсуждение