DIY-дисплей на Raspberry Pi: музыка, погода и уведомления
Создайте DIY‑дисплей на Raspberry Pi: показывайте статус Spotify/Sonos, прогноз погоды и другие уведомления. Пошаговое руководство с настройкой ПО.
Подготовка системы и компонентов
Установка Raspberry Pi OS, настройка SSH и обновление системы. Подготовка компонентов: Raspberry Pi 3B+ или новее, OLED-дисплей 1.3" SSD1351, карта памяти microSD, блок питания.
sudo apt update
sudo apt upgrade -yУстановка и настройка OLED-дисплея
Установка библиотеки luma.oled и настройка подключения дисплея к GPIO пинам Raspberry Pi. Создание конфигурационного файла для дисплея.
pip3 install luma.core luma.oled
# В display_config.py
from luma.core.serial import spi
from luma.oled.device import ssd1351
serial = spi(device=0, port=0)
device = ssd1351(serial, width=128, height=128, rotate=0)Установка необходимых библиотек
Установка библиотек для работы с API Spotify, OpenWeatherMap, Sonos и обработки изображений.
pip3 install spotipy pyowm requests soco pillowНастройка Spotify API
Регистрация приложения в Spotify Developer Dashboard, получение Client ID и Client Secret. Создание конфигурационного файла и скрипта для авторизации.
# В spotify_config.py
CLIENT_ID = 'ваш-client-id'
CLIENT_SECRET = 'ваш-client-secret'
REDIRECT_URI = 'http://localhost:8080/callback'
SCOPE = 'user-read-currently-playing user-read-playback-state'Настройка API погоды
Регистрация на OpenWeatherMap и получение бесплатного API-ключа. Создание конфигурационного файла для погоды.
# В weather_config.py
API_KEY = 'ваш-api-ключ-openweathermap'
CITY = 'Ваш город'
COUNTRY = 'Ваша страна (например, RU)'Создание основного приложения
Разработка основного приложения для отображения информации на OLED-дисплее. Оптимизация кода для работы с ограниченными ресурсами Raspberry Pi.
# Основной цикл приложения
while True:
display_spotify_info()
time.sleep(15)
display_weather_info()
time.sleep(15)Настройка автозапуска
Создание системного сервиса для автоматического запуска приложения при загрузке Raspberry Pi.
# /etc/systemd/system/spotify-display.service
[Unit]
Description=Spotify Display Service
After=network.target
[Service]
User=pi
WorkingDirectory=/home/pi
ExecStart=/usr/bin/python3 /home/pi/display_app.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetДобавление Sonos и расширение функциональности
Интеграция поддержки Sonos для отображения информации о воспроизведении. Добавление отображения системной информации, новостей и других данных.
# Функция для Sonos
def display_sonos_info():
try:
current_track = sonos.get_current_track_info()
if current_track['title']:
track_name = current_track['title']
artist_name = current_track['artist']
# Отображение информации на дисплее
except Exception as e:
print(f"Ошибка отображения Sonos: {e}")<!-- meta-description: Узнайте, как создать устройство на базе Raspberry Pi с OLED-дисплеем для отображения информации о воспроизведении Spotify/Sonos, прогноза погоды и других данных. Подробная инструкция с примерами кода. -->
# Raspberry Pi и OLED-дисплей для отображения деталей воспроизведения Spotify/Sonos, прогноза погоды и другой информации
**Ключевые слова:** Raspberry Pi, OLED дисплей, Spotify, Sonos, погода, DIY, хакинг, гаджеты, IoT
## Введение
В этом руководстве мы создадим компактное устройство на базе Raspberry Pi с OLED-дисплеем для отображения полезной информации: текущая композиция из Spotify/Sonos, прогноз погоды и другие данные. Это устройство может стать стильным элементом вашего интерьера или рабочего места, потребляя минимум энергии благодаря использованию OLED-технологии.
## Необходимые компоненты
Для сборки устройства нам понадобятся:
- Raspberry Pi (модель 3B+ или новее)
- OLED-дисплей (например, 1.3-дюймовый SSD1351 с разрешением 128x128)
- Карта памяти microSD (16 ГБ или больше)
- Блок питания для Raspberry Pi (5V, 2.5-3A)
- Дополнительно: корпус для Raspberry Pi, мини-клавиатура (для первоначальной настройки)
**Примечание:** Мы будем использовать OLED-дисплей вместо ЖК, так как он потребляет меньше энергии и обеспечивает более четкую картинку при небольшом размере. Для работы с таким дисплеем понадобится библиотека `luma.oled`.
## Подготовка системы
1. Скачайте и установите Raspberry Pi Imager с официального сайта.
2. Подключите карту памяти к компьютеру и запустите Raspberry Pi Imager.
3. Выберите "Raspberry Pi OS (32-bit)" с рекомендованным программным обеспечением.
4. Нажмите на значок настроек (шестеренка) и задайте:
- Имя хоста: `spotify-display`
- Включите SSH
- Установите пароль для пользователя `pi`
- Настройте Wi-Fi сеть
- Выберите ваш часовой пояс и язык
5. Запишите образ на карту памяти и вставьте ее в Raspberry Pi.
6. Подключите устройство к питанию и дождитесь загрузки.
7. Подключитесь к Raspberry Pi по SSH:
```bash
ssh pi@raspberrypi.local
# или, если не обнаруживается:
ssh pi@IP-адрес
- Обновите систему:
sudo apt update sudo apt upgrade -y
Установка и настройка дисплея
Мы будем использовать 1.3-дюймовый OLED-дисплей на базе контроллера SSD1351 с разрешением 128x128.
-
Установите зависимости для работы с дисплеем:
sudo apt install -y build-essential python3-dev python3-pip libjpeg-dev libpng-dev libopenjp2-7-dev -
Установите библиотеку
luma.oled:pip3 install --upgrade pip pip3 install luma.core luma.oled -
Подключите дисплей к Raspberry Pi:
- VCC - 3.3V
- GND - GND
- SCL - GPIO5 (SCL)
- SDA - GPIO3 (SDA)
- RES - GPIO24
- DC - GPIO25
- CS - GPIO8 (CE0)
-
Создайте файл конфигурации для дисплея:
nano display_config.pyДобавьте следующее содержимое:
from luma.core.serial import spi from luma.oled.device import ssd1351 serial = spi(device=0, port=0) device = ssd1351(serial, width=128, height=128, rotate=0) -
Проверьте работу дисплея:
nano test_display.pyfrom luma.core.render import canvas from display_config import device with canvas(device) as draw: draw.text((0, 0), "OLED Test", fill="white")python3 test_display.py
Установка необходимых библиотек
- Установите библиотеки для работы с API:
pip3 install spotipy pyowm requests - Установите библиотеку для работы с Sonos (если планируете использовать его):
pip3 install soco - Установите библиотеку для работы с изображениями:
pip3 install pillow
Настройка Spotify
-
Зарегистрируйте приложение в Spotify Developer Dashboard:
- Перейдите на https://developer.spotify.com/dashboard/
- Войдите в свой аккаунт (или создайте новый)
- Нажмите "Create an app"
- Заполните детали приложения (имя может быть любым, например "Raspberry Pi Display")
- Запишите Client ID и Client Secret
-
Создайте файл конфигурации для Spotify:
nano spotify_config.pyCLIENT_ID = 'ваш-client-id' CLIENT_SECRET = 'ваш-client-secret' REDIRECT_URI = 'http://localhost:8080/callback' SCOPE = 'user-read-currently-playing user-read-playback-state' -
Создайте файл для авторизации:
nano spotify_auth.pyimport spotipy from spotipy.oauth2 import SpotifyOAuth config = {} with open('spotify_config.py') as f: exec(f.read(), config) sp = spotipy.Spotify(auth_manager=SpotifyOAuth( client_id=config['CLIENT_ID'], client_secret=config['CLIENT_SECRET'], redirect_uri=config['REDIRECT_URI'], scope=config['SCOPE'] )) print("Access token:", sp.auth_manager.get_access_token()) -
Запустите скрипт авторизации и следуйте инструкциям.
-
Скопируйте полученный токен доступа в файл
spotify_config.py.
Настройка погоды
-
Зарегистрируйтесь на https://openweathermap.org/api и получите бесплатный API-ключ.
-
Создайте файл конфигурации для погоды:
nano weather_config.pyAPI_KEY = 'ваш-api-ключ-openweathermap' CITY = 'Ваш город' COUNTRY = 'Ваша страна (например, RU)' -
Создайте тестовый скрипт:
nano test_weather.pyimport pyowm from datetime import datetime import pytz config = {} with open('weather_config.py') as f: exec(f.read(), config) owm = pyowm.OWM(config['API_KEY']) mgr = owm.weather_manager() observation = mgr.weather_at_place(f"{config['CITY']}, {config['COUNTRY']}") w = observation.weather print(f"Температура: {w.temperature('celsius')['temp']}°C") print(f"Ощущается как: {w.temperature('celsius')['feels_like']}°C") print(f"Состояние: {w.detailed_status}") print(f"Скорость ветра: {w.wind()['speed']} м/с") print(f"Влажность: {w.humidity}%") -
Запустите скрипт для проверки:
python3 test_weather.py
Создание приложения для дисплея
Создайте файл display_app.py:
nano display_app.py
Добавьте следующий код с оптимизацией для Raspberry Pi:
import time
import requests
import json
from PIL import Image, ImageDraw, ImageFont
from luma.core.interface.serial import spi
from luma.core.render import canvas
from luma.oled.device import ssd1351
from io import BytesIO
import spotipy
from spotipy.oauth2 import SpotifyOAuth
import pyowm
import gc
# Импортируем конфигурации
try:
config_spotify = {}
with open('spotify_config.py') as f:
exec(f.read(), config_spotify)
config_weather = {}
with open('weather_config.py') as f:
exec(f.read(), config_weather)
except Exception as e:
print(f"Ошибка загрузки конфигурации: {e}")
# Инициализация дисплея
try:
from display_config import device
except Exception as e:
print(f"Ошибка инициализации дисплея: {e}")
# Инициализация Spotify
try:
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(
client_id=config_spotify['CLIENT_ID'],
client_secret=config_spotify['CLIENT_SECRET'],
redirect_uri=config_spotify['REDIRECT_URI'],
scope=config_spotify['SCOPE'],
cache_path=".cache"
))
except Exception as e:
print(f"Ошибка инициализации Spotify: {e}")
# Инициализация погоды
try:
owm = pyowm.OWM(config_weather['API_KEY'])
mgr = owm.weather_manager()
except Exception as e:
print(f"Ошибка инициализации погоды: {e}")
# Оптимизированная функция для отображения информации о Spotify
def display_spotify_info():
try:
# Получаем текущую трек
current_track = sp.current_user_playing_track()
if current_track is not None and current_track['is_playing']:
track_name = current_track['item']['name']
artist_name = current_track['item']['artists'][0]['name']
album_cover_url = current_track['item']['album']['images'][0]['url']
# Загружаем обложку альбома с ограничением размера
try:
response = requests.get(album_cover_url, timeout=5)
img = Image.open(BytesIO(response.content))
img = img.resize((64, 64)) # Уменьшаем размер для экономии памяти
except Exception as e:
print(f"Ошибка загрузки обложки: {e}")
img = Image.new('RGB', (64, 64), color='black')
# Отображаем информацию на дисплее
with canvas(device) as draw:
# Рисуем уменьшенную обложку альбома
for x in range(64):
for y in range(64):
pixel = img.getpixel((x, y))
if pixel != (0, 0, 0):
draw.point((x, y), fill="white")
# Добавляем текст
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMono.ttf", 8)
except:
font = ImageFont.load_default()
# Обрезаем длинные названия
if len(track_name) > 16:
track_name = track_name[:13] + "..."
if len(artist_name) > 16:
artist_name = artist_name[:13] + "..."
draw.text((65, 20), track_name, font=font, fill="white")
draw.text((65, 30), artist_name, font=font, fill="white")
except Exception as e:
print(f"Ошибка отображения Spotify: {e}")
finally:
gc.collect() # Принудительная сборка мусора
# Оптимизированная функция для отображения информации о погоде
def display_weather_info():
try:
# Получаем информацию о погоде с кэшированием
observation = mgr.weather_at_place(f"{config_weather['CITY']}, {config_weather['COUNTRY']}")
w = observation.weather
# Температура
temp = w.temperature('celsius')['temp']
feels_like = w.temperature('celsius')['feels_like']
# Состояние погоды
status = w.detailed_status
# Отображаем информацию на дисплее
with canvas(device) as draw:
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMono.ttf", 8)
except:
font = ImageFont.load_default()
# Рисуем упрощенную иконку погоды
if 'clear' in status.lower():
draw.ellipse((10, 10, 30, 30), outline="white")
elif 'cloud' in status.lower():
draw.arc((10, 10, 30, 30), 0, 360, outline="white")
elif 'rain' in status.lower() or 'shower' in status.lower():
for i in range(5):
draw.line((i*4, 20, i*4+2, 25), fill="white")
# Добавляем текст с ограничением длины
draw.text((35, 10), f"{temp:.0f}°", font=font, fill="white")
status_short = status[:10] + "..." if len(status) > 10 else status
draw.text((35, 20), status_short, font=font, fill="white")
draw.text((35, 30), f"В: {w.wind()['speed']:.1f} м/с", font=font, fill="white")
draw.text((35, 40), f"Вл: {w.humidity}%", font=font, fill="white")
except Exception as e:
print(f"Ошибка отображения погоды: {e}")
finally:
gc.collect()
# Основной цикл с обработкой ошибок
try:
while True:
display_spotify_info()
time.sleep(15)
display_weather_info()
time.sleep(15)
except KeyboardInterrupt:
print("Программа остановлена пользователем")
except Exception as e:
print(f"Критическая ошибка: {e}")
Настройка автозапуска
-
Создайте сервисный файл:
sudo nano /etc/systemd/system/spotify-display.service -
Добавьте содержимое:
[Unit] Description=Spotify Display Service After=network.target [Service] User=pi WorkingDirectory=/home/pi ExecStart=/usr/bin/python3 /home/pi/display_app.py Restart=always RestartSec=10 [Install] WantedBy=multi-user.target -
Включите и запустите сервис:
sudo systemctl enable spotify-display.service sudo systemctl start spotify-display.service -
Проверьте статус:
systemctl status spotify-display.service
Добавление Sonos
-
Установите библиотеку:
pip3 install soco -
Создайте файл
sonos_config.py:SONOS_IP = 'IP-адрес-вашего-Sonos' -
Добавьте функцию в
display_app.py:from soco import SoCo try: config_sonos = {} with open('sonos_config.py') as f: exec(f.read(), config_sonos) sonos = SoCo(config_sonos['SONOS_IP']) except Exception as e: print(f"Ошибка инициализации Sonos: {e}") def display_sonos_info(): try: current_track = sonos.get_current_track_info() if current_track['title']: track_name = current_track['title'] artist_name = current_track['artist'] with canvas(device) as draw: # Рисуем фон draw.rectangle((0, 0, 128, 128), outline="white", fill="black") try: font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMono.ttf", 8) except: font = ImageFont.load_default() if len(track_name) > 16: track_name = track_name[:13] + "..." if len(artist_name) > 16: artist_name = artist_name[:13] + "..." draw.text((0, 50), track_name, font=font, fill="white") draw.text((0, 60), artist_name, font=font, fill="white") except Exception as e: print(f"Ошибка отображения Sonos: {e}") finally: gc.collect() -
Обновите главный цикл:
while True: display_sonos_info() time.sleep(15) display_weather_info() time.sleep(15)
Расширение функциональности
Системная информация
def display_system_info():
try:
# Оптимизированный сбор данных
with open('/sys/class/thermal/thermal_zone0/temp') as f:
temp = float(f.read()) / 1000.0
with open('/proc/loadavg') as f:
loadavg = float(f.read().split()[0])
with canvas(device) as draw:
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMono.ttf", 8)
except:
font = ImageFont.load_default()
draw.text((0, 0), f"CPU: {loadavg:.2f}", font=font, fill="white")
draw.text((0, 10), f"Темп: {temp:.1f}°C", font=font, fill="white")
except Exception as e:
print(f"Ошибка системной информации: {e}")
finally:
gc.collect()
Новости (используя API NewsAPI)
-
Создайте файл
news_config.py:API_KEY = 'ваш-api-ключ-newsapi' COUNTRY = 'ru' -
Добавьте функцию:
def display_news(): try: config_news = {} with open('news_config.py') as f: exec(f.read(), config_news) url = f"https://newsapi.org/v2/top-headlines?country={config_news['COUNTRY']}&apiKey={config_news['API_KEY']}" response = requests.get(url, timeout=5) articles = response.json()['articles'][:3] with canvas(device) as draw: try: font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMono.ttf", 8) except: font = ImageFont.load_default() for i, article in enumerate(articles): title = article['title'] if len(title) > 20: title = title[:17] + "..." draw.text((0, i*10), title, font=font, fill="white") except Exception as e: print(f"Ошибка отображения новостей: {e}") finally: gc.collect() -
Обновите главный цикл:
while True: display_spotify_info() time.sleep(10) display_weather_info() time.sleep(10) display_system_info() time.sleep(10) display_news() time.sleep(10)
Решение возможных проблем
-
Дисплей не отображает ничего
- Проверьте соединения по пинам
- Убедитесь, что дисплей совместим с библиотекой
luma.oled - Попробуйте изменить параметры в
display_config.py
-
Ошибка при подключении к Spotify
- Убедитесь, что токен доступа не истек
- Проверьте правильность Client ID и Client Secret
- Убедитесь, что ваш Spotify-аккаунт имеет премиум-подписку
-
Ошибка при получении данных о погоде
- Проверьте правильность названия города и страны
- Убедитесь, что API-ключ активен
- Проверьте подключение к интернету
-
Дисплей мерцает или информация отображается некорректно
- Увеличьте паузы между обновлением информации
- Убедитесь, что дисплей получает стабильное питание
- Оптимизируйте код, как показано в руководстве
-
Высокое потребление памяти
- Используйте принудительную сборку мусора (
gc.collect()) - Уменьшайте размер загружаемых изображений
- Закрывайте соединения после использования
- Используйте принудительную сборку мусора (
Заключение
Теперь у вас есть полностью функциональное устройство на базе Raspberry Pi, которое отображает информацию о воспроизведении музыки, прогнозе погоды и других данных. Благодаря оптимизации кода для работы с ограниченными ресурсами устройства, оно будет работать стабильно даже на старых моделях Raspberry Pi.
Вы можете легко расширить его функциональность, добавляя новые источники информации и улучшая интерфейс. Такое устройство станет отличным дополнением для вашего дома или офиса, предоставляя полезную информацию в стильной форме.