Моя супруга всегда хотела, чтобы у нас был радиоприемник, который

  1. красиво выглядит; 
  2. легко регулируется; 
  3. обладает хорошим качеством звука; 
  4. проигрывает станции из интернета. 

Современный рынок предлагает большой выбор модных интернет-радиоприемников. Но все они оснащены либо сенсорным экраном, либо дорогим ЖК-дисплеем, либо проигрывают 1000 каналов, из которых 990 вам совсем не нужны. У нас имеется радиоприемник Universum 70-х годов. Правда, звук у него был нестабильный и оставлял желать лучшего. Немного поразмыслив на эту тему мне пришла в голову мысль, что микрокомпьютер Raspberry Pi, HifiBerry и несколько маленьких чипов помогут превратить винтажный раритет в онлайн-радиоприемник. 

Приступим к реализации замысла! И если получилось у меня, то вы тоже сможете это сделать! 

С чего начать? 

Подготовка оборудования 

Сборка винтажного радиоприемника 

Сначала я вскрыл радиоприемник и посмотрел, какие его части можно использовать повторно. Выяснилось, что большое колесо переключения каналов можно с легкостью подсоединить к поворотному переключателю KY040, который совместим с Raspberry Pi. Также я оставил переключатель вкл/выкл и регулятор громкости. Так как последний представляет из себя простой потенциометр, то его можно считывать с помощью аналого-цифрового преобразователя. HifiBerry будет ответственным за звук, а Raspberry Pi станет нашим ядром. Еще я подключу светодиод, показывающий, что все идет как надо. Итак, с настройкой оборудования закончили.

Подготовка к настройке ПО 

Будучи специалистом по обработке данных, для создания ПО радиоприемника я хотел выбрать простой язык программирования. Существует множество обучающих материалов о том, как взаимодействовать с пинами Raspberry Pi через Python. Поэтому выбор пал на этот язык. Что же мне было нужно для ПО? Прежде чем ответить на этот вопрос, поясню пожелания моей супруги к работе радиоприемника:

  1. Вращение колеса переключения каналов будет менять каналы. Эта опция должна работать, как в старом FM-радиоприемнике, в котором смена каналов сопровождается шумом. На отсутствие канала светодиод будет реагировать миганием, а при поимке сигнала будет светить постоянно. 
  2. Вращение регулятора громкости, соответственно, будет регулировать громкость. 

Вроде, ничего сложного. Все это может просто выполняться в скрипте, реагирующем на вращение KY040 или регулятора громкости. Этому скрипту потребуются параллельные процессы, так как регулятор громкости и KY040 должны быть независимы. Но у меня все еще оставался ряд вопросов: 

  1. Как управлять списком доступных каналов? 
  2. Как узнать, какой канал проигрывается и какая песня звучит прямо сейчас? 

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

Сборка радиоприемника 

Сначала, вооружившись паяльником, я соединил потенциометр регулятора громкости с чипом, после этого приклеил переключатель каналов к KY040 и подключил светодиод к Raspberry Pi. Затем считал сигналы со всех входов. Потребовалось немного времени, чтобы разобраться, как использовать параллельные процессы в Python. Главный принцип следующий:

import threading

class VolumeControl: 

  def start(self):
    while self._running:
      #делает что-нибудь, например считывает PIN
      sleep(0.05)
  def is_running(self):
     self._running
  def stop(self):
     self._running = False
  def set_running(self):
     self._running = True

# Определяет и запускает VolumeControl в отдельном потоке 
volume = VolumeControl()                               volume.set_running()
t_volume = threading.Thread(target=volume.start)                               t_volume.start()

# Останавливает поток 
volume.stop()
t_volume.join()

Как вы видите, я создал класс для каждого слушателя пинов GPIO (интерфейса ввода/вывода) Raspberry Pi. Этот класс будет выполнять весь свой код внутри цикла while. То есть он будет непрерывно проверять пины GPIO. После проверки кодом внутри цикла последует время для ожидания повторного считывания пина. 

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

