Ankündigung

Einklappen
Keine Ankündigung bisher.

SSH per executecommand ausführen

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    SSH per executecommand ausführen

    Hallo zusammen,

    ich habe folgendes Problem:
    Ich möchte WS2801 LED Streifen mit einem Rasperry ansteuern.
    Lokal oder per putty auf dem LED-Raspi funktioniert alles.

    Der Befehl (ausgeführt als User "pi") funktioniert tadellos.
    Für AN:
    /usr/bin/python /home/pi/ws2801.py 123 123 123

    Für AUS:
    /usr/bin/python /home/pi/ws2801.py 0 0 0

    Soweit gut.


    Nun möchte ich den LED-Raspi per Openhab steuern.
    Logge ich mich per putty auf den OH-Raspi ein (User Openhabian), kann ich folgenden Befehl eingeben:

    Für AN:
    sudo -u openhabian ssh -t -t pi@192.XXX.XXX.XXX 'sudo -u pi /usr/bin/python /home/pi/ws2801.py 123 123 123'

    Für AUS:
    sudo -u openhabian ssh -t -t pi@192.XXX.XXX.XXX 'sudo -u pi /usr/bin/python /home/pi/ws2801.py 0 0 0'

    Die SSH Keys funktionieren, es wird kein Passwort abgefragt.


    Nun zu meinem Problem:

    Packe ich den Commandline Befehl in eine ganz einfache Rule

    bekomme ich als Meldung im Log

    Code:
    2018-12-27 01:31:51.654 [INFO ] [lipse.smarthome.io.net.exec.ExecUtil] - executed commandLine 'sudo -u openhabian ssh -t -t pi@192.XXX.XXX.XXX 'sudo -u pi usr/bin/python /home/pi/ws2801.py 123 123 123''
    Es passiert aber nichts.
    Gebe ich den Befehl in der Shell ein, leuchten die LEDs auf.



    Hier die rule:

    Code:
    rule "WSxx Change"
    when
    Item WS28xx_Strip received command
    then
    
    //logInfo("WS Status", "ON")
    executeCommandLine("sudo -u openhabian ssh -t -t pi@192.XXX.XXX.XXX 'sudo -u pi /usr/bin/python /home/pi/ws2801.py 123 123 123'")
    
    end
    Hab ich da noch einen Fehler in der Syntax?

    Ich finde den Fehler nicht.....


    Hat da wer einen Tip?

    Gruß
    Yankee

    #2
    Ich hänge da schon mehrere Abende dran.

    Gibt es noch eine andere Möglichkeit, das openhab auf einem entfernten Raspi ein Python-Script ausführt?
    Netcat? Mqtt?


    Jemand einen Tip?

    Kommentar


      #3
      habe mich weiter schlau gelesen.

      bin dabei auf diese Seite gestoßen:

      www.klenzel.de "Automatischer SSH-Login" Besonderheiten bei Openhab"

      Mich macht nur stutzig, wenn ich auf der Shell als User openhab den folgenden Befehl ausführe, klappt alles.

      Code:
      openhab@openhabian2:/$ ssh -i /scripts/.ssh/id_rsa -t -t pi@xx.xx.xx.200 '/usr/bin/python /home/pi/ws2801.py 123 123 123'

      Lasse ich den gleichen Befehl per executeCommandLine verarbeiten, dann wird er nicht ausgeführt.
      An den Berechtigungen kann es meiner Meinung nach nicht liegen, dann würde er ohne weiteres nicht auf der Shell ausgeführt.

      So sieht die Rule aus:

      Code:
      rule "WSxx Change"
      when
      
      Item WS28xx_Strip received command
      
      then
      
      if (receivedCommand == ON){
      
      executeCommandLine("ssh -i /scripts/.ssh/id_rsa -t -t pi@xx.xx.xx.200 '/usr/bin/python /home/pi/ws2801.py 123 123 123'")
      logInfo("LEDStrip.rules", "LED Befehl AN gesendet!")
      
      }
      
      else if (receivedCommand == OFF){
      
      executeCommandLine("ssh -t -t pi@xx.xx.xx.200 'sudo -u pi /usr/bin/python /home/pi/ws2801.py 0 0 0'")
      logInfo("LEDStrip.rules", "LED Befehl AUS gesendet!")
      
      }
      end
      Hat da wer eine Idee?
      Ich weiß nicht mehr weiter.....


      Gruß
      Yankee

      Kommentar


        #4
        openHAB läuft unter dem User openhab, nicht unter dem User openhabian. Der User openhab hat default kein Terminal zugewiesen. Die Datei id_rsa muss auf Rechte 700 gesetzt sein, sonst weigert sich ssh, sie zu verwenden. Natürlich muss die Datei dem User openhab gehören. Der User openhab hat übrigens auch ein home-Verzeichnis, in dem man den Zweig ./.ssh/ für die Schlüsseldatei anlegen kann (dann kann man sich den -i - Parameter sparen).
        Ich habe mir ein python-Script geschrieben, welches als (winziger) mqtt Client auftritt. Damit entfällt das ganze rumgewurschtele mit ssh. Insbesondere macht mich das exec2-Binding hier verrückt, ich will aber eigentlich meine Steuerbefehle mit Items versenden, nicht über Rules (es sei denn, die Rule soll etwas austomatisieren, dann aber bitte über das passende Item)

        Kommentar


          #5
          Hallo,

          ich habe dem User "openhab" ein Terminal zugewiesen und kann mich auch als "openhab" einloggen.
          Hab auch als "openhab" die RSA-Keys erstellt und auf den ledraspi übertragen.
          Wenn ich dann den Befehl aus Post #3 eingebe (bin übrigens in Post #3 als "openhab" angemeldet ) wird der Befehl ohne "sudo", Passwortabfrage oder sowas ausgeführt.
          Lasse ich den Befehl per executeCommandLine auszuführen, dann gehts nicht.

          Ich stimme dir zu, die Befehle per Item zu versenden.
          Ist hier aber nicht möglich, da die Argumente (die 3 Ziffern am Ende des Befehls für den Anteil R+G+B) in der Rule für die Farbtemperatur angepasst werden.


          So sieht die Rule komplett aus.
          Code:
          rule "WSxx Change"
          when
          Item WS28xx_Strip received command
          then
          if (receivedCommand instanceof HSBType)
          {
           val red = ((WS28xx_Strip.state as HSBType).red * 2.55) as Number
           val green = ((WS28xx_Strip.state as HSBType).green * 2.55) as Number
           val blue = ((WS28xx_Strip.state as HSBType).blue * 2.55) as Number
           logInfo("WS Status", red.toString + "," + green.toString + "," + blue.toString)
          
          // executeCommandLine("/usr/bin/python3 /etc/openhab2/scripts/ws28xx.py " + red.toString + " " + green.toString + " " + blue.toString )
          
          // executeCommandLine("/usr/bin/python3 /etc/openhab2/scripts/ws28xx.py 123 123 123"
          
          
          
          }
          else if (receivedCommand == ON){
          //logInfo("WS Status", "ON")
          executeCommandLine("ssh -i /scripts/.ssh/id_rsa -t -t pi@192.168.178.200 '/usr/bin/python /home/pi/ws2801.py 123 123 123'",2000)
          
          logInfo("LEDStrip.rules", "LED Befehl AN gesendet!")
          }
          else if (receivedCommand == OFF){
          executeCommandLine("ssh -i /scripts/.ssh/id_rsa -t -t pi@192.168.178.200 '/usr/bin/python /home/pi/ws2801.py 0 0 0'",2000)
          logInfo("LEDStrip.rules", "LED Befehl AUS gesendet!")
          }
          end
          Bin im Moment nur mit den ON und OFF Kommandos am "spielen".

          Ist da noch ein Fehler drin?


          Kommentar


            #6
            Zumindest fällt mir kein Fehler auf.

            Was noch sein könnte, dass Du bestimmte (argh...) Leerzeichen durch doppelte @ ersetzen musst. Welchen Regeln dieses escapen folgt, habe ich bisher auch noch nicht begriffen, und ich bin schon seit OH1.0 dabei...
            Es könnte auch noch sein, dass Du den Pfad zu ssh mit angeben musst, also z.B. /bin/ssh (ich bin grad zu faul, nachzuschauen, wo ssh genau liegt)

            Ansonsten kannst Du natürlich ein Item verwenden, Du musst nur ein String Item nehmen und den String entsprechend (mit Leerzeichen als Trenner zwischen den Werten) definieren, hatte ich so im Einsatz.
            Ich komme grade nicht an mein RGB-mqtt-Python-Script ran, weil ich auf der Arbeit sitze und der entsprechende Raspberry wegen Winterpause auf der Werkbank ruht (Beleuchtung des Strandkorbs...), aber es war recht einfach, das umzusetzen.
            Zuletzt geändert von udo1toni; 29.12.2018, 21:55.

            Kommentar


              #7
              Ich habe den den Pfad zu /ssh angegeben.
              Leider ohne Erfolg.

              Macht der ssh Befehl denn immer soviel Ärger? Da gibts doch bestimmt jemanden, der einen ssh-Befehl über Openhab verschickt.


              MQTT habe ich auch schon dran gedacht.

              Habe Mosquitto auch schon installiert.
              Wie muss ich denn dann die Items ändern, das die Werte versendet werden?

              Und wie muss ich das Script anpassen, das der LedRaspi auf die gesendeten Werte reagiert?

              hier noch das script, welches auf dem ledraspi ausgeführt werden soll (ohne MQTT):

              Code:
              #!/usr/bin/env python3
              # -*- coding: utf-8 -*-
              
              import time, sys, inspect, ast
              import RPi.GPIO as GPIO
              
              # Import the WS2801 module.
              import Adafruit_WS2801
              import Adafruit_GPIO.SPI as SPI
              
              # Configure the count of pixels:
              PIXEL_COUNT = 41
              
              # other settings
              SPI_PORT   = 0
              SPI_DEVICE = 0
              
              pixels = Adafruit_WS2801.WS2801Pixels(PIXEL_COUNT, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE), gpio=GPIO)
              
              ################################################################################
              # DEFINE YOUR FUNCTIONS HERE
              ################################################################################
              
              def setRGBColor(pixels, r=255, g=255, b=255):
                  # cast from string to int
                  r, g, b = int(float(r)), int(float(g)), int(float(b))
                  pixels.set_pixels( Adafruit_WS2801.RGB_to_color( r, g, b ) )
                  pixels.show()
              
              
              if __name__ == "__main__":
                  if len(sys.argv) < 4:
                      sys.exit(1)
              
                  cmdargs = sys.argv[1:]
                  setRGBColor(pixels, cmdargs[0], cmdargs[1], cmdargs[2])
              Gibts da nicht was elegantes?

              Kommentar


                #8
                Auf die Schnelle hier ein anderes Script, welches ich dazu benutze, per MQTT zwei Dienste auf einem entfernten Rechner ein- und auszuschalten:
                Code:
                #!/usr/bin/python
                
                import configparser
                import logging
                import paho.mqtt.client as mqtt
                import time
                from sysdmanager import SystemdManager
                
                config = configparser.ConfigParser()
                config.read('/etc/default/mqttclient')
                
                log_file = (config['logging']).get('filename','/var/log/pymqtt.log')
                log_level = int((config['logging']).get('level','30'))
                logging.basicConfig(filename=log_file,format='%(asctime)s %(levelname)s:%(message)s', datefmt='%Y/%m/%d/ %H:%M:%S', level=log_level)
                
                MQTT_SERVER = (config['mqtt']).get('url','localhost')
                MQTT_PORT = int((config['mqtt']).get('port','1883'))
                MQTT_RECONNECT = int((config['mqtt']).get('reconnect','60'))
                MQTT_PATH = (config['mqtt']).get('path','/')
                MQTT_COMMAND = (config['mqtt']).get('command','cmnd')
                MQTT_STATE = (config['mqtt']).get('state','state')
                MY_COMMAND = MQTT_PATH+MQTT_COMMAND
                MY_STATE = MQTT_PATH+MQTT_STATE
                
                # The callback for when the client receives a CONNACK response from the server.
                def on_connect(client, userdata, flags, rc):
                
                    logging.info("Connected with result code "+str(rc))
                    if rc: logging.warning("Connecting resulted with" +str(rc))
                    # Subscribing in on_connect() means that if we lose the connection and
                    # reconnect then subscriptions will be renewed.
                    client.subscribe(MY_COMMAND)
                    logging.info("Subscribed to "+str(MY_COMMAND))
                
                # The callback for when a PUBLISH message is received from the server.
                def on_message(client, userdata, msg):
                    manager = SystemdManager()
                    logging.debug("got message!")
                    logging.info(msg.topic+" : "+str(msg.payload))
                    startunit=""
                    stopunit1=""
                    stopunit2=""
                    if str(msg.payload) == "1":
                        logging.debug("Payload is 1 -> CS")
                        stopunit1="cps.service"
                        startunit="calibre-server.service"
                    elif str(msg.payload) == "2":
                        logging.debug("Payload is 2 -> CPS")
                        startunit="cps.service"
                        stopunit1="calibre-server.service"
                    elif str(msg.payload) == "0":
                        logging.debug("Payload is 0 -> OFF")
                        stopunit2="cps.service"
                        stopunit1="calibre-server.service"
                    else:
                        logging.info("Payload is "+str(msg.payload)+" -> only send state")
                    if stopunit1 != "":
                        logging.debug("stop service "+stopunit1+"!")
                        manager.stop_unit(stopunit1)
                    if stopunit2 != "":
                        logging.debug("stop service "+stopunit2+"!")
                        manager.stop_unit(stopunit2)
                    client.publish(MY_STATE, payload="0", qos=0, retain=False)
                    logging.debug("published state 0 to "+MY_STATE)
                    if startunit != "":
                        logging.debug("wait until starting service!")
                        time.sleep(10)
                        logging.debug("starting service "+startunit+"!")
                        manager.start_unit(startunit)
                    logging.debug("publishing state")
                    if manager.is_active("cps.service"):
                        cpsstate="ON"
                        client.publish(MY_STATE, payload="2", qos=0, retain=False)
                        logging.debug("published state 2 to "+MY_STATE)
                    else:
                        cpsstate="OFF"
                    if manager.is_active("calibre-server.service"):
                        csstate="ON"
                        client.publish(MY_STATE, payload="1", qos=0, retain=False)
                        logging.debug("published state 1 to "+MY_STATE)
                    else:
                        csstate="OFF"
                    client.publish(MQTT_PATH+"cs/state", payload=csstate, qos=0, retain=False)
                    client.publish(MQTT_PATH+"cps/state", payload=cpsstate, qos=0, retain=False)
                    logging.debug("published state "+csstate+" to "+MQTT_PATH+"cs/state")
                    logging.debug("published state "+cpsstate+" to "+MQTT_PATH+"cps/state")
                
                    # more callbacks, etc
                
                client = mqtt.Client()
                client.on_connect = on_connect
                client.on_message = on_message
                
                client.connect(MQTT_SERVER, MQTT_PORT, MQTT_RECONNECT)
                
                # Blocking call that processes network traffic, dispatches callbacks and
                # handles reconnecting.
                # Other loop*() functions are available that give a threaded interface and a
                # manual interface.
                client.loop_forever()
                Ich wollte es schick haben, soll heißen, ich lese die erforderlichen Parameter zu Beginn aus einer Konfigurationsdatei ein. Weiterhin habe ich den systemdmanager, um die Dienste zu starten und zu stoppen, das sind natürlich alles Dinge, die Du nicht zwingend brauchst. Ich kann nicht versprechen, das konkrete RGB-Script noch dieses Jahr zu posten aber ich versuche daran zu denken.

                Was Du brauchst, ist der Import für paho.mqtt.client, danach musst Du die verschiedenen Routinen für den Connect (dort mit subscribe für die Empfangsrichtung), die Message (dort wertest Du die empfangene Nachricht aus und reagierst entsprechend, z.B. indem Du die passenden Farben an die RGB-Kette schickst) und einen loop. Sobald das Programm (am besten als Dienst) gestartet ist, stellt es die Verbindung zum Broker her und wartet auf Befehle. Natürlich kann die Message-Routine auch verwendet werden, um Nachrichten an MQTT zu senden, also z.B. eine Rückmeldung der eingestellten Farben.

                Kommentar


                  #9
                  Hi,
                  ich kenne das von Arbeit, da arbeiten wir auch mit Skripts über SSH, manche Befehle funktionieren da nicht weil nicht die ganze Userumgebung geladen wird.
                  Als Test könntest du mal versuchen den Befehl reboot über ssh zu schicken, falls das nicht geht würde ich darauf tippen, dass es dieses Problem ist.
                  Ich könnte ende der Woche noch mal unsere Linuxspezialisten darauf ansprechen was man da noch mal genau alles aufrufen muss.

                  Kommentar


                    #10
                    Zitat von udo1toni Beitrag anzeigen
                    Was noch sein könnte, dass Du bestimmte (argh...) Leerzeichen durch doppelte @ ersetzen musst. Welchen Regeln dieses escapen folgt, habe ich bisher auch noch nicht begriffen, und ich bin schon seit OH1.0 dabei...
                    Diese Problematik könnte man ggf. umgehen indem man den ganzen auszuführenden Befehl in ein Shellscript packt. Oder spricht da irgendwas gegen?
                    Als Bonus könnte man auch gleich per Parameter den zu setzenden Zustand übergeben…

                    Kommentar


                      #11
                      Grundsätzlich funktioniert das mit ssh schon, ich benutze es an mehreren Stellen.

                      Häufig scheitern solche Sachen daran, dass der Pfad in der shell definiert ist und bei Ausführung in openhab nicht. Daher würde ich in allen Skripten die Pfade zu allen externen Kommandos als absoluten Pfad angeben, auch in dem ws2801.py

                      Ansonsten langsam vorantasten: Was für Meldungen erscheinen im Log auf Client und Serverseite, ev. mal stderr und stdout in eine Datei umleiten und schauen was da steht. Oder im Skript einen Logeintrag schreiben lassen, um zu sehen ob es überhaupt läuft.

                      Per var String results = executeCommandLine() kommst Du an die Ausgabe des Aufrufs, mal schauen ob da etwas aufschlussreiches steht.

                      Kommentar

                      Lädt...
                      X