loading

Descripción.

El objetivo es tener un indicador visual que muestre si hay bicicletas disponibles en la parada (o paradas) de bicing que suelo usar. En mi caso la estación es la número 26 y la 121. Para ello, tendré unos indicadores LED que me digan si hay bicicletas (led color verde), si hay pocas (amarillo) o si no hay ninguna (rojo).

Componentes.

  • Los componentes necesarios para el montaje son:
  • Una Raspberry Pi B con Raspbian conectada a la red.
  • La API de Bicing.
  • Python instalado.
  • Una protoboard, cables, resistencias (330 Ω) y suficientes LEDs, mejor de varios colores.

Step 1: Paso 1: Consulta De Bicicletas Disponibles

API bicing.

Bicing pone a disposición una API para consulta del estado de sus estaciones. La información sobre la API se puede consultar en http://opendata.bcn.cat/opendata/ca/catalog/TRANSPORT/bicing/. En mi caso, usaré la API json, con lo que una llamada a http://wservice.viabicing.cat/v2/stations/26 me retorna:

{"stations":[{"id":"26","type":"BIKE","latitude":"41.407035","longitude":"2.181981","streetName":"Dos Maig","streetNumber":"230","altitude":"28","slots":"17","bikes":"1","nearbyStations":"120, 121, 177, 371","status":"OPN"}],"updateTime":1473934812}

Donde como puede verse se indica el número de bicicletas disponibles (“bikes”) y los huecos (“slots”).

Consulta de bicicletas.

El primer paso será obtener de modo sistemático las bicicletas disponibles. A partir de este valor, calculo el porcentaje de bicicletas disponibles y enciendo el led rojo (menos del 10% de bicicletas), el amarillo (menos del 30%) o el verde (más del 30% disponible). El código del programa Python será como sigue:

#!/usr/bin/python
# -*- coding: utf-8 -*- ''' @author: jayraldyn '''

import requests import logging import time

logging.basicConfig(level=logging.DEBUG)

def info_estacion(id_estacion): # La URL debería ser parametrizable url = 'http://wservice.viabicing.cat/v2/stations/' + str(id_estacion) logging.debug("URL API: " + url) # Construir objeto respuesta info = {} try: response = requests.get(url) logging.debug("Request: result = " + str(response.status_code)) if response.status_code == 200 or response.status_code == 304: # es OK data = response.json() stations = data[u'stations'][0] bikes = int(stations[u'bikes']) slots = int(stations[u'slots']) info['bikes'] = bikes info['slots'] = slots logging.debug("Bikes = " + str(bikes) + " - slots = " + str(slots)) else: # Error, de momento poca cosa, ¿no debería devolver nulo? logging.error("Error en la consulta") except: # Error en la llamada logging.error("Error en la llamada") return info

def color_estacion(info): if 'bikes' in info and 'slots' in info: pct = 100 * info['bikes'] / (info['slots'] + info['bikes']) logging.debug("bikes = " + str(info['bikes']) + " - PCT = " + str(pct)) if pct > 30: return "verde" elif pct > 10: return "amarillo" else: return "rojo" else: return "undef" # Polling de la estación # Los minutos deberían estar parmetrizados def consulta_estacion(id_estacion): # Ir mirando la info de la estación while True: info = info_estacion(id_estacion) logging.debug(info) logging.info("Cambiar a " + color_estacion(info)) logging.debug(" ---- Dormir durante 60 segundos ----") time.sleep(60) consulta_estacion(26)

Al ejecutar este programa se puede ver que va consultando periódicamente las bicicletas disponibles y decidiendo el color a mostrar:

DEBUG:root:URL API:  http://wservice.viabicing.cat/v2/stations/26
I...>
INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): wservice.viabicing.cat DEBUG:requests.packages.urllib3.connectionpool:"GET /v2/stations/26 HTTP/1.1" 200 249 DEBUG:root:Request: result = 200 DEBUG:root:Bikes = 0 - slots = 18 DEBUG:root:{'slots': 18, 'bikes': 0} DEBUG:root:bikes = 0 - PCT = 0 INFO:root:Cambiar a rojo DEBUG:root: ---- Dormir durante 60 segundos ---- DEBUG:root:URL API: http://wservice.viabicing.cat/v2/stations/26
I...
INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): wservice.viabicing.cat DEBUG:requests.packages.urllib3.connectionpool:"GET /v2/stations/26 HTTP/1.1" 200 249 DEBUG:root:Request: result = 200 DEBUG:root:Bikes = 2 - slots = 16 DEBUG:root:{'slots': 16, 'bikes': 2} DEBUG:root:bikes = 2 - PCT = 11 INFO:root:Cambiar a amarillo DEBUG:root: ---- Dormir durante 60 segundos ----

Step 2: Segundo Paso: Control De Los Leds.

Para controlar los leds, la Raspberry ofrece la GPIO , lo que completaré con una protoboard y evidentemente un juego de leds y resistencias. No explicaré el funcionamiento de la GPIO, pero hay mucha información en la web sobre su uso en Python, como por ejemplo este enlace. En primer lugar instalo la librería GPIO de Python:

apt-get install python-rpi.gpio

Para probar el control de un led, lo conecto a la protoboard, una patilla a la conexión de tierra (patilla 6) con una resistencia de 330 Ω y la otra patilla a la GPIO4 (patilla 7). La conexión queda más o menos como se ve en la imagen.

A continuación escribo un pequeño programa en Python que encienda el led durante 5 segundos:

#!/usr/bin/python
# -*- coding: utf-8 -*- ''' @author: jayraldyn ''' import RPi.GPIO as GPIO # La librería de Python para control del GPIO import time

# Numeración BCM, como podría ser cualquier otra GPIO.setmode(GPIO.BCM)

print "Detectada Raspberry Pi " + GPIO.RPI_INFO['TYPE'] + " rev." + str(GPIO.RPI_INFO['P1_REVISION']) + " (" + GPIO.RPI_INFO['RAM'] + ")" print "Versión GPIO: " + GPIO.VERSION

# El 4 será de salida GPIO.setup(4, GPIO.OUT)

# Activo el 4 y un segundo después lo desactivo print "--> Activo el pin 4 y espero 5 segundos" GPIO.output(4, GPIO.HIGH) time.sleep(5) print "--> Desactivo el pin 4" GPIO.output(4, GPIO.LOW)

# Dejarlo todo limpito antes de salir de casa GPIO.cleanup()

Lo que hace que el led se encienda durante 5 segundos tal como estaba previsto.

Step 3: Tercer Paso: Montando El Circuito Final Y Probándolo.

