https://d226lax1qjow5r.cloudfront.net/blog/blogposts/traffic-alert-through-sms-using-vonage-and-google-maps-api/traffic-alert.png

Alerta de tráfico a través de SMS con Vonage y Google Maps API

Publicado el March 2, 2023

Tiempo de lectura: 11 minutos

Visión general

En este mundo ajetreado en el que las piezas de la vida se mueven sin cesar, los usuarios valoran recuperar la información de la forma más cómoda posible. Esto no siempre es fácil, sobre todo en países como la India, donde la cobertura de la red de Internet en zonas remotas es más débil.

Supongamos, por ejemplo, que estás a punto de salir de la oficina para volver a casa después de un día ajetreado y quieres comprobar si hay tráfico en tu ruta, pero tu conexión a Internet es lenta. ¿Qué pasaría si pudieras enviar un SMS con tus posiciones de salida y llegada y obtener al instante la información sobre el tráfico? Te salvaría la vida.

En este artículo, voy a mostrar cómo se puede crear una alerta de tráfico a través de SMS utilizando Vonage y Google Maps API en Node.js.

Requisitos previos

Antes de empezar, asegúrate de haber instalado lo siguiente:

  • Node.js. Node.js es un entorno de ejecución JavaScript multiplataforma de código abierto.

  • ngrok - Se requiere una Account gratuita. Esta herramienta permite a los desarrolladores exponer a Internet un servidor de desarrollo local.

  • CLI de Vonage - Una vez instalado Node.js, puedes usar npm install -g @vonage/cli para instalarlo. Esta herramienta te permite crear y administrar tus aplicaciones de Vonage.

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

Una vez que hayas creado una Account, podrás encontrar tu API Key y API Secret en la parte superior del Panel de API de Vonage.

Vonage API dashboard

Una vez que haya recibido la Clave API y Secreto de la APIpuede utilizarlos para la SMS API.

API de Google Maps

También necesitaremos API de dirección de Google. Cree una Account de Google e inicie sesión para acceder a créditos gratuitos para utilizar la API de Google y la Clave API.

GCP account and API Key

Para obtener la clave API de Google Maps:

  • Ir a la Plataforma Google Maps > Página de credenciales.

  • En la página Credenciales, haga clic en Crear credenciales > Clave API. La Clave API muestra su recién creada clave API.

  • Haga clic en Cerrar. La nueva clave API aparece en la página Credenciales en Claves API.

Desglose de problemas

La implementación de esta aplicación puede dividirse en tres partes:

  1. Recibir y leer el mensaje SMS.

  2. Extrae las ubicaciones de origen y destino del texto del SMS y obtén los detalles del tráfico de la API de Google Maps.

  3. Procesa los datos de tráfico y devuelve el SMS en un formato textual y legible por humanos.

Configurar

Como nuestra aplicación se desarrollará en Node.js, asegúrate de tener Nodejs instalado en el sistema.

Instale las dependencias ejecutando este comando en su terminal:

npm install express body-parser dotenv

Crea un único archivo llamado App.js que ejecutará la aplicación en el puerto 3000 y manejará todo el procesamiento dentro de él.

Hemos utilizado el paquete dotenv paquete npm para obtener las variables de entorno. Usando esto, podemos almacenar secretos de forma segura.

const app = require('express')()
const bodyParser = require('body-parser')

if (process.env.NODE_ENV !== "production") {
    require("dotenv").config();
}

app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))

app.listen(process.env.PORT || 3000, "127.0.0.1", () => {
    console.log("Server Running on Port ", process.env.PORT || 3000);
});

Para almacenar y acceder a las variables de entorno, cree un archivo .env en su directorio raíz y añada las propiedades.

PORT = 3000

Se puede acceder a estas propiedades mediante process.env.PORT

Recibir SMS

El primer paso es recibir el SMS y leerlo. Vonage proporciona un SDK Node.js para usar clientes de SMS dentro de nuestra aplicación Node.

Puede seguir este tutorial sobre cómo puedes recibir el Mensaje en una aplicación Node.js

npm install @vonage/server-sdk

