Выбор загрузочного диска домашнего компьютера из Home Assistant

Мой основной компьютер — macbook, который всегда со мной, и на котором я делаю почти все что нужно как дома так и вне его. Но также есть домашний комп, на котором бывает оптимальнее делать ресурсоемкие задачи. Кроме того, некоторые вещи на маке делать неудобно или вовсе невозможно, поэтому на домашнем на разных дисках установлены windows, ubuntu и proxmox с десятком виртуалок под разные случаи. И меня всегда очень напрягала невозможность удаленно включить нужную операционную систему на домашнем, чтобы потом подключиться к ней удаленно и сделать все что нужно.

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

Конечно, без Home Assistant не обошлось.

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

Как например можно реализовать первый вариант? Взять служебный небольшой диск, можно даже флешку или DoM. Установить на нее какую нибудь легковесную linux, и в конфиг ее grub’а записать все остальные диски, имеющиеся на компе. Компьютер должен всегда первым делом загружать эту служебную ось, а она, загрузившись, должна взять откуда то команду о том какую целевую ось загрузить следующей, внести изменения в свой конфиг, и перезагрузить компьютер. А затем из загрузившейся целевой системы первым делом исправить конфиг того загрузчика обратно. В целом рабочий вариант, но мне кажется сложным и ненадежным.

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

Часть первая — железная.

Купил вот такое четырехканальное zigbee реле Tuya.

Пока ехало, нарисовал и напечатал конструкцию для крепления дисков и реле

571b32af123134d2f0ef1289f4ecad44.jpg

Немножко теории:
Современные sata диски по стандарту получают 5 (красный цвет) и 12 (желтый цвет) вольт. В целях совместимости еще 3,3 (оранжевый цвет) вольта иногда можно встретить, но чаще этот провод просто отсутствует.

a6e9cd76c856d9dd678791a83db52c89.png

Для работы SSD дискам нужно только 5 вольт. 12 по моему HDD нужно, а SSD без него прекрасно работают.
Поскольку у меня именно ssd, то врезаться будем в красный провод.

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

После сборки получилась такая конструкция:

bed3cb9e6d01418d412f66f4b06b1205.png

Фото к сожалению не финальное, первой сборки, и там есть неточности. На фото реле управляет желтыми проводами, а нужно красными. Верную версию забыл сфотографировать. Верхний диск действительно hdd, правильный диск был занят пока, потом заменю. А еще в финальной версии выкинул колодку и все провода пропаял, на них были потери напряжения и это негативно сказывалось на работе.
Провода включены в нормально закрытые разъемы, то есть в выключенном состоянии реле все диски включены.

Раз дисков 3, а каналов 4 -, а зачем же еще канал. А его я подключил к кнопке питания компьютера, прямо на контакты на материнке, в параллель к физической кнопке.

Следующим шагом было запитать реле и подключить его к home assistant. Для питания в закромах нашелся подходящий адаптер, ну, а в процессе подключения нет ничего нового.
В результате у меня в HA появилось устройство, управляющее всем что нужно

5dda65d95f261e5b22d69840616cbb96.jpg

Часть вторая — программная

Устройство есть, теперь надо сделать красиво.

Делаем скрипты в HA, которые будут нажимать на кнопки. Скрипт в данном контексте — это то же самое что автоматизация, только для ручного запуска, без авто-условий.

Скрипт запуска нужной операционной системы.

alias: Запустить Windows
sequence:
  - service: switch.turn_off
    data: {}
    target:
      entity_id:
        - switch.rele_diskov_kompiutera_l1
        - switch.rele_diskov_kompiutera_l2
        - switch.rele_diskov_kompiutera_l2
  - service: switch.turn_on
    data: {}
    target:
      entity_id:
        - switch.rele_diskov_kompiutera_l3
        - switch.rele_diskov_kompiutera_l2
  - service: switch.turn_on
    data: {}
    target:
      entity_id:
        - switch.rele_diskov_kompiutera_l4
  - delay:
      hours: 0
      minutes: 0
      seconds: 1
      milliseconds: 0
  - service: switch.turn_off
    data: {}
    target:
      entity_id:
        - switch.rele_diskov_kompiutera_l4
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.compon
    data: {}
  - delay:
      hours: 0
      minutes: 0
      seconds: 90
      milliseconds: 0
  - service: switch.turn_off
    data: {}
    target:
      entity_id:
        - switch.rele_diskov_kompiutera_l1
        - switch.rele_diskov_kompiutera_l2
        - switch.rele_diskov_kompiutera_l3
  - service: automation.trigger
    metadata: {}
    data:
      skip_condition: true
    target:
      entity_id: automation.proverka_sostoianiia_kompa
mode: single

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

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

Добавляем еще два скрипта, эмулирующих нажатие кнопки питания.

alias: Тык питание компа
sequence:
  - service: switch.turn_on
    data: {}
    target:
      entity_id:
        - switch.rele_diskov_kompiutera_l4
  - delay:
      hours: 0
      minutes: 0
      seconds: 1
      milliseconds: 0
  - service: switch.turn_off
    data: {}
    target:
      entity_id:
        - switch.rele_diskov_kompiutera_l4
