DIY-дисплей на Raspberry Pi: музыка, погода и уведомления

Создайте DIY‑дисплей на Raspberry Pi: показывайте статус Spotify/Sonos, прогноз погоды и другие уведомления. Пошаговое руководство с настройкой ПО.

Не указано
Алексей Кузнецов
Алексей Кузнецов
Системный администратор18 февраля 2026 г.

Подготовка системы и компонентов

Установка 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-адрес
  1. Обновите систему:
    sudo apt update
    sudo apt upgrade -y
    

Установка и настройка дисплея

Мы будем использовать 1.3-дюймовый OLED-дисплей на базе контроллера SSD1351 с разрешением 128x128.

  1. Установите зависимости для работы с дисплеем:

    sudo apt install -y build-essential python3-dev python3-pip libjpeg-dev libpng-dev libopenjp2-7-dev
    
  2. Установите библиотеку luma.oled:

    pip3 install --upgrade pip
    pip3 install luma.core luma.oled
    
  3. Подключите дисплей к Raspberry Pi:

    • VCC - 3.3V
    • GND - GND
    • SCL - GPIO5 (SCL)
    • SDA - GPIO3 (SDA)
    • RES - GPIO24
    • DC - GPIO25
    • CS - GPIO8 (CE0)
  4. Создайте файл конфигурации для дисплея:

    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)
    
  5. Проверьте работу дисплея:

    nano test_display.py
    
    from 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
    

Установка необходимых библиотек

  1. Установите библиотеки для работы с API:
    pip3 install spotipy pyowm requests
    
  2. Установите библиотеку для работы с Sonos (если планируете использовать его):
    pip3 install soco
    
  3. Установите библиотеку для работы с изображениями:
    pip3 install pillow
    

Настройка Spotify

  1. Зарегистрируйте приложение в Spotify Developer Dashboard:

    • Перейдите на https://developer.spotify.com/dashboard/
    • Войдите в свой аккаунт (или создайте новый)
    • Нажмите "Create an app"
    • Заполните детали приложения (имя может быть любым, например "Raspberry Pi Display")
    • Запишите Client ID и Client Secret
  2. Создайте файл конфигурации для Spotify:

    nano 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'
    
  3. Создайте файл для авторизации:

    nano spotify_auth.py
    
    import 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())
    
  4. Запустите скрипт авторизации и следуйте инструкциям.

  5. Скопируйте полученный токен доступа в файл spotify_config.py.

Настройка погоды

  1. Зарегистрируйтесь на https://openweathermap.org/api и получите бесплатный API-ключ.

  2. Создайте файл конфигурации для погоды:

    nano weather_config.py
    
    API_KEY = 'ваш-api-ключ-openweathermap'
    CITY = 'Ваш город'
    COUNTRY = 'Ваша страна (например, RU)'
    
  3. Создайте тестовый скрипт:

    nano test_weather.py
    
    import 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}%")
    
  4. Запустите скрипт для проверки:

    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}")

Настройка автозапуска

  1. Создайте сервисный файл:

    sudo nano /etc/systemd/system/spotify-display.service
    
  2. Добавьте содержимое:

    [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
    
  3. Включите и запустите сервис:

    sudo systemctl enable spotify-display.service
    sudo systemctl start spotify-display.service
    
  4. Проверьте статус:

    systemctl status spotify-display.service
    

Добавление Sonos

  1. Установите библиотеку:

    pip3 install soco
    
  2. Создайте файл sonos_config.py:

    SONOS_IP = 'IP-адрес-вашего-Sonos'
    
  3. Добавьте функцию в 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()
    
  4. Обновите главный цикл:

    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)

  1. Создайте файл news_config.py:

    API_KEY = 'ваш-api-ключ-newsapi'
    COUNTRY = 'ru'
    
  2. Добавьте функцию:

    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()
    
  3. Обновите главный цикл:

    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)
    

Решение возможных проблем

  1. Дисплей не отображает ничего

    • Проверьте соединения по пинам
    • Убедитесь, что дисплей совместим с библиотекой luma.oled
    • Попробуйте изменить параметры в display_config.py
  2. Ошибка при подключении к Spotify

    • Убедитесь, что токен доступа не истек
    • Проверьте правильность Client ID и Client Secret
    • Убедитесь, что ваш Spotify-аккаунт имеет премиум-подписку
  3. Ошибка при получении данных о погоде

    • Проверьте правильность названия города и страны
    • Убедитесь, что API-ключ активен
    • Проверьте подключение к интернету
  4. Дисплей мерцает или информация отображается некорректно

    • Увеличьте паузы между обновлением информации
    • Убедитесь, что дисплей получает стабильное питание
    • Оптимизируйте код, как показано в руководстве
  5. Высокое потребление памяти

    • Используйте принудительную сборку мусора (gc.collect())
    • Уменьшайте размер загружаемых изображений
    • Закрывайте соединения после использования

Заключение

Теперь у вас есть полностью функциональное устройство на базе Raspberry Pi, которое отображает информацию о воспроизведении музыки, прогнозе погоды и других данных. Благодаря оптимизации кода для работы с ограниченными ресурсами устройства, оно будет работать стабильно даже на старых моделях Raspberry Pi.

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

Поделиться:TelegramX / TwitterVK