Aplicación de Conexión con la Wemos D1

¿Qué es la Wemos D1?

Es una tarjeta de desarrollo similar a Arduino orientada especialmente al Internet de las cosas (IoT). Está basada en el SoC (System on Chip) ESP8266 el cual cuenta con conectividad a internet. Para el desarrollo de aplicaciones se puede elegir entre los lenguajes Arduino y Lua, pero al tratarse de Arduino se nos será más sencillo de usar y procederemos a trabajar con él.

image-2_thumb.jpg

¿Qué deseamos hacer con la Wemos D1?

El objetivo de nuestro experimento es el envío de datos a través de la red wifi hacia un servidor, esto resulta útil cuando se entre a modo producción ya que podemos tener una placa conectada a una red y ya no directamente a un computador y realizar el envío de datos que se van censando.

¿Qué herramientas hemos de implementar?

  • De lado de la aplicación web haremos uso de NodeJs, express, pug y morgan.
  • De lado del hardware haremos uso de una placa Wemos D1 y para su programación el Arduino IDE.

¿Cómo haremos el envío de datos?

Como ya comentamos lo haremos a través de la red wifi, eso implica que estamos haciendo uso del protocolo TCP/IP,  y de esta familia el HTTP, el cual se podría decir que es el protocolo más común en la conexión con internet, HTTP tiene un conjunto de métodos de petición, el que nos atañe es el método POST, que básicamente se encarga del envío de datos hacia el servidor; entonces hacemos el envío de datos mediante un método POST pero en formato JSON, hemos de configurar a nuestro servidor de tal forma que no permita otro tipo de dato que no sea en formato JSON. Entonces hay que ponernos manos a la obra.

Creación y Configuración del Servidor en Node JS y Express

Ya que el tópico que nos concierne no se trata del desarrollo de un servidor, vamos acelerar un poco esta sección (asumo que tienes NodeJs instalado), bueno primero debes de crear una carpeta donde ha de estar tu aplicación, luego de ello abres tu editor favorito (en mi caso Visual Studio Code), abres la terminal que viene incorporada con él, para crear nuestro proyecto debemos de hacer:

npm init --yes

Ahora instalamos nuestros módulos, los módulos que requerimos son express que nos sirve para el manejo de nuestra aplicación, morgan para la revisar que tipo de solicitudes se realizan a nuestro servidor y las respuestas del mismo, pug como motor de vistas (aunque dado el punto hasta donde hemos de llegar no será muy necesario) y mongoose para la gestión de una base de datos  haciendo:

npm i express morgan pug mongoose

Adicionalmente puedes instalar nodemon, nodemon es una herramienta que al inicializarse está a la escucha de cualquier cambio que se realice en los ficheros del servidor o incluso del cliente de nuestra aplicación, si ya lo tienes instalado puedes omitir esta instrucción, sino, te recomendaría que lo instales de forma global para que te sirva en futuras aplicaciones así como también para evitar el monótono reinicio manual de tu servidor.

npm i -g nodemon

Hecho todo esto, creamos la estructura básica de nuestra aplicación, creamos un fichero y lo llamamos index.js, en el mismo nivel una carpeta con el nombre backend y la otra con frontend, dentro de la carpeta backend creamos las carpetas config, database, routes, services, views, dentro de la carpeta frontend creamos las carpeta public y dentro de public las carpetas css, js e img.

esqueleto

Los demás ficheros que ves en la imagen se irán creando automáticamente o posteriormente, dentro de la carpeta config, creamos un fichero con el mismo nombre config.js con el siguiente código:

config

Dentro de la carpeta routes, creamos un fichero con el nombre rutas.js y dentro de el colocamos el siguiente código:

rutas

Como puedes observar estamos importando los servicios que hemos creado;sin embargo, no está resaltado ya que no se han usado, esto es por la dimensión de la aplicación y de lo que se intenta mostrar, esta estructura ya deja conectado los servicios y si en caso hubiese un procesamiento de datos, como por ejemplo un llamado a la base de datos o incluso guardar datos en la misma, se haría a través de los servicios. Entonces ¿Qué es lo que sucede en este fichero?, rutas está manejando las peticiones de las direcciones, y el tipo de petición, como puedes observar una petición de tipo POST, el cual se realiza directamente a la raíz de nuestra aplicación, cuando eso suceda hemos de imprimir en consola el cuerpo de la petición a través del req.body y enviaremos como respuesta un “Conectado“.

En la carpeta views creamos una carpeta que llamaremos layout y un fichero al que llamaremos index.pug, ambos al mismo nivel, ahora dentro de layout creamos un fichero al que llamaremos layout.pug

layout

Ok, vamos a detenernos un poco aquí, nuestra aplicación esta haciendo uso bootstrap para el css y cierta funcionalidad, bootstrap requiere de jquery; además de bootstrap estamos usando font-awesome para colocar iconos en nuestra aplicación, ambas librerías son implementadas a través de sus CDN, ¿Lo vamos a usar en estos momentos? NO, recuerda que estamos armando una aplicación que ha de servir para muchas cosas, no solo para el ejercicio de hoy. Cuando hemos creado nuestro layout vemos que estamos usando la palabra reservada block, block para pug representa uno de sus mecanismos para la herencia, esto lo vamos apreciar de la siguiente forma, en el archivo index.pug debemos de colocar lo siguiente:

index

Una enorme cantidad de código ¿huh?, pues aunque parezca risible esto es poderoso, hemos heredado del layout, si deseáramos agregar algo, simplemente tendríamos que modificar el bloque “contenido_principal“, pero por el momento no.

Ahora pasemos al lado del cliente, el lado del cliente es lo que de cara el usuario ve, entonces esto debe disponer de ciertos ficheros, por ejemplo debemos de crear un fichero para los estilos dentro de la carpeta css al que llamaremos main.css, luego dentro de js haremos los propio, un fichero main.js, si en caso nuestra aplicación requiera de imágenes, ya tenemos preparado nuestra carpeta que ha de cumplir esa función.

Finalmente nos avocamos al fichero index.js, este fichero es el que dará el arranque de nuestra aplicación y en él ha de colocarse todos los middlewares para que nuestra aplicación sea robusta, un middleware a pocas palabras es una función que realiza un procesamiento de datos cuando se realiza una petición específica y antes que se entregue una respuesta al cliente, podemos poner como ejemplo una autenticación de usuarios, la autenticación de usuarios se realiza a través de un formulario el cual viaja al servidor, este antes de entregar una respuesta es procesado por el middleware el cual valida si el usuario existe y que si su clave es la correcta, si en caso fuese correcto da pase a que se entregue una respuesta positiva con una vista específica y si no lo es, simplemente retorna nuevamente al formulario entregando una alerta de usuario o clave equivocados. Entonces el código de nuestro index.js será:

indexjs

Muy bien expliquemos un poco que es lo que está pasando aquí, de las líneas 1 al 6 estamos importando nuestros módulos, tanto los que hemos instalado como los que hemos creado (rutas, por ejemplo); cuando ya hemos importado los módulos debemos de crear un objeto de la aplicación y esto está en la instrucción de la línea 9, hecho ello debemos de configurar nuestro motor de vistas agregando su ubicación (la carpeta views) y definiendo como motor a pug.

En la línea 16 hacemos uso de morgan para observar las peticiones, luego en la línea 17 y 18 le decimos a express que procesaremos peticiones en formato JSON y bajo la codificación (application/x-www-form-urlencoded) (debemos de poner atención al content-type). En la línea 19 implementamos el uso de páginas estáticas, las páginas estáticas son aquellas que solo requieren ser descargadas una vez, estos son los ficheros  css o js que se encuentren de cara al cliente y que hemos colocado en nuestra carpeta public.

Finalmente en la línea 22, solicitamos la conexión con nuestra base de datos, y si en caso se obtuviera éxito en la conexión, la aplicación estará activa y a la escucha en el puerto que le hemos designado, en nuestro caso el puerto 3000, esto responde a la lógica de que no tiene sentido que la aplicación arranque hasta que los datos de las bases de datos necesarios para nuestra aplicación no están ya en línea, ahora bien, esto trae un pequeño contratiempo, pues tienes que tener mongodb instalado y que esté corriendo, lo cual es otro tópico, es por ello que te sugiero que cambies todo de la línea 22 en adelante por:

app.listen(config.puerto,()=>{console.log("Estamos conectados");});

Con esto nuestra aplicación ya está lista, para ponerla en marcha en la terminal de nuestro Editor, hacemos:

nodemon

Si ya lo hemos instalado, veremos que nodemon por defecto buscar el fichero index.js, si hemos decidido llamarlo de otra forma solo basta con:

nodemon nombre_archivo

Configuración del Wemos D1

Existen muchos tutoriales, aunque no específicamente relacionados a la Wemos D1, sino al mini o en su defecto al esp8266 y que se conecta directamente al Arduino, entonces esto hace un tanto insufrible entender el como funciona, además de la existencia de muchos artículos con distintos métodos para su implementación lo hace aún más complicado, más aún cuando yo al ser un desarrollador de lenguaje de alto nivel pretendo incursionar en lenguajes  y sus librería de medio nivel, no encontré tutorial en el cual obtuviese una referencia por cada paso que se da, entonces decidí hacer el propio, tratando de cubrir todas las posibles preguntas que se nos puedan presentar.

Entonces nuestro objetivo principal es el envío de datos, haciendo uso del wifi  el cual hace uso del protocolo TCP/IP específicamente del http, esta referencia se hace ya que existe y que es muy usado el UDP, la diferencia básica entre uno y el otro, es que en el primero los datos son enviados y por así decirlo verificados y no existe “pérdida de datos” (sí…claro), mientras que el otro envía los datos sin verificar si estos llegaron de forma correcta y los sigue enviando, este último es muy usado en videollamadas, donde la pérdida de datos no se aprecia más que quizá en un deterioro momentáneo de la imagen, no es muy ilógico pensar en esta forma de comunicación ya que si te encuentras colectando datos del ambiente el que se pierda un par de datos no resulta tan perjudicial ante la masiva colección de datos que se obtenga ya que para definir que algo ha variado críticamente al menos debe expresarse en un intervalo de tiempo algo prudente (no puedes decir que llovió solo porque cayó una gota), ahora ¿Cómo es la lógica del programa?, pues debemos de hacer lo siguiente:

  • Obtener la conexión wifi con nuestra red
  • Verificar si la conexión se mantiene
  • Si la conexión se mantiene entonces podemos hacer envío de datos a nuestro servidor a través del método POST y directamente a la raíz de nuestra aplicación web.
  • Cerrar la conexión, no se puede enviar una nueva sino se ha cerrado la anterior.

