Código Python para la programación de la estación meteorológica

Antes de comenzar a programar la estación meteorológica si no habéis visto el post anterior sobre la configuración de la Raspberry echadle un vistazo para aseguraros de que vuestra Raspberry está debidamente configurada para poder utiliziar el sensor BMP180

Entonces cómo comente en la presentación del blogg el objetivo principal de esta serie de posts será la de implementar una estación meteorológica en un Raspberry y además, subir los datos que recojamos a un canal en ThingSpeak para poder ver los datos que recoge nuestro sensor en cualquier momento desde cualquier dispositivo con acceso a internet. Para ello, si es que todavía no tenéis una cuenta en ThingSpeak, debéis registraros.  

Una vez os halláis registrado no hace falta que hagáis nada más, ya que todo lo relacionado con la gestión de los canales lo haremos desde el programa. El programa tendrá cuatro partes principales, en la primera parte, haremos una petición al servidor de ThingSpeak para que nos de una lista de los canales que tenemos operativos en nuestra cuenta. La segunda parte del programa, la utilizaremos para borrar todos los canales que tengamos operativos en ese momento con un nombre determinado, para no ir acumulando canales en cada ejecución del programa y no tener que perder el tiempo eliminándolos a mano desde la propia página. Es decir, cada vez que ejecutemos el programa crearemos un canal con el nombre Clima, por ejemplo, para subir los datos de la estación, por lo que con el fin de no tener varios canales con el mismo nombre lo que haremos será borrar los viejos automáticamente desde el programa antes de crear uno nuevo. La tercera parte del programa la dedicaremos a crear el canal y la última a leer la información del sensor y subir los datos. 

Lo primero que haremos será crear un archivo tipo Python, para ello escribiremos en el terminal este comando sudo nano /home/pi/Documents/Programas/BMP180/estacion.py por su puesto, el directorio puede ser el que vosotros queráis. Después de haber hecho esto se nos abrirá el editor de texto donde comenzaremos a escribir el programa. 

Lo primero que haremos será importar todas las librería que necesitemos a lo largo del programa, para ello utilizaremos la sentencia import. 

  
import Adafruit_BMP.BMP085 as BMP085
import urllib

Después para facilitar el uso de las funciones del sensor haremos lo siguiente:
  
sensor = BMP085.BMP085()

De esta manera siempre que queramos leer una de las variables que recoge el sensor sólo tendremos que escribir sensor.función en lugar de BMP085.BMP85().función. Ahora bien, una vez aquí comenzaremos con la primera de las cuatro partes principales del programa, la petición para conseguir la lista de canales que tenemos en nuestra cuenta. Pero antes, explicaré como funciona ThinSpeak. 

Si nos metemos en nuestro perfil y vamos al apartado Account>>My profile veremos en la aparte de la derecha un apartado con el título ThingSpeak Settings donde veremos otros tres apartados Time zone, User API Key y MQTT API Key. Ahora mismo, a nosotros sólo nos interesa la User API Key, esta contraseña se utiliza como una especie de identificador, cada vez que queramos hacer trabajar a nivel usuario dentro de ThingSpeak, es decir, para crear un canal, borrarlo etc. necesitaremos incluir este identificador en la petición que le hagamos a la página.

Para hacer una petición sea la que sea, siempre tendremos que seguir una serie de pasos, primero estableceremos conexión con la página a la que queremos acceder, segundo especificaremos el método que vamos a utilizar que por lo general será, GET para pedir información a la página y POST para mandar información a la página. Después crearemos la URI, la cual nos permitirá acceder a una sección determinada dentro de la página, para después especificar qué es lo que se quiere enviar o lo que se quiere recibir (párametros). Una vez hecho esto, juntaremos todo (lo codificaremos), el método, la URI y los párametros y haremos la petición a la página. Por último, recibiremos la respuesta de la página y la decodificaremos para ver si todo ha ido bien y e el caso de que no haya sido así ver que es lo que ha fallado.

Dicho esto, veremos que es lo que debemos enviar para conseguir que ThingSpeak nos devuelva el listado de todos los canales que tenemos en nuestra cuenta. Para ello accederemos al siguiente enlace. Si nos fijamos se puede ver que hay un listado de diferentes funcionalidades, si hacemos click en una de ellas se nos abrirá otra página, donde aparecerá explicado cuales son el método, URI y parámetros a enviar a la hora de hacer una petición a ThingSpeak para esa funcionalidad en concreto.  Entonces, si queremos obtener un listado de todos los canales que hay en nuestra cuenta haremos click sobre List All You Public Channels. Cabe destacar que el formato con el que enviaremos y recibiremos los datos será JSON ya que nos facilitará mucho las cosas a la hora de desglosar la información. 



El código para la obtener la lista de los canales y la definición de las claves quedarán de la siguiente manera: 

   Write_API_Key = ""  #Clave que necesitaremos para escribir en el canal que vamos a crear
   Read_API_Key = ""  #Clave que necesitaremos para leer desde el canal que vamos a crear
   User_API_Key =  "XXXXXXXXXXXXXXXX" #Clave de usuario mencionada antes, aquí cada uno pone la suya
   print "--> Creando Conexion TCP..."
   conn_TCP = httplib.HTTPConnection("api.thingspeak.com") #Expresión para crear la conexión con ThinSpeak
   conn_TCP.connect()  #Estableciendo conexión
   print "--> Conexion TCP establecida"
   print "--> Lista de canales del usuario"
   print "--> Enviando peticion HTTP"
   metodo = "GET" 
   uri = "/channels.json"
   cabeceras = {'Host': 'api.thingspeak.com',
                  'Content-Type': 'application/x-www-form-urlencoded'}
   
   params = {'api_key': User_API_Key,
             }
   params_encoded = urllib.urlencode(params) #Codificación de los parametros
   print "    Params: " + params_encoded
   cabeceras['Content-Length'] = len(params_encoded)
   conn_TCP.request(metodo, uri, headers=cabeceras, body=params_encoded) #Juntamos toda la información para hacer la petición
   print "--> #Peticion HTTP enviada"
   print "--> #Recibiendo respuesta HTTP" 
   respuesta = conn_TCP.getresponse() #Respuesta a la petición del listado de canales
   estatus = respuesta.status #Código para saber si ha habido errores
   print "    Status: " + str(estatus)
   contenido = respuesta.read() #Contenido de la respuesta
   print "    Contenido: " + contenido

El contenido de la respuesta tendrá la siguiente forma:


Como podemos apreciar en la imagen anterior, el contenido del mensaje es muy difícil de entender a simple vista, por lo tanto utilizaremos un desglosador de información json para ver que como extraer la información que nos hace falta para identificar el canal que queremos borrar. Para utilizar el desglosador basta con copiar el contenido de de la respuesta y hacer click en Viewer, al hacerlo pasaremos de ver el contenido como en la imagen anterior a verlo de la siguiente manera.


Entonces, vista la forma desglosada de la información que aparece en el json que nos devuelve ThingSpeak cuando le pedimos el listado de los canales, teniendo en cuenta que si queremos borrar canales con un nombre determinado tenemos que acceder al atributo 'name' para obtener el nombre de dicho canal. Una vez explicado como obtener el atributo al que queremos acceder, veremos ahora cuales son el método, URI y parámetros que debemos enviar en la petición para poder borrar un determinado canal. Para ello, al igual que antes, accederemos  al siguiente enlace. Una vez ahí, miraremos en la lista de acciones cual es la que nos interesa, en este caso Delete a Channel. Como podemos ver, el método ahora será DELETE, la URI será /channels/ la ID del canal.json y los parámetros a enviar serán la ID del canal a borrar y la User API Key, que como podemos apreciar en al imagen anterior, es otro de los datos que nos proporciona el json que nos devuelve ThingSpeak cuando hacemos la petición para obtener el listado de nuestros canales.

Entonces el código para borrar el un canal con un nombre determinado quedará de la siguiente manera: 
contenido_parseado = json.loads(contenido)
nChannels = len (contenido_parseado)
cont = 0
while cont
    identidad="contenido_parseado[cont][id]  
    nombre = contenido_parseado[cont][name]
    if nombre == "Clima"
        print "--> Borrando canal"
        print "--> Enviando peticion HTTP"
        metodo = "DELETE"
        uri = "/channels/" +str(identidad) + ".json"
        cabeceras = {'Host': 'api.thingspeak.com',
                     'Content-Type': 'application/x-www-form-urlencoded'}
        params = {'api_key': User_API_Key,
                  'id': identidad
                  }
        params_encoded = urllib.urlencode(params)
        print "    Params: " + params_encoded
        cabeceras['Content-Length'] = len(params_encoded)
        conn_TCP.request(metodo, uri, headers=cabeceras, body=params_encoded)
        print "--> Peticion HTTP enviada"
        print "--> Recibiendo respuesta HTTP"
        respuesta = conn_TCP.getresponse()
        estatus = respuesta.status
        print "    Status: " + str(estatus)
        contenido = respuesta.read()
        print "    Contenido: " + contenido

    cont = cont +1

Una vez aquí pasaremos a la creación de un nuevo canal al cual subiremos los datos. Para ello como hemos hecho anteriormente primero analizaremos cuales son el método, URI y parámetros que debemos enviar en la petición. Como ahora queremos crear un canal dicha información estará en Create a Channel. Ahora, el método será POST, la URI será /channels.json y los parámetros serán toda la infromación relativa al canal (User API Key, los datos que se van a subir, el nombre del canal etc.) En esta aplicación en concreto subiremos tres datos: la temperatua, la persión atmosférica y la presión de saturación del vapor. Entonces el código para la creación del canal quedará de la siguiente forma:

print "--> Creando canal en ThingSpeak"
   print "--> Enviando peticion HTTP"
   metodo = "POST" #definimos el método
   uri = "/channels.json" #definimos la URI
   cabeceras = {'Host': 'api.thingspeak.com',
             'Content-Type': 'application/x-www-form-urlencoded'}

   params = {'api_key': User_API_Key, #Definimos los parámetros
             'field1': "Temp (C)",
             'field2': "P (Pa)",
             'field3': "Psat(Pa)",
             'name': "Clima",
             'public_flag': 'true'}

   params_encoded = urllib.urlencode(params) #codificamos la información
   print "    Params: " + params_encoded
   cabeceras['Content-Length'] = len(params_encoded) 
   conn_TCP.request(metodo, uri, headers=cabeceras, body=params_encoded) #hacemos la petición
   print "--> Peticion HTTP enviada"
   print "--> Recibiendo respuesta HTTP"
   respuesta = conn_TCP.getresponse() #obtenemos la respuesta
   estatus = respuesta.status
   print "    Status: " + str(estatus)
   contenido = respuesta.read()  
   print "    Contenido: " + contenido #visualizamos al respuesta para ver si ha habido algún error

Después de crear el canal ya sólo nos queda ver cómo subir los datos, para ello seguiremos el mismo proceso que las anteriores veces. En primer lugar, veremos cuales son el método, URI y parámetros necesarios para subir los datos cuya información obtendremos en Update a Channel Feed. Como podemos ver en el enlace anterior para poder actualizar los datos será necesario obtener la Write Apy Key del nuevo canal. Para ello, lo haremos de igual modo que lo hicimos para obtener el nombre y la ID del canal que queríamos borrar.

Entonces, la última parte del código, la relativa a la subida de los datos quedará de la siguiente manera: 

contenido_parseado = json.loads(contenido) #Desglosamos la información obtenida al crear el canal
   Write_API_Key = contenido_parseado['api_keys'][0]['api_key'] #Conseguimos la Write APY Key

   while True: #Entramos en un bucle infinito para subir datos durante un periodo de tiempo indeterminado
       Temp = sensor.read_temperature() # Obtenemos la temperatura en Celcius del sensor
       Psat = 611.2*math.exp((17.62*Temp)/(243.12+Temp)) #calculamos la presión de saturación
       P = sensor.read_pressure() #obtenemos la presión atmosférica
       print "Temp= " + str (Temp) + "C"+ " P =  " +str (P) + "Pa"+ " Ps = " + str (Psat)  #visualizamos los datos que vamos a subir                                                                                                                                            
       print "--> Subiendo datos a ThingSpeak"
       print "--> Enviando peticion HTTP"
       metodo = "POST" #definimos el método
       uri = "/update.json"#definimos la URI
       cabeceras = {'Host' : 'api.thingspeak.com',
                    'Content-Type': 'application/x-www-form-urlencoded'}

       params = {'api_key' : Write_API_Key, #definimos lo parámetros
                 'field1': Temp,
                 'field2': P,
                 'field3': Psat
                 }

       params_encoded = urllib.urlencode(params) #codificamos la información
       print "    Params: " + params_encoded
       cabeceras['Content-Length'] = len(params_encoded)
       conn_TCP.request(metodo, uri, headers=cabeceras, body=params_encoded) #hacemos la petición 
       print "--> Peticion HTTP enviada" 
       print "--> Recibiendo respuesta HTTP"
       respuesta = conn_TCP.getresponse() #obtenemos la respuesta
       estatus = respuesta.status
       print "    Status: " + str (estatus)
       contenido = respuesta.read()
       print "    Contenido: " + contenido #visualizamos al respuesta para ver si ha habido errores
       time.sleep(15) #esperamos 15s para no saturar el canal
Con esto damos por finalizada la parte relativa al código python del proyecto. Por lo tanto, si ahora accedemos a nuestra cuenta de ThingSpeak deberíamos tener un nuevo canal denominado Clima, en donde se estarán subiendo nuevos datos de temperatura, presión atmosférica y presión de saturación cada 15s. 




Comentarios

Entradas populares de este blog

Modelado y control del péndulo invertido

Modelado y control del sistema de suspensión de un autobús

Graficar en Google Charts