El siguiente paso es configurar la API de entrada y agregarla a la consola de Vonage. De esta manera, cada vez que se envíe un SMS a nuestro número, se llamará a la API de entrada y podremos leer ese SMS.

Hay un tutorial detallado sobre cómo configurar la API de entrada y leer los SMS.

La API de entrada es lo que exponemos a cualquier aplicación de terceros a la que envían los datos.

Cualquier GET o POST que reciba nuestra API /webhooks/inbound-sms reciba será pasada a la función handleInboundSms función

app.route("/webhooks/inbound-sms")
.get(handleInboundSms)
.post(handleInboundSms);

function handleInboundSms(request, response) {
    // reads the SMS body
    const params = Object.assign(request.query, request.body);

    // process the SMS text
    getTrafficDetailsAndSendSMS(params);

    // notify that we have received SMS
    response.status(204).send();
}

Para que esta API de entrada funcione, tendremos que poner en marcha nuestra aplicación. Podemos hacerlo utilizando ngrok.

Para configurar la aplicación en vivo, primero configurar ngrok.

Y luego ejecuta la aplicación node localmente

node App.js "Server Running on Port 3000"

Una vez que la aplicación local se está ejecutando, podemos asignarla y ponerla en marcha utilizando ngrok.

ngrok http 3000

Resultado esperado:

Ngrok CLI output

Una vez que la aplicación esté activa, recibiremos una URL pública, por ejemplo https://58c8-103-179-3-99.in.ngrok.io

Agrega esta URL al panel de Vonage para que podamos escuchar la API entrante.

Vonage SMS dashboard

Ahora que ya podemos recibir el SMS, procesemos el texto y obtengamos la información de tráfico de Google.


Obtener la información de tráfico entre dos rutas utilizando la API de Google Maps

Para extraer la información de origen y destino de los SMS que recibimos a través de la API de entrada, es necesario que el texto del SMS tenga un formato determinado para que se pueda analizar mejor. He creado una plantilla sencilla que es más fácil de procesar.

Por ejemplo, para recibir información sobre el tráfico entre Bombay y Pune, creemos el siguiente SMS:

Traffic between Mumbai and Pune

En el ejemplo anterior Mumbai es el origen y Pune es el destino.

En la función getTrafficDetailsAndSendSMS(params); podemos tomar el cuerpo del SMS y extraer la fuente.

function getTrafficDetailsAndSendSMS(params) {
    // get the source and destination by parsing the text
    const { origin, destination } = parseText(params);

    // get the traffic details and routes
    const routes = getTrafficDetails({ origin, destination });

    // send back the SMS
    sendSMS(params.msisdn, routes);
}

Analizar texto

Para encontrar las rutas, tendremos que extraer el origen y el destino de los SMS que hemos recibido.

El método parseText(params) extrae el origen y el destino del texto del SMS y lo devuelve.

function parseText({ text }) {
    let sampleText = "Traffic between mumbai and pune";
    if (text) {
   	 sampleText = text;
    }

    sampleText = sampleText.trim();
    const characters = sampleText.split(" ");
    const origin = characters[2];
    const destination = characters[4];

    return { origin, destination };
}

Obtenga información sobre el tráfico

Ahora esto source y destination se pueden pasar a la API de matriz de distancias de Google que obtiene los detalles del tráfico.

Para realizar una llamada a la API desde nuestra aplicación necesitaríamos axiosasí que vamos a añadir esa dependencia.

npm install axios

Para obtener la información de tráfico tenemos que pasar el parámetro departure_time en el parámetro de consulta. Estamos pasando now para obtener los detalles del tráfico actual.

Además, hemos establecido el mode como driving. Esto se puede hacer configurable y puede ser aceptado a través del SMS junto con las rutas para proporcionar una mejor experiencia de usuario.

async function getTrafficDetails({ origins, destinations }) {
    try {
   	 const YOUR_API_KEY = process.env.GOOGLE_MAP_API_KEY;
   	 const mode = "driving";
   	 const departure_time = "now";

   	 var  config = {
   		 method:  "get",
   		 url:  `https://maps.googleapis.com/maps/api/directions/json?origins=${origins}&destinations=${destinations}&mode=${mode}&departure_time=${departure_time}&language=en-US&key=${YOUR_API_KEY}`,
   	 };

   	 let response = await axios(config);
   	 response = await response.data;

   	 const  routes = getRoutes(response);
   	 return  routes.join(" \n\n ");
    } catch (e) {
   	 console.error("There was some error while getting routes details", e);
    }
}

A continuación se muestra un ejemplo de respuesta de la API de Google Maps.

const response = {
  	routes: [
    	{
      	bounds: {
        	northeast: { lat: 41.8781139, lng: -87.6297872 },
        	southwest: { lat: 34.0523525, lng: -118.2435717 },
      	},
      	copyrights: "Map data ©2022 Google, INEGI",
      	legs: [
        	{
          	distance: { text: "579 km", value: 932311 },
          	duration: { text: "8 hours 48 mins", value: 31653 },
          	duration_in_traffic: { text: "8 hours 55 mins", value: 932311 },
          	end_address: "Panvel",
          	end_location: { lat: 37.0842449, lng: -94.513284 },
          	start_address: "Mumbai",
          	start_location: { lat: 41.8781139, lng: -87.6297872 },
          	steps: [],
          	traffic_speed_entry: [],
          	via_waypoint: [],
        	},
        	{
          	distance: { text: "217 km", value: 349512 },
          	duration: { text: "3 hours 17 mins", value: 11799 },
          	duration_in_traffic: { text: "3 hours 40 mins", value: 932311 },
          	end_address: "Alephata",
          	end_location: { lat: 35.4675612, lng: -97.5164077 },
          	start_address: "Panvel",
          	start_location: { lat: 37.0842449, lng: -94.513284 },
          	steps: [],
          	traffic_speed_entry: [],
          	via_waypoint: [],
        	},
        	{
          	distance: { text: "1,328 km", value: 2137682 },
          	duration: { text: "19 hours 28 mins", value: 70097 },
          	duration_in_traffic: { text: "20 hours 22 mins", value: 932311 },
          	end_address: "Pune",
          	end_location: { lat: 34.0523525, lng: -118.2435717 },
          	start_address: "Alephata",
          	start_location: { lat: 35.4675612, lng: -97.5164077 },
          	steps: [],
          	traffic_speed_entry: [],
          	via_waypoint: [],
        	},
      	],
      	summary: "I-55 S and I-44",
      	warnings: [],
      	waypoint_order: [0, 1],
    	},
  	],
  	status: "OK",
	};

Compruebe la estructura de respuesta completa

Hemos procesado la respuesta que recibimos de la API de Google Direction y hemos formado una cadena legible a partir de ella que nos mostrará las diferentes rutas que podemos tomar y cuánto tiempo y distancia puede llevarnos llegar al destino.

Para formar la cadena, tomamos todos los caminos de las rutas dadas, su distancia y el tiempo para llegar al destino normalmente y con tráfico.

Convertiremos todas las rutas a una cadena legible por humanos y luego las devolveremos juntas.

Para procesar la respuesta, utilizaremos funciones auxiliares.

const  getRoutes = ({ routes }) => {

// calculate the overall distance of all the routes

return  routes.reduce((a, b, l) => {
const { legs } = b;

 

let  via = "";
let  normalTime = 0;
let  timeInTraffic = 0;

 

// for each route, calculate the distance path wise, from one to another

const  distance = legs.reduce((x, y, i) => {

const { distance, duration, duration_in_traffic, steps, start_address, end_address } = y;

normalTime += getTimeInMinutes(duration.text);

timeInTraffic += getTimeInMinutes(duration_in_traffic.text);

 

if (i !== legs.length - 1) {

via = via ? via + " -> " + end_address : end_address;

}

const  string = `From ${start_address} to ${end_address} it takes ${duration.text} normally and ${duration_in_traffic.text} in traffic to cover a distance of ${distance.text}`;

x.push(string);
return  x;
}, []);

// for the final string
const  finalString = `Route${l + 1} via ${via} will take ${processTime(
normalTime
)} normally and ${processTime(
timeInTraffic
)} in traffic. Path via breakdown is: ${distance.join(" AND ")}`;

// push the string
a.push(finalString);
return  a;
}, []);
};