Debemos de tener una consideración respecto al como se comunica el Wemos, como haz podido apreciar, el Wemos solo tiene una salida micro-usb, por el cual se suministra energía y datos, así que procura conseguir un cable con dichas condiciones y no solo de energía, al hacerlo te darás cuenta que W10 buscará el driver y en muchas ocasiones quizá ya lo tengas instalado, sino debes de instalarlos (CH340)

Entonces procedemos a  abrir nuestro IDE de Arduino, como nota y quizá en siguientes publicaciones tenga éxito en ello, soy de los que prefieren el minimalismo al momento de programar, es algo tedioso tener que usar un IDE acorde a cada lenguaje que estés programando, es cierto que muchos IDE’S hacen un trabajo genial pero no siempre es completo, en este caso es con Visual Studio Code, al inicio estuve programando Arduino con él, estuvo genial; sin embargo, Arduino expresa cierto errores en la importación de librerías y sus rutas respectivas, problemas de ser usado con intermediarios, estoy revisando que lo causa, pero hasta los comentarios en las redes hablan de un defecto propio de Arduino y que por el momento resulta imposible de solucionar, tampoco podemos usar el Arduino Web Editor, ya que hemos de instalar una librería que no está soportada en él, esto implica que, de forma justificada debamos de usar el IDE de Arduino para programar rompiendo el minimalismo al programar.

Puesto todos los justificantes sobre la mesa procederemos a trabajar; muy bien lo primero que necesitamos hacer es instalar las librerías que la obtenemos de aquí, como te haz dado cuenta es un fichero JSON, el cual debe ser colocado en:

libreriasesp8266.png

Luego de ello nos dirijamos hacia la sección de placas e instalamos la librería, para ello vamos a “Herramientas”->”Placa”->”Gestor de Tarjetas”, en el buscamos “esp8266”:

driver1

Hecho eso seleccionamos nuestra placa con la misma instrucción anterior, solo que ahora en lugar de entrar a “Gestionar Tarjetas“, buscaremos nuestra tarjeta en el listado que aparece. Existen tutorial donde se hace referencia a la Wemos D1 R2, pero esta de igual forma ha de trabajar:

placa.png

Con esto ya hemos finalizado la preparación de nuestro entorno en Arduino, pasemos al código. Lo primero que debemos de hacer es incluir las librerías:

#include ;
#include ;

Ahora debemos de definir la velocidad de paso de bits por segundo y la conexión con el wifi, te muestro el código en la función setup() y explicaremos poco a poco:

void setup(){
 Serial.begin(115200);
 Wifi.begin("el_nombre_de_tu_red","la_clave_de_tu_red");
 while(Wifi.status()!=WL_CONNECTED){
   delay(500);
   Serial.println("Intentando conectar");
 }
 Serial.println("Estamos conectados");
}

Expliquemos un poco este asunto, con Serial.begin() hemos configurado la velocidad de bits por segundo, y también como mencionamos en el esquema inicial, es primordial asegurar la conexión antes que realizar cualquier cosa, esto se logra con Wifi.begin() el cuál tiene sobrecarga de constructores, entre uno de ellos se encuentra el paso de parámetro de la red y su respectiva clave. Necesitamos asegurarnos que nuestro dispositivo se conecta a la red, para ello el objeto Wifi hace uso del método Wifi.status() el cual devuelve una serie de mensajes de acuerdo a su condición, WL_CONNECTED hace referencia a que se ha logrado la conexión, entonces mientras el valor que devuelve el método estatus sea diferente a ese mensaje se realizará un bucle a través de un while con una demora de medio segundo, finalmente cuando se logra la conexión se sale del bucle e imprimimos que estamos conectados.

El siguiente paso es que mientras estemos conectados podamos enviar nuestros datos a el servidor, como esto ha de ser repetitivo, lo debemos de colocar en la función loop() y a través de un condicional que esté preguntando si estamos conectados, conectados enviamos los datos

loop

 Como mencionamos Wifi.status() retorna un mensaje respecto a la conexión, siendo que WL_CONNECTED es que estamos conectados, si esa condición se cumple, debemos de armar la cabecera y el cuerpo de nuestro mensaje donde estarán nuestros datos, esto lo logramos creando una instancia de la clase HTTPClient, lo primero es inicializar el cliente indicando la ip y el puerto dentro de una cadena String, para ello hacemos uso del método begin() la ip de nuestro computador lo podemos hallar abriendo una consola CMD y digitando ipconfig, el puerto es el que en nuestro servidor habíamos configurado, en este caso es el puerto 3000.

Iniciada la conexión del cliente procedemos agregar la cabecera, esto es importante pues de acuerdo a como esté configurado tu servidor aceptará o no la consulta, nosotros hemos configurado que nuestro servidor atienda en el formato JSON y que el tipo de datos se envía como application/x-www-form-urlencoded, entonces debemos de decirle a nuestra cabecera que la información que vamos a enviar está en ese mismo tipo de dato y ello se define en la línea 19 a través del método addHeader().

El cuerpo de la consulta es agregado como parámetro cuando se llama al método POST de la instancia de la clase HTTPClient, estamos un texto que dice “Hola Mundo“, y este método nos ha de retornar un valor, este valor corresponde a una respuesta código de HTTP y es necesario observar si existe algún error, es por ello que se evalúa si existe un valor -1, lo cual implica un error.

Si todo ido bien, podemos obtener la respuesta en forma de una cadena de texto usando el método getString(), finalmente debemos de cerrar el cliente con el método end().

Muy bien con todo ello, ya tenemos preparado los dos macro componentes de nuestra aplicación, nuestro servidor está corriendo y nuestra placa ya está transmitiendo datos, para se observe el resultado final, les dejo aquí un vídeo con la prueba, por cierto, disculpen la emoción que me embargó que se obtuviera la data.

Anuncios

Arduino y Envío de Datos a un Servidor Parte 2

Anteriormente:

Habíamos ya obtenido la configuración necesario de los servicios y estábamos creando los ficheros en cada una de las carpetas del esqueleto de nuestra aplicación:

inicio7

Ahora vamos a seguir las demás carpetas:

Carpeta Routes

La carpeta routes es la encargada del direccionamiento de las peticiones que se hagan a través del cliente, por ejemplo cuando un cliente accede a nuestra página web lo que está haciendo es una petición de la raíz (“/”) y si tuviéramos un menú como por ejemplo data, es el cliente quién realiza una petición a la ruta (“/data”), para ello usamos una instancia de la clase Router de Express, entonces dentro de la carpeta creamos un archivo rutas.js,  este fichero ha de gestionar dos tipos de solicitud, una relacionada a los datos y otra a la raíz, entonces:

const servicio=require("../services/servicio");//las rutas son las que consumen los servicios que hemos creado
const rutas=require("express").Router(); //creamos la instancia de Router
//cuando se ingresa a la aplicación se realiza una petición get
rutas.get("/",(req,res)=>{
 res.render("index"); // ¿recuerdan el archivo index.pug?, pues aquí se renderiza

});

rutas.get("/data,async(req,res)=>{
 let datos=await servicio.getDatos();
 res.send(datos);
});

module.exports=rutas;

Expliquemos un poco esto, anteriormente hemos creado un fichero index.pug, en el cual cuando se renderice arrojará un fichero index.html, ahí radica la magia, render es un método de express relacionado con la respuesta hacia el cliente. La segunda ruta que es “/data”, tiene como callback una función que posee async/await pero, ¿Por qué lo posee?, pues esta función ha de hacer uso del servicio y su método getDatos() y getDatos es una función que está trabajando con las promesas y esto toma su tiempo, así que es como decir que si getDatos ha de tomar su tiempo la función que lo use también ha de tomar su tiempo, ahora que recordemos que lo retorna getDatos es un arreglo de datos y que será enviado a través del método send asociado a la respuesta al cliente. Finalmente exportamos las rutas.

El fichero Index.js

El  fichero index es el fichero más importante pues es el que ha de poner en marcha el servidor, en el se encuentra todas las configuraciones globales requeridas para el despliegue de nuestra aplicación, entonces vamos a colocar todo el contenido y procederemos a explicar las sentencias más importantes:

const express=require("express");
const config=require("./backend/config/config");
const path=require("path");
const mongoose=require("mongoose");
const rutas=require("./backend/routes/rutas");
const app=express();