mode: single
alias: Долгий тык питание компа
sequence:
  - service: switch.turn_on
    data: {}
    target:
      entity_id:
        - switch.rele_diskov_kompiutera_l4
  - delay:
      hours: 0
      minutes: 0
      seconds: 5
      milliseconds: 0
  - service: switch.turn_off
    data: {}
    target:
      entity_id:
        - switch.rele_diskov_kompiutera_l4
mode: single

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

Теперь можно позапускать скрипты и насладиться перещелкиванием реле и запуском нужных осей. Но еще некрасиво. Добавим еще немного свистелок. Лично мне не хватает наглядной информации о том что сейчас запущено.

Сделаю это так — после запуска каждая из операционных систем будет периодически стучаться в HA представляться и сообщать что она запущена. А тот соответственно будет проверять — было ли обновление состояния, и если нет то считать комп выключенным. Получится такой примитивный активный мониторинг.

В HA добавляем вспомогательный элемент типа Список. Назовем его например compstate и заполним списком с текущими. И еще один типа Переключатель — compon.

e3559f26cd7e8ca2ddf9af6bb9a32206.jpg

Для возможности обращения по api добавим токен. Это делается в параметрах текущего пользователя

ce1af564c0a4bf6a4dc76e77f7eddc83.jpg

Теперь со всех операционных систем надо настроить обращение по api и передачу состояния. Я не буду описывать конкретные методы, они могут отличаться в разных системах. Суть проста. Надо отправить POST запрос на http://ip_адрес_сервера_HA:8123/api/states/input_select.compstate, авторизоваться токеном, и передать json с одним из вариантов, добавленных ранее в список. В большинстве случаев подойдет curl, он есть и для windows. Ну то есть добавляем в cron или в планировщик вызов курла, или делаем это любым другим подходящим способом.

curl \
  -H "Authorization: Bearer тут_вставить_токен" \
  -H "Content-Type: application/json" \
  -d '{"state": "ubuntu"}}' \
  http://ip_адрес_сервера_HA:8123/api/states/input_select.compstate

Можно попробовать, и убедиться что состояние вспомогательного элемента compstate меняется.

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

alias: Проверка состояния компа
description: ""
trigger: []
condition: []
action:
  - repeat:
      sequence:
        - if:
            - condition: or
              conditions:
                - condition: state
                  entity_id: input_select.compstate
                  state: windows
                  for:
                    hours: 0
                    minutes: 3
                    seconds: 0
                - condition: state
                  entity_id: input_select.compstate
                  state: ubuntu
                  for:
                    hours: 0
                    minutes: 3
                    seconds: 0
                - condition: state
                  entity_id: input_select.compstate
                  state: proxmox
                  for:
                    hours: 0
                    minutes: 3
                    seconds: 0
          then:
            - service: input_boolean.turn_off
              target:
                entity_id: input_boolean.compon
              data: {}
            - service: input_select.select_option
              target:
                entity_id: input_select.compstate
              data:
                option: offline
        - delay:
            hours: 0
            minutes: 2
            seconds: 0
            milliseconds: 0
      while:
        - condition: state
          entity_id: input_boolean.compon
          state: "on"
mode: single

Поясню. После запуска автоматизации она каждые две минуты повторяет одну и ту же проверку пока включен вспомогательный элемент compon.
Проверяем — если элемент compstate в течение 3 минут уже равен одному из значений списка, то делаем вывод что компьютер выключен или не отвечает, меняем статус на offline и виртуальный переключатель выключаем, после чего завершаем автоматизацию.

Ну и последний пункт — отображаем все на панели управления. Для этого добавляем на панель lovelace вертикальный стек с таким кодом:

type: vertical-stack
cards:
  - type: markdown
    content: >
      {% set p = states('input_boolean.compon') %} Компьютер {{ 'включен' if p
      == "on" else 'выключен' if p == "off" }}. 

      {% set s = states('input_select.compstate') %} Состояние - {{ 'Загружен
      windows' if s == "windows" else 'Загружен ubuntu' if s == "ubuntu" else
      'Загружен proxmox' if s == "proxmox" else 'offline' if s == "offline" }}. 
  - type: entities
    entities:
      - entity: script.windows
      - entity: script.ubuntu
      - entity: script.proxmox
      - entity: script.unknown
      - entity: script.unknown_2

Поясню — сверху показываем markdown карточку, в которой выполняем простые сравнения. Если переключатель compon включен то пишем Компьютер включен, иначе Компьютер выключен.
И второй строчкой выводим состояние compstate.
Снизу выводим команды запуска наших скриптов.
Вот что получается:

177b20b46300bf5b9ddb5e110d0115a4.jpeg

Я специально сделал скриншот с мобильного, чтобы показать насколько я теперь свободен в запуске нужной системы на домашнем компе:)

Вот как то так. Статья получилась несколько сумбурная, но надеюсь интересная. Помните — Home Assistant это не только ценный мех, но и возможность управления другими компьютерами.

© Habrahabr.ru