Забытые технологии древних — картинка в картинке на ТВ для умного дома

от автора

Привет, Хабр! Сегодня я расскажу о своем опыте автоматизации умного дома, а именно о выводе изображения PiP с камеры на тв.

Пример вывода изображений с камер

Пример вывода изображений с камер

Обычно ОС (webOS, Tizen и тд) тв закрыта и не предполагает кого‑либо внешнего управления, например, включение\выключение или вывод картинки в картинке. Но на Android TV с этим проще — можно запустить любое приложение, а наделив его правами SYSTEM_ALERT_WINDOW, вывести его поверх любых других (в том числе видео плеера или изображения с HDMI), этим и воспользуемся.

Дано два телевизора: Xiaomi Q1 на Android TV к нему подключены Nvidia Shield и Xbox и LG TV на webOS с подключенным к нему FireTV Stick — цель вывести видео с камер при звонке в дверь. Умный дом управляется через Home Assistant.

Настройка андроид тв\приставки

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

Для начала на Android TV необходимо выдать права разработчика, для этого в настройках ОС, нужно несколько раз кликнуть по Номеру сборки, а после этого в параметрах разработчика нужно включить Отладку и тут же, не отходя от кассы, можно телевизор\приставку добавить в HomeAssistant через интеграцию Android Debug Bridge.

Добавление Android TV в Home Assistant
Добавление устройства в HA

Добавление устройства в HA
Запрос на отладку

Запрос на отладку
все домашние Андроид ТВ добавлены

все домашние Андроид ТВ добавлены

Теперь скачиваем APK PiPup и устанавливаем на ТВ командами:

adb connect YOUR_ANDROID_TV_IP_ADDRESS

adb install app-debug.apk

adb shell appops set nl.rogro82.pipup SYSTEM_ALERT_WINDOW allow

Команды ADB можно вызывать прямо из Home Assistant

Приложение PiPup открывает на устройстве веб порт 7979и принимает POST JSON данные, которые необходимо вывести на экране тв, например:

{   "duration": 30,   "position": 0,   "title": "Your awesome title",   "titleColor": "#0066cc",   "titleSize": 20,   "message": "What ever you want to say... do it here...",   "messageColor": "#000000",   "messageSize": 14,   "backgroundColor": "#ffffff",   "media": { "image": {     "uri": "https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/cfcc3137009463.5731d08bd66a1.png", "width": 480   }} }

У media: "video" есть недостаток, по крайней мере на Amazon FireTV, проигрываемое основное видео на тв приставке автоматически ставится на паузу, поэтому я вообще решил не использовать такой тип медиа.

Проверить можно так:

curl -d "@post.json" -H "Content-Type: application/json" -X POST http://ANDROID_TV_IP_ADDRESS:7979/notify

Настройка умного дома

Веб запросы в HA вызываются через интеграцию rest_command, создадим удобные сервисы (для отправки уведомления в виде текста, изображения и веб содержимого), для этого нужно сохранить код ниже в файле notification_on_tv.yaml по пути /homeassistant/rest_commands

pipup_text_on_tv:   url: http://{{ ip }}:{{ port | default(7979) }}/notify   content_type: 'application/json'   verify_ssl: false   method: 'post'   timeout: 20   payload: >     {       "duration": {{ duration | default(20) }},       "position": {{ position | default(0) }},       "title": "{{ title | default('') }}",       "titleColor": "{{ titleColor | default('#50BFF2') }}",       "titleSize": {{ titleSize | default(12) }},       "message": "{{ message }}",       "messageColor": "{{ messageColor | default('#fbf5f5') }}",       "messageSize": {{ messageSize | default(14) }},       "backgroundColor": "{{ backgroundColor | default('#0f0e0e') }}"     }  pipup_image_on_tv:   url: http://{{ ip }}:{{ port | default(7979) }}/notify   content_type: 'application/json'   verify_ssl: false   method: 'post'   timeout: 20   payload: >     {       "duration": {{ duration | default(20) }},       "position": {{ position | default(0) }},       "title": "{{ title | default('') }}",       "titleColor": "{{ titleColor | default('#50BFF2') }}",       "titleSize": {{ titleSize | default(10) }},       "message": "{{ message }}",       "messageColor": "{{ messageColor | default('#fbf5f5') }}",       "messageSize": {{ messageSize | default(14) }},       "backgroundColor": "{{ backgroundColor | default('#0f0e0e') }}",       "media": {          "image": {           "uri": "{{ url }}",           "width": {{ width | default(640) }}         }       }     }   pipup_url_on_tv:   url: http://{{ ip }}:{{ port | default(7979) }}/notify   content_type: 'application/json'   verify_ssl: false   method: 'post'   timeout: 20   payload: >     {       "duration": {{ duration | default(20) }},       "position": {{ position | default(0) }},       "title": "{{ title | default('') }}",       "titleColor": "{{ titleColor | default('#50BFF2') }}",       "titleSize": {{ titleSize | default(10) }},       "message": "{{ message }}",       "messageColor": "{{ messageColor | default('#fbf5f5') }}",       "messageSize": {{ messageSize | default(14) }},       "backgroundColor": "{{ backgroundColor | default('#0f0e0e') }}",       "media": {          "web": {           "uri": "{{ url }}",            "width": {{ width | default(640) }},           "height": {{ height | default(480) }}         }       }     }

и прописать этот файл в основном файле конфигурации HA /homeassistant/configuration.yaml

rest_command: !include_dir_merge_named rest_commands

После этого нужно перезагрузить HA и мы сможем вызывать наши новые сервисы для вывода текста, изображений или веб содержимого, например:

service: rest_command.pipup_image_on_tv data:   title: Привет   message: Хабр   ip: 192.168.0.94   titleColor: red   position: 0   url: https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/cfcc3137009463.5731d08bd66a1.png

Вывод live видео с камер

Для вывода потока с подключенных камер HA использует внутренний проксирующий сервис на основе ffmpeg, который отдает фронтенду поток в виде «бесконечной» картинки с заголовком multipart/x-mixed-replace; boundary=--frameboundary ссылку на поток можно получить через атрибуты устройства камера — entity_picture, который (к нашей радости) содержит также одноразовый токен доступа, это, в свою очередь, дает доступ к картинке без авторизации, пример:

http://HA_IP:8123/api/camera_proxy/camera.doorbell_repeater_b8b7?token=fd31891d4e34b6a45bf26fbba48af42f71f6abd0d797994fe529c280536e5e78

Атрибуты подключенных камер

Поток с (почти) любой IP камеры можно завести в HomeAssistant через интеграцию https://github.com/AlexxIT/go2rtc#go2rtc-home-assistant-integration

К сожалению такой поток «бесконечной» картинки нельзя просто так отдать в наш новый сервис pipup_image_on_tv — ничего не выведется (компонента не умеет работать с такими картинками). Так же не сработает если отдать в pipup_url_on_tv, нужна обертка в виде простой веб страницы с этой картинкой.

HA умеет хранить и отдавать статичные пользовательские ресурсы, которые лежат по пути /homeassistant/www, создадим там страницу с выводом картинки с камеры, например, /homeassistant/www/fullscreen/my_fullscreen_panel.html

<!DOCTYPE html> <html> <head>     <title>Fullscreen Panel</title>     <style>        body, html {             margin: 0;             padding: 0;             width: 100%;             height: 100%;             overflow: hidden;         }     </style> </head> <body>     <img id="myImage" src="" alt="stream"> <script>     async function getState(entity_id) {         const response = await fetch('/api/states/' + entity_id, {             headers: {                 'Authorization': 'Bearer СЕКРЕТНЫЙ_КОД',                 'Content-Type': 'application/json'             }         });         if (response.ok) {             const data = await response.json();             return data.attributes;         } else {             console.error('Failed to fetch state');             return null;         }     }      document.addEventListener("DOMContentLoaded", async function() {         const urlParams = new URLSearchParams(window.location.search);          const entity_id = urlParams.get('camera_entity');         const attributes = await getState(entity_id);         if (attributes) {             const img_stream_url = attributes.entity_picture.replace('camera_proxy', 'camera_proxy_stream');             document.getElementById('myImage').src = img_stream_url;         }     }); </script> </body> </html> 

ID камеры на страницу будем передать через параметр camera_entity, а url к картинке (с токеном) будем получать через встроенный в HA REST сервис /api/states/, для доступа к нему в HA нужно получить постоянный авторизационный токен, тут http://HA_IP:8123/profile/security

И прописать его в HTML тут (осторожно: этот ключ дает полный доступ к HA, но для внутренней сети это нестрашно)

const response = await fetch('/api/states/' + entity_id, {             headers: {                 'Authorization': 'Bearer СЕКРЕТНЫЙ_КОД',                 'Content-Type': 'application/json'             }         });

Еще, атрибут camera_entity содержит только статичную картинку, поэтому в пути нужно заменить camera_proxy на camera_proxy_stream, что уже сделано у меня в коде.

Теперь в браузере на PC, alias: Показать live с камеры с переданным ID и текстом sequence: - parallel: - service: rest_command.pipup_url_on_tv metadata: {} data: ip: 192.168.0.215 title: "{{ title }}" url: >- http://HA_IP:8123/local/fullscreen/my_fullscreen_panel.html?camera_entity={{ camera_entity }}&nocache={{ range(1, 51) | random }} width: 320 height: 200 - service: rest_command.pipup_url_on_tv metadata: {} data: ip: 192.168.0.94 title: "{{ title }}" url: >- http://HA_IP:8123/local/fullscreen/my_fullscreen_panel.html?camera_entity={{ camera_entity }}&nocache={{ range(1, 51) | random }} width: 320 height: 200 description: "" icon: mdi:camera fields: camera_entity: selector: entity: {} name: Сущность камеры required: true title: selector: text: null name: Сообщение

Также, на всякий случай, я создал автоматизацию, которая запускает сервис PiPup на тв (при переходе из спящего режима), если вдруг телевизор решит его прибить:

alias: Перезапуск сервиса картинка в картинке на XiaomiTV, если тв прибьет его description: "" trigger:   - platform: device     device_id: ID ANDROID TV     domain: media_player     entity_id: Player ID     type: idle condition: [] action:   - service: androidtv.adb_command     target:       device_id: ID ANDROID TV     data:       command: >-         ps -ef | grep -v grep | grep pipup || shell am start         --activity-task-on-home -n nl.rogro82.pipup/.MainActivity mode: single

Ну и, как пример, основная автоматизация, когда курьер принес заказ:

alias: Курьер пришел description: "" trigger:   - platform: state     entity_id:       - sensor.smartintercom_line_status     to: Открытие двери condition:   - condition: state     entity_id: switch.smartintercom_delivery     state: "on" action:   - service: script.alice_play_text     data:       message: Кажется курьер пришел, открыла дверь   - wait_for_trigger:       - platform: state         entity_id:           - binary_sensor.camera_hub_g2h_e718_motion_sensor         to: "on"     timeout:       hours: 0       minutes: 4       seconds: 0       milliseconds: 0     continue_on_timeout: false   - service: script.alice_play_text     data:       message: Курьер у входной двери   - service: script.live_stream     metadata: {}     data:       camera_entity: camera.camera_hub_g2h_e718_camera_stream_management0       title: Курьер у входной двери mode: single

И автоматизация при звонке на дверной замок: включение экрана планшета и трансляция видео на тв:

alias: Включение экрана планшета при звонке и показ live с камеры звонка description: "" trigger:   - platform: device     device_id: bba92ec78885fa381662ae945f2ee231     domain: homekit_controller     type: doorbell     subtype: single_press condition: [] action:   - service: script.door_tablet_screen_on     metadata: {}     data: {}   - service: script.live_stream     metadata: {}     data:       camera_entity: camera.doorbell_repeater_b8b7       title: Звонят в дверь mode: single

Мира!


ссылка на оригинал статьи https://habr.com/ru/articles/830340/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *