Controlemos entradas y relés con nuestro teléfono

Vista pictórica de la interfaz de control para el teléfono con entradas y salidas activas.
Vista pictórica de la interfaz de control para el teléfono con entradas y salidas activas.

Para este proyecto usaremos una Raspberry PI come servidor web y como software nos apoyaremos a un micro-framework llamado Flask, hecho en Python. No obstante sea un instrumento muy potente, permite también de hacer pequeñas aplicaciones como la descrita en este artículo. Dispone ya de un servidor incorporado por lo que no es necesario instalar otros programas como Apache o PHP.

Ingredientes necesarios

  1. Una Raspberry PI (mejor si es la 3).
  2. Un transmisor WiFi (en el caso de la Raspberry PI 3 no es necesario porque se encuentra ya incorporado).
  3. Una red WiFi operativa (por ejemplo la de casa).
  4. Sistema operativo Raspbian (distribución NOOBS que he ya explicado en artículos precedentes).
  5. Algunos relés de salida y pulsadores de entrada (yo usé 3 y 3, como indicado en el circuito).
  6. Python 3 y Flask ya instalados (todo ya presente en la distribución NOOBS del sitio oficial Raspberry).
Elementos necesarios para nuestro proyecto.
Elementos necesarios para nuestro proyecto.

Para los que deseen ver como se instala el sistema operativo Raspbian en la Raspberry y otros elementos de configuración los invito a leer mis artículos anteriores sobre Raspberry y Python. Para este proyecto es necesario que la Raspberry PI esté conectada a nuestra red WiFi. Para eso podemos usar un módulo WiFi con conector USB externo o ya incorporado en el caso de la Raspberry PI 3.

El circuito electrónico

Circuito con los pulsadores conectados a las entradas de las Raspberry PI (conector principal).
Circuito con los pulsadores conectados a las entradas de las Raspberry PI (conector principal).

Usaremos el mismo circuito electrónico del proyecto anterior y que pueden observar en las figuras. En reposo, las tres entradas GPIO23, GPIO24 y GPIO25 se encuentran a nivel lógico de masa, gracias a las resistencias de 4,7K. Cuando accionamos los pulsadores conectados a positivo (3,3V), el nivel lógico de ellas pasa a "1".

Circuito con los relés conectados, a través del circuito integrado ULN2003 al conector principal de la Raspberry PI.
Circuito con los relés conectados, a través del circuito integrado ULN2003 al conector principal de la Raspberry PI.

Para los relés he usado el circuito integrado ULN2003 conectado a las salidas GPIO17, GPIO22 y GPIO27, especialmente indicado para este tipo de aplicaciones y cuya descripción se encuentra en mi post "El ULN2003". El circuito es bastante simple de hacer y pueden montarlo en una breadboard o en una placa universal de islas. Quizás más adelante proyecte un circuito impreso con más canales que podría servirme para usar la Raspberry en aplicaciones domóticas.

El Software

Ahora pasamos al software. Mi objetivo era hacer las cosas lo más simples posibles por lo que me he limitado a los elementos fundamentales para que la aplicación funcione. Si hemos instalado el sistema operativo Raspbian a través de la distribución NOOBS, disponible en el sitio oficial de la Raspberry, encontraremos ya todo el software que necesitamos: Python 3, la librería RPi.GPIO para controlar las entradas y las salidas y el framework Flask para todo el resto. Si hemos comprado una Raspberry PI nueva y no sabemos por donde empezar los invito a leer mi "Controlando leds con una Raspberry" donde explico en modo detallado como instalar NOOBS y el sistema operativo.

Ahora preparemos el ambiente de trabajo.

1. Con el "File Manager" de Linux, desde la carpeta del usuario ( "pi" ), creamos las carpetas "Inventable" y dentro de ella otra llamada flask como indicado en la figura. En la carpeta flask, creamos un nuevo file llamado test_flask.py

Estructura de las carpetas y de los archivos necesarios para probar nuestro programa de test.
Estructura de las carpetas y de los archivos necesarios para probar nuestro programa de test.

2. Hacemos doble click sobre este file y se abrirá automáticamente el editor de Python IDLE. Escribimos el siguiente código:


1
2
3
4
5
6
7
8
9
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hola Mundo!!"

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000, debug=True)

3. Lo salvamos y dejando abierto el editor (nos servirá más adelante), abrimos el terminal de Linux y non ubicamos dentro de la carpeta flask (cd Inventable/flask). Después escribimos:

sudo python test_flask.py

Si todo funciona bien, veremos en el terminal algo parecido a esto:

Texto en el terminal que indica que el Server Flask está activado.
Texto en el terminal que indica que el Server Flask está activado.

Quiere decir que el server funciona y que el programa está activado.

4. Ahora abrimos un browser (el icono con el mundo en la barra superior) y escribimos en la casilla de direcciones lo siguiente:

localhost:5000

Veremos una página blanca con el texto "Hola Mundo!".

Vista del browser de la Raspberry PI con el programa de test.
Vista del browser de la Raspberry PI con el programa de test.

Perfecto, funciona todo, ahora pasamos nuevamente al terminal que habíamos dejado abierto y detenemos el server apretando la tecla CTRL + la tecla "C". Tendría que aparecernos nuevamente el pront de Linux. Dejemos abierto el terminal que nos servirá después.

5. Ahora escribamos el código de los programas definitivos. Siempre dentro de la carpeta flask, creamos un nuevo file llamado flask_io_v1.py y también otra sub-carpeta que la llamaremos "templates".

Estructura de las carpetas y de los archivos necesarios para nuestro programa definitivo.
Estructura de las carpetas y de los archivos necesarios para nuestro programa definitivo.

Hacemos doble click sobre flask_io_v1.py y se abrirá nuevamente el editor de Python IDLE. Escribimos el siguiente programa y lo salvamos:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""----------------------------------------------------------------------------
 Project:       Flask In/Out server
 File:          flask_io_v1.py
 Version:       1.0
 Purpose:       Controlar 3 entradas y 3 salidas
 Author:        Gabriel Rapetti to Inventable.eu
 Created:       08/02/2018
 Copyright:     Creative Commons (CC) BY-NC-SA  
-------------------------------------------------------------------------------
"""

import RPi.GPIO as io
from flask import Flask, render_template

app = Flask(__name__)

# Colores de botones e indicadores en la página HTML
# --------------------------------------------------
COLOR_ON ='#FD4'
COLOR_OFF = '#AAA'

io.setmode(io.BCM)              # modo in/out pin del micro
io.setwarnings(False)           # no señala advertencias de pin ya usados

# Diccionario con la configuración y el estado de las entradas y las salidas del micro
# --------------------------------------------------------------------------------------
pins = {
    1 : {'nombre' : 'IN-1',  'tipo' : io.IN,  'pin' : 23, 'estado' : io.LOW, 'color' : COLOR_OFF},
    2 : {'nombre' : 'IN-2',  'tipo' : io.IN,  'pin' : 24, 'estado' : io.LOW, 'color' : COLOR_OFF},
    3 : {'nombre' : 'IN-3',  'tipo' : io.IN,  'pin' : 25, 'estado' : io.LOW, 'color' : COLOR_OFF},
    4 : {'nombre' : 'OUT-1', 'tipo' : io.OUT, 'pin' : 17, 'estado' : io.LOW, 'color' : COLOR_OFF},
    5 : {'nombre' : 'OUT-2', 'tipo' : io.OUT, 'pin' : 27, 'estado' : io.LOW, 'color' : COLOR_OFF},
    6 : {'nombre' : 'OUT-3', 'tipo' : io.OUT, 'pin' : 22, 'estado' : io.LOW, 'color' : COLOR_OFF},
    }

# Configura los pines del micro como entradas
# y salidas en base a la información del diccionario
# ----------------------------------------------------------
for num_io in pins:
    io.setup(pins[num_io]['pin'], pins[num_io]['tipo'])
    if pins[num_io]['tipo'] == io.OUT:
        io.output(pins[num_io]['pin'], io.LOW)

# Función que lee el estado de las entradas y salidas
# del microcontrolador y memoriza todo en el diccionario
# -----------------------------------------------------------        
def lee_estados():
    for num_io in pins:
        pins[num_io]['estado'] = io.input(pins[num_io]['pin'])
        if pins[num_io]['estado'] == io.LOW:
            pins[num_io]['color'] = COLOR_OFF
        else:
            pins[num_io]['color'] = COLOR_ON
           
# Función que genera la página Html principal usando el template
# --------------------------------------------------------------------    
@app.route("/")
def main():

    # Actualiza el diccionario con el estado de todo
    # ----------------------------------------------
    lee_estados()

    # Copia el diccionario principal en el diccionario que será pasado a la pagina html
    # ---------------------------------------------------------------------------------
    templateData = {'pins' : pins}

    # Hace el render del template generando la pagina HTML
    # ----------------------------------------------------
    return render_template('flask_io_v1.html', **templateData)

# Función que genera la página Html después de una acción
# --------------------------------------------------------------------
@app.route("/")
def action(change):

    # Botón apretado, cambio de estado de un relé
    for num_io in pins:
        if pins[num_io]['nombre'] == change:
            io.output(pins[num_io]['pin'], not io.input(pins[num_io]['pin']))
   
    # Actualiza el diccionario con el estado de todo
    # ----------------------------------------------
    lee_estados()
   
    # Copia el diccionario principal en el diccionario que será pasado a la pagina html
    # ---------------------------------------------------------------------------------
    templateData = {'pins' : pins}
   
    # Hace el render del template generando la pagina HTML    
    # ----------------------------------------------------
    return render_template('flask_io_v1.html', **templateData)            

# --------------------------------------------------------
# Main
# --------------------------------------------------------
if __name__=="__main__":
    app.run(host='0.0.0.0', port = 5000, debug = True)

6. Ahora nos movemos a la sub-carpeta "templates" y ahí creamos otro file vacío llamado flask_io_v1.html. Hacemos click con la tecla derecha del mouse sobre este file, se abrirá un menú contextual y elegimos "Text Editor". Con este editor de texto normal escribimos el siguiente programa y lo salvamos:

Código completo de la página html.
Código completo de la página html. Como verán es una imagen porque creaba problemas escribir el código directamente en el post. Al final del artículo encontrarán el código para pajar.

7. En el terminal que estaba abierto, lanzamos nuevamente el server escribiendo:

sudo python flask_io_v1.py

Tendría que aparecer el mismo mensaje de la vez anterior:

* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger pin code: (un número)

Abrimos nuevamente el browser y escribimos en la barra de direcciones:

localhost:5000

Milagrosamente tendría que aparecernos un panel como el de la figura.

Haciendo click en los rectángulos inferiores (OUT) podemos activar o desactivar los relés mientras que el estado de los pulsadores podemos verlos en los rectángulos superiores (IN). El programa hace un refresh automáticamente cada 3 segundos.

Si hemos llegado a este punto y todo funciona correctamente podemos controlar nuestros relés desde un smarphone conectado al WiFi local. Para ello debemos saber cual es el IP de la Raspberry PI. Abrimos otra instancia del terminal y escribimos:

sudo ifconfig

Aparecerán una serie de datos, a nosotros nos interesa el IP de la Raspberry que se encuentra en el último bloque llamado wlan0, en el segundo renglón con el nombre "inet". In mi caso por ejemplo es: 192.168.0.70. Nos anotamos este número y cerramos este terminal. Ahora desde el browser de nuestro smartphone escribimos como dirección el IP que habíamos anotado seguido por dos puntos y el número 5000. Veremos el panel de control de los relés y de las entradas como antes, con el browser de la misma raspberry.

Veamos como funcionan los programas:

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

El primer renglón sirve para decirle a linux que el file en cuestión es un programa Python y que debe ser ejecutado a través del interprete Python. El segundo renglón dice al interprete de codificar el programa en formato UTF-8 (Unicode Transformation Format, 8 bit).

"""----------------------------------------------------------------------------
Project: Flask In/Out server
File: flask_io_v1.py
Version: 1.0
Purpose: Controlar 3 entradas y 3 salidas
Author: Gabriel Rapetti to Inventable.eu
Created: 08/02/2018
Copyright: Creative Commons (CC) BY-NC-SA
-------------------------------------------------------------------------------
"""

Este es un comentario con información del proyecto.

import RPi.GPIO as io
from flask import Flask, render_template

Aquí importamos las librerías para las entradas / salidas y el framework Flask

app = Flask(__name__)

Creamos una instancia de Flask llamada "app" (que será nuestro programa)

COLOR_ON ='#FD4'
COLOR_OFF = '#AAA'

Creamos dos variables como constantes para memorizar los colores de las teclas encendidas y apagadas que usaremos más adelante, en el programa.

io.setmode(io.BCM)
io.setwarnings(False)

Decimos a Python de usar la numeración de entradas y salidas del micro y de no señalarnos advertencias en el caso de pines ya usados.

pins = {
1 : {'nombre' : 'IN-1', 'tipo' : io.IN, 'pin' : 23, 'estado' : io.LOW, 'color' : COLOR_OFF},
2 : {'nombre' : 'IN-2', 'tipo' : io.IN, 'pin' : 24, 'estado' : io.LOW, 'color' : COLOR_OFF},
3 : {'nombre' : 'IN-3', 'tipo' : io.IN, 'pin' : 25, 'estado' : io.LOW, 'color' : COLOR_OFF},
4 : {'nombre' : 'OUT-1', 'tipo' : io.OUT, 'pin' : 17, 'estado' : io.LOW, 'color' : COLOR_OFF},
5 : {'nombre' : 'OUT-2', 'tipo' : io.OUT, 'pin' : 27, 'estado' : io.LOW, 'color' : COLOR_OFF},
6 : {'nombre' : 'OUT-3', 'tipo' : io.OUT, 'pin' : 22, 'estado' : io.LOW, 'color' : COLOR_OFF},
}

Creamos un diccionario anidado (una matriz de matrices con claves) con todos los datos relacionados a nuestras entradas y salidas. Cada entrada/salida tiene un nombre, el número de pin del micro, una variable que mantiene el estado y otra con el color de la tecla. Por defecto (default), ponemos el estado y el color de cada elemento a OFF.

for num_io in pins:
    io.setup(pins[num_io]['pin'], pins[num_io]['tipo'])
    if pins[num_io]['tipo'] == io.OUT:
        io.output(pins[num_io]['pin'], io.LOW)

Este ciclo for configura los pines del micro como entradas o salidas en base a los datos que hemos memorizado en nuestro diccionario.

def lee_estados():
    for num_io in pins:
        pins[num_io]['estado'] = io.input(pins[num_io]['pin'])
        if pins[num_io]['estado'] == io.LOW:
            pins[num_io]['color'] = COLOR_OFF
        else:
            pins[num_io]['color'] = COLOR_ON

Esta función que será llamada periódicamente por el ciclo principal lee las entradas del micro e actualiza los estados memorizados en el diccionario principal.

@app.route("/")
def main():
    lee_estados()
    templateData = {'pins' : pins}
    return render_template('flask_io_v1.html', **templateData)

El primer renglón que empieza con @ es un decorador de Python y es un elemento clave del framework Flask: hace en modo que cuando pondremos en el browser la dirección de nuestra página web, se ejecutará la función del renglón siguiente, en este caso "main()"

Dentro de la función main(), primero llamamos a lee_estados() que nos actualizará el diccionario con el estado de las entradas. Después creamos una copia idéntica de nuestro diccionario que llamaremos "templateData". Por último, gracias a la función render_template(), creamos al vuelo una página html usando como modelo el file "flask_io_v1.html" (que veremos dentro de poco) y que se encuentra guardado en la carpeta "templates". La función render_template acepta como parámetro también, la copia de nuestro diccionario. Es una función muy importante porque representa la conexión entre el mundo web (html, css, js) y la parte en Python.

@app.route("/")
def action(change):

Aquí tenemos otro decorador. La función "action()" que lo sigue será llamada si apretamos una tecla en nuestra página html.

for num_io in pins:
    if pins[num_io]['nombre'] == change:
        io.output(pins[num_io]['pin'], not io.input(pins[num_io]['pin']))

Change es una variable que contiene el nombre de la tecla que hemos apretado. Buscamos con un ciclo for en nuestro diccionario a que tecla corresponde y cuando la encontramos, invertimos el estado de la salida de nuestro relé (si está apagado lo encendemos, si está encendido lo apagamos).

lee_estados()
templateData = {'pins' : pins}
return render_template('flask_io_v1.html', **templateData)

Ya que estamos, aprovechamos también para leer el estado de las entradas, usando el mismo sistema que hemos usado en la función main().

if __name__=="__main__":
app.run(host='0.0.0.0', port = 5000, debug = True)

El primer renglón dice a Python de activar el server solo si nuestro programa se llama "main" y es una técnica muy usada en Python cuando nuestro programa se encuentra distribuido entre varios files (no en nuestro caso). El segundo renglón activa el server sobre todas las direcciones locales de la Raspberry (0.0.0.0) usando el puerto 5000. El parámetro debug = True nos permite de ver sobre el terminal los diálogos entre browser y server. Es muy útil desde un punto de vista didáctico y también en el caso de tener problemas.

Ahora veamos la parte html. Los primeros renglones son los clásicos de una página web excepto:

http-equiv="refresh" content="3"

Esta instrucción hace un refresh de la página cada 3 segundos y nos sirve para monitorear las entradas (los pulsadores).

Para simplificar, la hoja de estilo (CSS) se encuentra incorporada en la misma página HTML (no como un file separado). Estas instrucciones, entre los tags < style >, sirven para mejorar gráficamente la página.

En el cuerpo de la página HTML () se encuentran dos tablas (< table >), una para las entradas y una para los relés. Dentro de ellas, mezclados con elementos HTML clásicos, podemos observar algunas construcciones sintácticas particulares que sirven de conexión con la parte en Python. Por ejemplo { % for io_num in pins % } es un ciclo for que explora el diccionario que hemos pasado a la página, { % if pins[io_num].tipo == true % } es una instrucción condicional IF, siempre relacionada con nuestro diccionario mientras que { { pins[io_num].nombre } } pone el contenido de la variable pins[io_num].nombre en la página html.
Para su funcionamiento, flask usa internamente un motor de template llamado Jinja2. Este motor posee una sintaxis particular que permite de introducir en una página html elementos dinámicos como instrucciones y variables que serán controladas desde el programa en Python .
Para indicar una instrucción se usan los símbolos {% %} mientras que para las variables se usan los símbolos { { } } . En la figura siguiente podemos ver la sintaxis:

Tipos de estructura dentro del código html, usando Flask (Jinja2).
Tipos de estructura dentro del código html, usando Flask (Jinja2).

Las instrucciones pueden ser por ejemplo, un ciclo FOR o un condicional IF mientras que las variables son las que hemos pasado desde Python. Veamos un ejemplo:

Ejemplo de estructura condicional dentro del código html, usando Flask (Jinja2).
Ejemplo de estructura condicional dentro del código html, usando Flask (Jinja2).

En este caso hemos usado un condicional IF con una hipotética variable "pluto". Si pluto está definida, la página html mostrará el texto "Pluto existe!!". Si no lo es, veremos el texto "Pluto no existe!!". Observen que es necesario terminar el bloque condicional "if" con un "endif".

Como pueden intuir, el tema tratado es extenso y articulado. No es mi intención hacer un curso de Python o de Flask (mis limitados conocimientos en materia no me lo permitirían). Existe bastante documentación disponible en Internet para poder ir más en profundidad. De cualquier manera, seguiré mis estudios, tratando de describir mi experiencia desde una perspectiva "fundamentalmente electrónica".

Nota final: me doy cuenta que la complejidad del argumento puede hacer que este artículo no sea fácil de entender. Confieso que me hubiera gustado obtener los mismos resultados en un modo más simple pero no lo he logrado. Quizás es un límite mío pero tengo la sensación que el control a través de Internet es intrínsecamente complicado. Cito una frase atribuida a Einstein que sintetiza el concepto: "Todo debería hacerse tan simple como sea posible, pero no más simple que eso".

Hasta pronto.

Gabriel

logo_descarga

Raspberry_Flask_rele (1483 descargas )

Artículos relacionados:

Controlemos entradas y salidas de una Raspberry PI en Python – Parte 1

Controlemos entradas y salidas de una Raspberry PI en Python – Parte 2

Controlando leds con una Raspberry PI

Como controlar un relé con un transistor

Indice de todos los artículos de Inventable

Los contenidos de este blog son originales y están bajo una licencia Creative Commons BY_NC_ND

Controlemos entradas y relés con nuestro teléfono ultima modifica: 2018-04-08T13:19:51+02:00 da inventable

15 comentarios sobre “Controlemos entradas y relés con nuestro teléfono”

  1. hola, perdón la molestia, no entiendo la página html, ¿para que sirven los símbolos { % y todo eso ? ¿por qué no se usa html normal?
    gracias

    1. Hola Eduardo, esos símbolos hacen que la página html sea dinámica, es decir, que cambie el contenido mostrado en base al estado de las entradas y las salidas de la Raspberry. Todo lo que se encuentra dentro de las llaves { } será remplazado por información dinámica, por ejemplo el contenido de variables Python. De esa forma se logra generar páginas web que cambian lo que muestran en un segundo momento. En lenguajes de programación lado Server como el PHP es una cosa muy común.

  2. Buenas tardes, quería saber si es posible controlar los relés fuera de casa. Saludos.

    1. Hola Gastón, tu pregunta es pertinente pero yo no he provado. Creo que es necesario apoyarse a un servicio externo. Quizás, más adelante investigaré sobre el tema.

      Gabriel

    2. ¡Hola!
      Si bien ya pasaron mas de 2 meses desde tu pregunta, la respuesta puede servirte y también a otros lectores:

      Podrías conectarte a través de internet al Raspberry Pi (RPi) de tu casa para controlar los relés.
      Para esto necesitarás dos cosas:
      1 – Saber la dirección IP pública del modem/router que da acceso a internet en tu casa.
      2 – Configurar el modem/router para que envíe hacia la IP del RPi las comunicaciones del puerto 5000

      Explicación:
      1) Saber la dirección IP pública del modem/router que da acceso a internet en tu casa:
      Esto es necesario porque para cargar en tu smartphone (u otro dispositivo) la página de control a través de internet no podrás usar la dirección IP del RPi (porque estás en internet y no en la red de tu casa) sino que deberás pasar la comunicación a través de tu router, que tiene una dirección IP privada en tu red local y otra dirección IP pública «externa» con la cual se conecta a internet (esta es la que nos interesa en este punto).
      Usualmente esa dirección pública no es permanente y puede cambiar en cualquier momento, por lo que podrías usar un servicio gratuito de DNS dinámica, como DynDNS, No-IP, etc para asignarle un nombre a la IP pública de tu casa. Ese nombre no cambia y apuntará siempre a la IP pública de tu casa aunque esta IP cambie por reinicio del modem, corte del servicio, etc…
      Con ese nombre de IP pública accederás a la página de control del RPi desde tu smartphone, notebook, etc a través de internet
      En el ejemplo del artículo (primera ilustración) dentro de la red local de la casa se accede con la IP privada del RPi: http://192.168.0.70:5000
      Desde internet accederías con la IP pública del modem/router o con el «nombre» de IP dinámica que le asignaste, por ejemplo: http://control-casa.dyndns.com:5000
      NOTA: La forma de suscribir y activar/configurar este servicio varía según el proveedor que elijas y los dispositivos que tengas

      2) Configurar el modem/router para que envíe hacia la IP del RPi las comunicaciones del puerto 5000:
      Para poder acceder a la página de control desde internet como se describe al final del punto anterior, tendrás que configurar primero el modem/router de tu casa y decirle que debe redireccionar el puerto 5000 hacia la IP privada del RPi, ya que los datos que entran y salen por este puerto son gestionados por el servidor que corre en el RPi..
      Para configurar esto, entrarás en tu casa a la configuración del router usando su IP privada, usuario y contraseña (detallados en la documentación del modem/router o en una etiqueta que puede tener pegada) y definir la redirección del puerto 5000 hacia la IP del RPi.
      NOTA: La forma de hacerlo varía según la marca y modelo del router
      Lo harás por única vez, pero si cambias la IP de tu RPi tendrás que modificar esta redirección en el router, por lo que es conveniente que configures el RPi con una IP fija.

      Esquemáticamente:

      Si estás en tu casa los dispositivos están en la misma red local y tienen sus respectivas IP privadas por lo que se comunicarán entre sí directamente a través del wifi o switch de tu router:

      Smartphone, PC, etc Router RPi

      Si te comunicas desde lejos, por internet, estarás en otra red que no es la de tu casa, por lo que el router intermediará entre las dos redes encaminando los datos que viajan por el puerto 5000 entre tu smartphone y el RPi:

      Smartphone, PC, etc Router (redirección) RPi

      ¡Saludos!

      1. Repito la última parte…

        Esquemáticamente:

        Si estás en tu casa los dispositivos están en la misma red local y tienen sus IP privadas; la comunicación es así:

        Smartphone, PC, etc —-red local wifi o cable—- Router —-red local wifi o cable—- RPi

        Si te comunicas desde lejos, por internet, estarás en otra red que no es la de tu casa, por lo que el router intermediará entre las dos redes encaminando los datos que viajan por el puerto 5000 entre tu smartphone y el RPi:

        Smartphone, PC, etc —-red Internet, IP pública— Router (redirección) —-red local wifi o cable, IP privada—- RPi

        1. Hola Nestor, que interesante tu respuesta. Veo que conoces el tema. El acceso directo a una red doméstica a través de Internet es un argumento muy de actualidad y de gran potencialidad pero yo he preferido evitarlo hasta ahora porque representa también un gran riesgo a nivel de seguridad. No escludo de profundizar el tema más adelante. De cualquier manera te agradezco mucho la información que nos has brindado.
          Gabriel

  3. Hola buenas noches,

    Gracias por los artículos publicados, son muy didácticos.

    Tengo el siguiente problema:
    He ejecutado y seguido las instrucciones, pero al intentar acceder a la página web, me da el siguiente error:

    jinja2.exceptions.TemplateNotFound

    Con el «test_flask.py» me funciona correctamente el servidor web, pero al ejecutar el «flask_io_v1.py»
    el servidor parece que funciona, pues me sale el siguiente mensaje en el terminal:
    * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
    * Restarting with stat
    * Debugger is active!
    * Debugger pin code: (un número)

    Pero si intento acceder a la web me dice lo de que no encuentra el template

    jinja2.exceptions.TemplateNotFound

    Por favor me podrían indicar cómo solucionarlo. He revisado la estructura de directorios y está como se indica en el artículo.
    Gracias.

    1. Hola Ramón, parece que el programa no encuentra el file flask_io_v1.html que debería estar en la sub-carpeta llamada «template» bajo la carpeta flask ¿Has puesto flask_io_v1.html en el lugar correcto?

      Gabriel

      1. Hola Gabriel,

        Gracias por la respuesta.
        La estructura de directorios creo que la tengo bien:

        pi@Raspberry:~/Inventable/flask $ cd template
        pi@Raspberry:~/Inventable/flask/template $ ls
        flask_io_v1.html
        pi@Raspberry:~/Inventable/flask/template $ cd ..
        pi@Raspberry:~/Inventable/flask $ sudo python flask_io_v1.py
        * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
        * Restarting with stat
        * Debugger is active!
        * Debugger pin code: 739-214-525

        Pero sigue haciendo lo mismo, me da el error de que no encuentra el archivo html

        jinja2.exceptions.TemplateNotFound
        TemplateNotFound: flask_io_v1.html

        Ya no se que puedo probar…….

        Gracias.

  4. Hola Gabriel, gracias por tus tutorial, si es por ti no hubiera entrado en python nunca
    Tengo el mismo problema que Ramón y el browser me muestra lo siguiente
    Algún patch mal en algún lado de nuestra máquina ????
    ___________________________________________________________
    jinja2.exceptions.TemplateNotFound
    TemplateNotFound: flask_io_v1.html

    Traceback (most recent call last)
    File «/usr/lib/python2.7/dist-packages/flask/app.py», line 1997, in __call__
    return self.wsgi_app(environ, start_response)
    File «/usr/lib/python2.7/dist-packages/flask/app.py», line 1985, in wsgi_app
    response = self.handle_exception(e)
    File «/usr/lib/python2.7/dist-packages/flask/app.py», line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
    File «/usr/lib/python2.7/dist-packages/flask/app.py», line 1982, in wsgi_app
    response = self.full_dispatch_request()
    File «/usr/lib/python2.7/dist-packages/flask/app.py», line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
    File «/usr/lib/python2.7/dist-packages/flask/app.py», line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
    File «/usr/lib/python2.7/dist-packages/flask/app.py», line 1612, in full_dispatch_request
    rv = self.dispatch_request()
    File «/usr/lib/python2.7/dist-packages/flask/app.py», line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
    File «/home/pi/Inventable/flask/flask_io_v1.py», line 68, in main
    return render_template(‘flask_io_v1.html’, **templateData)
    File «/usr/lib/python2.7/dist-packages/flask/templating.py», line 133, in render_template
    return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list),
    File «/usr/lib/python2.7/dist-packages/jinja2/environment.py», line 851, in get_or_select_template
    return self.get_template(template_name_or_list, parent, globals)
    File «/usr/lib/python2.7/dist-packages/jinja2/environment.py», line 812, in get_template
    return self._load_template(name, self.make_globals(globals))
    File «/usr/lib/python2.7/dist-packages/jinja2/environment.py», line 774, in _load_template
    cache_key = self.loader.get_source(self, name)[1]
    File «/usr/lib/python2.7/dist-packages/flask/templating.py», line 57, in get_source
    return self._get_source_fast(environment, template)
    File «/usr/lib/python2.7/dist-packages/flask/templating.py», line 85, in _get_source_fast
    raise TemplateNotFound(template)
    TemplateNotFound: flask_io_v1.html
    The debugger caught an exception in your WSGI application. You can now look at the traceback which led to the error.
    To switch between the interactive traceback and the plaintext one, you can click on the «Traceback» headline. From the text traceback you can also create a paste of it. For code execution mouse-over the frame you want to debug and click on the console icon on the right side.

    You can execute arbitrary Python code in the stack frames and there are some extra helpers available for introspection:

    dump() shows all variables in the frame
    dump(obj) dumps all that’s known about the object
    Brought to you by DON’T PANIC, your friendly Werkzeug powered traceback interpreter.

  5. Vale, funcionando
    El directorio tiene que llamarse templates terminado en «s» no template como dice el post

    Un saludo

    1. Nolo has descubierto un error muy importante en la redacción del artículo (templates en lugar de template) que no hubiera permitido el correcto funcionamiento del programa.Ya he corregido el texto y también la figura. Espero que Ramón vea la corrección. Te estoy muy agradecido.

      Gabriel

Los comentarios están cerrados.