// helper function extract to hours and minutes from text
// and return time in minutes

const  getTimeInMinutes = (timeText) => {

timeText = timeText.split(" ");

let  hrs = timeText[0];

let  mins = timeText[2];

return  parseInt(hrs) * 60 + parseInt(mins);

};

 

// helper function to get hours and mins from the time

const  processTime = (time) => {

const  hrs = Math.floor(time / 60);

const  mins = time % 60;

return  `${hrs} hours ${mins} mins`;

};

Este método nos devolverá el array de rutas con la distancia por camino en tiempo normal y en tráfico y podemos devolverlas en formato textual.

Devuelva el SMS con los detalles del tráfico

En la función getTrafficDetails() estamos procesando una respuesta de la API de tráfico y utilizando esta respuesta para generar un texto que contiene los detalles del tráfico. El texto de salida tiene este aspecto:

"Route1 via Panvel -> Alephata will take 31 hours 33 mins normally and 32 hours 57 mins in traffic. Path via breakdown is:  From Mumbai to Panvel it takes 8 hours 48 mins normally and 8 hours 55 mins in traffic to cover a distance of 579 km AND From Panvel to Alephata it takes 3 hours 17 mins normally and 3 hours 40 mins in traffic to cover a distance of 217 km AND From Alephata to Pune it takes 19 hours 28 mins normally and 20 hours 22 mins in traffic to cover a distance of 1,328 km"

"Route2 via Eastern Express Highway -> Lonavala will take 11 hours 33 mins normally and 12 hours 57 mins in traffic. Path via breakdown is:  From Mumbai to Eastern Express Highway it takes 7 hours 48 mins normally and 7 hours 55 mins in traffic to cover a distance of 579 km AND From Eastern Express Highway to Lonavala it takes 2 hours 17 mins normally and 2 hours 40 mins in traffic to cover a distance of 200 km AND From Lonavala to Pune it takes 1 hours 28 mins normally and 2 hours 22 mins in traffic to cover a distance of 1,28 km"

Este texto generado contiene el tiempo que se tarda en llegar al destino desde el lugar de origen en horas normales y en horas punta. Podemos devolver esta información al mismo número de teléfono del que recibimos la entrada.

Podemos usar el SMS API de Vonage para enviar la información. Cuando recibimos el SMS, también recibimos el número de móvil del remitente al que podemos devolver el SMS.

async function sendSMS(msisdn, routes) {
    try {
   	 const data = qs.stringify({
   		 from: "Vonage APIs",
   		 text: routes,
   		 to: msisdn,
   		 api_key: process.env.VONAGE_API_KEY,
   		 api_secret: process.env.VONAGE_API_SECRET,
   	 });

   	 const config = {
   		 method: "post",
   		 url: "https://rest.nexmo.com/sms/json",
   		 headers: {
   		 "Content-Type": "application/x-www-form-urlencoded",
   		 },
   		 data: data,
   	 };

   	 let response = await axios(config);
   	 response = await response.data;
    } catch (e) {
   	 console.error("There was some error while sending sms", e);
    }
}

Puede encontrar el código fuente de esta aplicación aquí

Conclusión

Ahora que hemos creado la alerta de tráfico instantánea a través de la notificación por SMS, puedes consultar este artículo para crear un sistema de alerta diferente con SMS, o a través de WhatsApp utilizando Mensajes API de Vonage.

La participación de la comunidad siempre es bienvenida. Únete a Vonage en GitHub para ver ejemplos de código y en Slack de la comunidad para preguntas o comentarios. Envía a los desarrolladores de Vonage un tweet y cuéntales algo interesante que hayas creado con las API de Vonage.

También puedes ponerte en contacto conmigo en mi blog learnersbucket.com donde escribo artículos sobre desarrollo web.

Compartir:

https://a.storyblok.com/f/270183/400x400/2f974eecd7/pranav_400.png
Pranav ShindeAutor invitado

Pranav es ingeniero de software sénior en Moneycontrol, donde construye aplicaciones web de última generación con React y Next.js. También escribe sobre rendimiento y optimización en LearnersBucket.