В детстве у нас с сестрой была гора VHS-кассет, которые мы бесконечно пересматривали. Современная видеоколлекция моих детей сильно от них отличается. Она полностью цифровая и разбросана по разным сервисам. Я хотел поделиться с ними магией осязаемости носителя из моего детства.

У меня двое пацанов, старшему разрешается посмотреть полчаса телевизор с утра и ещё полчаса вечером. Обычно он точно знает, что хочет посмотреть, но ему приходится ждать, пока кто-то из родителей возьмёт пульт и откроет нужное приложение.

Это заставило меня задуматься: почему бы не объединить новое и старое? Я хотел, чтобы у сына была более активная роль в выборе того, что он хочет посмотреть, несмотря на цифровой формат.

Несколько лет назад я увидел, как кто-то распечатал любимые музыкальные альбомы с NFC-меткой внутри, и решил сделать что-то подобное для своих детей.

▍ Конечный результат


Вот, что я в результате создал:


Это коллекция ламинированных обложек фильмов и мультфильмов с NFC-меткой внутри. Сыну остаётся только выбрать нужный фильм и положить его на считыватель NFC. Всем остальным займётся Home Assistant.

Вот видео того, как работает система:

▍ Proof-of-concept и материалы


Я начал с изготовления простого прототипа. В одном из моих наборов электроники нашёлся считыватель NFC (RC522) и несколько NFC-меток.

Я подключил считыватель NFC к плате ESP32 и прошил на неё ESPHome. Затем я положил NFC-метку на считыватель и увидел, что она появляется в логах ESPHome.

И это всё, что мне нужно было проверить. Я зашёл на AliExpress и купил оборудование для «продакшена»:


У меня уже было множество плат ESP32 (LOLIN32 lite), но когда я увидел версию Super Mini, то обязан был её купить. Посмотрите на эту красоту:


▍ Прошиваем ESPHome


Когда все детали прибыли, я подключил считыватель NFC к ESP32 с помощью следующих контактов:

SS (SDA) -> GPIO7
SCK (SCK) -> GPIO4
MOSI -> GPIO6
MISO -> GPIO5


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

Затем я создал файл конфигурации ESPHome. Мне пришлось добавить несколько особых platformio_options, чтобы он заработал на версии ESP32 Super Mini, но в целом это оказалась очень простая конфигурация.

---
substitutions:
  devicename: "nfc-scanner"
  friendly_name: "NFC Scanner"

packages:
  esphome: !include common/esphome.yaml
  api: !include common/api.yaml
  logger: !include common/logger.yaml
  wifi: !include common/wifi.yaml

esphome:
  # Магические переменные, необходимые, чтобы заработала ESP32C3 Super Mini
  platformio_options:
    board_build.f_flash: 40000000L
    board_build.flash_mode: dio
    board_build.flash_size: 4MB
  on_boot:
    priority: 600
    then:
      - rtttl.play: 'short:d=4,o=5,b=100:16e6,16e6'

esp32:
  variant: ESP32C3
  board: esp32-c3-devkitm-1
  framework:
    type: esp-idf

status_led:
  pin:
    number: GPIO8
    inverted: true

output:
  - platform: ledc
    pin: GPIO3
    id: buzzer

rtttl:
  output: buzzer

spi:
  clk_pin: GPIO4
  mosi_pin: GPIO6
  miso_pin: GPIO5

rc522_spi:
  cs_pin: GPIO7
  on_tag:
    then:
      - rtttl.stop:
      - homeassistant.tag_scanned: !lambda 'return x;'
      - rtttl.play: 'short:d=4,o=5,b=100:16e6,16e6'

Если вы будете собирать устройство самостоятельно, то необязательно использовать те же номера контактов.

Моя старая конфигурация ESPHome для LOLIN32 Lite
---
substitutions:
  devicename: "nfc-scanner"
  friendly_name: "NFC Scanner"

packages:
  esphome: !include common/esphome.yaml
  api: !include common/api.yaml
  logger: !include common/logger.yaml
  wifi: !include common/wifi.yaml

esphome:
  platform: ESP32
  board: lolin32
  on_boot:
    priority: 600
    then:
      - rtttl.play: 'short:d=4,o=5,b=100:16e6,16e6'

output:
  - platform: ledc
    pin: GPIO32
    id: buzzer

rtttl:
  output: buzzer

spi:
  clk_pin: GPIO18
  mosi_pin: GPIO23
  miso_pin: GPIO19

rc522_spi:
  cs_pin: GPIO15
  on_tag:
    then:
      - rtttl.stop:
      - homeassistant.tag_scanned: !lambda 'return x;'
      - rtttl.play: 'short:d=4,o=5,b=100:16e6,16e6'

После завершения прошивки ESPHome устройство отобразится в Home Assistant, но без записей. Не нужно паниковать, это нормально. Оно будет отправлять события tag_scanned. Подробнее об этом я расскажу позже, когда мы всё автоматизируем.

▍ 3D-печать корпуса и коробки для видеоколлекции


Чтобы защитить электронику и провода от шаловливых детских ручек, я спроектировал и распечатал простой корпус.

Это корпус

У него очень простая конструкция. Единственная сложность возникла с креплением ESP32. В отличие от других плат разработки, у ESP32C3 Super Mini нет отверстий под винты, поэтому я спроектировал простой механизм с зажимами.

Не волнуйтесь, ESP32 не висит в воздухе. Он опирается на припаянные контакты GPIO внизу корпуса.

Для проектирования и компоновки всех деталей я использовал Fusion360 (благодарю Ханса Вурста за публикацию модели Super Mini на GrabCAD).

Смоделировав каждую деталь, можно проверить, хорошо ли они сочетаются друг с другом

Ещё я распечатал красивую коробочку для хранения NFC-карт:


▍ Создание карт «DVD»


После завершения разработки считывателя мне оставалось лишь изготовить карты «DVD». Я хотел печатать непосредственно на ПВХ-картах, но мой принтер на это неспособен.

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


Затем я вырезал наклейки и приклеил их на ПВХ-карты.


Ещё я задизайнил обратную сторону карт, на которой изложен краткий сюжет фильма, дата выпуска и студия.


Первую версию карт я просто распечатал на принтере и ламинировал
Я распечатал небольшие обложки фильмов в формате буклета, засунул внутрь NFC-метки, а потом ламинировал их.

Буклет защищал NFC-метку и позволял извлечь её в будущем.

▍ Автоматизация Home Assistant


И последняя часть проекта: создание автоматизации Home Assistant, которая будет воспроизводить нужный фильм после сканирования метки.

Мы храним фильмы в Plex и воспроизводим их через Apple TV. В Plex есть два способа воспроизведения видео:


По моему опыту, интеграция Plex слишком неудобна и ненадёжна. Нужно включить Apple TV, запустить приложение Plex и дождаться, пока оно станет доступным в Home Assistant; лишь после этого можно отправить команду воспроизведения конкретного фильма.

Интеграция с Apple TV работает практически мгновенно. Достаточно лишь отправить «глубокую ссылку»!

Формат «глубоких ссылок» (deep link) задокументирован на форуме Plex, он довольно прост. Вот «глубокая ссылка» для воспроизведения медиа:

plex://play/?metadataKey=UNIQUE_MEDIA_ID&server=SERVER_ID

ID сервера Plex можно найти на этой странице или поискав clientIdentifier вашего сервера.

Дальше мне нужно было понять, какие данные ESPHome отправляет Home Assistant при сканировании метки. Я открыл Developer Tools в Home Assistant и начал прослушивать события tag_scanned. Положив метку на считыватель, я увидел событие:

event_type: tag_scanned
data:
  tag_id: 1D-20-E2-06-96-00-00
  device_id: a93f971bb9622b266286460c3f2ac640
origin: LOCAL
time_fired: "2023-11-13T14:57:06.765528+00:00"
context:
  id: 01HF4JZB6DHY26TWZ903Z01BJ9
  parent_id: null
  user_id: null

Самое интересное здесь — это tag_id. Этот ID я сопоставил с ID фильма в Plex.

Вот как выглядит полная автоматизация:

- alias: "NFC Reader - Plex"
  description: ""
  mode: single
  trigger:
  - platform: event
    event_type: tag_scanned

  # Разрешаем воспроизводить фильмы только по утрам и вечерам.
  # Широкое временное окно, чтобы обеспечить гибкость расписания.
  condition:
  - condition: or
    conditions:
    - condition: time
      after: '05:00:00'
      before: '09:00:00'
    - condition: time
      after: '18:00:00'
      before: '19:50:00'  # Пора спать!
  action:
  - variables:
	  # Сопоставляем ID каждой метки с Plex ID. Атрибут "name"
	  #  не используется, но удобен для отладки.
      NFC_MAPPING:
        53-77-08-69-71-00-01:
          name: Ratatouille
          plex_id: 37353
        53-72-08-69-71-00-01:
          name: Coco
          plex_id: 3135
        04-D3-F2-FD-9F-61-81:
          name: Bing
          playlist_id: 4586
        04-36-F6-32-5F-61-80:
          name: Bumba
          playlist_id: 4587
		# ...

  - if:
    # Проверяем, находится ли отсканированная метка в mapping
    - alias: "NFC tag is in the mapping"
      condition: template
      value_template: "{{ trigger.event.data.tag_id in NFC_MAPPING }}"
    then:
    # Включаем Apple TV (и сам телевизор), когда он находится в режиме ожидания
    - if:
      - condition: state
        entity_id: media_player.appletv_living
        state: standby
      then:
      - service: media_player.turn_on
        data: {}
        target:
          entity_id: media_player.appletv_living
      - delay:
          seconds: 5
	
    # Если сопоставленная метка имеет "plex_id", то воспроизводим его как фильм.
    - if:
        - condition: template
          value_template: "{{ \"plex_id\" in NFC_MAPPING[trigger.event.data.tag_id] }}"
      then:
        - action: media_player.play_media
          data:
            media_content_type: url
            media_content_id: >-
              plex://play/?metadataKey=%2Flibrary%2Fmetadata%2F{{NFC_MAPPING[trigger.event.data.tag_id].plex_id}}&server=xxxxxxxxxxxxxx
        target:
          entity_id: media_player.appletv_living
		  
    # Если сопоставленная метка имеет "playlist_id", воспроизводим случайный пункт из плейлиста.
    - if:
        - condition: template
          value_template: "{{ \"playlist_id\" in NFC_MAPPING[trigger.event.data.tag_id] }}"
      then:
        - action: media_player.play_media
          data:
            media_content_type: url
            media_content_id: >-
              plex://play/?metadataKey=%2Fplaylists%2F{{NFC_MAPPING[trigger.event.data.tag_id].playlist_id}}&server=xxxxxxxxx
        target:
          entity_id: media_player.appletv_living

	# Устанавливаем подходящую (низкую) громкость на Sonos Beam
	# При работе с динамиком eARC элементы управления громкостью
	# Apple TV поддерживают только команды вверх/вниз.
    - service: media_player.volume_set
	  data:
	    volume_level: 0.17
	  target:
	    entity_id: media_player.sonos_tv

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


Я был впечатлён! И мой старший сын тоже. Он сразу понял, что можно использовать эту систему в любое время. Я стремился не к этому, поэтому добавил условие, позволяющее запускать автоматизацию только по утрам и вечерам.

Apple TV поддерживает «глубокие ссылки» и для других сервисов. Вот примеры для самых популярных сервисов потокового воспроизведения:

  • Netflix (используется обычный URL):
    • https://www.netflix.com/title/80234304

  • Disney+ (используется обычный URL):
    • https://www.disneyplus.com/movies/coco/db9orsI5O4gC

  • YouTube (используется обычный URL, в котором https:// заменено на youtube://)
    • Отдельное видео: youtube://www.youtube.com/watch?v=ah3ezprtgmc
    • Плейлист: youtube://www.youtube.com/watch?v=v=FkUn86bH34M&list=PLzvRQMJ9HDiQF_5bEErheiAawrJ-2zQoI&pp=iAQB

Единственная проблема с этими сервисами заключается в том, что перед началом воспроизведения они требуют выбрать профиль. В случае Plex можно включить «auto login», но для других сервисов я этого не пробовал.

▍ Воспроизведение случайных эпизодов


У меня возникла проблема с «глубокими ссылками» Plex — невозможность воспроизведения случайного эпизода сериала. Я обошёл эту трудность, просто не став делать NFC-карты для сериалов, к разочарованию моих сыновей.

Спустя пару месяцев после разработки этой системы я нашёл пост на форуме Plex о том, что можно создавать умные плейлисты, перемешивающиеся при каждом открывании. И это работало даже с «глубокими ссылками»!

То есть, решить проблему оказалось довольно просто: создать «умный плейлист» в Plex. Перейти в библиотеку (фильм или сериал) и изменить значение первого раскрывающегося меню с «All» на «Advanced Filters».

Далее нужно сконфигурировать фильтры. Я создал по одному умному плейлисту для каждого сериала, но можно и перемешивать разные сериалы.


Затем я поменял порядок сортировки с «Title» на «Randomly». После этого Plex будет перемешивать плейлист при каждом открытии, в том числе и при переходе по «глубокой ссылке»!

ID плейлиста можно найти, перейдя к плейлисту в Plex Web UI и скопировав URL:

http://192.168.2.1:32400/web/index.html#!/server/{SERVER_ID}/playlist?key=%2Fplaylists%2F{PLAYLIST_ID}&context=source%3Acontent.playlists.video~0~0

«Глубокая ссылка» для плейлиста немного отличается от ссылки для фильма:

plex://play/?metadataKey=%2Fplaylists%2F{PLAYLIST_ID_GOES_HERE}&server={ЗДЕСЬ_SERVER_ID}

▍ Дальнейшее развитие проекта


Меня впечатлила даже первая версия, но в будущем я бы хотел кое-что изменить.

Во-первых, я хочу заменить считыватель NFC на PN532. Он намного меньше и позволит сделать корпус поменьше.

▍ Почему физические носители — это здорово


Почему же я заморочился всем этим, чтобы у моих детей было что-то осязаемое? Мне кажется, у такой системы есть множество преимуществ.

Первое: ограниченный выбор фильмов. В детстве у меня не было бесконечного каталога фильмов, только с десяток VHS-кассет и DVD. Мы смотрели одни и те же фильмы снова и снова, каждый раз обнаруживая новые детали, которые бы в противном случае упустили.

Второе: это даёт моим детям независимость. Они сами могут решать, что хотят посмотреть, не прося нас брать пульт и запускать приложение. Они просто подходят к коробке с картами, выбирают фильм и включают его. Точно так же, как мы делали с VHS и DVD.

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

Наконец, у нас есть только один телевизор и два получасовых интервала на его просмотр. То есть им придётся учиться договариваться и идти на компромиссы. Они должны быстро выбрать фильм, или потерять это время просмотра. Или, например, подойти к этой задаче творчески и придумать систему, определяющую, кто будет выбирать фильм: ты можешь выбирать утром, я выбираю вечером.

Я не могу подтвердить все эти утверждения доказательствами или исследованиями. Но я искренне верю, что это поможет им освоить ценные навыки. И я считаю, что это намного лучше, чем давать детям неограниченный доступ к Netflix, Disney+, YouTube или любому другому потоковому сервису.

▍ Я ненавижу потоковые сервисы?


Конечно, нет. У меня уже много лет есть подписка на Spotify, и время от времени я подписываюсь на другие потоковые сервисы. Дело в том, что я смотрю не так много фильмов и сериалов, так что их стоимость себя не оправдывает.

Вместо них я покупаю любимые фильмы на Blu-ray и сохраняю их на сервер Plex. Это даёт мне три важных преимущества.

Во-первых, мой сын снова и снова смотрит одни и те же фильмы (особенно мультфильмы Pixar). Подписка на Disney+ стоит €10,99 в месяц, но за такую цену я могу купить с рук 3-4 диска Blu-ray. Они очень дешёвые, а после покупки диска он ваш навечно.

Во-вторых, на дисках Blu-ray есть множество дополнительного контента. Особенно мне нравятся разделы «За кулисами» («behind the scenes») и «Удалённые сцены» («deleted scenes»), которые есть на большинстве дисков. В потоковых сервисах их не всегда можно найти.

Наконец, на Blu-ray есть дублированные версии на разных языках. Для детей это большой плюс, особенно если они маленькие.

▍ Заключение и файлы


Я очень доволен этой системой, и жду, когда мой младший сможет пользоваться ею.

Если хотите изготовить что-то подобное сами, то вот мой файл Fusion360, который можно использовать или доделать.

Telegram-канал со скидками, розыгрышами призов и новостями IT ?

Комментарии (7)


  1. Revolt-or-die
    11.09.2024 13:53
    +2

    "разрешается посмотреть полчаса телевизор с утра и ещё полчаса вечером" меня это расстроило в тексте, хоть мне никогда и не запрещали


    1. consumerdefault
      11.09.2024 13:53

      у меня в школе на перемене показывали мультики и оказалось за три дня можно до конца школы насмотреться


  1. kos9078
    11.09.2024 13:53

    Но ведь на эти карты можно сразу записать ссылку (любые бинарные данные)...
    Вы все равно сделали наклейки. Это намекает на то, что маппинг менять не предполагается после "выпуска карты в оборот". А сейчас конфиг кажется перегруженным этим маппингом...


  1. Audrius_P
    11.09.2024 13:53

    Можно было просто вытатуировать QR код на лбу сына !


  1. kenomimi
    11.09.2024 13:53

    Надо еще сделать на картах с вероятностью в 10% показ "слова пастыря" или "играй гармонь" вместо мультиков - чтобы понимали, как страдал папка в своё время.


    1. consumerdefault
      11.09.2024 13:53

      и видосы про благоустройство балкона


  1. RifleR
    11.09.2024 13:53

    Они могут посмотреть большую часть одного фильма или понемногу из десяти фильмов

    Понимаю еще давать смотреть целую получасовую серию мультсериала, но позволять только полчаса из двухчасового фильма за один раз? Я бы назвал это издевательством над человеком. Или, если это ребенок, то можно делать с ним все, что захочется?