question

MPCPRO avatar image
MPCPRO asked

Getting alexa to read JSON (Temperature and Humidity from arduino uno)

Hey guys.

I am really new into programming but I am trying to find a way so I can ask alexa "TemperatureHumidity" etc. I followed mostly this guide here:

https://www.hackster.io/44560/amazon-echo-read-temperature-and-humidity-from-sensor-0d9b73

But he used PHP to post his json information while my Arduino Uno with Ethernetshield is posting my temperature and humidity in json only. (Check it out here: http://mpconline.tk:1470 )

Example (incase my arduino is offline:

{,"temperature":"17.00","humidity":"33.00"}

I copied his Node.js 6.10 code to my lambda coding, but I am trying to find a way to modify it to read the json from my arduino uno. The only thing I can see I have to change is the host , path and port (which I did). Though I am still unable to get Alexa to get anything from my site. Something about:

"The remote endpoint could not be called, or the response it returned was invalid."

So I was wondering if anyone couild go through the example code I used to see if there's anything obvious I should have changed?

'use strict';


/**
 * This sample demonstrates a simple skill built with the Amazon Alexa Skills Kit.
 * The Intent Schema, Custom Slots, and Sample Utterances for this skill, as well as
 * testing instructions are located at http://amzn.to/1LzFrj6
 *
 * For additional samples, visit the Alexa Skills Kit Getting Started guide at
 * http://amzn.to/1LGWsLG
 */


var http = require('http');


// --------------- Helpers that build all of the responses -----------------------


function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: 'PlainText',
            text: output,
        },
        card: {
            type: 'Simple',
            title: "SessionSpeechlet - " + title,
            content: "SessionSpeechlet - " + output,
        },
        reprompt: {
            outputSpeech: {
                type: 'PlainText',
                text: repromptText,
            },
        },
        shouldEndSession: shouldEndSession
    };
}


function buildResponse(sessionAttributes, speechletResponse) {
    return {
        version: '1.0',
        sessionAttributes,
        response: speechletResponse,
    };
}




// --------------- Functions that control the skill's behavior -----------------------


function getWelcomeResponse(callback) {
    // If we wanted to initialize the session to have some attributes we could add those here.
    const sessionAttributes = {};
    const cardTitle = 'Welcome';
    const speechOutput = "Welcome to P H P o C. How can I help you?"
    // If the user either does not reply to the welcome message or says something that is not
    // understood, they will be prompted again with this text.
    const repromptText = "How can I help you?";
    const shouldEndSession = false;


    callback(sessionAttributes,
        buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
}


function handleSessionEndRequest(callback) {
    const cardTitle = 'Session Ended';
    const speechOutput = 'Thank you for trying the Alexa Skills Kit sample. Have a nice day!';
    // Setting this to true ends the session and exits the skill.
    const shouldEndSession = true;


    callback({}, buildSpeechletResponse(cardTitle, speechOutput, null, shouldEndSession));
}


function createTemperatureAttributes(temperature) {
    return {
        temperature: temperature
    };
}


/**
 * Read temperature in the session and prepares the speech to reply to the user.
 */
function readTemperatureInSession(intent, session, callback) {
    const cardTitle = intent.name;
    let repromptText = '';
    let sessionAttributes = {};
    const shouldEndSession = true;
    let speechOutput = '';
	var body = '';


	//Update 
	var httpPromise = new Promise( function(resolve,reject){
		http.get({
			host: '192.168.1.207',
			path: '',
			port: '1470'
		}, function(response) {
			// Continuously update stream with data
			response.on('data', function(d) {
				body += d;
			});
			response.on('end', function() {
				// Data reception is done, do whatever with it!
				console.log(body);
				resolve('Done Sending');
			});
		});
	});
	httpPromise.then(
		function(data) {
			var info = JSON.parse(body);
			console.log('Function called succesfully:', data);
			sessionAttributes = createTemperatureAttributes(info.temperature);
			speechOutput = "Temperature is " + info.temperature + " degree Celsius. Humidity is " + info.humidity + " percent";
			repromptText = "Temperature is " + info.temperature + " degree Celsius. Humidity is " + info.humidity + " percent";
			console.log(speechOutput);
			callback(sessionAttributes,buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
		},
		function(err) {
			console.log('An error occurred:', err);
		}
	);
}


// --------------- Events -----------------------


/**
 * Called when the session starts.
 */
function onSessionStarted(sessionStartedRequest, session) {
    console.log("onSessionStarted requestId=${sessionStartedRequest.requestId}, sessionId=${session.sessionId}");
}


/**
 * Called when the user launches the skill without specifying what they want.
 */
function onLaunch(launchRequest, session, callback) {
    console.log("onLaunch requestId=${launchRequest.requestId}, sessionId=${session.sessionId}");


    // Dispatch to your skill's launch.
    getWelcomeResponse(callback);
}


/**
 * Called when the user specifies an intent for this skill.
 */
function onIntent(intentRequest, session, callback) {
    console.log("onIntent requestId=${intentRequest.requestId}, sessionId=${session.sessionId}");


    const intent = intentRequest.intent;
    const intentName = intentRequest.intent.name;


    // Dispatch to your skill's intent handlers
    if (intentName === 'TemperatureHumidity') {
        readTemperatureInSession(intent, session, callback);
    } else if (intentName === 'AMAZON.HelpIntent') {
        getWelcomeResponse(callback);
    } else if (intentName === 'AMAZON.StopIntent' || intentName === 'AMAZON.CancelIntent') {
        handleSessionEndRequest(callback);
    } else {
        throw new Error('Invalid intent');
    }
}


/**
 * Called when the user ends the session.
 * Is not called when the skill returns shouldEndSession=true.
 */
function onSessionEnded(sessionEndedRequest, session) {
    console.log("onSessionEnded requestId=${sessionEndedRequest.requestId}, sessionId=${session.sessionId}");
    // Add cleanup logic here
}




// --------------- Main handler -----------------------


// Route the incoming request based on type (LaunchRequest, IntentRequest,
// etc.) The JSON body of the request is provided in the event parameter.
exports.handler = (event, context) => {
    try {
        console.log("event.session.application.applicationId=${event.session.application.applicationId}");


        /**
         * Uncomment this if statement and populate with your skill's application ID to
         * prevent someone else from configuring a skill that sends requests to this function.
         */
        /*
        if (event.session.application.applicationId !== 'amzn1.echo-sdk-ams.app.[unique-value-here]') {
             context.fail("Invalid Application ID");
        }
        */


        if (event.session.new) {
            onSessionStarted({ requestId: event.request.requestId }, event.session);
        }


        if (event.request.type === 'LaunchRequest') {
            onLaunch(event.request,
                event.session,
                function callback(sessionAttributes, speechletResponse) {
					context.succeed(buildResponse(sessionAttributes, speechletResponse));
				});
        } else if (event.request.type === 'IntentRequest') {
            onIntent(event.request,
                event.session,
                function callback(sessionAttributes, speechletResponse) {
					context.succeed(buildResponse(sessionAttributes, speechletResponse));
				});
        } else if (event.request.type === 'SessionEndedRequest') {
            onSessionEnded(event.request, event.session);
            context.succeed();
        }
    } catch (e) {
        context.fail("Exception: " + e);
    }
};

If you also need my arduino json code part: (t is the live temperature reading, while h is the live humidity reading).

            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: application/json");  // JSON response type
            client.println("Connection: close");               // close connection after response
            client.println();
            // open JSON
            client.print("{");
            // temperature
            client.print(",\"temperature\":\"");
            client.print(t);
            client.print("\"");
            // humidity
            client.print(",\"humidity\":\"");
            client.print(h);
            client.print("\"");
            // close json
            client.println("}");


My Intent Schema and Sample Utterances:

{
  "intents": [
    {
      "intent": "TemperatureHumidity"
    }
  ]
}
TemperatureHumidity tell me temperature and humidity
TemperatureHumidity tell me current temperature and humidity
alexa smart homethermostat
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

davorin avatar image
davorin answered

Alexa only allows connections to HTTPS port 443 with a valid SSL certificate...

Even for local network connections like getting a camera feed from a Raspberry Pi requires this.

10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

MPCPRO avatar image
MPCPRO answered

So, I gotta find a way to get my arduino to post its info to another third party that has a valid SSL Certificate, which then alexa can use?

1 comment
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Tsuneki@Amazon avatar image Tsuneki@Amazon commented ·

Hi MPCPRO,

Please check SSL options here for details.

0 Likes 0 ·