//motor de vistas
app.set("views",path.join(_dirname,"/backend/views"));
app.set("view engine","pug);
//middlewares
app.use(express.urlenconded({extended:true});
app.use(express.json());
app.use(express.static(path.join(_dirname,"frontend/public/")));
app.use(rutas);
mongoose.connect(config.mongodb.URI,{useNewUrlParser:true}).then(db=>{
 app.listen(config.puerto,()=>{console.log("Estamos conectados");});
});   

Nuestra aplicación ha de ser gestionada por el framework express.js  por lo tanto debemos de requerirlo, necesitamos de las configuraciones relacionadas al puerto y la dirección de la base de datos que se encuentran en el fichero config, así también necesitamos enlazar la ruta raíz de la aplicación con valga la redundancia con nuestra aplicación, esto lo hacemos con el módulo path que pertenece a nodejs y enlazaremos estas rutas con su método join que une segmentos de ruta, para saber la ruta raíz hacia nuestra aplicación utilizamos la variable de entorno _dirnamenecesitaremos también hacer uso de las bases de datos entonces requerimos a mongoose, También requerimos decirle a express como se han de gestionar las rutas y ello lo definimos en el fichero rutas.js es por eso que lo requerimos.

Cuando todos los módulos que necesitamos ya los hemos instanciado, lo primero que debemos de hacer es crear nuestra aplicación de express y esto lo hemos hecho con:

  const app=express();

Con nuestra aplicación debemos de configurarla y una de las primeras configuraciones es decirle como  y quien ha de renderizar las vistas (views -> index.pug), entonces debemos de configurar el motor de vistas y eso se ha realizado con las instrucciones:

app.set("views",path.join(_dirname,"/backend/views")); //indicamos donde están las vistas
app.set("view engine","pug);//y quien las va a gestionar;

Luego de ello debemos de implementar los middlewares, los middlewares son funciones que realizan acciones previas a la entrega o canalización de solicitudes de datos, los middlewares al realizar acciones pueden hacer tratamiento de los datos y pasarlos a otras funciones o ser ellas mismas la función final, una mejor definición aquí, los middlewares son empleados o llamados a través del método use, los middlewares más importantes de nuestra aplicación son las rutas y el uso de páginas estáticas (que solo necesitan ser cargadas una vez) (express.static):

app.use(express.static(path.join(_dirname,"frontend/public/")));
app.use(rutas);

Por último, ya que estamos usando mongo como la base de datos para almacenar y solicitar los datos, no tiene sentido que la aplicación inicie si las conexión con la base de datos no se ha concretado, ya que podríamos obtener muchos errores, entonces:

 mongoose.connect(config.mongodb.URI,{useNewUrlParser:true}).then(db=>{
     app.listen(config.puerto,()=>{console.log("Estamos conectados");});
})

La conexión a la base de datos se realiza a través del método connect el cual se gestiona a través de las promesas, entonces si es que se logró la conexión con la base de datos, ponemos nuestro servidor con todas las configuraciones previas en funcionamiento, esto se hace a través del método listen de la aplicación express().

La carpeta JS de la ruta frontend/public

En esta carpeta creamos el fichero main.js, este fichero será el que solicite la data constantemente, entonces:

$document.ready(function(){ //cuando el documento haya cargado llamará a la función
  setInterval(function(){ //creamos una función anónima
   $.get("/data,{},res=>{
     console.log(res);
    });
  },5000);
});

Expliquemos lo puesto hasta ahora, recordemos que el fichero index es:

2

Estamos haciendo de la librería jquery, entonces lo que queremos es que cuando el documento esté cargado se llame a una función, en este caso una función anónima donde implementaremos la función setInterval, la cual ejecutará una función cada intervalo de tiempo que le asignemos:

setInterval(function(){ 
    $.get("/data,{},res=>{
     console.log(res);
    });
  },5000);

Nuestra función será ejecutada cada 5 segundos, ¿Y qué es lo que haremos cada 5 segundos? pues debemos hacer una solicitud get a la ruta “/data” (recordemos que esa ruta ya la hemos implementado en el servidor), nuestra solicitud no incluirá parámetro alguno, y por el momento cuando obtiene la respuesta simplemente la imprime por consola, recordemos que la data que se nos envía es un arreglo de objetos que tienen un atributo “Y” donde se almacenó el valor del sensor.

Muy bien, tenemos los datos, pero no solo deseamos imprimirlos por consola,sino que estos se muestren a través del navegador en un gráfico de barras, para ello hemos de usar chart.js, para hacer uso de chart.js lo hemos incluido en nuestro index, pero también hemos creado un canvas el cual tiene como id:”mi_grafico”, entonces el primer paso es capturar el id e indicar que el contexto será un gráfico en 2d (getContext), y esto lo hacemos con:

let elemento_dom=documento.getElementById("mi_grafico").getContext("2D");

Ahora creamos un arreglo vacío, en este arreglo lo que queremos es almacenar los últimos 10 valores que contenga nuestra base de datos, es decir los últimos 10 valores obtenidos en la respuesta del método get, es por ello que luego recorremos la respuesta y asignamos sus valores al arreglo.

let datos=[];
for(let i=res.length-1;i>res.length-11;i++){
 datos.push(res[i].y);
}

Al tener los datos podemos pasarlo al constructor del gráfico de barras de chart.js, el constructor de barras es de la siguiente forma:

var myBarChart = new Chart(ctx, {
    type: 'bar',
    data: data,
    options: options
})

El atributo ctx es la variable donde hemos capturado el canvas, entonces podemos hacer los siguiente:

let chart=new Chart(elemento_dom,{
  type:"bar",
  data:{contenido}


}); 

Debemos de poner especial interés en el atributo data, data posee un conjunto de propiedades como por ejemplo las etiquetas de cada uno de los elementos del gráfico (eje x), como estamos capturando los últimos 10 elementos, entonces el mismo de captura será pues como una etiqueta, las etiquetas pueden ser un arreglo de etiquetas y una etiqueta puede tomar un número o una cadena de texto, las etiquetas se expresan en el atributo labels. Luego necesitamos configurar el datasets (dataset_properties) es un arreglo de objetos con propiedades, haremos uso de la propiedad label y llamaremos a nuestro gráfico “Datos”, luego usaremos la propiedad data y le asignaremos el arreglo de objetos datos, entonces quedando finalmente:

data:{
 labels:datos,
 datasets:[{
  label:"Datos",
  data:datos
 }]
}

Entonces nuestro archivo main.js quedaría:

main.png

Con esto está todo listo de nuestra aplicación, que nos queda, pues ponerla en marcha para ello debemos de ir a la terminal y hacer lo siguiente:

node index.js

Incluso mejor que ello deberíamos instalar el módulo nodemon de forma global de la siguiente forma (esto hará que siempre esté instalado y sea de uso para cualquier otra aplicación), igualmente en la terminal:

npm i -g nodemon
//cuando terminó de instalar hacemos en el terminal
nodemon 

Nodemon por defecto siempre buscará el archivo index.js y estará atento a todo cambio que se suceda en los ficheros de js, entonces toca finalmente ir al navegador y hacer en el:

localhost:3000

Arduino y Envío de Datos a un Servidor Parte 1

Anteriormente habíamos podido conectar nuestro arduino a la red (aquí), tal que cualquier cliente se conecte al ip que hemos asignado a nuestro dispositivo pueda ver los datos que se obtienen del sensor de luz. En esta ocasión hemos de enviar la data a un servidor que montemos y que se muestre a través de gráficos para que se aprecie en tiempo real la data y como esta cambia en el transcurso del tiempo; sin embargo, la variante es que lo haremos a través de JavaScript y el uso de Firmata, así que no entraremos mucho en detalle del significado de las sentencias a menos que sea uno nuevo, así que empecemos.

conjunto

Del lado de Arduino

Para la programación utilizaremos el arduino web editor; sin embargo en esta ocasión la programación no recae con fuerza sobre lo que programemos sobre Arduino sino que lo que queremos lograr en palabras comprensibles es que Arduino sea reconocido por así decirlo como un periférico y que podemos acceder a los datos que recibe a través del sensor (recordar que estamos usando el sensor del artículo anterior, que es un sensor de luz), para lograr ello hemos de usar el protocolo Firmata, ¿Qué es Firmata?, podemos usar esta definición:

Firmata es un protocolo genérico para la comunicación con microcontroladores desde software instalado en un ordenador. Este protocolo se puede implementar en cualquier arquitectura de microcontroladores, así como en cualquier paquete de software. El objetivo de firmata es permitir controlar completamente Arduino desde software instalado en un ordenador, sin escribir una sola línea de código de Arduino (autor).

Muy bien entonces abrimos el arduino web editor, como definitivamente ya tienes instalado el plugin de arduino (sino no funcionaría tu arduino con el arduino web editor) buscamos el icono en la barra de tareas de windows, hacemos click derecho en el y marcamos la opción “go to Arduino create” , cuando se abre la interfaz en el navegador seleccionamos arduino web editor y ahora sí estaremos en la interfaz principal, en la interfaz principal debes ir a examples, marcar la pestaña “from libraries” (te saldrá una lista de librería) desplazarte hasta la librería firmata hacer click en el y en el menú que se despliega seleccionar el fichero “StandardFirmataPlus“, opcionalmente puedes guardar el fichero cambiando su nombre y guardando o simplemente quemando de una sola vez su contenido en nuestro arduino, y eso es todo lo que tendremos que hacer con el arduino

1.png

52608784_263557454562541_5756407597242515456_n.jpg

Del Lado del Servidor

Para el servidor te recomiendo que leas esto (parte 1, parte 2), con el fin que puedas entender o conocer los módulos que hemos de emplear, es cierto que se podría hacer un poco más ligero; sin embargo, quedarían en el aire más preguntas de las que podrían quedar con este post, es decir, muchas librerías de lado del cliente construyen su propio servidor, al cual pues poco o nada de control puedes tener sobre el, o existen otras que las instrucciones se centran exclusivamente en el desarrollo de la recepción de datos de Arduino.

logo

Dicho esto para poder trabajar con el servidor lo haremos con NodeJs, lo que significa que lo debes de instalar, así también se ha de usar mongo para las bases de datos con lo cual también debes de instalarlo, así también no te olvides de iniciar Mongo, o agregarlo para el inicio automático cuando el computador se encienda; hecha la instalación, crea una carpeta, dale un nombre, y abre tu editor favorito (en mi caso VSCode) y navegas hasta la carpeta que haz creado con tu editor, bueno abres la terminal incorporada de VSCODE (Ver->Terminal o abres la terminal de node js y navegas hasta la carpeta que haz creado) y haces:

npm init --yes

Dicha instrucción es el arranque de un proyecto en NodeJs, ahora hemos de proceder a instalar los módulos necesarios, ¿Qué módulos hemos de necesitar?, para el manejo del servidor, las rutas, los ficheros hemos de utilizar express, express no tiene una curva de aprendizaje muy alta y hace gran parte del trabajo que necesitamos hacer en NodeJs, luego necesitamos gestionar las base de datos, y aunque podríamos hacerlo directamente con mongo, para agilizar el trabajo hemos de utilizar mongoose, mongoose nos permite realizar todas las operaciones y configuraciones que haríamos con mongo pero de una forma más sencilla, también necesitamos un motor de vistas y para ello utilizaremos pug, pug nos permite desplegar páginas en html que tengan un tratamiento previo, el tratamiento previo es muy utilizado cuando nuestra páginas han de desplegar contenidos dinámicos (como por ejemplo un red social donde cada usuario tiene su propio perfil), en nuestro caso o para la dimensión de la aplicación esto un paso opcional, ya que podríamos utilizar solo las páginas estáticas, pero lo quise montar ya que con esta aplicación podrías intentar ir más allá de  lo que representa este ejemplo; finalmente y quizá el más importante es la instalación de jhonny-five, jhonny-five es una librería que te permite usar JavaScript para poder ejecutar ordenes o recibir datos desde tu arduino, y esto es lo vital pues tenemos a nuestro arduino enviando datos y debemos de capturarlos y podemos hacer ello a través de Jhonny-five; procedemos a instalar las librerías:

npm i express pug mongoose

johnny-five-fb

Ahora procedemos a instalar jhonny-five, para instalar esta librería debes saber que tiene unos pre-requisitos, los cuales están listados aquí, estos incluyen el módulo del conjunto de herramientas de windows los cuáles podrían tener sus propios pre-requisitos, entonces:

npm i -g --production windows-build-tools
npm i -g node-gyp
npm i johnny-five

Hecha la instalación de los módulos, debes de crear la siguiente estructura de archivos:

inicio7

Aunque esta estructura es genérica, habrá algunas carpetas que en su momento te darás cuenta que no son necesarias, muy bien entonces vamos carpeta por carpeta, dentro de

Carpeta Config

la carpeta config creamos un fichero que se llame config y sea del tipo js, dentro del fichero colocamos:

const config={
 puerto:process.env.PORT || 3000,
 mongodb:{
           URI:process.env.MONGODB_URI || "mongodb://localhost:27017/arduino1"
         }
}module.exports=config;

El fichero config se encarga de almacenar las direcciones o accesos a bases de datos o puertos, como podemos observar estamos requiriendo en primera instancia a las propiedades del entorno (PORT y MONGO_URI) que por lo general son brindadas cuando subimos nuestra aplicación a la nube, en caso de no existir dichas propiedades lo que se haces asignar arbitrariamente un valor como por ejemplo en el caso del puerto el cual mientras esté en el localhost será de 3000, esto de igual forma ocurre con la dirección de la base de datos, sobre la base de datos no te preocupes si esta no existe, pues si mongo detecta que no existe la crea.

Carpeta Views

Dentro de la carpeta views creamos un fichero de tipo pug que se llame index (index.pug), dentro del index vamos a hacer uso de las librería de jQuery y ChartJS (para la creación de las barras estadísticas) y todo ello será centralizado en nuestro propio fichero que se llama main.js, quedando de la siguiente forma:

2.png

Como podrás notar hemos creado un canvas que tiene como id mi_grafico, este canvas será donde despleguemos nuestra gráfica de barras, esto es todo sobre la carpeta views.

Carpeta Database

Su nombre está más que claro de cual es el fin que persigue esta carpeta, mongoose trabaja a través de esquemas, estos esquemas podríamos decir que son representaciones de la estructura de los documentos pertenecientes a la base de datos y que se expresa a través de los modelos, entonces debemos de crear un fichero que se llame modelo.js y en el hacemos:

const mongoose=require("mongoose");//requerimos al módulo general mongoose
const Schema=mongoose.Schema; // creamos una instancia de Esquema

const datos=new Schemma({//creamos un esquema que se llama datos
  y:Number // el cual tiene un único tipo de dato que se llama "Y" y es de tipo Number
});

//exportamos el modelo, así cuando otro fichero lo requiera importará el modelo ya implementado.
module.exports=mongoose.model("data",datos);

Carpeta Services

Dentro de esta carpeta crearemos ficheros que serán los encargados de realizar toda la lógica que se necesita en la aplicación, como lo es guardar elementos en la base de datos o llamar a los elementos de la base de datos, necesitamos dos ficheros, uno de los cuáles será el que realice los servicios relacionados a la recepción de datos de parte del sensor y lo almacene dentro de la base de datos que hemos creado, este fichero lo llamaremos servicio_sensor.js, y debe contener lo siguiente:

const five=require("johnny-five") //requerimos el módulo johnny-five el cual se comunica con el arduino
const Modelo=require("../database/modelo"); //requerimos el modelo que hemos creado
const placa=new five.Board({port:"COM5"});

let valor=0; //creamos una variable general que este almacene el valor del sensor y que pueda ser utilizada por todas las demás funciones
placa.on("ready",function(){ //nos ponemos a la escucha de eventos en nuestra placa
  let luz=new five.Light("A0");
  luz.on("change",function(){
     valor=this.value;
  });
});
async function guardar(){
 let x=new Modelo({y:valor}); // creamos un documento a través del modelo
 await x.save(); //guardamos el documento
}
module.export=setInterval(guardar,2000); //exportamos la función

Expliquemos un poco lo que hay aquí, la instrucción:

new five.Board({port:"COM5"});

Crea una representación de tu placa física (del arduino) y debemos de indicarle el puerto en el que está conectado tu arduino, en el caso de windows es a través del COM, ahora bien Board (el enlace posee información de los parámetros, métodos y eventos de la clase, como ready por ejemplo) tiene más propiedades y parámetros, luego hemos asignado esta instancia ha la constante placa, luego debemos de poner a la escucha a nuestra placa y para ello utilizamos el método on, este método requiere estar a la escucha pero de eventos y el primer evento que debe escuchar es el evento ready, ready sucede luego que la placa se haya inicializado, cuando ocurre ready este llama a un callback (función), es en esta función en el que  inicializamos la escucha del sensor (sensor de luz recuerda) a través de:

let luz=new five.Light("A0");
luz.on("change",function(){
valor=this.value;
});

La clase Light  opcionalmente puede recibir el parámetro relacionado al pin (pero por lo general sino lo colocas no podrá detectarlo, así que lo tomaremos como obligatorio), el pin es el pin donde se encuentra tu sensor en la placa física, en nuestro caso en el pin A0. A la instancia de la clase (luz) debemos de ponerla a la escucha del evento “change” el cual es el evento que está a la escucha de cualquier valor que se obtenga desde el pin, cuando se captura un valor este forma parte de las propiedades de la instancia Light, y podemos obtener dicho valor a través de la propiedad value (value devuelve el valor en crudo sin tratamiento alguno), finalmente el valor obtenido lo asignamos a la variable general “valor” que hemos creado.

Pero necesitamos guardar dicho valor dentro de nuestra base de datos, entonces por eso hemos creado una función que realice ello:

async function guardar(){
let x=new Modelo({y:valor}); // creamos un documento a través del modelo
await x.save(); //guardamos el documento
}}

Como el guardar puede tomar su tiempo, debemos de manejarlo a través de las promesas, esto quiere decir que debemos de implementar el async/await para estar a la espera que concluya el guardado de los datos, el guardado de los documentos (ver sección updating)se hace creando una instancia de los mismos a través del uso del modelo y haciendo uso del método save; así también debemos de asegurar que el guardado se ejecute cada intervalo de tiempo, para ello cuando exportemos el fichero, lo que exportaremos será la función setIntervalsetInterval el cual tiene como requisito indicar una función y el tiempo en mili segundos en el cual se ha de volver a ejecutar dicha función, hemos colocado que se guarden los datos cada 2000 mili segundos lo que hace 2 segundos, esto variable ya que dependerá del comportamiento que desees, es decir que debes someterlo a la pregunta ¿Qué tan drástico será el cambio de valores en el sensor cada cierto tiempo x?, en nuestro caso estamos colocando a 2 segundos con fines demostrativos, pero piénsalo, bueno con esto hemos terminado con el fichero de servicio relacionado al sensor.

Ahora debemos de crear un fichero de servicio que atienda la lógica de la obtención de datos de parte del servidor, a este fichero lo llamaremos servicio.js y debe contener:

const Modelo = require("../database/modelo");
require("./sensor_servicio"); //ponemos en marcha el guardado de datos desde el sensor a la bbdd
async function getDatos(){
 let datos=[];
 datos=await Modelo.find();
 return datos;
}
module.exports={getDatos}

La recuperación también toma un tiempo por lo cual debemos de usar async/await; la recuperación lo hacemos a través del modelo y su método find, este método puede incluir un parámetro de búsqueda; sin embargo, como nosotros requerimos de todos los datos, podemos dejarlo en vacío, ahora bien cuando se devuelven los datos se devuelven un arreglo de estos datos, es por eso que hemos creado un arreglo y finalmente lo que hace la función es retornar dicho arreglo pero ya con los campos poblados. Con esto hemos finalizado todo lo requerido respecto a la carpeta services.

Así concluye la primera parte de este tutorial. Saludos.

Desarrollo de un CRUD – 2

Anteriormente:

Hasta el momento hemos configurado todo lo que necesitamos respecto a los módulos y de nodemon, ahora lo que debemos hacer es armar el esqueleto de nuestra aplicación, es decir que tipo de carpetas y archivos han de ser requeridos para su funcionamiento, una buena práctica es que nuestra aplicación sea lo más modular posible, y esto se logra a través de la subdivisión de los componentes que tiene esta, así también resultará más sencillo realizar cambios o revisar los errores que ocurran.

Esqueleto de la Aplicación

Vamos a centrarnos inicialmente en el back-end, Nuestra aplicación debe contener ficheros que puedan gestionar los distintos requerimientos de una aplicación, para nuestra aplicación en particular vamos a necesitar ficheros que gestionen nuestra base de datos, las rutas, las vistas, ciertas configuraciones generales y los controladores, podemos entonces crear carpetas y dentro de ellas crear los ficheros que hemos de necesitar, entonces las carpetas quedarían de la siguiente forma:

inicio9

 

Hecho esto temporalmente nos vamos a centrar en las carpetas config, routes y services;  la primera contendrá información de importancia general para toda la aplicación, podemos colocar el token de nuestra aplicación, la dirección, usuario y clave de nuestra base de datos y otras tantas cosas más; en la carpeta routes, hemos de colocar todo lo referido a las solicitudes get y post que se hagan desde el cliente, el fichero que contenga tiene que albergar todas las posibles respuestas de las direcciones que se soliciten,  pero dado que de vez en cuando las respuestas pueden requerir de un relativo procesamiento es más adecuado pasar ese procesamiento a un servicio, entonces creo que está demás decir que en la carpeta services se crearán ficheros que se encargarán del procesamiento ya sea de solicitudes o de cálculos extensos.

Carpeta Config

Dentro de la carpeta “configuraciones” creamos un fichero llamado config.js; ya en el fichero creamos una constante llamada config y que es un objeto, este objeto tendrá como propiedades un puerto y una propiedad objeto llamada mongodb que contendrá la dirección hacia nuestra base de datos o incluso los usuarios y clave si es que se tuviera alguna, y además una propiedad referida al token de nuestra aplicación, exportamos el objeto y ya estará disponible para los demás, esto queda de la siguiente forma:

 

esqueleto2

Se estila que el puerto cuando trabajamos en localhost sea el puerto 3000 (aunque en la práctica puede ser cualquiera); sin embargo, cuando este suba a un servidor, será el servidor el que nos entregue un puerto de forma automática o tendremos nosotros que solicitar al administrador del servidor que nos habilite un puerto; si en caso es de forma automática entonces debemos hacer que NodeJs busque ese puerto y eso lo hace a través del objeto global process, este objeto nos provee información y control sobre el actual proceso de NodeJs, sin entrar en profundidad, process posee una propiedad env que retorna un objeto conteniendo el entorno del usuario, eso quiere decir que en process.env.PORT estamos solicitando a nuestro entorno cual es el puerto (PORT) asignado. Esto de igual forma ocurre con la base de datos, en el cual solicitamos la propiedad MONGODB_URI que será la dirección de nuestra base de datos, esto cobra interés cuando estamos llevando ya a la nube nuestra aplicación (y nuestro entorno, donde nos sirven el servidor contiene dichas propiedades), ambas propiedades de nuestro objeto tienen un parámetro (||), tal que en caso de no existir dicha propiedad pues nosotros asignamos tanto el puerto como la ruta.

Debemos de hacer una pequeña observación respecto a como debe ir la ruta, esta ruta es algo especial, es decir la ruta posee un formato que es definida en mongoDB de la siguiente forma:

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]

Esa es la estructura completa, incluso se aconseja en el caso de localhost indicar que estamos en el localhost y el puerto al cual está la escucha mongodb  que es el 27017, finalmente luego de ella se agrega el nombre de la base de datos, como nuestra aplicación no posee usuario ni clave, entonces quedaría como se muestra:

mongodb://localhost:27017/aplicacion

Si la base de datos no existe mongoDB la creará automáticamente.

Cuando ya todas las propiedades del objeto han sido definidas procedemos a exportarlo a través de la instrucción module.exports, esta instrucción de NodeJs hace un tratamiento de los ficheros y su contenido a través de los módulos, tal como mencionamos, los módulos surgen ante la problemática de la complejidad que puede resultar hacer una aplicación y que en JavaScript todos los ficheros comparten un mismo espacio de los nombres globales pudiendo en consecuencia sobrescribirse algunas de ellas por error. Los módulos permiten limitar el alcance de ello evitando conflictos con otros ficheros y solo exponiendo aquello que deseamos del mismo a través de la instrucción exports (aquí encontrarás una explicación mucho más detallada), es así que luego de crear nuestro objeto constante exportamos únicamente ese objeto, esto lo veremos con mayor amplitud posteriormente.

Carpeta Routes

Express es el framework con el cual estamos trabajando nuestra aplicación, nuestra aplicación responde a solicitudes realizadas a través del cliente, estas solicitudes se realizan cada vez que un usuario visita nuestra aplicación y hace click a un enlace o envía información  o la solicita a través de un formulario, en nuestro caso hace referencia a los “endpoints” (rutas para facilitar las cosas) y como el servidor responde a dichas solicitudes. Express trata las rutas a través de su propiedad Router el cual crea una nuevo objeto router, este objeto es el que hace el tratamiento entre los middlewares y los accesos a las rutas, su construcción es de la siguiente forma:

var router = express.Router([options]);

Como vemos las opciones valga la redundancia no son obligatorias, para ello (revisa el link – Router – si estás interesado en saber de que tratan estas opciones); bueno, todas estas instrucciones debemos de plasmarlas en un archivo dentro de la carpeta routes, a este archivo lo llamaremos rutas y será del tipo javascript.

Lo primero que debemos hacer es crear el objeto router, y lo haremos requiriéndolo, en NodeJs un módulo se requiere que es casi lo mismo a importar, pero se hace uso de la palabra reservada requiredentro de require podemos incluir el nombre del módulo, que si está instalado por lo general node js lo autocompletará o podemos indicar la ruta del archivo donde se encuentra los objetos o métodos que deseamos usar, como en nuestro caso ya tenemos instalado express, podemos hacer:

const rutas=require("express").Router();

Lo que está ocurriendo en esta línea es que estamos invocando a express y encadenando la creación del objeto router, si quisiéramos agregar opciones sería entre los paréntesis que deberíamos agregarlo, creado el objeto y que hemos llamado o asignado a una constante rutas, podemos generar respuestas a las solicitudes básicas dentro de un CRUD, que son crear, leer, actualizar y borrar, estas solicitudes se expresan a través de los métodos post, get,put, delete. Cuando un usuario entra a nuestra aplicación, la primera vista que se le presenta es la raíz, es decir que lo primero que lee es la raíz, para ello entonces debemos de hacer uso del método get  el cual tiene el siguiente constructor:

app.get(path,callback,[callback])

Debemos de indicar la ruta, si hablamos de la raíz entonces la ruta es “/“, y el callback es la función que ha de responder cuando el cliente haga solicitud de dicha ruta, ahora vemos que hay la opción de colocar una serie de callbacks, esto es porque más adelante por ejemplo si agregamos una autenticación tendría que pasar primero por saber si se está autenticado y si es que lo está pasar al siguiente callback para enrutar al cliente, pero por el momento solo hemos de usar un callback, entonces nuestra primera respuesta será de la siguiente forma:

rutas.get("/",(req,res)=>{
  res.send("Hola Mundo");
});

Como rutas es nuestro objeto router debemos usarlo para el manejo de las rutas, nota que el callback es una función flecha, que contiene dos parámetros, el primero es req, que hace referencia al request (consulta) que podría hacer el cliente, por ejemplo cuando un usuario se pudiera logear en una aplicación sus credenciales viajan a través del request o si solicitamos una data específica, también viaja por ese medio, cuando la ruta existe, se espera una respuesta que viaje hacia el cliente y esto se hace a través del parámetro res que es el response de la aplicación, dentro de la función flecha colocamos esta respuesta, hemos usado el método send el cual puede enviar objetos, en este caso una cadena de texto.

Con esto ya tenemos el enrutamiento básico de nuestra aplicación, es decir al menos ya podríamos tener una respuesta cuando el cliente visita la raíz de nuestra aplicación, pero debemos hacer que este objeto (rutas) esté disponible de su uso por los demás ficheros, en especial del index.js que es en donde hemos de dar funcionamiento a nuestra aplicación desde el lado del servidor, para ello, usaremos nuevamente la siguiente sentencia:

module.exports=rutas

Bueno, esto seria por el momento, en la siguiente sesión, veríamos un poco de lo que es la conexión con la base de datos e identificar el site map para ver las rutas que hemos de requerir en nuestra aplicación.

WebSockets y Socket.io – Haciendo un Webchat

Las aplicaciones en tiempo real son tema de desarrollo para este año y su expansión se espera para los siguientes, es cuestión de lógica que en la naturaleza humana se desee una interacción más vívida con otros seres humanos, una experiencia que antes era un poco impensable y  que tuvo y tiene como su mejor representante a los videojuegos, los videojuegos en tiempo real nos permiten vivir experiencias muy variadas aun cuando sea una mecánica sencilla de aprender, el hecho de interactuar con otro ser humano y que pareciese que está cerca de nosotros ha marcado el éxito de muchos de ellos como DOTA por ejemplo; también podemos decir que antes la implementación de este tipo de comunicaciones bidireccionales resultaban muy complejas, pero desde que se introdujo los websockets de forma nativa en html5 ha permitido un rápido crecimiento de aplicaciones de tiempo real; uno de los ejemplos más sencillos es la implementación de un webchat, es así que en esta oportunidad hemos de realizarlo, así que, manos a la obra.

Vamos a ir un poco veloz sobre las instrucciones de preparación con la finalidad que en un solo artículo podamos entender todo lo relacionado a un webchat, entonces:

  • Debemos de crear una carpeta con el nombre de nuestro proyecto, con el IDE VSCODE abrimos la carpeta, así también abrimos el terminal de VSCODE y en el hacemos:
npm init --yes
  • En el mismo terminal instalamos los módulos que en producción hemos de necesitar:
npm i express socket.io
  • Módulos que en la etapa de desarrollo son muy necesarios:
npm i -D nodemon
  • Vamos al fichero package.json y agregamos / modificamos las siguientes líneas:

2

  • Creamos la estructura de ficheros de nuestra aplicación (la cual está dentro de la carpeta del proyecto, si haz seguido los pasos a estas alturas ya tienes tanto la carpeta node_modules, y los ficheros package), en este caso debemos de tener la siguiente estructura:

1

Si deseas profundizar sobre el cómo y porqué de estos archivos o módulos, puedes revisarlo aquí.

Nos centramos sobre el fichero index.js que es en donde hemos de implementar nuestro servidor, para ello hemos de usar express y para la comunicación bidireccional hemos de usar socket.io, entonces debemos de requerirlos:

const express=require("express");
const path=require("path");
const Socketio=require("socket.io);
const app=express();

Para nuestra aplicación, no hemos de necesitar un motor de vistas, sino que las páginas serán cargadas una sola vez y sobre ellas se ha de trabajar, es por ello que debemos de decirle a express que se han de usar archivos estáticos y que estos serán despachados desde la carpeta “public“:

app.use(express.static(path.join(_dirname,"frontend/public")));

Ahora debemos de poner a la escucha nuestro servidor, pero hay que tener consideración de lo siguiente, nuestra aplicación podría estar alojada en la nube, por lo que de vez en cuando es el servidor quien asigna de forma automática el puerto sobre el cual la aplicación estará la escucha, cosa que no ocurre muy a menudo en nuestro localhost y que por lo general se estila usar el puerto 3000, entonces debemos hacer que pueda tener ambas opciones:

let servidor=app.listen(process.env.PORT || 3000,()=>{
  console.log("Estamos en funcionamiento");
})

app.listen nos devuelve un http.server que es el servidor listo que ha de usar socket.io, es por ello que lo asignamos a una variable servidor.

Hasta este punto ya hemos desarrollado todo lo relacionado a nuestro servidor, desde aquí solo resta usar socket.io; cuando hablamos de comunicación bidireccional, esta se implementa en socket.io a través de eventos, de los cuales existen sockets que están a la escucha o emitiendo dichos eventos. Para implementarse socket.io se compone de dos partes:

  • Un servidor integrado con (o montado sobre) NodeJs Http.Server (lo que nos devuelve el app.listen).
  • Una librería del lado del cliente que carga sobre el navegador

De lado del servidor

Desde el inicio hemos requerido el módulo, ahora lo que debemos es crear el servidor socket.io, por ello:

const io=Socketio(server)

Esta instrucción la encontramos aquí, y tiene 3 formas de implementarse:

const io=require("socket.io")();
o
const servidor=require("socket.io");
const io=new Server(httpServer,[opciones]);
o
const servidor=require("socket.io");
const io=servidor.listen(http.server,[opciones]);

Aunque pareciese un tanto confuso, opcionalmente puedes optar usar la palabra reservada “new” o hacer que escuche al http.server con el método listen.

Implementado el servidor, ahora debemos recordar que socket.io trabaja a través de eventos, y el primer evento que el servidor debe escuchar es cuando se ha realizado una conexión desde el cliente, este evento se denomina “connection” y se implementa a través del método on, este método tiene el siguiente constructor:

socket.on(evento_nombre,callback);

Entonces lo implementamos de la siguiente forma:

io.on("connection",socket=>{
  .....
});

El método on nos devuelve un socket, y lo vemos incluso cuando mostramos el constructor del método, pero ¿Qué es un socket?, usando la misma definición de socket.io:

El socket es la clase fundamental para la interacción con los clientes, un socket pertenece a un “namespace” (por defecto “/”) y utiliza un cliente para comunicarse“.

Es decir que sobre sockets hemos de emitir y estar a la escucha de los eventos que generemos. Entonces cuando se estableció ya una conexión, debemos de ponernos a pensar en la estructura que debe de tener nuestro chat. Nosotros debemos de poder recibir mensajes y llamaremos a ese evento: “chat_mensaje“, cuando el servidor escucha un mensaje, debe poder replicarlos a los demás, es decir debe emitirlo a los demás clientes y como se trata del mismo mensaje podemos llamar de igual forma al evento como “chat_mensaje“, quedando entonces:

io.on("connection", socket=>{
 socket.on("chat_mensaje", data=>{
   io.sockets.emit("chat_mensaje",data);
});
});

14

Todos los eventos se generan a partir de que se establece una comunicación con el cliente, es por ello que los demás métodos están dentro del método “on” asociado al servidor socket.io; recordemos que este “on” asociado al servidor nos devuelve un socket, entonces hemos colocado este socket a la escucha (a través de asociarlo a un método “on“) de un evento que se llama “chat_mensaje“, pero ahora este on asocia al callback un parámetro que puede ser de cualquier tipo (esencialmente ese es el dato que envía el cliente), pero como mencionamos cuando se recibe un mensaje este debería ser retransmitido a todos los demás, es ahí (nota los anidamientos) que se “emite” un evento, el emitir un evento se realiza a través del servidor hacia todos con el método “emit” el cual tiene el siguiente constructor:

socket.emit(evento_nombre,[data],[f(x)])

Como podemos observar el constructor es similar al método “on“, dado que buscamos transmitir los mensajes a los demás clientes y hacer lo más instructivo el ejemplo lo llamamos de la misma forma:

io.sockets.emit("chat_mensaje",data);

Pero observamos que hay algo de particular cuando decimos io.sockets, como ya sabemos io ya es el servidor de socket.io y que un socket está asociado a un namespace, entonces cuando colocamos el término sockets al servidor de socket.io estamos haciendo referencia al namespace de la raíz, esto tiene lógica pues desde el servidor y su raíz es que hemos de comunicar a todos los clientes el mensaje que está contenido en data. Entonces por el momento es todo lo que tenemos que hacer en el lado del servidor.

De lado del Cliente

Tal como hemos observado el árbol de ficheros en la carpeta “public” tenemos un index.html que debe tener la siguiente forma final:

15

En la cabecera tenemos que hemos agregado la fuente Nunito que nos proporciona google-fonts, además hemos agregado nuestra propia hoja de estilos en el fichero main.css, dado que es una hoja de estilos, no entraremos en profundidad al respecto de ello:

16

Entonces debemos de centrarnos en el contenido dentro de el id=chat_container, la estructura la es la siguiente:

17

El chat_container, es el contenedor de todo el chat y dentro de él nos encontramos con el chat_ventana que contiene dos div uno (salida) donde hemos de mostrar los mensajes que hagan otros usuarios y el segundo (acciones) con el fin de mostrar cuando se esté ejecutando alguna acción, como la de “escribir“, finalmente los inputs donde hemos de colocar nuestro usuario y mensaje.  

Finalmente llegamos a la zona de los scripts, y podemos observar que tenemos una librería denominada socket.io.js, esta librería es otorgada por el servidor para que el cliente pueda comunicarse con él, ya que recordemos que hasta el momento no hemos implementado como ha de conectarse el cliente con el servidor, pues lo hará a  través de esta librería, incluso si colocamos en el navegador la ruta obtendremos lo siguiente:

3.png

Con todo esto ya tenemos finalizado el index.html, ahora pasamos a revisar el fichero de JavaScript que se denomina chat.js.

Lo primero que debemos de hacer es obtener el objeto de socket.io para el cliente a través del término io de la siguiente forma:

const socket=io();

Si revisamos el constructor de io tenemos:

io([url],[opciones])

Observamos que tenemos la posibilidad de ingresar una ruta específica, esto es muy útil cuando trabajamos con diferentes espacios, como por ejemplo un chat diferente para cada área de la empresa, en este caso cuando no le colocamos un ruta por defecto esta será “/” la raíz, ahora bien lo que nos devuelve es un socket, ¿recuerdan? el socket es para todo y es con este mismo socket que estaremos a la escucha o emitiendo algún evento.

Hecho esto, vamos declarar las variables que tenemos por cada uno de los id:

let mensaje=document.getElementById("mensaje");
let usuario=document.getElementById("usuario");
let boton=document.getElementById("enviar");
let salida=document.getElementById("salida");
let acciones=document.getElementById("acciones");

Debemos asignar al botón un evento click:

boton.addEventListener("click",function(){
 e.preventDefault();
......
.....
});

Cada vez que se crea un mensaje y al enviarlo haciendo click, internamente debemos de emitir un evento relacionado al socket, pero este evento ya ha sido definido como “chat_mensaje“, entonces dentro del listener del botón hacemos:

socket.emit("chat_mensaje",{
 usuario:usuario.value,
 mensaje:mensaje.value
});

Como podemos observar conjuntamente con la emisión del evento estamos enviando un objeto que contiene tanto el valor del input usuario así como el mensaje (este objeto llegará al servidor y se retransmitirá a todos los clientes conectados). Ahora debemos de ponernos en la situación que nosotros no hemos emitido el mensaje pero si otro cliente, entonces implica que debemos de también estar a la escucha de un evento que será “chat_mensaje“, pero este ya debe estar fuera del listener del botón, entonces:

socket.on("chat_mensaje", function(data){
 salida.innerHTML+="<p><strong>"+data.usuario+"</strong>:"+data.mensaje;
 acciones.innerHTML="";
});

Cada vez que se escucha el evento “chat_mensaje” se agrega los datos recibidos como parte de una estructura html dentro del div salida, también vemos que el div acciones agrega una estructura vacía, y ¿Qué es lo que queremos hacer con el div acciones?, pues queremos que cuando un cliente esté digitando un mensaje, este se observe, para ello debemos de agregar un evento relacionado al teclado de la siguiente forma:

mensaje.addEventListener("keypress",function(){
  socket.emit("chat_escribiendo",usuario.value);
});

socket.on("chat_escribiendo",function(data){
 acciones.innerHTML="<p><em>"+data+"</em> está escribiendo</p>";
});

Este evento de teclado está asociado al div mensaje, lógico, cuando estemos digitando debe dispararse el evento, cuando ocurre el evento el socket emite su propio evento enviando el valor del usuario (básicamente el nickname que se colocó), pero tal como emite debe estar a la escucha del mismo evento (esto cuando otro cliente es el que escriba), cuando ello ocurra, debe en el div acciones recuperar la data y escribir un fragmento html. El lado del cliente queda finalmente:

19

En el lado servidor nuevamente

Hecho esto queda agregar este evento en el lado del servidor, entonces en index.js y dentro de:

io.on("connection", socket=>{
 socket.on("chat_mensaje", data=>{ 
    io.sockets.emit("chat_mensaje",data); 
 });
 socket.on("chat_escribiendo", data=>{
 socket.broadcast.emit("chat_escribiendo",data);
}); 

});

Notamos que ahora estamos usando la palabra reservada broadcast, esto responde a la siguiente lógica, cuando vamos a emitir el evento que estamos escribiendo un mensaje, no nos importa que nosotros seamos informados que estamos escribiendo un mensaje, sino solo los demás clientes, entonces broadcast es un modificador que hará ello.

Esto es todo lo que debemos realizar para tener nuestro webchat, podemos ver una imagen del resultado:

18

P5 Play El Dinosaurio de Google parte final

Anteriormente:

Hasta el momento ya tenemos todas las clases que son necesarias para nuestro juego, hemos creado el dinosaurio, los cactus y las aves, hemos observado que tanto los cactus y las aves tienen los mismos métodos con poca variación en su algoritmo, finalmente lo que resta es colocar todas las instancias de cada una de las clases en el fichero main.js, y ejecutar sus métodos en las funciones preload(), setup() y draw().

Al inicio del fichero es donde hemos de crear las instancias, una instancia de una clase en JavaScript se hace de la siguiente forma:

var rex= new Dinosaurios();
var planta=new Cactus();
var ave=new Aves();

JavaScript nos hace sencillo la creación de las instancias, pero ¿Notas algo diferente?, ahora estamos usando el prefijo var en lugar de let ¿Cuál su diferencia y cuando usarlo?, pues su principal diferencia radica en el alcance de la variable, cuando nosotros declaramos una variable con el prefijo let, limitamos la variable al bloque donde esta se encuentre; sin embargo, al usar el prefijo var, la variable es de alcance global no importando el bloque en el que se encuentre y dado que deseamos que nuestras instancias estén disponibles para cualquier función las declaramos de alcance global (esto es un tanto desaconsejado en términos que solo se debería usar variables de alcance global cuando ya sea inevitable no hacerlo), aquí encontrarás una pequeña reseña de ello. Ahora bien, hasta el momento solo tenemos las funciones setup() y draw  en el main, ahora debemos de agregar la función preload(), recordemos que preload se llama antes de setup() y hemos de usarlo para la carga de los recursos de nuestro juego, entonces inicialmente queda así:

final1Recordemos que en cada clase hay un método que se llama cargar, el cual está enfocado en la carga de los recursos necesarios para el juego, también tenemos un método que hace referencia a la creación, en la clase Dinosaurio se llama crear y en el cactus y las aves se llama crearGrupo, todos los métodos de carga debemos de ubicarlos en la función preload y los de creación dentro de setup quedando de la siguiente forma:

final2 Entonces ya hemos cargados los recursos y creado los sprites; sin embargo, tenemos que colocar los métodos que supervisan el movimiento, la muerte y las colisiones, estas funciones deben ir en draw()  quedando de la siguiente forma:

final3

Vemos que hay una función que no está asociado a alguna instancia, esta función pertenece a P5 Play (drawSprites)  y recibe un parámetro de grupo, pero en caso de no recibirlo se encargará de ejecutar todos los sprites en el orden que se encuentren.

Hasta este punto ya hemos colocado todos los métodos de las clases que hemos creado, pero tenemos aun pendientes unas cuantas correcciones, recordemos que cuando explicábamos la muerte del dinosaurio vimos que al ser verdadera la colisión esta llamaba a la función  juegoTerminado(), pero esta función aún no la hemos creado y tampoco se iba a crear dentro de la clase dinosaurio, ya que esta función estaría encargada de detener todo el juego, entonces su campo de acción es global por lo que debe ser creada en el fichero main.

juegoTerminado

Esta función debe estar en capacidad de hacer lo siguiente, debe cambiar la animación del dinosaurio a muerto, así también debe comunicar a quien lo requiera que se ha producido un gameOver por así decirlo y sobretodo debe poder detener la actualización de los sprites, para ello observemos lo siguiente:

final4

El cambiar la animación del dinosaurio a través de su instancia “rex“, rex debe acceder a la propiedad “dino“, recordemos que dino es el sprite de la clase y sobre él ha girado todos los métodos de P5 Play, para cambiar la animación debemos de usar el método changeAnimation() que recibe como parámetro el key que le asignamos a cada una de las animaciones al momento de crearlas, también el uso de una variable denominada gameOver esta debe ser declarada e inicializada en false en al mismo nivel de las instancias de las clases de la siguiente forma:

var gameOver=false;

Se inicia en falso ya que al iniciar el juego es imposible que se tenga un gameOver pero cuando el juego finalice, gameOver debe ser verdadero, cuando finalice el juego de la misma forma debemos de comunicar a p5play que debe detener la actualización de los sprites esto se hace con la función updateSprites() indicando como parámetro “false“. Ahora ocurre lo siguiente, tenemos a nuestro dinosaurio funcionando y de pronto este muere, y entonces surge la inquietud ¿Cómo hacemos que inicie un nuevo juego?, para ello debemos de crear una función similar a juegoTerminado y la llamaremos juegoNuevo.

juegoNuevo

Esta función debe estar en capacidad de remover todos los sprites que se encuentren en la escena, ya que se trata de un juego nuevo todas dinámicas deben de reiniciarse, la variable gameOver debemos asignarle un valor de falso y  tenemos que reactivar la actualización de los sprites, esto lo hacemos de la siguiente forma:

 

final5

Tan igual que en “rex” la planta y el ave deben acceder a quien representa al sprite, el cual es cactusGrupo y aveGrupo respectivamente, debe entonces usarse en ellos el método removeSprites() que removerá todos los sprites que contenga el grupo, de forma similar con las aves; cambiamos el valor de gameOver, pues al iniciarse un juego este debe ser falso,  y entregamos como parámetros a la función updateSprites un true; para que nuevamente todo sea puesto en marcha; ahora no es que apenas el dinosaurio muera es que el juego lanza un evento que llama a la función juegoNuevo, debemos hacer que exista un botón en el cual un evento esté a la escucha de cuando se hizo click en él, además podemos de agregar un letrero de gameOver y ¿Por qué no? el puntaje, entonces vamos en un pequeño orden, agreguemos el puntaje:

Puntaje

El puntaje es un texto que hará uso de una fuente, la fuente debe ser cargada en el preload, entonces declaramos una variable global denominada fuente, esta fuente va ser afectada directamente por el puntaje que se logre mientras el dinosaurio esté vivo, entonces podemos decir que existe un contador que inicia en cero cuando arranca el juego:

var texto;
var fuente;
var contador=0;

Para cargar la fuente vamos a preload y hacemos:

fuente=loadFont("./recursos/imagenes/GeBody.ttf");

loadFont es un método de P5Js encargado de cargar las fuentes. Este texto debe ir con cierto estilos, para ello creamos una función miTexto(), dentro de miTexto colocamos:

function miTexto(){
     textSize(36);
     fill("#ED225D");
     textFont(fuente);
}

y a esta función la colocamos en el setup(), es decir:

function setup(){
.....
.....
miTexto();
}

Como el puntaje se ha de actualizar constantemente y este aumenta en función del tiempo o distancia que haya recorrido el dinosaurio, significa que si hemos de escribir un texto y este se encuentre en constante modificación, para ello la mejor forma es hacerlo dentro del draw, entonces en draw hacemos:

text(""+contador,width-100,50);

Pero esto por si solo no es suficiente, ya que el contador debe detenerse cuando gameOver sea true,  además si observas solo estamos concatenando el texto vacío con el contador, todo ello a través del método text de P5Js, entonces lo que debemos hacer es implementar un setInterval en el setup que revise cada cierto tiempo si el gameOver es true o false y en caso de ser false el contador aumente en uno, entonces en el setup hacemos:

setInterval(function(){if(gameOver==false){contador++;}},100);

Además cuando gameOver sea true ya no se va aumentar el valor del contador, pero debemos también que cuando inicie un nuevo juego este contador deba volver a cero, entonces en la función juegoNuevo() agregamos:

contador=0;

Entonces todo lo del puntaje queda de la siguiente forma:

final6

El Botón

Hasta el momento tenemos el puntaje, pero no tenemos como llamar a la función juegoNuevo, esto comentamos que lo haríamos a través de un botón, entonces manos a la obra, conjuntamente con el botón debe salir una imagen que hable del game over , entonces creamos una variable a la altura de las instancias de las clases de esta forma:

var boton;
var imagenGameOver;

En la función preload hemos de cargar el recurso de la  imagen de game over de la siguiente forma:

imagenGameOver=loadImage("./recursosimagenes/gameOver.png");

Para el botón hemos de usar un artilugio en el que a una imagen le daremos la acción de un botón, para ello a la variable botón la inicializamos en setup de la siguiente forma además de agregar la posición:

boton=createImg("./recursos/imagenes/reset.png" ).position(width/2,height/2);

El método que hemos empleado para crear la imagen es createImg  es un método de P5DOM el cual crea un tag img en el DOM y recibe como parámetro la dirección de la imagen, a esto hemos encadenado la posición a través del método position también de p5DOM y que recibe como parámetros la ubicación en X e Y. Queremos que nuestro botón esté al centro del canvas, pero que al iniciar el juego el botón esté escondido, para esconderlo debemos de usar el método hide de P5DOM entonces en setup de igual forma:

boton.hide();

Además de que esté escondido, debemos de hacer que esté a la escucha del evento click (es decir cuando sea presionado), entonces al ser un elemento de p5DOM podemos agregarle un oyente a través de la  función mousePressed el cual recibe como parámetro una función que se llamará cuando el evento ocurra, y la función que se llamará sera a juegoNuevo, entonces:

boton.mousePressed(juegoNuevo);

Ahora debemos de asegurarnos que cuando la variable gameOver sea true el botón deje de estar escondido y además que se agregue la imagen de game over, para agregar la imagen hemos de usar el método  image de P5Js que recibe como parámetros la imagen que está pre-cargada en preload y la posición (como verás la posición está un poco desfasada del centro con el fin dar la apariencia que se despliega en el centro) , como debemos de verificarlo en cada iteración lo más conveniente es colocarlo dentro del draw():

if(gameOver){
boton.show();
image(imagenGameOver,width/2-30,height/2+30);
}

Por último, cuando el usuario presione el botón  y se llame a juegoNuevo, el botón debe de ocultarse de nuevo, entonces el método hide debe ser agregado dentro de la función juego nuevo:

function juegoNuevo(){
.......
.......
boton.hide();
}

 

Un último detalle

Para agregarle mayor interés al juego vamos hacer que la velocidad de los cactus y de las aves esté en un aumento progresivo tal que cuando se pierda le restauramos su velocidad inicial, para hacer ello debemos de recurrir nuevamente al setInterval, entonces vamos a la función setup y hacemos:

function setup(){
........
......
setInterval(function(){planta.velocidadCactus-=0.2;ave.velocidadAve-=0.2},3000);
}

 Es decir estamos haciendo ambas velocidades más negativas en 0.2 cada 3 segundos, pero ahora cuando se pierda debemos de restaurar las velocidades base, entonces en juegoNuevo debemos:

function juegoNuevo(){
.....
......
planta.velocidadCactus=-4;
ave.velocidadAve=-4;
.......
......
updateSprites(true);
boton.hide();
}

Esta modificación o restauración de la velocidad debe estar antes de la actualización de los sprites, entonces finalmente el juego queda de la siguiente forma:

final7

final8

 

Ahora solo basta con ejecutar en el terminal la instrucción http-server y se creará un servidor y copiamos el enlace y lo abrimos en el navegador, para ello debes de tener instalado el modulo http-server, sino lo tienes en tu terminal de node la cual está incorporada en VSCODE haces los siguiente:

npm i http-server

final9

Eso sería todo respecto al juego del dinosaurio de google, espero que lo hayan podido disfrutar, saludos.

 

Desarrollo de un CRUD – 1

Introducción

Todos los caminos nos llevan a Roma, y en el camino del desarrollo nos encontramos con diversas tecnologías  convergentes hacia un mismo propósito, es así que cuando se empieza a programar uno sueña en que sabiendo HTML (he iniciamos pensando que ello es saber programar) ya está todo lo necesario para sumergirnos en este mundo, pero nos damos cuenta que ese mundo, realmente era un mundo, tan amplio y más allá de lo que podemos ver en nuestro horizonte y de ese horizonte decidimos tomar un pedazo diminuto y nos embarcamos a la mar hacia allá. Dentro de las muchas aplicaciones web existen los CRUD, los CRUD no son más que el acrónimo de “crear, leer, actualizar y borrar” dentro de una aplicación que necesariamente haga uso de bases de datos, dentro de las muchas formas en que es posible hacerlo, existe una en la que podríamos decir está marcando tendencia ya sea porque es nueva (eso es relativo) o porque tiene un mejor rendimiento respecto a lo convencional, ya que esos aspectos dependen mucho del ojo de quien lo mira no voy a entrar en mucho detalle de porque se debe hacer de esa forma, sino te contaré un poco la razón por la cual lo elegí; creo que como muchos inicié desde el lado front-end  de una aplicación, cuando tenía que finalmente pasar hacia el back-end me di con la sorpresa que tenía que aprender un nuevo lenguaje como PHP, lo cual ya representaba algo tedioso para mi dado que estaba aprendiendo tanto JavaScript como Java, me preguntaba si acaso con un mismo lenguaje no pudiera ser posible hacer todo lo relacionado a una aplicación web y la respuesta no tardó en llegar, esta respuesta vino diciendo que acoplando un conjunto de tecnologías cada una especializada en un determinado campo, esto  era posible y sobretodo bajo un mismo lenguaje que era JavaScript, como para mi fue en cierta forma la panacea, esta vez te traigo un ejemplo de desarrollar lo más cercano a una aplicación completa, veremos si el tiempo nos alcanza para incluso darle cierta autenticación a nuestra aplicación pero por el momento el alcance está definido solo hasta que se ponga en marcha, inicio esta serie de artículos queriendo darte una orientación y no necesariamente sea esta perfecta, ya que también me encuentro en constante aprendizaje. Bueno ya empecemos.

Instalación

  • NodeJs: Al ser JavaScript es obvio que hemos de usar Node Js el cual en su misma página dice: “Es un entorno de ejecución para JavaScript construido con el motor JavaScript V8 de Chrome” el cual funciona de forma perfecta para la capa de servidor, es esencial que tengas instalado node js.

1_LSfLSMQ1kPuHnyCPLNEKgQ.png

  • Visual Studio Code: Es el editor estrella del momento, fue la gran jugada de Microsoft para este año que pasó 2018, aunque ciertamente puedes usar el editor que mejor prefieras la serie de pantallas que se mostrarán serán hechas bajo este entorno, así que es solo una recomendación para reducir el estrés de ir aprendiendo algo (descarga).

opengraph-home.png

  • MongoDB: MongoDB es una base de datos NoSQL orientado a documentos y cuya particularidad es que guarda las estructuras de datos en documentos similares a JSON,

inicio3.png

Inicio

Antes de abrir el editor creamos una carpeta con el nombre que deseamos de nuestra aplicación, luego de ello podemos abrir el VSCode  y en “Archivo->Abrir_carpeta” buscamos la carpeta que hemos creado, esa carpeta será donde toda nuestra aplicación será colocada. Cuando ya estemos en la carpeta vamos al menú  “Ver->Terminal“, al hacer ello se nos desplegará una sección en la parte inferior de VSCode, VScode reconoce de forma automática las instrucciones en node ya que tiene realmente un terminal incorporado. Cuando ya se han hecho todos los preparativos en la terminal escribimos lo siguiente:

npm init --yes

Esta instrucción lo que hará es crear el archivo package.json, en el cual se almacenará toda la información relacionada a nuestra aplicación incluyendo los módulos que usemos, si revisamos el archivo veremos que es algo parecido a esto:

inicio1

Lo particular hasta el momento es que  el elemento main hace referencia a index.js, y es en index.js donde plasmaremos todo lo necesario para que nuestra aplicación esté en funcionamiento. Ahora, para nuestra aplicación hemos de necesitar de otros módulos para trabajar, por ejemplo, necesitamos un motor que maneje las vistas, un framework que nos facilite la creación de una aplicación web e incluso otro que nos ayude con la comunicación de nuestra base de datos. Lo esencial es la instalación del framework, para ello vamos a usar express jstal como dicen los creadores de express, express es: “Una infraestructura de aplicaciones web Node.js mínima y flexible que proporciona un conjunto de características para las aplicaciones web y móviles“, para los mortales y que nos resulta más familiar express es el php de node js.

express

Luego necesitaremos a pug js, pug js  es un motor de plantillas enfocado en hacer más rápida la codificación de html y ha sido implementado con JavaScript para trabajar con NodeJs, básicamente es un preprocesador de código y que entrega un html, cuando un usuario haga solicitud sobre una página el servidor debe de responder entregando información personalizada acorde a cada usuario y es en esas circunstancias en que lo que se entregue responde a variables que deben estar insertadas en el html, y es ahí  que pug cobra especial interés.

pug.png

Finalmente y por el momento, hemos de instalar mongoose, mongoose es un marco de JavaScript que se usa comúnmente en una aplicación NodeJs con una base de datos de MongoDB, podríamos decir que es un modelador de datos de objetos (ODM en inglés) y que es una librería para MongoDB (por cierto debes tener instalado ya como se indicó mongoDB).

mongoose.png

Otro módulo que más es un tanto auxiliar será morgan, morgan nos permite ver en consola cuáles son las solicitudes de parte del cliente sean estas un get o un post y las respuestas que se han entregado.

Todos estos módulos son instalados con la siguiente instrucción:

npm i express mongoose pug morgan

Hecho  esto ahora debemos de instalar un módulo más que nos ha de ayudar solo durante el desarrollo de la aplicación, este módulo se llama nodemon y lo que hace básicamente es estar a la escucha de cualquier cambio que nosotros realizamos sea en el cliente o en el servidor, a excepción de si es una vista, ocurre que si no tuviéramos este módulo con cualquier cambio que hagamos en nuestro servidor este tendría que ser reiniciado manualmente, para ello nodemon se hace cargo de eso. Al ser un módulo que se usa solo en la etapa de desarrollo debemos de indicar ello, entonces la instrucción será:

npm i -D nodemon

La -D está haciendo referencia a que es una dependencia de desarrollo, finalmente nuestro package.json debería lucir de la siguiente forma:

inicio6

Vemos ahora que se han creado los apartados de “dependencies” que hace referencia  a las módulos instalados y que serán usados en el modo producción  y a “devDependencies” que hace referencia a los módulos que sólo serán usados durante la etapa de desarrollo (en la imagen no se aprecia pues, ya tengo instalado de forma global a nodemon), así también cuando todos los módulos han sido instalados podemos observar que se ha creado una carpeta denomina node_modules, es en esa carpeta donde estarán todos nuestros módulos.

Luego que hemos instalado todas las dependencias, procedemos a crear el esqueleto de nuestra aplicación, (express trae una pero es demasiado amplia, bueno quizá porque debe responder a todo de inquietudes) nosotros hemos de usar el siguiente esquema, podemos decir que una aplicación tiene un lado front-end y un lado back-end y dentro del backend estará el index.js, dado que el index.js  que es el principal archivo de gestión, . Entonces, nuestro esqueleto debería quedar básicamente de la siguiente forma:

inicio7

Finalmente (creo que lo voy escribiendo 3 veces) queda modificar la sección “scripts” de nuestro package.json, quedando de la siguiente forma:

inicio8

¿Qué hemos agregado? hemos agregado la propiedad “start” que es usada por la mayoría servicios para iniciar la aplicación, en start se agrega la ruta donde se encuentra nuestro index.js y que esta ejecuta con node, también hemos agregado una propiedad definida como “dev” con la ruta respectiva pero con la particularidad que esta se ejecuta con nodemon. Desde este punto muy poco hemos de tocar el package.json, así que en la siguiente entrega procederemos a configurar nuestro servidor a través de express.js en el fichero index.js.