Проверить, вращается ли колесо переключения каналов: 

Если да, вращается, то светодиод начинает мигает, а проигрыватель воспроизводит шум. 

Если не вращается или канал не найден, светодиод остается включенным, а проигрыватель ищет канал в словаре и проигрывает его. Воспользуйтесь onlineradiobox, чтобы определить, какая песня играет в данный момент. 

Проверить, вращается ли регулятор громкости. 

Установим, находится ли он в верхнем или нижнем положении и изменим уровень громкости системы. 

Я сохранил текущую песню и канал как файл json на SD-карте Raspberry Pi, а также перехватил все ошибки и записал их в лог-файл на Raspberry Pi.

Весь код для этой части сборки радиоприемника можно найти на Github. Вы ошибаетесь, если думаете, что все эти процессы простые. Потребовалось 900 строк кода, чтобы радиоприемник заработал. 

Сборка веб-приложения 

Процесс сборки приложения оказался гораздо проще. По моему замыслу оно должно предоставлять следующие возможности: 

  1. Показывать сверху содержание файла json канала, воспроизводимого в данный момент. йц
  2. Содержать форму для заполнения с возможностью добавлять каналы к списку. Она должна включать URL канала и его название, а также URL Online Radio Box. 
  3. Содержать список текущих каналов и предоставлять возможность удалять ненужные из них с помощью кнопки “-”. 
  4. Содержать кнопку для сохранения текущего списка каналов. 
  5. Содержать кнопку для восстановления списка каналов, отображаемого при входе в приложение. 
  6. Хранить все настройки в файле json, к которым скрипт должен иметь доступ. 

FlaskApps предоставляет прекрасную возможность использовать шаблоны. Применительно к нашему случаю я создал один шаблон для текущего канала, другой — для добавления канала и третий — для его удаления. Вот, собственно говоря, и все. 

Сложнее всего мне было понять общие принципы работы FlaskApp. Считается, что эти приложения взаимодействуют с REST-API, который обычно обрабатывает большую часть логики. Важно то, что при открытии приложения происходит обращение к объекту session, содержащему последнюю информацию, которая отображается в приложении. Поэтому только в самом начале мне потребовалось загрузить список каналов из json. Каждый раз, отдавая команду приложению перезаписать этот файл, мне приходилось обновлять объект session с помощью session.pop

После того как я разобрался с session, работать с Flask стало просто. Вы создаете объекты, содержащие определенные значения, затем передаете их в шаблон HTML, который отобразит эти значения в соответствующих плейсхолдерах. 

Весь код моего приложения также доступен на Github: https://github.com/zappingseb/radioflask/blob/master/views.py

Настройка Raspberry Pi 

Последний, но не менее важный этап — установка необходимых компонентов на Raspberry Pi.

  • Сделайте Hifi-Berry аудиоустройством по умолчанию. 
  • Создайте совместно используемую папку для добавления кода в Raspberry Pi. 
  • Подключите Raspberry к WiFi. 
  • Добавьте все необходимые библиотеки Python, например Flask или RPI.GPIO. 
  • Сделайте python3 версией языка по умолчанию. 
  • Настройте запуск скрипта радио при загрузке Raspberry Pi. 

Настало время собрать свой собственный радиоприемник! 

В этой статье мы только начали знакомство с технологией по сборке радиоприемника. Весь код размещен на Github, а сам радиоприемник — на eBay в виде комплекта DIY (“Сделай сам”), который включает не только все необходимые части, но и подробное описание этапов сборки и настройки. 

Комплект для сборки винтажного онлайн-радиоприемника 

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Sebastian Wolf: Let a vintage radio become an online radio

Предыдущая статьяKubernetes: сэкономьте до 50% с вытесняемыми объектами
Следующая статьяБиоинформатика? С R это легко!