Enviando SMS usando bluetooth, un celular GSM y python

Estuve investigando una manera rápida, sencilla y con pocas líneas de código para poder enviar mensajes de texto usando un script, esto tiene utilidad para muchas aplicaciones, entre ellas el sistema nagios de monitoreo que estamos colocando en el trabajo.

La idea “adicional” de usar bluetooth surge de la posibilidad de evitar el uso de cables para transmitir los mensajes, para darle capacidades “bluetooth” a un equipo desktop convencional, simplemente agregamos un dongle bluetooth (que cuesta como 5 dólares en amazon) como este:

Y agregamos los paquetes necesarios:

aptitude install bluetooth bluez bluez-firmware bluez-utils python-bluez

Descubriendo dispositivos encendidos con python

El siguiente script (discovery.py) permite detectar qué equipos bluetooth están al alcance:

import bluetooth

lista = bluetooth.discover_devices(lookup_names = True)
print 'Lista de Dispositivos Bluetooth'
print 'Se encontraron %d' % len(lista)

for hwaddr, nombre in lista:
     print " %s - %s" % (hwaddr,nombre)

Nos mostrará algo como esto:

Se encontraron 1
 00:25:47:BC:8B:7F - Pheno

Determinación del Servicio:

El servicio Dial-Up Networking es el utilizado para enviar un mensaje SMS, el puerto dependerá del tipo de equipo y la cantidad de servicios asociados; si ejecutamos el comando:

sdptool browse 00:25:47:BC:8B:7F

Obtendremos algo como esto:

Service Name: Dial-Up Networking
Service RecHandle: 0x10019
Service Class ID List:
 "Dialup Networking" (0x1103)
Protocol Descriptor List:
 "L2CAP" (0x0100)
 "RFCOMM" (0x0003)
 Channel: 22
Language Base Attr List:
 code_ISO639: 0x454e
 encoding:    0x6a
 base_offset: 0x100
Profile Descriptor List:
 "Dialup Networking" (0x1103)
 Version: 0x0100

Reportando que el puerto para la conexión será el 22; pero esto también lo podemos hacer con Python, ampliando un poco el script discovery.py:

import bluetooth

lista = bluetooth.discover_devices(lookup_names = True)
print 'Lista de Dispositivos Bluetooth'
print 'Se encontraron %d' % len(lista)

for hwaddr, nombre in lista:
 print " %s - %s" % (hwaddr,nombre)
 services = bluetooth.find_service(address=hwaddr)
   if len(services) > 0:
     port = 0
     for svc in services:
       if  svc["name"] == "Dial-Up Networking":
       port = svc["port"]
       if port != 0:
         print "Encontrado Dial-Up Networking port = %d\n" % (port)

Al ejecutarlo reporta lo siguiente:

Se encontraron 1
00:25:47:BC:8B:7F – Pheno
Encontrado Dial-Up Networking port = 22

Sabiendo que nuestro dongle bluetooth funciona (y obviamente la mac-address de nuestro teléfono GSM con bluetooth), procedemos al siguiente paso, que es enviarnos mensajes de texto.

Enviando SMS con python

Con el siguiente script, podemos enviar un SMS usando GSM:

import bluetooth

#bluetooth address
addr = '00:25:47:BC:8B:7F'

#puerto
port = 22

#telefono
mobile = '584xxxxxxxxx' #de la forma 58 4[operadora][numero]
#mensaje a enviar
data = 'Test SMS'

# crear un socket bluetooth rfcomm
socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)

# la funcion connect pide los parametros direccion y puerto (address, port)
socket.connect((addr, port)) #abrir un socket al bt
#inicializamos el dialogo AT con el modem
socket.send('ATZ\r')
print socket.recv(1024)
#valor "1" indica que el SMS es solo texto
socket.send('AT+CMGF=1\r')
print socket.recv(1024)
#Telefono al que enviaremos el SMS
socket.send('AT+CMGS="+\"mobile\""\r')
print socket.recv(1024)
socket.send(data+chr(26)) #data + CTRL+Z
print socket.recv(1024)

