domingo, 13 de octubre de 2013

Monitoreando ruteador con Raspberry Pi

Continuando con nuestros experimentos con el Rasperrry Pi. Decidimos crear un monitor de tráfico para el ruteador. Nuestra compañía de internet nos impone un límite mensual, por lo que nos es útil saber el consumo que llevamos en un día.

La primer opción fue escanear el tráfico directamente de la red e ir contando el tamaño de los datos transmitidos. Sin embargo, esta solución no funciono, ya que al estar conectados al ruteador, sólo recibimos paquetes que están destinados al Raspeberry o paquetes broadcast.

La segunda opción fue conectarse directamente al ruteador y extraer la información del tráfico del día. Para ello, primero nos conectamos manualmente al ruteador y monitoreamos el tráfico usando Wireshark, esto nos permitió aprender que el ruteador usa autenticación básica y que la página que contiene la información del tráfico se llama traffic.htm. Esto también nos ayudo a inspeccionar el contenido de traffic.htm y observar que una variable de javascript contiene la información que necesitamos.

Con toda esta información, la lógica del programa es muy sencilla.

  1. Inicializar IO y prender todos los LEDs durante 3 segundos para diagnosticar LEDs en mal estado.
  2. Ciclo infinito:
    1. Obtener traffic.htm del ruteador
    2. Extraer tráfico del día
    3. Desplegar en formato binario usando los LEDs el tráfico del día en cientos de MB
Está imagen es cuando el tráfico del día ha sido un poco más de 800MB.


El código en python es el siguiente:

import urllib2
import re
import base64
import time
import RPi.GPIO as GPIO

def get_router_page():
  theurl = 'http://192.168.1.1/traffic.htm'
  username = 'admin'
  password = 'your_password'
  req = urllib2.Request(theurl)
  
  # First try without username/password
  try:
    handle = urllib2.urlopen(req)
  except IOError, e:
    pass
  else:
    return handle.read()

  # Now try with authentication
  base64string = base64.encodestring(
                '%s:%s' % (username, password))[:-1]
  authheader =  "Basic %s" % base64string
  req.add_header("Authorization", authheader)
  
  try:
    handle = urllib2.urlopen(req)
  except IOError, e:
    print e
    return None
  
  return handle.read()


def get_traffic_in_MB(page):
  for line in page.split('\n'):
    match = re.search(
      r'\s*var\s*traffic_today_total\s*=\s*"(.*)"\s*;\s*', 
      line)
    if match:
      return match.group(1).replace(',','')
  return None


def is_bit_set(value, bit):
  mask = 1 << bit
  return (value & mask)


def display_traffic(traffic_MB):
  traffic_in_100_MB = int(float(traffic_MB) / 100)
  
  if traffic_in_100_MB > 31:
    traffic_in_100_MB = 31
  print traffic_in_100_MB
  GPIO.output(LED_0_PIN,is_bit_set(traffic_in_100_MB,0))
  GPIO.output(LED_1_PIN,is_bit_set(traffic_in_100_MB,1))
  GPIO.output(LED_2_PIN,is_bit_set(traffic_in_100_MB,2))
  GPIO.output(LED_3_PIN,is_bit_set(traffic_in_100_MB,3))
  GPIO.output(LED_4_PIN,is_bit_set(traffic_in_100_MB,4))


def init_IO():
  # Init outputs
  GPIO.setmode(GPIO.BCM)
  GPIO.setup(LED_0_PIN,GPIO.OUT)
  GPIO.setup(LED_1_PIN,GPIO.OUT)
  GPIO.setup(LED_2_PIN,GPIO.OUT)
  GPIO.setup(LED_3_PIN,GPIO.OUT)
  GPIO.setup(LED_4_PIN,GPIO.OUT)
  
  # Test all leds
  GPIO.output(LED_0_PIN,True)
  GPIO.output(LED_1_PIN,True)
  GPIO.output(LED_2_PIN,True)
  GPIO.output(LED_3_PIN,True)
  GPIO.output(LED_4_PIN,True)
  time.sleep(3)
  GPIO.output(LED_0_PIN,False)
  GPIO.output(LED_1_PIN,False)
  GPIO.output(LED_2_PIN,False)
  GPIO.output(LED_3_PIN,False)
  GPIO.output(LED_4_PIN,False)

LED_0_PIN = 23
LED_1_PIN = 24
LED_2_PIN = 25
LED_3_PIN = 8
LED_4_PIN = 7
init_IO()

while True:
  page = get_router_page()
  if page is not None:
    traffic = get_traffic_in_MB(page)
    if traffic is not None:
      display_traffic(traffic)
  time.sleep(60)
GPIO.cleanup()


Saludos.

miércoles, 9 de octubre de 2013

Cómo almacenar una imagen en formato .bmp desde un osciloscopio Rigol DS1102CA

En varios de mis laboratorios que involucran el uso del osciloscopio para observar alguna señal de voltaje o corriente he visto que se me pide hacer un dibujo de lo que observo en la pantalla e incluirlo en el reporte final, sin embargo, creo que es mucho mejor incluir la imagen que aparece en la pantalla del osciloscopio.

Al principio comencé a tomar fotografías del osciloscopio hasta que me percaté de la entrada para USB que posee el modelo DS1102CA de Rigol (que es el que he utilizado con mayor frecuencia) y decidí investigar cómo utilizarla para almacenar las imágenes que se obtienen en la pantalla. Estos son los pasos a seguir para poder obtener una imagen con formato .bmp desde el osciloscopio usando un USB:

  1. Una vez que obtienes tus resultados en la pantalla, conecta tu USB en la entrada para USB del osciloscopio:
  2. Dentro del recuadro "Menu", presiona el botón "Storage":
  3. En la pantalla del osciloscopio aparece el menú correspondiente a las opciones para guardar información (Storage). Selecciona el formato en el que deseas guardar la imagen (en este caso Bit map), de no seleccionar este formato, la imagen se guarda por defecto como "Waveform" y no podrás visualizarla como lo haces con otras imágenes como .jpg o .bmp.
  4. En el menú de "Storage", selecciona la opción "External", la cual le indica al osciloscopio que usarás tu dispositivo USB para guardar la información (en este caso la imagen):
  5. Hecho lo anterior, observarás el siguiente menú de opciones:
    Puedes guardar el archivo con el nombre "NewFile0" que es el que aparece por defecto o puedes editar el nombre utilizando la perilla que se encuentra junto a los botones del recuadro "Menu". Para ello, solo gira la perilla y verás como navega hacia la izquierda o derecha seleccionando cada letra del alfabeto. Dependiendo del nombre que desees, posiciona el cursor con la perilla y presiónala para seleccionarla. Es un proceso algo lento así que te recomiendo que elijas un nombre corto pero significativo.
  6. Presiona el botón que está al lado de la opción "Save" (Guardar).
La imagen que guardé en mi USB para este ejemplo es la siguiente:

Una vez que termines de guardar las imágenes que deseas utilizar en tu trabajo, reporte, tarea, etc., puedes desconectar el USB. Guardar los resultados de algún experimento o laboratorio en forma de imagen te permite analizarlos mejor y con más precisión.

sábado, 14 de septiembre de 2013

Programmando TI84 – ciclo infinito

Resulta que un programa para mi TI84 tenía un ciclo infinito, mi primer opción fue tratar de apagarla, pero no respondía. Por lo que mi segunda opción fue quitarle las pilas, pero eso fue una mala idea, porque al prenderla me apareció que la RAM se había corrompido y todos mis programas fueron borrados.

Lo único que tenía que hacer era presionar la tecla “ON”, lo cual genera un mensaje para interrumpir el programa.

Referencia:
http://www.dummies.com/how-to/content/the-while-end-command-on-the-ti84-plus.html

Saludos.

jueves, 12 de septiembre de 2013

Prendiendo un LED con Raspberry Pi

Esta tarea fue bastante sencilla, este tutorial explica que librerías de Python tenemos que instalar para controlar los pines de entrada/salida.

El siguiente programa en Python comanda la salida del pin 7 a 1 (3.3V) durante 5 segundos.
#!/usr/bin/env python
import RPi.GPIO as GPIO, time

GPIO.setmode(GPIO.BCM)
GPIO.setup(7,GPIO.OUT)
GPIO.output(7,True)
time.sleep(5)
GPIO.output(7,False)
GPIO.cleanup()

Como pueden ver es bastante legible, sólo esta instrucción parece algo rara:

GPIO.setmode(GPIO.BCM)

y tiene que ver con la forma en la que se enumeran los pines.



Saludos.

sábado, 7 de septiembre de 2013

Python no encuentra funciones en modulo

El siguiente error me pareció bastante curiosos, que decidí compartirlo. Cree un pequeño programa en Python para hacer unas pruebas con sockets. Se me ocurrió llamarle a mi archivo socket.py. De hecho al inicio sólo tenía dos líneas:

import socket
s = socket.socket( socket.AF_PACKET , socket.SOCK_RAW , socket.ntohs(0x0003))

Pero al tratar de ejecutarlo me marcaba errores del siguiente tipo:

AttributeError: 'module' object has no attribute 'AF_PACKET'

Lo que está pasando es que Python primero busca los módulos en el directorio actual, en este caso como mi archivo se llama socket.py, se importaba a si mismo, en lugar de importar el módulo de las librerías de Python.

Simplemente renombré mi archivo a mi_socket.py y me aseguré de borrar el archivo socket.pyc que se había generado en el directorio actual.

Referencia: http://stackoverflow.com/questions/13422356/socket-isnt-working-in-python

Saludos.

martes, 3 de septiembre de 2013

Primeros pasos con Raspberry Pi

Iniciaremos una nueva serie para compartir nuestros experimentos con un recién adquirido Raspberry Pi. Decidimos comprar un kit que además del Raspberry, también trae su fuente que se conecta al micro USB, una tarjeta SD con un sistema operativo ya configurado, un estuche y cable HDMI. Se nos hizo una buena oferta. Además como el sistema operativo ya esta listo para usarse, es muy rápido empezar a jugar con el hardware. De cualquier forma, estamos planeando en futuros experimentos, el compilar directamente un sistema operativo.

Por el momento esta configuración nos permitió hacer nuestro primer experimento muy fácilmente. Definitivamente el lugar para iniciar son los tutoriales de Adafruit.

Inicialmente conectamos el Raspberry a un mouse, teclado y monitor, pero sólo lo hice para realizar la configuración inicial. La configuración más importante es habilitar SSH, para poder conectarnos remotamente.

Después de esto, nos conectamos remotamente usando SSH para instalar VNC. El Raspberry está conectado vía Ethernet al ruteador. Y listo, ya podemos utilizar remotamente nuestro Raspberry, el cual sólo esta conectado al ruteador y a su fuente.


Nuestro siguiente experimento será prender un LED.

Saludos.

Para ver los demás post de esta serie da clic en el tag Raspberry Pi.

domingo, 1 de septiembre de 2013

Procesando varias fotos con Phatch

Últimamente he estado subiendo algunas fotos a Facebook y mandando varias por correo; sin embargo, note que la resolución y tamaño de las fotos es muy grande, por ejemplo 3648 x 2736, y estas fotos usualmente sólo las verán en un celular. Aun cuando Facebook y Gmail hacen un muy trabajo reduciendo el tamaño de las fotos, no esta de más el reducir el tamaño de las fotos previamente.


El principal detalle, es que pasa si queremos redimensionar 100 fotos; hacerlo una por una, no es una tarea muy atractiva. Para ello podemos usar el programa llamado “Phatch”, que permite ejecutar una secuencia de operaciones a varias fotos.

Phatch lo pueden instalar en Ubuntu. El proceso es muy sencillo, sólo tienen que crear una lista de comandos que quieren aplicar a todas fotos de un folder. En la siguiente imagen, estoy indicando que quiero redimensionar cada foto a un máximo de 800x800 manteniendo las proporciones originales y guardarlas en mi escritorio en el folder nuevas.


También se pueden aplicar acciones como cambiar el contraste y el brillo. Una vez que tengamos la lista de comandos, seleccionamos ejecutar y Phatch nos pedirá el directorio fuente y nos mostrará todas las imágenes que procesará. Al finalizar el procesamiento presenta un resumen del número de imágenes y el tiempo empleado.



En este caso, las fotos originales miden alrededor de los 4MB, las fotos generadas miden alrededor de los 100KB



Algo muy útil, es que las listas de acciones se pueden guardar. Este script de Phatch para redimensionar fotos ya lo he usado varias veces.

Saludos.

domingo, 20 de enero de 2013

Métricas del grafo de hash tags

Tutorial de Grafos
Anterior        Índice       

El programa que extrae la información usando la API de Twitter está usando exploración aleatoria. Es decir, selecciona aleatoriamente el siguiente hash tag a solicitar. Este enfoque resulta muy práctico y nos permite descubrir muchos hash tags. Por ejemplo, después de haber ejecutado el programa algunas horas, este ha visitado alrededor de 3,000 nodos pero ha descubierto alrededor de 150,000. Esto nos da un grafo bastante incompleto, lo cual puede ser frustrante al momento de ejecutar algoritmos como el de encontrar la ruta más corta, ya que es muy probable que si seleccionamos dos nodos al azar sólo haya una ruta entre ellos. Lo ideal sería poder visitar la mayoría de los nodos que conocemos; el problema es que el realizar las peticiones de tweets es una operación costosa.

Por ello es que decidí modificar el programa para visitar sólo aquellos hash tags que luzcan más “relevantes”. La definición de relevancia es un tanto arbitraria y la definí intuitivamente. Obtuve algunas métricas con los nodos que he visitado hasta el momento para obtener un parámetro que no fuera del todo subjetivo.

NOTA: las siguientes conclusiones están basadas en los aproximadamente 3,000 hash tags que visite usando el programa descrito en secciones anteriores. Por lo que estás conclusiones pueden ser incompletas e incluso incorrectas, pero son un buen inicio para los propósitos de este tutorial.

El término hash tag y nodo son equivalentes en la siguiente discusión.

La primer métrica es el número de vecinos de un nodo: en promedio tienen 133 vecinos. En la siguiente gráfica observamos que más del 40% de los nodos tienen 90 o más vecinos. Esto concuerda con nuestros resultados (sólo 3,000 visitados pero ya llevamos 150.000 descubiertos); es decir, el universo de nodos descubiertos crece muy rápidamente conforme vamos visitando más nodos.

Es interesante ver como hay también un buen porcentaje de nodos con muy pocos vecinos, tal vez esto se deba a hash tags esporádicos.

Bueno, regresando a la pregunta de qué es un nodo relevante, decidí ver la fortaleza entre dos hash tags, y esto es simplemente cuantas veces aparece un hash tag en la búsqueda de otro. Por ejemplo, cuando buscamos #Toluca, de los 400 tweets obtenidos, el hash tag #futbol apareció 20 veces; en este caso digo que la fortaleza de #Toluca a #futbol es 20.

La siguiente gráfica muestra la distribución de las fortalezas de los enlaces. Noten como el 70% de los enlaces sólo tienen fortaleza 1, pareciera que la mayoría de las relaciones entre hash tags son esporádicas. Sin embargo, existe un porcentaje considerable de enlaces con fortaleza igual o mayor a 9.

Precisamente está es la métrica que utilicé para decidir que nodos visitar. Sólo visitaremos aquellos nodos que estén muy conectados a alguno de los nodos que hayamos visitado. Obviamente hay que cuidar no ser muy restrictivo que lleguemos al punto de no encontrar más nodos. Para ello obtuve la siguiente gráfica donde podemos ver que aproximadamente la mitad de los nodos están conectados a por lo menos otro nodo con fortaleza 9 o mayor. Lo cual es un buen indicador que aún cuando estamos reduciendo el espacio de búsqueda, seguiremos encontrando nuevos nodos.

Primero probé con enlaces de fortaleza 4, pero aún así el número de nodos conocidos crecía muy rápidamente. Así que ajuste este valor a 10.

El código lo pueden encontrar aquí. El archivo tweets_old.zip contiene la información usada para las métricas. El archivo tweet_graph.py calcula y despliega las métricas. Tweet_search.py es el programa de extracción de tweets con las modificaciones mencionadas.

Tutorial de Grafos
Anterior        Índice       

sábado, 12 de enero de 2013

Creación del grafo de hash tags

Tutorial de Grafos
Anterior        Índice        Siguiente

Ahora que ya tenemos datos podemos empezar a crear nuestro grafo. Existen dos formas principales de representar un grafo: matriz de adyacencia o lista de adyacencia. Aquí usaremos una lista de adyacencia, en particular, usaremos un diccionario de adyacencia.

El programa twitter_graph.py contiene un ciclo doble donde construye el grafo. Después entra a un cliclo donde podemos teclear un hash tag y despliega los 10 hash tags vecinos más frecuentes.

Nuestro grafo lo representamos con un diccionario de diccionarios. En el diccionario externo las llaves son los nodos del grafo y los valores son los vecinos de este nodo. Siendo más precisos, un valor es otro diccionario, donde las llaves son los vecinos y los valores representan el número de veces que un hash tag apareció.

Veamos un ejemplo de la variable que apunta al grafo en el programa usando los resultados de la imagen anterior.

  • graph["#cozumel"]
    : contiene los vecinos del hash tag #cozumel.
  • graph["#cozumel"]["#cancun"]
    : regresa el número de veces que #cancun apareció en la búsqueda de #cozumel, en este caso 10 veces.

Vale la pena mencionar dos funciones de los diccionarios en python que ayudan a hacer código más compacto. El siguiente fragmento de código agrega el hash tag al grafo en caso de ser necesario.

if hash_tag not in graph: 
  graph[hash_tag] = dict() 
links = graph[hash_tag]

Esto es equivalente a usar la función setdefault, la cual regresa el valor asociado con la llave (primer parámetro), en caso de no existir, inserta la llave con el segundo parámetro en el diccionario y por último regresa ese nuevo valor.

links = graph.setdefault(hash_tag, dict()) 

El siguiente código inicializa e incrementa el número de ocurrencias de un vecino.

if neighbor not in links: 
  links[neighbor] = 1 
else: 
  links[neighbor] = links[neighbor] + 1

Esto se puede reemplazar por la siguiente línea de código:

links[neighbor] = links.get(neighbor,0) + 1

La función get regresa el valor asociado con la llave o en caso de no existir regresa el segundo parámetro.

El código lo pueden encontrar aquí. Para ejecutarlo sólo recibe la carpeta donde están guardados los tweets:

python twitter_graph.py ./tweets

También incluí un archivo zip que contiene alrededor de 3,000 hash tags consultados, sólo tienen que descomprimir este archivo. AVISO: algunos de los hash tags pueden resultar ofensivos, pero eso es lo que encontró el programa.

En el siguiente post veremos algunas métricas de este grafo.

Tutorial de Grafos
Anterior        Índice        Siguiente