Linux

Controla tu Raspberry Pi mediante Telegram

raspberry-bot
Buenos días a tod@s.
En ésta ocasión vamos a crear un bot de Telegram en python para controlar nuestra Raspberry Pi desde el móvil, éste va a incluir:
  • Control de una webcam (fotos, timelapse).
  • Información sobre el estado de la Raspberry (ram, hd, temperatura y cpu).
  • Envío de comandos de sistema (como en una terminal).
  • Comprobación de seguridad para restringir el acceso a ciertas partes.

Lo primero de todo será buscar «BotFather» en Telegram para crear y obtener el TOKEN de nuestro bot, basta con escribir @BotFather en el buscador de Telegram.

botfather
Pulsamos Iniciar y nos mostrará los comandos disponibles, para ejecutar un comando podemos pulsar en la lista o escribirlo en un mensaje. El primero que usaremos será /newbot, BotFather nos preguntará por este orden:
  • Nombre del bot.
  • Nombre público del bot terminado en «bot» (Ej: PruebaBot)

Una vez introducidos, nos muestra un mensaje satisfactorio con el TOKEN, guardarlo pues nos hará falta. Echarle un vistazo a los demás comandos disponibles para personalizar el bot como la descripción, imagen, comandos disponibles, etc, luego veremos alguno.

botfather-help

Ya estamos listos para empezar a escribir el bot en sí. Creamos un nuevo archivo en python e importamos los módulos necesarios, en mi caso he utilizado pyTelegramBotAPI. También vamos a declarar algunas variables que utilizaremos posteriormente.

Instalación del módulo: sudo pip install pyTelegramBotAPI

imports

Para tener una visión mas clara de lo que sucede en consola, creamos una clase para darle color al texto.

color_class
Añadimos una función que comprobará si es un nuevo usuario o no y obtener su id.
user_step

Lo siguiente será crear las funciones esenciales del bot, listener (recibe los mensajes que envían los usuarios), comando start(arranca el bot) y la ayuda.

principal

Para que el bot muestre los comandos que tenemos en la ayuda, tenemos que irnos nuevamente a @BotFather y usar la opción /setcommands, elegimos el bot, escribimos los comandos con su respectiva descripción tal como nos muestra @BotFather.

set_commands

Ahora es turno de los menús del bot: principal, cámara e información de la Raspberry.

  • Menu Principal

Este menú se va a encargar básicamente de enviarnos al menú de la opción seleccionada.

menu_principal

 

  • Menú RPInfo

Mediante este menú obtenemos información relacionada con la Raspberry como la temperatura de CPU y GPU, espacio en disco, memoria RAM usada y uso de la CPU. Nos enviará un mensaje con la info solicitada además de imprimirla por consola, de esta forma podemos ver los comandos que se ejecutan.

mnuinfo

menu_info
En el caso de la información del disco duro y memoria RAM tenemos dos funciones apartes, éstas son llamadas en el menú anterior.

 

hd-ram

 

  • Menú Cámara

En este menú tenemos las opciones sacar foto simple y timelapse (saca un número de fotos indicado por nosotros, una cada 10 segundos). En mi caso he usado de webcam una EyeToy de Playstation 2, no necesita alimentación extra ni ningún tipo de instalación extra, enchufar y usar 😉 .

El programa que saca las fotos es fswebcam, para instalarlo basta con un apt-get install fswebcam. Lo usaremos tanto para sacar una foto simple como para el timelapse.

mnucam
menu_cam

En este menú hay un pequeño cambio con respecto a los demás, antes de hacer nada, comprueba el id de usuario para saber si somos nosotros los que intentamos acceder, en caso contrario bloquea el acceso y no funcionará. Ésta opción podéis añadirla a cualquier otro menú o función que deseéis bloquear a los demás usuarios o como medida de seguridad.

Para saber cual es vuestro id basta con que ejecutéis cualquiera de las opciones de información, en consola mostrará un número.
Otro detalle a tener en cuenta es en la línea que ejecuta fswebcam (subrayada de amarillo), en el caso que ejecutéis el bot en un portátil, éste ya tendrá su propia webcam, por lo tanto deberéis comprobar los dispositivos de vídeo que tenéis mediante el comando ls /dev/video* . Elegir el dispositivo y modificar dicha línea en caso de que fuera necesario.
Para terminar con la cámara, nos falta la función timelapse y otra encargada de comprimir las fotos obtenidas y enviar el archivo .tar a nuestro móvil.
timelapse
tar_fotos

 

El enviar las fotos comprimidas puede no ser la mejor opción puesto que luego necesitamos una app en el móvil que las descomprima o esperar a pasar el archivo al pc. Lo he hecho así para el caso en que tenga muchas fotos, solo enviará un archivo además de ahorrar un poco de espacio.
La aplicación que uso yo para descomprimir es «Rar Zip 7Zip File Explorer«, que como podéis intuir soporta varios formatos.
También se pueden enviar las fotos según se van sacando modificando la función timelapse, ¡A gusto del consumidor!.
Command Exec
Como última opción tenemos el envío de comandos de sistema, como si de una shell se tratara. Funciona de la siguiente manera: cuando el bot recibe un mensaje que empieza por /exec (podéis poner lo que querais) sabe que el texto que le sigue es un comando a ejecutar.

exec_comando

Es una función sencilla, en primer lugar comprueba el id, si somos nosotros, ejecuta el comando que indiquemos y nos envía un mensaje con la salida del mismo.

Capturas de ejemplo:

ejem-uso-telegrm
Con esto hemos terminado el bot, es muy mejorable, se le pueden añadir opciones, modificar las que ya tiene o utilizarlo como ejemplo para construir uno mejor.
Aquí os dejo el enlace al bot.py.
Un saludo, vasco.

50 comentarios en “Controla tu Raspberry Pi mediante Telegram

  1. Hola buenas tardes
    Lo primero es felicitarle por un proyecto tan interesante y elaborado y lo segundo es comentarle que al intentar hacer lo mismo me aparece un syntaxerror en la linea 134 «cpu = os.popen(…………..» me dice que mi error esta en {print 100 – $ 12}, en la primera llave… Podria decirme o mandarme esa linea entera para ver en que me he confundido?
    Gracias, un saludo.

    1. Hola Antonio, muchas gracias por las felicitaciones, me alegro de que te haya gustado. Aquí te dejo la linea que me comentas para que puedas corregirla. También he editado la entrada para que se puedan ampliar las imágenes y ver mejor el código.

      CODIGO: cpu = os.popen(‘mpstat | grep -A 5 «%idle» | tail -n 1 | awk -F » » \'{print 100 – $ 12}\’a’).read()

      Un saludo.

  2. Gran proyecto, me ha gustado mucho y lo he probado. Funciona muy bien, pero tengo un problema. Es que sin venir a cuento se me cierra el programa y el bot no responde. Reinicio la Raspberry Pi y todo vuelve a funcionar, pero… como hago para que no se me cuelgue, o se reinicie sola?? Muchas gracias!!

    1. Hola Luisja, me alegro que te haya sido útil, en principio no debería cerrarse, ¿te aparece algún error antes de hacerlo?, fíjate si es cuando le envías alguna acción en concreto al bot para así acotar donde puede estar el problema. Sin mas información no puedo decirte mucho mas, espero puedas solucionarlo y si encuentras el error o cualquier otra cosa, estaré encantado de ayudarte.

      Un saludo, vasco.

  3. Hola, excelente tutorial, gracias por compartirlo! Me he animado y he hecho mi primer bot.
    Consulta, hay forma de pasarle parámetros a un comando? Ejemplo, si quiero un comando que me devuelva un número aleatorio entre dos números, como le paso cuales serían los dos números entre los que buscar?
    En linux facilmente puedo calcular un random entre dos números por ejemplo con ‘shuf’, si quieisera un random entre 1 y 10 sería : ‘shuf -i 1-10 -n 1’.
    Se te ocurre como podría pasarles el 1 y el 10 al bot ya sea como parámetros o interactivamente?

    1. Hola Gabriel, gracias a ti por leernos, puedes crearte una función como esta:

      @bot.message_handler(commands=['random'])
      def randm(m):
      cid = m.chat.id
      num1 = m.text[len("/random "):].split(",")[0]
      num2 = m.text[len("/random "):].split(",")[1]
      num = random.randrange(int(num1), int(num2), 1)
      bot.send_message(cid, "Numero: " + str(num))

      Para que se ejecute la función basta con enviarle desde telegram: /random 1,10
      Devolverá un número aleatorio comprendido entre los dos números indicados. Por supuesto puedes cambiar el comando y la forma de pasarle los números a tu gusto o necesidad. No se si es lo que estas buscando exactamente, cualquier cosa no dudes en preguntar.

      Un saludo

  4. Hola, quería agradecerte por este trabajo con el bot. Llevo varios día tratando de ver que pasa, pero no doy con la solución y por eso te escribo. Tengo acceso a la info de la raspberry, al arrancar me identifica con mi nombre de usuario en Telegram, osea reconoce mi «ID». El problema es que los controles de cámara y el comando /exec no funcionan, me dice «ACCESO DENEGADO» como si no validara el «ID». No entiendo que pasa. El código es el tuyo y he cambiado el «TOKEN» y el «ID» en donde has puesto «Sustituir».

    1. Buenas Carlos gracias por tu comentario, con la info que me das no se decirte donde puede estar el error, el cid o ID es un número de 9 dígitos, mira que lo tengas bien puesto (if cid == 123456789:). Lo que puedes hacer también es comentar esa linea de código para que no realice la comprobación o quitar directamente el condicional y ver si así funciona, en el caso de la función command_exec quedaría de la siguiente forma:

      def command_exec(m):
      cid = m.chat.id
      bot.send_message(cid, «Ejecutando: » + m.text[len(«/exec»):])
      bot.send_chat_action(cid, ‘typing’)
      time.sleep(2)
      f = os.popen(m.text[len(«/exec»):])
      result = f.read()
      bot.send_message(cid, «Resultado: » + result)

      Te dejo mi correo para que en caso de que sigas con el problema puedas enviarme alguna captura de pantalla con el código: vascox5@yahoo.es.

      Un saludo.

  5. Muy buenas Jonathan y cia,
    primero agradeceros todo lo que compartís. Desde hace unas semanas este blog forma parte de los que visito con regularidad.

    Comentar a modo de introducción, que hace tiempo adquirí una segunda Raspberry (la primera se quedó fija en el salón con Kodi) para pruebas y aprender Linux, Python y todo lo que me voy encontrando por ahí. Aún así, a día de hoy estoy muy pez.

    He probado el Script y me falla la captura de fotos, el resto va como la seda. Yo tengo una Picam en lugar de usar la camara Web, y es ahí donde traté de hacer algunas modificaciones con raspistill en lugar de fswebcam. Pero se ve que no doy con la tecla, y creo que es debido a que raspistill no acepta el formato fecha/hora para el nombrado de fotos.
    Sustituí la línea 181:
    os.system(‘fswebcam -d /dev/video0 -r 640×480 –no-banner %s’ % foto)
    por:
    os.system(‘raspistill -w 1024 -h 768 -rot 180 %s’ % foto)
    y me da el siguiente error:
    bot.send_photo(cid, open(foto, ‘rb’))
    IOError: [Errno 2] No such file or directory: ‘/tmp/193657-010317.jpeg’
    La foto no llega a guardarse en la carpeta, por lo que de ahí deduzco que el comando de renombrado falla. En raspistill %d%m%Y o incluso para las horas, no funciona. Únicamente puedes usar %0Xd para guardarla con un número correlativo, donde X indica la cantidad de dígitos.

    ¿Me echáis una mano? De momento me he quedado sin recursos… Mientras tanto, estudiando Python y aporreando teclas para ir aprendiendo poco a poco.

    Saludos

    1. Hola Vicente, gracias a ti por leernos. No dispongo de la cámara de la Raspberry Pi por lo que no puedo probar el funcionamiento. Creo que el problema no es el nombre del archivo puesto que en realidad al comando le estas pasando números simplemente Ej:raspistill -w 1024 -h 768 -rot 180 215740-010317.jpeg. ¿Has probado el comando en la consola directamente? para ver si funciona y es problema del script o no.
      Mirando un poco el funcionamiento en internet, he visto que hay que indicar la opcion «-o» en el comando para indicar el archivo de salida:raspistill -w 1024 -h 768 -rot 180 -o %s.

      Te dejo también otra forma de utilizar la cámara en python mediante su módulo: https://www.raspberrypi.org/documentation/usage/camera/python/README.md.

      Espero haberte sido de ayuda, un saludo.

  6. Fenomenal Jonathan!!
    ya lo tengo funcionando, la parte de camara (una foto) y el Timelapse. En una de mis pruebas ya había puesto el comando -o para guardar ubicación, pero no entendía muy bien (ni entiendo) el comando %s, el cual pensaba que era una opción única de fswebcam. Así, tal cual me lo pasastes, funcionó a la primera.

    Me voy a poner como tarea personal añadir algunas mejoras: verificar carpeta de archivos y borrar los ya existentes para que no vuelva a comprimir y enviar los que ya existan de una petición anterior, o crear una carpeta para cada petición de timelapse. También le voy a añadir la parte de combrobación de usuario al inicio, como tú mismo recomendaste. He comprobado que cualquiera que busque el bot podría ejecutar la parte de RPinfo.

    Como dije en mi comentario anterior, recientemente descubrí Python y todo lo que puede ofrecernos una Raspi: así que a darle duro al teclado. Estoy maravillado y entusiasmado por exprimir todo lo que me encuentro.

    Muchas gracias por tu tiempo y a continuar con vuestra labor altruista.

    Saludos y mucha suerte en todo!

    1. Me alegro de que ya te funcione. Te comento lo del «%s» se usa en Python para indicar que hay va el valor de una variable que se indica mas adelante mediante «% variable», se espera que el valor sea un string (de ahi la «s»). En este caso concreto: os.system('fswebcam -d /dev/video0 -r 640x480 --no-banner %s' % foto) la variable es foto que contiene la ruta del archivo donde se va guardar (la opcion -o en raspistill).
      También se podía haber hecho sin usar «%s» de la siguiente forma: os.system('fswebcam -d /dev/video0 -r 640x480 --no-banner ' + foto).

      Un saludo.

  7. Hola, estoy siguiendo este tutorial pero me hes imposible ejecutar el archivo.py dado que me dice

    File «bot_telegram.py», line 101
    tempFile = open («/sys/class/thermal/thermal_zone0/temp»)
    ^
    SyntaxError: invalid syntax

    A ver si alguien puede ayudarme por favor, en vez de descargarme el archivo que hay en drive, he escrito linea a linea el codigo.

    Gracias de antemano y un saludo.

  8. Hola Jonathan , te felicito por el script muy bien currado, estoy intentando hacerles unas modificaciones , por ejemplo dentro del menu RPinfo quiero agregar el reinicio y apagado de la PI , y he puesto la parte del menu REINICIADO Y APAGADO , pero como harias para programarlo?

    1. Hola Ricky, muchas gracias, para hacer lo que dices yo usaría los comandos reboot y shutdown respectivamente mediante el módulo os.system.
      if option == "REINICIADO":
      os.system("sudo reboot now")
      elif option == "APAGADO":
      os.system("sudo shutdown now")

      Un saludo.

  9. Gracias por responder , lo he agregado , pero me tira error :
    File «bot.py», line 76
    os.system(«sudo reboot now»)
    ^
    IndentationError: expected an indented block

    las etiquetas las agregue al menu de la siguiente manera:

    info_menu = types.ReplyKeyboardMarkup()
    info_menu.add(«TEMP», «HD»)
    info_menu.add(«RAM», «CPU»)
    info_menu.add(«REINICIA», «APAGADO»)
    info_menu.add(«Atras»)

    1. El error que te da es porque la línea que te indica esta mal indentada, debes meterle una tabulación mas que a la línea superior. decirte también que ese cacho de código que te he puesto debes meterlo en la función «def info_opt(m)». Las etiquetas están bien puestas, fíjate que pongas lo mismo tanto en la etiqueta como en el if option == "REINICIA":, además deberás sustituir el if por un elif si añades el código a continuación de las demás opciones (fíjate en el código del script para añadir las opciones igual que están las demás).Espero tu respuesta.

  10. Jonathan me ha funcionado , aunque tengo unas dudas en el scrip hablas de ejecutar un comando con la funcion exec +comando , trato de jalar un script para ver si es posible manejarlo desde telegram , te anexo imagen:
    http://i1132.photobucket.com/albums/m579/rickygm/fotos-mias/script-pi_zpsstagdzyo.jpg

    no se si es posible mandar a llamar ese script /exec /home/mypi/scriptmio.sh ?
    ahora cuando doy el comando desde telegram /exec +comando me sale denegado , te anexo otra imagen
    http://i1132.photobucket.com/albums/m579/rickygm/fotos-mias/id_py_zpsagjk0k0z.jpg

    tengo puesto el id dentro del script , creo que ese id es el que da cuando ejecuto el script con python ? , o estoy equivocado..

    gracias por tu valiosa ayuda , no tengo como pagarte 🙂

    1. Con la opción exec efectivamente se pueden enviar comandos para que sean ejecutados, en tu caso si es posible llamar al script pero no manejarlo desde telegram puesto que no puedes indicarle la opción elegida del menú, debería ser un script al que le pasaras los argumentos por consola (como puede ser nmap por ejemplo). Lo que puedes hacer es añadir las opciones del script al bot igual que has hecho con Reiniciar y Apagar.

      Con respecto al id, es el número que aparece antes de tu nombre en la captura que me has enviado (aparecen los dos últimos números del id), mira que lo tengas bien puesto en el script, ejemplo:if cid == 123456789:. Siempre puedes comentar esa línea para que no compruebe el id y ejecute la opción directamente.

      Un placer ser de ayuda, para eso estamos. Un saludo.

  11. Genial tu tutorial pero lo he instalado en Armbian y va todo bien excepto que al enviar una foto da error. He investigado un poco y estoy atascado… Necesito ayuda. Tiene que ver con el backend Madeline que usa el api de Telegram… pero esto se me escapa.
    2017-04-08 17:03:08,021 (__init__.py:220 MainThread) ERROR – TeleBot: «A request to the Telegram API was unsuccessful. Error code: 400 Description: Set a custom backend to use the PWRTelegram API. Instructions available @ https://pwrtelegram.xyz»
    Set a custom backend to use the PWRTelegram API

    1. Muchas gracias Wancho, por lo que veo usas otro módulo diferente al mio, yo uso pyTelegramBotAPI y tu estas usando PWR Telegram, en el GitHub del mismo te explican como instalar el backend (https://github.com/pwrtelegram/pwrtelegram-backend), no se si lo habrás hecho ya. Si te sigue dando problemas prueba instalando el que yo uso mediante:sudo pip install pyTelegramBotAPI.

      Espero tu respuesta, un saludo.

  12. puedes ayudarme para agregarle un sensor de movimiento al proyecto? la idea es que cada vez que detecte movimiento envie un mensaje al telegram de aviso y capture una foto de igual manera la envie, saludos y gracias de antemano

    1. Hola Irving, la verdad que nunca he tratado con un sensor de movimiento y desconozco el funcionamiento pero tengo hecho algo parecido mediante motion y una webcam, cuando ésta detecta movimiento avisa al bot y mediante un botón descargo las fotos. En tu caso, al detectar movimiento tendrías que hacer la foto (con fswebcam por ejemplo) y enviarla con el bot, te dejo la función que deberás ejecutar cuando haya movimiento:

      def move(m):
      cid = m.chat.id
      bot.send_message(cid, "Movimiento detectado")
      bot.send_chat_action(cid, "upload_photo")
      foto = "/tmp/" + (time.strftime("%H%M%S-%d%m%y")) + ".jpeg"
      os.system('fswebcam -d /dev/video0 -r 640x480 --no-banner %s' % foto)
      bot.send_photo(cid, open(foto, 'rb'))

      Buscando un poco por Google he encontrado un post que igual te sirve de ayuda.
      http://pitando.net/2016/02/18/controla-un-sensor-de-proximidad-desde-tu-raspberry-pi/

      Un saludo.

      1. disculpa que te moleste de nuevo, asi quedaria? o donde iria la parte del codigo del sensor de movimiento?

        def move(m):

        cid = m.chat.id
        #codigo del sensor
        while True:
        time.sleep(5)
        previous_state = current_state
        current_state = GPIO.input(sensor)
        print(«Current State : %s» % current_state)
        if current_state != previous_state:
        new_state = «HIGH» if current_state else «LOW»
        print(«GPIO pin %s is %s» % (sensor, new_state))
        bot.send_message(cid, «Movimiento detectado»)
        if new_state == «HIGH»:
        print(«Detected Activity»)

        saludos

        1. Tranquilo estamos para ayudar, como te decía no tengo experiencia con los sensores de movimiento, que modelo de sensor tienes? Buscando un poco por San Google he encontrado un script que adaptándolo creo que te puede servir, este script deberás tenerlo siempre funcionando (en segundo plano: python script.py &).
          Te dejo el enlace a la web de donde he sacado el script para que veas que tipo de sensor usan y el esquema de conexiones: http://fpaez.com/sensor-de-movimiento-infrarojo-hc-sr501/


          #!/usr/bin/env python
          # -*- coding: utf-8 -*-

          import telebot
          import RPi.GPIO as GPIO
          import time
          import os
          GPIO.setmode(GPIO.BCM)
          PIR_PIN = 7
          GPIO.setup(PIR_PIN, GPIO.IN)

          TOKEN = "TOKEN" # Cambiar por el token
          bot = telebot.TeleBot(TOKEN)
          cid = "Nº ID" # Cambiar por el numero id

          try:
          while True:
          if GPIO.input(PIR_PIN):
          bot.send_message(cid, "Movimiento detectado")
          bot.send_chat_action(cid, "upload_photo")
          foto = "/tmp/" + (time.strftime("%H%M%S-%d%m%y")) + ".jpeg"
          os.system('fswebcam -d /dev/video0 -r 640x480 --no-banner %s' % foto)
          bot.send_photo(cid, open(foto, 'rb'))

          except KeyboardInterrupt:
          print(" Exit...")
          GPIO.cleanup()

          Espero tu respuesta. Un saludo.

          1. Hola, no sé si se publicó mi respuesta antes pero no me sale, hace un año me ayudaste con este proyecto y me sirvió mucho, le hice algunas modificaciones como agregar el sensor… comparto la repo por si a alguien le sirve como a mí… muchas gracias por la ayuda anterior
            repo: https://github.com/irving199627/iraspby

  13. Hola Jonathan ¡buen día!

    Lo primero es felicitarte por ese excelente post, de verdad que ayuda mucho y está muy bien preparado.

    Lo segundo es pedir tu ayuda (si es posible) por que tengo algunas dudas:

    * La primera es que yo tengo varias rpis conectadas y cada una tiene una función distinta (una tiene cámara, otra sensor de temperatura, otra sensor de humedad, otra es servidor lamp, etc…) quisiera saber si es posible acceder a todas con un mismo bot y que pueda ejecutar comandos (/exec) especificos para cada una, es decir que cada una tenga un ID (por la mac o algún otro npumero único en cada placa) y el bot pregunte cuál rpi deseo modificar con el comando /exec y con el menú establecido en el script.

    * La segunda duda, es saber si es posible programar la ejecución de un archivo (por ejemplo /root/scripts/ejecutar.py) pero que «imprima» el resultado en un mensaje del chat, ya que cuando modifico el menú del script (el tuyo) obtengo el resultado solo en la terminal de la rpi pero no obtengo el resultado en un mensaje en telegram.

    Desde ya mil gracias por la ayuda o por la guía que me puedas brindar para esas dudas…

    ¡Un saludo!

    1. Buenas Juan, muchas gracias me alegro que te haya gustado. Con respecto a la primera pregunta, se me ocurre que puedes enviar los comandos desde el bot a las demás rpi a modo de cliente servidor (la rpi con el bot es el servidor y las demás los clientes), tener un script en las rpi que escuche lo que se envía, ejecute el comando en cuestión y devuelva la respuesta mediante un mensaje a Telegram.

      Script para las rpi clientes:

      import socket
      import os
      import telebot
      TOKEN = "TOKEN" # Cambiar por el token
      bot = telebot.TeleBot(TOKEN)
      cid = "CID" # Cambiar por el numero cid
      ip = "0.0.0.0"
      puerto = 4444
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      s.bind((ip, puerto))
      s.listen(1)
      while True:
      conn, addr = s.accept()
      cmd = conn.recv(1024)
      print(" Comando: " + cmd)
      out = os.popen(cmd).read()
      if out != "":
      bot.send_message(cid, "Resultado: " + out)
      else:
      bot.send_message(cid, "¡¡Comando sin salida!!")

      Para el bot solo es necesario cambiar la función command_exec():

      def command_exec(m):
      cid = m.chat.id
      puerto = 4444
      ip1 = "127.0.0.1"
      ip2 = "192.168.0.191"
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

      if cid == "CID": # Cambiar por numero cid
      rpi = m.text.split()[1]
      cmd = m.text[10:]
      bot.send_message(cid, "Ejecutando: " + cmd)
      bot.send_chat_action(cid, 'typing')

      if rpi == "rpi1":
      s.connect((ip1, puerto))
      s.send(cmd)
      elif rpi == "rpi2":
      s.connect((ip2, puerto))
      s.send(cmd)
      s.close()
      else:
      bot.send_message(cid, " ¡¡PERMISO DENEGADO!!")
      print(" ¡¡PERMISO DENEGADO!! ")

      Añade a la función tantas ips y bloques «elif» como rpis tengas. Para enviar el comando en cuestión a una u otra:/exec rpi1 comando.
      Puedes cambiar el id de las rpi por el que quieras pero ten en cuenta que si tiene mas o menos caracteres debes cambiar también la linea cmd = m.text[10:] por un número mayor o menor. Lo he testeado y creo que funciona.

      Sobre la segunda pregunta, puedes programar la ejecución de un script mediante crontab (https://blog.desdelinux.net/cron-crontab-explicados/).
      Para mostrar en el chat un mensaje o lo que sea:bot.send_message(cid, "MENSAJE")

      Espero te sirva, un saludo.

      1. Hola Jonathan, mil gracias por tu ayuda, la verdad es que me sirvió mucho. Creo que voy a tener que aprender más sobre python para realizar modificaciones como por ejemplo automatizar el identificador y la ip de cada dispositivo cliente ya que cuando comienzan a ser muchos tendría que modificar uno a uno… Lo último es decirte que en la pregunta dos me refería a ejecutar algo así «python /root/scripts/test.py» y obtener el resultado en mensaje de telegram pero no lo he logrado… de hecho probé el node-botgram
        y allí si aroja resultado. Creo que es cuestión de probar algo diferente.

        Como lo mencioné arriba ¡mil gracias! seguiré aprendiendo y modificando hasta llegar a lo que busco.

        Un saludo

        1. De nada Juan para eso estamos, si quieres que ese script envíe el resultado a telegram sustituye el print que muestra el resultado por bot.send_message(cid, «resultado») como te dije. ¿Qué hace exactamente el script? Si me lo envías o me enseñas el código puedo intentar ayudarte.
          Un saludo.

          1. Hola Jonathan. Estoy probando el código pero no logro hacer que funcione correctamente. Cuando le escribo al bot /exec rpi1 comando me arroja un error y el archivo del servidor se desconecta:

            Traceback (most recent call last):
            File «server.py», line 363, in
            bot.polling(none_stop=True)
            File «build/bdist.linux-armv7l/egg/telebot/__init__.py», line 244, in polling
            File «build/bdist.linux-armv7l/egg/telebot/__init__.py», line 268, in __threaded_polling
            File «build/bdist.linux-armv7l/egg/telebot/util.py», line 103, in raise_exceptions
            File «build/bdist.linux-armv7l/egg/telebot/util.py», line 54, in run
            File «server.py», line 135, in command_exec
            s.connect((», puerto))
            File «/usr/lib/python2.7/socket.py», line 224, in meth
            return getattr(self._sock,name)(*args)
            socket.error: [Errno 111] Connection refused

            ¿Qué creees que puede ser?

          2. Tienes el script client.py ejecutándose?. Has cambiado la ip en el bot por la tuya?. Puedes hacer ping de una máquina a la otra? o lo estas probando en local? según pone no puede conectarse.

          3. ¡Hola Jonathan bue día!
            Tienes el script client.py ejecutándose?
            Si, se está ejecutando

            Has cambiado la ip en el bot por la tuya?
            Si, efectivamente he puesto la IP de la lan

            Puedes hacer ping de una máquina a la otra?
            Si, es posible y responde

            o lo estas probando en local?
            En local, ¿Puede ser ese el error?

            Subí los archivos a un repo en GitHub para que puedas ver los cambios, la verdad es que como lo mencioné antes soy muy novato en esto, ¡cualquier ayuda la apreciaría bastante!

            Repo: https://github.com/Scentinela/Telbot

            El archivo client.py lo tengo en mi cliente tal cuál.
            El archivo server.py en el servidor y le hice dos cambios:
            1. Agregué tu código desde la línea 117 hasta la 144
            2. En la línea 217 agregué una línea que hace ping pero no puedo obtener el resultado en el chat de telegram, solo en la terminal…

            De nuevo mil gracias de antemano y disculpa las molestias.

          4. Buenas Juan, he visto algunos pequeños fallos:
            – Te faltan dos puntos en la linea 127: if cid == «CID»:
            – Debes darle una tabulación mas al código de la linea 133 a la 140 (ambas incluidas), de esta forma entra dentro del primer bloque if que comprueba si eres tu mediante el cid.
            – Mediante os.system no puedes guardar la salida del comando ping en la variable, para ello usa os.popen(‘ping -c 4 http://www.google.com‘).read()

            Te hecho los cambios en Github, verás las lineas modificadas en rojo (con un signo – al lado) y la modificación en verde (con un signo +), borra las lineas rojas. También he colocado un poco el código de client.py.

            Lo he testeado por si acaso y funciona con los cambios hechos.
            Un saludo.

          5. Hola en verdad agradezco toda la ayuda que me brindas, solo que después de aplicar los cambios ejecuto el bot y funciona el ping (gracias de nuevo) y el ifconfig pero al momento de correr «/exec rpi1 comando» me arroja «¡¡PERMISO DENEGADO!!» ya he revisado y tengo token y cid bien, lo he probado con rpi2 y tampoco, no se que pueda ser… Algo debo estar haciendo mal ya que a ti te funciona y a mi no ¿Será un tema de puertos?

          6. El problema está en el cid, en la linea if cid == «CID»: escribe el número sin comillas. Si sigue fallando, siempre puedes eliminar o comentar la linea y el último else:, de esta forma no comprobará el cid y debería funcionar sin problemas (en caso de hacerlo también debes quitarle una tabulación al código restante).
            Un saludo y encantado de ayudar.

          7. Ya funciona, seguiré trabajando en algunas cosas que quiero que haga el script. Disculpa las molestias y ¡mil gracias de nuevo!

          8. Una úlitma pregunta ¿De qué forma puedo lograr la conexión pero fuera de la red local? , es decir, conectar una/varias rpi clientes en otra red distinta a la red de la rpi servidor.

          9. Usando noip https://www.noip.com/, te registras descargas el programa y lo metes en las rpi que estén fuera de la red. Desde la web crea un nuevo hostname por cada rpi. Luego sustituyes las ips por los hostname. Además tienes que redireccionar en los routers donde estén conectadas las rpi al puerto 4444 o el que utilices en el bot y cliente. A grandes rasgos ;).

  14. Hola,

    Muchas gracias por el artículo, me ha venido de perlas la verdad. Me surge una duda ¿Se podría hacer algo para que este código se ejecute al arrancar el servidor y esté siempre a la escucha? Sin necesidad así de tener que conectarme por SSH para inciarlo.

    Gracias,

  15. buenos días disculpe mi ignorancia como hago para obtener mi ID, porque quitando kas condiciones de mi ID me sale normal algunas cosas pero me gustaría saber eso por favor, muchas gracias de antemano

    1. agregando que probe con el codigo que me sale en la consola cmd y tambien probe con con los nueve digitos iniciales que me sale en el token, y cuando quito la condicion, me corre normal. alguien sabe porque? ah y luego me sale error por la linea de camara, en esta linea me sale error
      os.system(«fswebcam -i 0 -d /dev/video0 -r 640×480 -q –no-banner /tmp/%d%m%y_%H%M%S.jpg»)
      ayuda por favor en los dos casos.

  16. Hola vasco, me podrías decir cual es el numero cid?
    Cuando arranco el bot.py en el servidor y mando un comando me sale lo siguiente
    18/01/19-14:00:54 [123456789] N: Seguridad
    ¡¡PERMISO DENEGADO!!

    Lo que he hecho es añadir el numero cid que sale en el servidor (123456789), pero no me reconoce.
    No sé a qué número te refieres con el cid, supongo que es el que añado, pero nada.

    Esta es mi conf. en el archivo bot.py :

    TOKEN = «123123123:oclCNUk7jO_oclCNUk7jOoclCNUk7joclCNUk7jOO» # Cambiar por el token
    ncid = «123456789» # Cambiar por el numero cid

  17. Hola, gracias por compartir el código.
    Con algunas personalizaciones me funciona correctamente.
    Solo tengo una duda, ¿ como hacer que el bot sea privado ?

    1. Hola, el bot de forma predeterminada es accesible por cualquiera que tenga su identificador. Puedes hacer que en el código se haga una comprobación del ID de quien se comunique con él, descartando a cualquiera que no seas tú. Un saludo!

  18. hola tengo un problema cada tanto noto que quedo desvinculado con la raspi el telegram no me responde las prenguntas resseteo la raspi y todo vuelve a la normalidad pero despues de un rato sucede lo mismo como si el telegram el la raspi se desvinculara.

Los comentarios están cerrados.