简体   繁体   中英

node.js Https call return undefined. Amazon AWS

Edit. The code is now updated since first post:

"It now works like this: FIrst time running the pooltemp is undefined. If run one more time immediately I get pooltemp = 30 (which is the new temp). That at least says that the call to thingspeak is working. If I run it again after a few minutes it is again undefined first time. Seems that AWS keeps the value for a while after the function finish."

I am completely new to node.js but have the following code, which I have written mostly with cut & paste. It is running in Amazon AWS, responding to an Alexa call. I am trying to read a thingspeak channel to get the temperature in my pool.(The url returns a json with temperature The channel is updated by an esp8266 which is measuring the pooltemp and posts it to the channel. Unfortunately I am only getting undefined pooltemp. I create the function getCall() to get the temperature from thinspeak. When I use the variable pooltemp in handlerinput it is undefined. Everything else work fine. If I hardcode pooltemp in handlerinput I get the response I want. The code is as following . am appreciating all help. Thank you:

/* eslint-disable  func-names */
/* eslint-disable  no-console */



const Alexa = require('ask-sdk');


var https = require('https');
var pooltemp;


  getCall();




//ThingSpeak Data Access

function getCall() {
  var options = {
    protocol: 'https:', 
    host: 'api.thingspeak.com',
    path: '/channels/494722/feeds.json?api_key=9HILOGJ9P2HRDPNO&results=1',
    method: 'GET'
  };

  var getReq = https.request(options, function(res) {
    console.log("\nstatus code: ", res.statusCode);
    var jsonData = '';
    res.on('data', function(data) {
        jsonData += data;
    });
    res.on('end', function() {
      console.log('We have all the data');
      var result = JSON.parse(jsonData);
      console.log('data: ', result);
      console.log('Pool temperature: ', result.feeds[0].field1);
      // Save the latest pool temperature.
      pooltemp = result.feeds[0].field1;
    });
  });

  //end the request
  getReq.end();
  getReq.on('error', function(err) {
    console.log("Error: ", err);
  });
}


const GetNewFactHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'LaunchRequest' ||
      (request.type === 'IntentRequest' &&
        request.intent.name === 'GetNewFactIntent');
  },



  handle(handlerInput) {


    //  var pooltemp = 22;
    var factIndex;
    const factArr = data;
    if (pooltemp <= 15) {
      factIndex = 0;
    }
    if (15 < pooltemp == pooltemp < 20) {
      factIndex = 1;
    }
    if (20 <= pooltemp == pooltemp < 25) {
      factIndex = 2;
    }
    if (pooltemp >= 25) {
      factIndex = 3;
    }


    const randomFact = factArr[factIndex];
    const speechOutput = 'Hold on a second, I will check for you.<break time="1s"/>Today it is ' + pooltemp + ' degrees in the pool. ' + randomFact;
    return handlerInput.responseBuilder
      .speak(speechOutput)
      .withSimpleCard(SKILL_NAME, randomFact)
      .getResponse();

  },
};

const HelpHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' &&
      request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak(HELP_MESSAGE)
      .reprompt(HELP_REPROMPT)
      .getResponse();
  },
};

const ExitHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' &&
      (request.intent.name === 'AMAZON.CancelIntent' ||
        request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak(STOP_MESSAGE)
      .getResponse();
  },
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
    console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);

    return handlerInput.responseBuilder.getResponse();
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
    console.log(`Error handled: ${error.message}`);

    return handlerInput.responseBuilder
      .speak('Sorry, an error occurred.')
      .reprompt('Sorry, an error occurred.')
      .getResponse();
  },
};

const SKILL_NAME = 'Space Facts';
const GET_FACT_MESSAGE = 'Here\'s today temperature: ';
const HELP_MESSAGE = 'You can say tell me a space fact, or, you can say exit... What can I help you with?';
const HELP_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Goodbye!';

const data = [
  'It is freezing cold. Swimming only for idiots',
  'It is not for whimps, but you may swim. Do you dare go for it?',
  'Wich is a nice temperature for a norwegian.',
  'This is quite comfortable and a swim should be really nice ',

];

const skillBuilder = Alexa.SkillBuilders.standard();

exports.handler = skillBuilder
  .addRequestHandlers(
    GetNewFactHandler,
    HelpHandler,
    ExitHandler,
    SessionEndedRequestHandler
  )
  .addErrorHandlers(ErrorHandler)
  .lambda();

I've checked this out and made a few modifications to the getCall() function, it should work now:

function getCall() {
  var options = {
    protocol: 'https:', 
    host: 'api.thingspeak.com',
    path: '/channels/494722/feeds.json?api_key=9HILOGJ9P2HRDPNO&results=1',
    method: 'GET'
  }

  var getReq = https.request(options, function(res) {
    console.log("\nstatus code: ", res.statusCode);
    var jsonData = '';
    res.on('data', function(data) {
        jsonData += data;
    });
    res.on('end', function() {
       console.log('We have all the data');
       var result = JSON.parse(jsonData);
       console.log('data: ', result);
       console.log('Pool temperature: ', result.feeds[0].field1);
       // Save the latest pool temperature.
       poolTemp = result.feeds[0].field1;
    });
  });

  //end the request
  getReq.end();
  getReq.on('error', function(err) {
    console.log("Error: ", err);
  });
}

getCall();

You could also try this at the start of your script:

getCall();
setInterval(getCall, 10000);

This would refresh the pool temperature every 10 seconds.

Currently you function getCall() is executing asynchronously, So pooltemp is undefined. Because of javascript asynchrouns nature before the successful execution of getCall() function, it moves on to if condition

Here I made a changes in getCall function using javascript callback. Also in GetNewFactHandler handle() method after the successful execution of getCall function remaining conditions will be executed.

/* eslint-disable  func-names */
/* eslint-disable  no-console */
const Alexa = require('ask-sdk');

var https = require('https');

//ThingSpeak Data Access
function getCall(callback) {
  //initialize options values, the value of the method can be changed to POST to make https post calls
  var options = {
    protocol: 'https:', 
    host: 'api.thingspeak.com',
    path: '/channels/494722/feeds.json?api_key=9HILOGJ9P2HRDPNO&results=1',
    method: 'GET'
  };

  //making the https get call
  https.request(options, function(res) {
    console.log("\nstatus code: ", res.statusCode);
    let data = ''

    // A chunk of data has been recieved from request stream.  
    res.on('data', function(chunk) {
        data += chunk;
    });

    // Once the whole response has been received, return response as callback
    res.on('end', () => {
      console.log('We have all the data');
      var result = JSON.parse(data);
      console.log('data: ', result);
      console.log('Pool temperature: ', result.feeds[0].field1);
      // Save the latest pool temperature.
      const poolTemp = result.feeds[0].field1;
      callback(null, poolTemp);
    });
  })
  .on('error', function(err) {
    callback(err);
  });
}

const GetNewFactHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'LaunchRequest' ||
      (request.type === 'IntentRequest' &&
        request.intent.name === 'GetNewFactIntent');
  },

  handle(handlerInput) {

    getCall((err, pooltemp) => {
        //Error handling implementation
        if(err) {
            console.log("Error: ", err);    
        }
        //Validating condition after successful response from getCall       
        //  var pooltemp = 22;
        var factIndex;
        const factArr = data;
        if (pooltemp <= 15) {
          factIndex = 0;
        }
        if (15 < pooltemp == pooltemp < 20) {
          factIndex = 1;
        }
        if (20 <= pooltemp == pooltemp < 25) {
          factIndex = 2;
        }
        if (pooltemp >= 25) {
          factIndex = 3;
        }

        const randomFact = factArr[factIndex];
        const speechOutput = 'Hold on a second, I will check for you.<break time="1s"/>Today it is ' + pooltemp + ' degrees in the pool. ' + randomFact;
        return handlerInput.responseBuilder
          .speak(speechOutput)
          .withSimpleCard(SKILL_NAME, randomFact)
          .getResponse();
    }
  },
};

const HelpHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' &&
      request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak(HELP_MESSAGE)
      .reprompt(HELP_REPROMPT)
      .getResponse();
  },
};

const ExitHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' &&
      (request.intent.name === 'AMAZON.CancelIntent' ||
        request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak(STOP_MESSAGE)
      .getResponse();
  },
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
    console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);

    return handlerInput.responseBuilder.getResponse();
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
    console.log(`Error handled: ${error.message}`);

    return handlerInput.responseBuilder
      .speak('Sorry, an error occurred.')
      .reprompt('Sorry, an error occurred.')
      .getResponse();
  },
};

const SKILL_NAME = 'Space Facts';
const GET_FACT_MESSAGE = 'Here\'s today temperature: ';
const HELP_MESSAGE = 'You can say tell me a space fact, or, you can say exit... What can I help you with?';
const HELP_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Goodbye!';

const data = [
  'It is freezing cold. Swimming only for idiots',
  'It is not for whimps, but you may swim. Do you dare go for it?',
  'Wich is a nice temperature for a norwegian.',
  'This is quite comfortable and a swim should be really nice ',

];

const skillBuilder = Alexa.SkillBuilders.standard();

exports.handler = skillBuilder
  .addRequestHandlers(
    GetNewFactHandler,
    HelpHandler,
    ExitHandler,
    SessionEndedRequestHandler
  )
  .addErrorHandlers(ErrorHandler)
  .lambda();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM