Microsoft Bot Framework: Iniciar la conversación desde el lado del bot

Uno de los escenarios en los que he estado trabajando estos días es que sea el bot el que inicie la conversación con el usuario. Para este post voy a explicartelo con el siguiente ejemplo: tengo una aplicación en Node.js que entre diario a las nueve y media de la mañana comprueba el tiempo que hace en unas coordenadas concretas y envía dicha información por uno de los canales a los usuarios suscritos. Los módulos que he utilizado para este ejemplo son forecast, para comprobar el tiempo actual, ms-rest, para gestionar las credenciales del cliente que se conectará con el servicio de bots,  y botconnector para hacer la llamada al servicio de bots y que este enrute mi mensaje al usuario por el canal adecuado.

//modules
var Forecast = require('forecast'),
    msRest = require('ms-rest'),
    connector = require('botconnector');

// Initialize credentials for connecting to Bot Connector Service
var appId = process.env.appId || 'delayservicebot';
var appSecret = process.env.appSecret || 'MY_APP_SECRET';
var credentials = new msRest.BasicAuthenticationCredentials(appId, appSecret);

//Get forecast
var forecast = new Forecast({

    service: 'forecast.io',
    key: 'MY_FORECAST_IO_API_KEY',
    units: 'celcius'
});

//Retrieve weather information from coordinates (Madrid)
forecast.get([40.4167754, -3.7037901999999576], function (err, weather) {

    if (err) return console.dir(err);

    //Get currently weather
    console.dir(weather);
    console.log("Current weather condition: %s", weather.currently.summary);

    //Send info via Telegram
    sendWeather(weather);
});


function sendWeather(weatherInfo, cb) {

    var client = new connector(credentials);
    var options = { customHeaders: { 'Ocp-Apim-Subscription-Key': credentials.password } };

    var msg = {
        to: {
            channelId: 'telegram',
            address: 'USER_ID_IN_TELEGRAM'
        },
        from: {
            channelId: 'telegram',
            address: 'delayservice_bot'
        },
        text: "Current weather condition: " + weatherInfo.currently.summary
    };


    client.messages.sendMessage(msg, options, function (err, result, request, response) {
        if (!err && response && response.statusCode >= 400) {
            err = new Error('Message rejected with "' + response.statusMessage + '"');
        }
        if (cb) {
            cb(err);
        }
    });
}

Como puedes ver en el código anterior, la parte que se encarga de enviar la información del tiempo al usuario es la función sendWeather donde primero se monta el mensaje en un Object Literal y acto seguido se envia a través de client.messages.sendMessage. En el apartado to del mensaje los únicos valores necesarios son el channelId, que en este caso es telegram, y el id del usuario en Telegram en la propiedad address. Este id puede conseguirse de varias formas: la más sencilla es que los usuarios que se quieran beneficiar del servicio sean capaces de suscribirse y que el bot tenga un repositorio donde recuperar estos suscritos (por no complicar el ejemplo se utilizará un id de un único usuario). Para este ejemplo vamos a recuperar el id del usuario buscando directamente con la aplicación web de Telegram. Para ello, busca tu usuario a través de la búsqueda de la aplicación web y al hacer clic para iniciar una conversación verás que en la URL aparece un número con una u como prefijo, ese es el user id.

Telegram - User ID
Telegram – User ID

Al ser mi aplicación un proceso en segundo plano, lo voy a alojar en un web job, ya que estos soportan Node.js.

Add WebJob - Forecast
Add WebJob – Forecast

Como el proceso debe lanzarse a las 9:30 de lunes a viernes, he utilizado la expresión CRON 0 30 9 * * 1-5 . Sin embargo puedes lanzarlo bajo demanda desde el portal para comprobar que todo funciona correctamente a través de la acción Run.

WebJobs - Run
WebJobs – Run

Al lanzarlo el usuario que has elegido recibirá un mensaje del bot similar a este:

delayservicebot - weather result
delayservicebot – weather result

¡Saludos!