socket.close()

La salida del script será algo como esto:

ATZ
OK

AT+CMGF=1
OK

AT+CMGS="+584xxxxxxxxx"
>
Test SMS
OK

Notas adicionales

Pueden agregar la configuración del dispositivo en /etc/bluetooth/rfcomm.conf para que haga enlace automáticamente y no esté solicitando bind+contraseña (y sea una conexión en confianza entre el teléfono y el PC):

rfcomm0 {
# Automatically bind the device at startup
bind yes;

# Bluetooth address of the device
device 11:22:33:44:55:66;

# RFCOMM channel for the connection
channel 1;

# Description of the connection
comment “Mobile Phone Pheno”;
}

Agregan la entrada y reinician el demonio bluetooth

/etc/init.d/bluetooth restart

TODO

* Aprovechar los posixGroups del LDAP y usar py-ldap para iterar sobre todos los miembros de un grupo (ejemplo: Soporte o Redes), extraer su atributo “mobile” y pasarlo al script como número a enviar (pueden ser varios destinatarios).

* Integrar discovery.py y send_sms.py en un único script, así el script descubre la dirección, el puerto, abre el socket, envía el SMS y se desconecta (con import sys podemos hacer sys.exit(0) para salir del script con confianza).

* Agregar excepciones (como el bluetooth.btcommon.BluetoothError 112; Host is Down) para gestión de errores del script.

Acerca de phenobarbital

http://about.me/phenobarbital

Publicado el 26 marzo 2010 en Blogeando!, Cultura Libre, PlanetaLinux, Programacion, Python, trucos de la abuela, Weyu y etiquetado en , , , , , , , . Guarda el enlace permanente. 37 comentarios.

  1. epale hermano… buenisimo el articulo…. tengo una pregunta.. como hago para saber la direccion mac de mi cel? tengo un samsung b3310.. hay alguna forma conectar el dispositivo a la laptop y conocer la direccion? o como hago en ese caso? bueno, si sabes algo de eso me avisas… para montar mi sistema…

    • phenobarbital

      Como verás, ahí hay un código que permite descubrir la mac y el puerto del servicio prestado por el celular; simplemente tomas el equipo celular, le enciendes el bluetooth y ejecutas el script discovery.py que este te reportará la mac y el puerto que usarás para montar tu sistema de SMS.
      Necesitas obvio, una portatil con bluetooth donde correrás el script discovery.py.

  2. ah ok… la funcion “hwaddr” me da la mac de mi cel… rayos, que descuidado soy… ese es el problema de leer los articulos desde el celular…

    Descubriendo dispositivos encendidos con python

    El siguiente script (discovery.py) permite detectar qué equipos bluetooth están al alcance:

    import bluetooth

    lista = bluetooth.discover_devices(lookup_names = True)
    print ‘Lista de Dispositivos Bluetooth’
    print ‘Se encontraron %d’ % len(lista)

    for hwaddr, nombre in lista:
    print ” %s – %s” % (hwaddr,nombre)

    Nos mostrará algo como esto:

    Se encontraron 1
    00:25:47:BC:8B:7F – Pheno

  3. Claro, hwaddr es la direccion y nombre el nombre del equipo …

  4. Qué bien, pude enviar mensajes, pero no me funcionó el script para encontrar el puerto. Use el puerto 1 y pudo enviar:
    import bluetooth
    addr = ‘C0:38:F9:72:F1:D2’
    port = 1
    data = ‘python y bluetooth’
    socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
    socket.connect((addr, port))
    socket.send(‘ATZ\r’)
    print socket.recv(1024)
    socket.send(‘AT+CMGF=1\r’)
    print socket.recv(1024)
    socket.send(‘AT+CMGS=”+994681777″\r’)
    print socket.recv(1024)
    socket.send(data+chr(26))
    print socket.recv(1024)
    socket.close()

  5. Bueno yo he conseguido que detecte la MAC del telefono e incluso conectar con el Nokia. Ademas despues de asociar el PC con el telefono para que no pida el pin siempre me slae el mensaje de:

    ATZ

    OK

    AT+CMGF=1

    OK

    Pero de enviar mensajes.. nada de nada

    Si me mandas u correo te respondo con los scripts que tengo y me dices a ver si ves algo que este mal porque lo necesito para un proyecto de la uni gracias!

    • phenobarbital

      Lo más primordial, para que un SMS pueda salir, es la selección del puerto, el cual no es el mismo para los distintos tipos de equipos, ejemplo, en el comentario anterior, transmite por el puerto 1, pero en mi nokia xpressmusic, transmito por el puerto 22, incluso de misma marca (nokia, motorola) los puertos son distintos entre distintas versiones.
      verifica muy bien el puerto de transmisión, ¿te ha funcionado el script de descubrimiento de mac y puerto?

  6. Tengo el bluetooth dongley con el he hecho lo siguiente:

    discover.py (no da error al ejecutar):

    Lista de Dispositivos Bluetooth
    Se encontraron 1

    AA:BB:CC:DD:EE:FF – nombre_de_mi_movil

    (donde AA:BB:CC:DD:EE:FF es su MAC y nombre_de_mi_movil a el nombre que le di en su momento al movil y que le aparece al que me busca por bluetooth)

    Luego ejecuto el comando para determinar los servicios del movil:

    sdptool browse AA:BB:CC:DD:EE:FF

    y me da unos servicios. Adjunto el cacho que nos interesa:

    .
    .
    .
    Service Name: Dial-up Networking Gateway
    Service Description: Dial-up Networking Gateway
    Service Provider: /a/mobile/system/cl.gif
    Service RecHandle: 0x10001
    Service Class ID List:
    “Dialup Networking” (0x1103)
    Protocol Descriptor List:
    “L2CAP” (0x0100)
    “RFCOMM” (0x0003)
    Channel: 1 ==> Este supongo que es el que nos interesa
    Language Base Attr List:
    code_ISO639: 0x656e
    encoding: 0x6a
    base_offset: 0x100
    code_ISO639: 0x6672
    encoding: 0x6a
    base_offset: 0xc800
    code_ISO639: 0x6465
    encoding: 0x6a
    base_offset: 0xc803
    code_ISO639: 0x6974
    encoding: 0x6a
    base_offset: 0xc806
    code_ISO639: 0x6573
    encoding: 0x6a
    base_offset: 0xc809
    code_ISO639: 0x6e6c
    encoding: 0x6a
    base_offset: 0xc80c
    code_ISO639: 0x7472
    encoding: 0x6a
    base_offset: 0xc80f
    code_ISO639: 0x7074
    encoding: 0x6a
    base_offset: 0xc812
    Profile Descriptor List:
    “Dialup Networking” (0x1103)
    Version: 0x0100
    .
    .
    .
    Como dices el el script discovery.py (ampliado) tambien sirve aunque al ejecutarlo me da un error:

    File “PuertoDialUp.py”, line 10
    if len(services) > 0:
    ^
    IndentationError: unexpected indent

    Aún asi ya se cual es el puerto asi que aunque este script me tire un error ya sabia cual era el puerto.

    Ahora me dispongo a ejecuatr el script para enviar el sms:

    (Te adjunto el codigo que he puesto porque como es que sea un experto en esto temas es posible que haya puesto mas algo)

    import bluetooth

    #bluetooth address
    addr = ‘AA:BB:CC:DD:EE:FF’ -> El que hemos sacado al principio

    #puerto
    port = 1 -> El puerto que hemso sacado antes.

    #telefono
    mobile = ‘6927076XX’ #de la forma 58 4[operadora][numero]

    **Esta parte no la he entendido muy bien. No se que quieres decir con de la forma 58 4[operadora][numero]

    #mensaje a enviar
    data = ‘prueba’

    # crear un socket bluetooth rfcomm
    socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)

    # la funcion connect pide los parametros direccion y puerto (address, port)
    socket.connect((addr, port)) #abrir un socket al bt
    #inicializamos el dialogo AT con el modem
    socket.send(‘ATZ\r’)
    print socket.recv(1024)
    #valor “1” indica que el SMS es solo texto
    socket.send(‘AT+CMGF=1\r’)
    print socket.recv(1024)
    #Telefono al que enviaremos el SMS
    socket.send(‘AT+CMGS=”+\”mobile\””\r’)
    print socket.recv(1024)
    socket.send(data+chr(26)) #data + CTRL+Z
    print socket.recv(1024)

    socket.close()

    Despues me aparece el mensaje como que todo se ha enviado bien, incluso la luz de la pantalla del movil se enciende pero no se envia nada a ningun lado.

    ATZ
    OK

    AT+CMGF=1
    OK

    AT+CMGS=”+”mobile””
    > prueba

    Siento que sea tan largo!!

  7. phenobarbital

    La forma 58-4 es porque para enviar mensajes de texto, el número de teléfono viene en la forma:
    +[codigo del pais][codigo de la operadora][numero de telefono]

    Mi país (venezuela) es 58
    Todas las operadoras de acceso movil, su numero comienza en 4
    ejemplo:
    movistar: 414
    digitel: 412
    movilnet: 416

    Y luego viene el numero. debes colocar tanto tu número (para autenticar contra la operadora) como el número de destinatario correctamente, sino no enviará nada.

    Y Si, channel es lo que interesa.

  8. Muy buena información, sin duda muy útil pero me estaba preguntando si hay alguna posibilidad de que se pueda recibir SMS en la computadora, es decir, que al recibir un SMS en un celular se pueda registrar en la computadora.

    Otra duda, los datos del operador telefónico unicamente cambian en el numero q introducimos? En mi caso les escribo desde México y obviamente la operadora es diferente.

    Gracias por la información!

    • phenobarbital

      Pues sip … se puede leer el buzón de entrada (cada cierto tiempo) de un teléfono para ver los SMS.

      Los datos cambian y son de acuerdo al país:
      venezuela = 58 (código de acceso directo internacional)
      operadora = 424 (movistar gsm)
      teléfono = xxxxxxx

      es igual, salvo que cambia tus datos por los de méxico.

      Saludos!

  9. Una de las dificultades que encontré era la de encontrar el puerto. Donde y como debo usar la siguiente línea:

    sdptool browse 00:25:47:BC:8B:7F

    afortunadamente pude usar el puerto 1, pero me gustaría saber como usar la línea anterior ya que con el código en Python no me fue buen.

  10. phenobarbital

    Hola Sandro, esa línea es un comando de consola linux, sdptool es una herramienta que viene con el paquete bluez, básico para tener soporte bluetooth en Linux.

  11. Y si mi conexión es vía usb, cómo detecto la dirección mac y el puerto de mi celular?, al coenctarlo a la pc me salen 3 opciones: usarlo como almacenamiento masivo, como camaraweb o como puerto com… lo hice como puerto com pero necesito saber su dirección mac y puerto. Ayudaaaaa!!!

    • phenobarbital

      Si tu conexión es usb (modem com) se abre una conexión por el puerto /dev/ttyUSB, el script de acá (que usa bluetooth sockets) no es tu solución.

      Si no quieres programar mucho, tu solución es a través de gammu; es una librería que permite “dialogar” con teléfonos de varias marcas.

      Verás un artículo sobre gammu en mi blog gracias a tu comentario! …

  12. ESQ SI NO NOS DAN NUESTRA CONTRASEÑA NUNCA VAMOS A ENVIAR SMS DESDE UNA COMPU A UN CEL

  13. Saludos. En primera instancia quiero felicitar al creador de este foro, excelente. Les informo que logre realizar una aplicacion con las especificaciones planteadas aca. Mi pregunta es la siguiente. Si deseo enviar ese mensaje a varios numeros a la vez como lo haria. Gracias

    • Hola LuisM gracias por el comentario …

      Te comento que luego que envias el numero:

      socket.send(‘AT+CMGS=”+994681777″\r’)
      print socket.recv(1024)

      No solo deberías recibir el socket.recv sino que además, deberías recibir el retorno (“>”) del comando, luego de ese retorno (unos pocos segundos) podrás enviar el segundo AT+CMGS y así sucesivamente …

      Suerte y gracias por el comentario!

      • Gracias amigo. Estoy intentando realizar lo que comente anteriormente pero usando hilos, de tal manera que al enviar el mensaje se cree un hilo con todos los numeros a los que quiero enviar ese mismo mensaje, se iran desbloqueando a medida que vayan enviandose cada uno de ellos. Hasta ahora no lo he logrado pero estoy trabajando en eso. Si logro hacerlo se los hare saber. Mil gracias.

  14. Buenas:
    Estoy ahora desarrollando un proyecto (aun sin nombre) para gestionar el móvil vía Bluetooth y buscando información encontré esta entrada de tu blog y me gustaría contar con tu permiso para incluir el código en mi programa (como no, tu nombre saldrá en los creditos)
    En mi nick esta el enlace al tema que abrí en los foros de la comunidad hispana de Linux Mint al respecto (espero que no lo consideres spam)

    • Siempre a la orden para lo que necesites … podrías buscar código en el proyecto gammu y otros que también sirven para gestionar móviles …

  15. hola como estas, esta interesante tu articulo y estoy empesando en la programacion en java y me gustaria hacer una aplicacion de escritorio que descubra los dispositivos molviles y les envia un mensaje mediante bluetooth y veo que es algo parecido a lo que tu haces y que ria ver si me puedes ayudar, como ya te dije estoy empesando con java es para un proyecto en la universidad y te atradeceria mucho la ayuda que puedas brindarme

    • Con respecto a Java no podría ayudarte mucho, puesto que no programo en java … si acaso cambias de opinión y deseas hacerlo en python, te ayudo cuando gustes! …

      Saludos!

  16. estoy leyendo tu informacion y creo haber encontrado lo que necesito. mira lo que quiero es poner un transmisor bluetooth de 2 watts en una antena a 10 metros de altura , para poder enviar un mensaje a una cantidad de celulares que estén dentro de este campo magnético pero no se si puedo enviar un mensaje a un celu que no me aparezca en la lista (por la distancia 2km) aunque en el celu aparezca mi señal. que crees según tu experiencia. arriba tu escribisteis esto: ” Integrar discovery.py y send_sms.py en un único script, así el script descubre la dirección, el puerto, abre el socket, envía el SMS y se desconecta (con import sys podemos hacer sys.exit(0) para salir del script con confianza).” según esta info crees que podría enviar un mensaje a un celular con las condiciones ya antes mencionadas? agradecería tu atención y gracias.

    • Tienes ciertos problemas técnicos para plantear una *solución* así:
      Primero, esta solución envía mensajes SMS, ¿como piensas descubrir los números telefónicos de todos los dispositivos que estén a tu alcance?, para hacer un descubrimiento de las “propiedades” del telefono, requieres de un proceso de “pairing” que es tu segundo problema técnico.
      Segundo: el proceso de “pairing” (emparejado) depende de una relación de confianza alrededor de una clave de emparejamiento entre tú dispositivo y el dipositivo del “cliente”, debes confiar en que la gente le dirá “aceptar conexión entrante” de una fuente absolutamente desconocida y de la cual no tienen ni siquiera vista.
      Y he ahí el tercer problema: No puedes por ley de telecomunicaciones, poner emisores de más de 1W en ningún lado sin la autorización expresa de CONATEL, so pena de estar contaminando el espectro, puesto que en “condiciones regulares” bluetooth tiene solamente un alcance de 400 mts.

  17. Muy buena informacion. felicitaciones
    tengo una pregunta como le hago para averiguar el codigo de operadora de movistar y de claro en el Peru

  18. Johana Almeida

    ESTOY CORRIENDO EL PROGRAMA EN WINDOWS PORQUE EN LINUX ME SALE ERROR EN ALGUNAS LINEAS
    S ALGUIEN PODRIA AYUDARME YA QUE ME SALE ERROR DE SINTAXIS EN LA SIGUIENTE LINEA}

    socket.send(‘AT+CMGS=”+994681777″\r’)

    PODRIAN AYUDARME!!!! DE URG
    COMO ES LA SYNTAXIS CORRECTA???

  19. ok fíjate en las comillas. socket.send(‘AT+CMGS=″+994681777″\r’)

  20. Hola esta muy buena tu web, y estos articulos eran justamente lo que estaba buscando. Llevo algo de tiempo aprendiendo python y habia intentado infrustuosamente con sockets y esas cosas, pero no lo había logrado. Comenze leyendo un articulo sobre linux, y de verdad el resto de los artículos que conseguí fue mejor que el anterior que había leído, te felicito. Inclusive tengo un pequeño blog, y puse un enlace al tuyo.

    Te hago una consulta aparte. el script para enviar mensajes, funciona a la perfección cuando lo hago manual, por consola, pero cuando lo ejecuto como un script, creo que el sistema va muy rapido y no deja al sistema enviar los datos al socket, lo unico que sale es esto:

    A
    T
    Z

    Tendras idea porque el script no espera al socket, tengo linux con python 2.6.6

    • Dependiendo del equipo, tendrás que agregar “pausas”, para ejecutarlo en modo script, ¿la razón?, no puedes enviar intermitentemente mensajes SMS, las celdas operadoras hacen “pausas” y esas pausas limitan la capacidad total de mensajes que puede enviar el teléfono …
      Técnicamente no podrás enviar más de 100 mensajes por minuto en GSM, así que deberás adaptar el script para que haga “pausas” por cada conexión que haga efectiva.

      • gracias por la respuesta, pero estoy enviando un solo sms, es decir puse tu script lo puse en un archivo y lo ejecute. eso fue todo.

        La pregunta es, al ejecutar este script deberia salirme como pones arriba o como te puse antes?

  21. Saludos.

    He estado probando el código, pero me da un error, o al menos me muestra lo siguiente por pantalla al resultar la ejecución del script:
    ATZ
    OK

    AT+CMGF=1
    ERROR

    MENSAJE.

    tienes alguna idea de porqué esté sucediendo esto? puse el número del país, que es 52 y los 10 dígitos del número celular a enviar, el puerto para la conexión fue el puerto 4.

    Gracias y saludos, excelente blog

  22. hoola buen post. solo una pregunta, ke pagina me recomiendas para mas informacion como esta. mi cel es un nokia 5800 me hace tiempo quise hacer lo ke posteas aki. ahora lo ke hice es controlar cargas de 127v a distancia usando el acelerometro y bluetooth desde el cel.
    pero me interesa mas info como esta..
    por cierto la solucion que le di a esto hace tiempo fue conectar un cel por bluetooth a la pc y configurandolo como un puerto de comunicaciones COM-XX y en la PC hice una app en Visual basic en la cuan defini los comandos AT del movil, en la cual solo haciendo un par de clics se podian enviar y recivir sms y hacer llamadas… mmm bueno les comento esto por si a alguien le sirve. podrian optar por esta otra opción.

  23. Saludos desde México, excelente información, sólo que tengo un problema parecido al que Manuel menciona en un comentario anterior; así que un poco de ayuda es muy apreciada.

    El problema surge en la parte:
    +[codigo del pais][codigo de la operadora][numero de telefono]

    Sé entonces que el códido del país es 52, podría ser redundante pero no encuentro mucha info en el internet. Por acá se manejan números de 10 dígitos (teléfonos moviles), entonces la sección del código de la operadora es el problema; Wikipedia me sugiere https://en.wikipedia.org/wiki/Mobile_country_code. He probado con los códigos correspondientes a movistar y telcel pero no consigo nada de nada.

  1. Pingback: [python] usando gammu para enviar SMS | Phenobarbital con Soda!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: