En la clase de hoy vamos a aprender a realizar conexiones SSH y SFTP para enviar archivos y ejecutar scripts desde una Raspberry conectada por red local.
Todo el código mostrado a continuación se encuentra en este archivo.
En la carpeta del curso encontrarás el índice con las clases publicadas.
Importacion de los módulos y configuración
Para realizar este trabajo usaremos la bilioteca paramiko. Esta nos proporciona unos sencillos métodos de apertura e interacción mediante conexiones vía SSH y SFTP.
Desde aquí puedes acceder a un pequeño tutorial de cómo instalarla y su uso básico.
from paramiko import SSHClient, AutoAddPolicy
from os import environ
Configuración
Ahora añadimos las variables de entorno que usaremos para conectarnos a la raspberry:
Si no sabes cómo funciona el modulo
environ
puedes aprenderlo desde aquí.
RASPBERRY_LOCAL_IP = environ.get('RASPBERRY_LOCAL_IP', '')
RASPBERRY_LOCAL_USERNAME = environ.get('RASPBERRY_LOCAL_USERNAME', '')
RASPBERRY_LOCAL_PASSWORD = environ.get('RASPBERRY_LOCAL_PASSWORD', '')
Debemos asegurarnos de establecer la IP de nuestra Raspberry como fija. Si no sabes cómo hacerlo aquí tienes un tutorial.
Inicialización
Instanciamos el cliente SSH y abrimos la conexión.
ssh = SSHClient()
ssh.set_missing_host_key_policy(AutoAddPolicy())
ssh.connect(RASPBERRY_LOCAL_IP,
username=RASPBERRY_LOCAL_USERNAME,
password=RASPBERRY_LOCAL_PASSWORD)
La clase Raspberry
Luego creamos el objeto principal que usaremos para comunicarnos con nuestra Raspberry. Vamos a incorporarle un método para enviarle archivos y otro para descargarlos.
class Raspberry:
"""Crea una conexión con una raspberry en local por SSH y SFTP."""
def __init__(self):
pass
def upload(self, filepath_in, filepath_out):
ftp = ssh.open_sftp()
ftp.put(filepath_in_filepath_out)
return True
def download(self, filepath):
ftp = ssh.open_sftp()
ftp.get(filepath)
return True
Añadiendo más funcionalidad
Podemos añadir otros métodos para ejecutar scripts en remoto:
def execute(self, command):
stdin, stdout, stderr = ssh.exec_command(command)
return (stdout.readlines(), stderr.readlines())
def run_script(self, filepath, language='python3'):
command = '{} {}'.format(language, filepath)
return self.execute(command)
def send_script(self, filepath_in, filepath_out, imports=[],
execute=False, language='python3'):
self.upload(filepath_in, filepath_out)
filepath_curt = filepath_out.split('/')
filename = filepath_cut.pop()
storage_dir = '/'.join(filepath_cut)
if type(imports) in (list, set):
for ipath in imports:
import_filename = ipath.split('/')[-1]
self.upload(ipath, {}/{}.format(storage_dir,
import_filename))
elif type(imports) is str:
import_filename = imports.split('/')[-1]
self.upload(imports, {}/{}.format(storage_dir,
import_filename))
else:
raise TypeError(str(type(imports)) + "is not a valid/
type for the parameter 'imports'"
if execute == True:
response = self.run_script(filepath_out, language=language)
return response
return True
execute
ejecuta un comando desde la raspberry. Toma un parámetro:command
(str
): el comando a ejecutar.
run_script
ejecuta un script en la raspberry. Toma dos parámetros:filepath
(str
): ruta hacia el script en la raspberry.language
(str
): comando para ejecutar el script.
send_script
envía un script con sus dependencias. Toma cinco parámetros:filepath_in
(str
): ruta hacia el script en nuestro ordenador.filepath_in
(str
): ruta donde almacenar el script en la raspberry.imports
(array
/str
) rutas hacia los archivos que necesita importar (las dependencias se colocarán en el mismo directorio del script).execute
(bool
) Elige si quieres ejecutar el script tras enviarlo o no.language
(str
): comando para ejecutar el script.