Python Scripts aus Home Assistant ausführen

Ich habe in den letzten Tagen an einem Script gebaut, dass ich aus dem Home Assistant ausführen möchte.

Aufgabestellung
Im Dashboard möchte ich Buttons einbauen über die ich ein Python Script ausführen möchte. Das Script soll eine SSH Verbindung zu einem remote Rechner aufbauen und diesen dann herunterfahren. Es sollen unterschiedliche Rechner heruntergefahren werden können. Dazu wird das Script beim Starten mit Argumenten gefüttert, die dann das Ziel festlegen, und welches Kommando ausgeführt werden soll.

Python
Möchte man Python als Scriptsprache verwenden, sollen in der Regel auch Bibliotheken nutzbar sein. Die Einbindung eines Moduls erfolgt dann üblicherweise über das Schlüsselwort import <modul-name>.
Für das Anlegen eines SSH-Clients möchte ich gerne das Modul paramiko verwenden. Über das Terminal lässt sich die Bibliothek per

pip install paramiko

installieren

Nachdem ich mein Python Skript erstellt habe, lief es im Terminal problemlos, so dass mit der Integration in HA begonnen werden konnte.

Hier gibt es dann schon den ersten Haken.Die Standard Python Installation unterstützt nicht die Verwendung des Schlüsselworts import. Aber es gibt ja noch andere Python Integrationen in HA.
Letztendlich bin ich bei PythonScriptsPro gelandet, die per HACS installierbar ist. Sie ersetzt dann die standard python_script Komponente.

In der Configuration.yaml kann die Python Unterstützung über folgenden Eintrag aktiviert werden:

#support python scripts
python_script:
  requirements:
  - instagrapi
  - datetime
  - paramiko>=3.4.0

Die zusätzlichen Module die importierbar sein sollen, sind dann unter requirements konfiguriert.

Hier das Script:

import paramiko

logger.debug(data)

ha_target = data.get("dns")
ha_command = data.get("command")

def paramiko_if(host, port, command):
    

    # Create object of SSHClient and 
    # connecting to SSH
    ssh = paramiko.SSHClient()

    # Adding new host key to the local 
    # HostKeys object(in case of missing)
    # AutoAddPolicy for missing host key to be set before connection setup.
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    ssh.connect(host[0], port, host[1], host[2])

    # Execute command on SSH terminal 
    # using exec_command
    stdin, stdout, stderr = ssh.exec_command(command)
    resp = stdout.read()
    stderr.read()
    ssh.close()

    logger.info(f"SSH response:\n{ resp }")


def switch_device(device, command):
    if device == 'NAS':
        host = ['<IP-Adresse>', '<USER>', '<PASSWORT>']
        port = '28'
        paramiko_if(host, port, command)
   if device == 'weiterer Rechner':
       .........




logger.info("shutdown.py executed")


switch_device(ha_target, ha_command)

Die Zugangsdaten der Rechner habe ich in dem Python Script in der Struktur host angelegt. An das Script werden die Daten “dns” und “command” übergeben. Dns enthält dabei den Rechnernamen (also z.B. NAS), command das Kommando, dass auf dem Remote Rechner auszuführen ist.

Die logger.info Ausgabe wird übrigens im home-assistant.log eingetragen, dass sich im standard CONFIG Verzeichnis befindet. Ein Logeintrag könnte dann so aussehen:

2024-02-11 23:33:32.603 INFO (SyncWorker_40) [custom_components.python_script] shutdown.py executed
2024-02-11 23:33:32.623 INFO (Thread-11) [paramiko.transport] Connected (version 2.0, client OpenSSH_8.9p1)
2024-02-11 23:33:32.698 INFO (Thread-11) [paramiko.transport] Authentication (password) successful!
2024-02-11 23:33:32.921 INFO (SyncWorker_40) [custom_components.python_script] SSH response:
b''

Ansteuern des Scripts
Im Dashboard habe ich mir folgende Elemente angelegt.

image

Dadurch kann ich jeden einzelnen Rechner per Wake on Lan hochfahren und auch wieder ausschalten. Bei den Buttons handelt es sich um custom button cards.

Die Erkennung, wann ein Gerät online ist, erfolgt über die Ping integration. Diese stellt den Gerätezustand (on- oder offline) als binary_sensor zur Verfügung. Der yaml Code für das NAS Laufwerk sieht dann wiefolgt aus:

type: vertical-stack
cards:
  - type: horizontal-stack
    cards:
      - type: entity
        entity: binary_sensor.192_168_110_43
        state_color: true
        name: Nas
        card_mod:
          style: |
            ha-card {
              height: 80px !important;

            }
            ha-card .value{
              font-size: 17px;
            }
      - type: horizontal-stack
        cards:
          - type: custom:button-card
            entity: switch.virtual_switch_1
            size: 30px
            entity_picture: /local/wol.png
            show_entity_picture: true
            card_mod:
              style: |
                ha-card {
                  height: 80px !important;

                }    
            tap_action:
              action: call-service
              service: wake_on_lan.send_magic_packet
              metadata: {}
              data:
                broadcast_port: 9
                mac: 00:11:32:7B:xx:xx
              confirmation:
                text: '[[[ return `Wake On Lan durchführen` ]]]'
          - type: custom:button-card
            entity: switch.virtual_switch_1
            size: 30px
            entity_picture: /local/shutdwn.png
            show_entity_picture: true
            card_mod:
              style: |
                ha-card {
                  height: 80px !important;

                }  
            tap_action:
              action: call-service
              service: python_script.exec
              data:
                file: python_scripts/shutdown.py
                dns: NAS
                command: sudo shutdown -h now
              confirmation:
                text: '[[[ return `shutdown durchführen ?` ]]]'

Die weiteren Elemente sind nach dem Gleichen Schema aufgebaut. Es geht also mit einem horizontalen Stack weiter.

Das Aufwecken per WOL geschieht über die Core funktionalität und den dazugehörigen Service wake_on_lan.send_magic_packet kombiniert mit der MAC Adresse meines Geräts.

Das Herunterfahren läuft über das Python script (Shutdown.py heißt das auf meinem System) ab. Dem Python Service werden beim Aufruf wie eingangs erwähnt, die Daten dsn und das Kommando command übergeben.

Dabei unterscheiden sich die Befehle zum Herunterfahren von Unix- und Windows-Systemen

  • Unix: sudo shutdown -h now
  • Windows: shutdown /s /t 5

Damit die Rechner nicht versehentlich gestartet oder heruntergefahren werden, wenn man den Button drückt, habe ich noch eine “Confirmation” eingebaut. Somit erfolgt die Ausführung des Befehls erst nach Bestätigung durch den Anwender.

Auf Wunsch kann ich auch noch kurz beschreiben, wie der SSH-Server auf einem Windows Rechner aufzusetzen ist, damit der Shutdown funktioniert.

1 „Gefällt mir“

Hallo, ich bin neu eingestiegen in Home Assistant und würde diese Aktion gerne in meine Automation integrieren für mich ist das leider nicht ganz logisch kannst du davon vielleicht eine Videoanleitung machen? Außerdem möchte ich diesen Python Befehl aus Node RED ansteuern. Kannst du mir dafür auch Tipps geben?

Hi Stefan. Ehrlich gesagt ist mir der Aufwand für eine Videoanleitung zu groß. Weiterhin scheint Deine Aufgabenstellung auch eine andere zu sein. Vielleicht kannst Du die ja mal näher beschreiben.

So wie ich Dich verstehe, möchtest Du das Python-Script direkt aus Node-Red aufrufen. Das Script funktioniert aber nur für den Shutdown. Ich übergebe dem Python Script zwei Parameter: Den Gerätenamen (dns) und das Kommando (command). Das Script macht nichts anderes als über SSH das Kommando auszuführen. Dazu müssen natürlich korrekte Login Daten im Script hinterlegt sein: ’ <IP-Adresse>', ‘<USER>’, ‘<PASSWORT>’ müssen mit den korrekten Daten befüllt sein. Genauso wie wenn Du Dich per Terminal über SSH am gerät anmeldest.

Ich denke es gibt verschiedene Möglichkeiten von Node Red aus mit Python Scripts zu arbeiten. Es gibt die Möglichkeit die Palette zu erweitern um Python Scripts in Node Red zu verwalten. Dann könntest Du das Script quasi als Javascript-Ersatz direkt in Node Red verwenden.

Die andere Möglichkeit besteht vermutlich darin eine Node-Red Exec Funktion zu verwenden um Python Scripts auszuführen. Zum Aufwecken kann man die Node-Red Palette erweitern: node-red-node-wol (node) - Node-RED. Die Funktion kann anscheinend Magic Packets verschicken.

Warum wird denn nicht direkt SSH aus Node Red heraus benutzt?

Ja, vermutlich wäre das dann sogar der einfachste Weg.

Ich muss gestehen das ich von Python-Scripts in HA wieder Abstand genommen habe, ist mir zuviel HACS da drin und man sieht ja wie oft derzeit Projekte nicht weiterentwickelt oder eingestampft werden. Und wenn im HA wieder die Python Version angehoben wird, gibts wahrscheinlich wieder Probleme.
Für Windows Shutdowns hab ich einfach das RPC Shutdown Add-On genommen. Ist offiziell, wird also weiter unterstützt. Den Rest mach ich mit einem kleinen Powershell Rest-Listener in einem Docker.

Mein Problem besteht eigentlich nur darin das ich, wenn ich ein Python Script ausführen möchte aus Node RED, das der Befehl python (usr/bin/python) /Pfad/zum/Script/Script.py nicht gefunden wird da Node RED aus welchem Grund auch immmer keinen Zugriff auf Python hat. Bash geht einwandfrei. Ich habe ein bestehendes Python Script welches ich einbauen wollte.

Ok. Das ist leider bei mir nicht möglich, da ich einige Linuxrechner (z.B. neben PC auch ein Synology NAS und etliche RasPi) am Start habe. Ich wüßte nicht, dass die RPC unterstützen. Bzgl. HA und Python kompatibilität habe ich nicht wirklich Erfahrung. Aber es ist natürlich vorstellbar, dass es bei einem major Update auf eine höhere Version Probleme mit Scripten gibt.

Ok. Das ist dann aber eigentlich ein völlig anderes Thema “Python Script aus Node Red in Home Assistant ausführen”. Mach doch einfach ein neues Thema auf.