Para montar el circuito final, pongo dos conjuntos de tres leds (verde, amarillo y rojo) a ambos extremos de la protoboard, conectados a los GPIO17, GPIO27 y GPIO22 (primer grupo) y a GPIO10, GPIO9 y GPIO11 (segundo grupo), representando así las dos estaciones de Bicing más cercanas (en mi caso la 26 (Dos de Maig) y la 121 (Castillejos).

El circuito queda como se puede ver en la imagen.

A continuación escribo un pequeño programa en Python que enciende un color para una estación determinada (estación 1 o 2):

#!/usr/bin/python
# -*- coding: utf-8 -*- ''' @author: jayraldyn ''' import logging import RPi.GPIO as GPIO # La librería de Python para control del GPIO import time import argparse

# Los arrays de GPIOs de los dos grupos GPIOS = (17, 27, 22), (10, 9, 11) logging.basicConfig(level=logging.DEBUG)

def getParameters(): # Tomar parámetros de la línea de comandos # # Parametros: # - estación # - color # parser = argparse.ArgumentParser(description="Parametros de color_estacion.py:") parser.add_argument("estacion", help="estación") parser.add_argument("color", help="color")

args = parser.parse_args() return args

def inicializarGPIO(): # Numeración BCM, como podría ser cualquier otra GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False)

logging.debug("Detectada Raspberry Pi " + GPIO.RPI_INFO['TYPE'] + " rev." + str(GPIO.RPI_INFO['P1_REVISION']) + " (" + GPIO.RPI_INFO['RAM'] + ")") logging.debug("Versión GPIO: " + GPIO.VERSION)

# Poner todos los GPIO de salida for grupo in 0,1: for gpio in GPIOS[grupo]: logging.debug("Poniendo GPIO" + str(gpio) + " en modo OUT") GPIO.setup(gpio, GPIO.OUT)

def ponerColor(estacion, color): # primero hay que apagar los leds de la estación logging.debug("Poner color " + color + " en la estación " + str(estacion)) for gpio in GPIOS[estacion]: GPIO.output(gpio, GPIO.LOW) # a continuación, poner el color if color == "verde": logging.debug("Activar GPIO" + str(GPIOS[estacion][0])) GPIO.output(GPIOS[estacion][0], GPIO.HIGH) elif color == "amarillo": logging.debug("Activar GPIO" + str(GPIOS[estacion][1])) GPIO.output(GPIOS[estacion][1], GPIO.HIGH) elif color == "rojo": logging.debug("Activar GPIO" + str(GPIOS[estacion][2])) GPIO.output(GPIOS[estacion][2], GPIO.HIGH)

inicializarGPIO() args = getParameters() ponerColor(int(args.estacion), args.color)

De modo que cuando se escribe en la línea de comandos:

./color_estacion.py 0 rojo
./color_estacion.py 1 amarillo

Las dos filas de leds cambian de color según lo esperado.

Step 4: Cuarto Paso: Todo Junto.

Una vez llegados hasta aquí, ya tengo todo lo necesario para hacer el montaje. Basta con fusionar el programa inicial que comprueba la disponibilidad de las estaciones con el del control de leds. La aplicación resultado (bicing.py) recibe tres parámetros:

  • el identificador de estación a monitorizar (en mi caso son dos, la 26 y la 121),
  • el juego de LEDs a encender para mostrar el estado de la estación (0 o 1),
  • y el número de segundos en que se repite la consulta.

El código quedaría más o menos así:

#!/usr/bin/python
# -*- coding: utf-8 -*- ''' @author: jayraldyn '''

import requests import logging import time import datetime import RPi.GPIO as GPIO # La librería de Python para control del GPIO import argparse

# Los arrays de GPIOs de los dos grupos GPIOS = (17, 27, 22), (10, 9, 11) logging.basicConfig(level=logging.DEBUG)

def get_parameters(): # Tomar parámetros de la línea de comandos # # Parametros: # - estación # - leds # - segundos # parser = argparse.ArgumentParser(description="Parametros de color_estacion.py:") parser.add_argument("estacion", help="ID de la estación según Bicing") parser.add_argument("leds", help="conjunto de LEDs a usar") parser.add_argument("segundos", help="segundos a esperar en cada consulta")

args = parser.parse_args() return args

def inicializar_gpio(): # Numeración BCM, como podría ser cualquier otra GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False)

logging.debug("Detectada Raspberry Pi " + GPIO.RPI_INFO['TYPE'] + " rev." + str(GPIO.RPI_INFO['P1_REVISION']) + " (" + GPIO.RPI_INFO['RAM'] + ")") logging.debug("Versión GPIO: " + GPIO.VERSION)

# Poner todos los GPIO de salida for grupo in 0,1: for gpio in GPIOS[grupo]: logging.debug("Poniendo GPIO" + str(gpio) + " en modo OUT") GPIO.setup(gpio, GPIO.OUT)

def poner_color_leds(color, estacion): logging.debug("Poner color " + color + " en la estación " + str(estacion)) # primero hay que apagar los leds de la estación for gpio in GPIOS[estacion]: GPIO.output(gpio, GPIO.LOW) # a continuación, poner el color if color == "verde": logging.debug("Activar GPIO" + str(GPIOS[estacion][0])) GPIO.output(GPIOS[estacion][0], GPIO.HIGH) elif color == "amarillo": logging.debug("Activar GPIO" + str(GPIOS[estacion][1])) GPIO.output(GPIOS[estacion][1], GPIO.HIGH) elif color == "rojo": logging.debug("Activar GPIO" + str(GPIOS[estacion][2])) GPIO.output(GPIOS[estacion][2], GPIO.HIGH)

def info_estacion(id_estacion): # La URL debería ser parametrizable url = 'http://wservice.viabicing.cat/v2/stations/' + str(id_estacion) # Construir objeto respuesta info = {} try: response = requests.get(url) logging.debug("Request: result = " + str(response.status_code)) if response.status_code == 200 or response.status_code == 304: # es OK data = response.json() stations = data[u'stations'][0] bikes = int(stations[u'bikes']) slots = int(stations[u'slots']) info['bikes'] = bikes info['slots'] = slots logging.debug("Bikes = " + str(bikes) + " - slots = " + str(slots)) else: # Error, poca cosa se puede hacer logging.error("Error en la consulta") except: # Error en la llamada logging.error("Error en la llamada") return info

def color_estacion(info): if 'bikes' in info and 'slots' in info: pct = 100 * info['bikes'] / (info['slots'] + info['bikes']) logging.debug("bikes = " + str(info['bikes']) + " - PCT = " + str(pct)) if pct > 30: return "verde" elif pct > 10: return "amarillo" else: return "rojo" else: return "undef"

# Polling de la estación def consulta_estacion(id_estacion, leds, segundos): # Ir mirando la info de la estación, bucle infinito while True: info = info_estacion(id_estacion) logging.debug(info) color = color_estacion(info) logging.debug("Cambiar estación " + str(id_estacion) + " a " + color) poner_color_leds(color, leds) logging.debug(" ---- Dormir durante " + str(segundos) + " segundos ----") time.sleep(segundos)

inicializar_gpio() args = get_parameters() consulta_estacion(int(args.estacion), int(args.leds), int(args.segundos))

De ese modo, si quiero lanzar un “daemon” para monitorizar cada 60 segundos la estación 26 y mostrar el resultado en el primer juego de LEDs, hago:

nohup ./bicing.py 26 0 60 &

Y con esto ya tenemos un monitor visual de bicicletas disponibles del bicing.

<p><font><font>Cool Raspberry Pi project.</font></font></p>

About This Instructable

93views

1favorite

License:

More by jayraldyn:Monitor visual de bicicletas disponibles (bicing) 
Add instructable to: