Things used in this project

Hardware components:
Phpoc blue per 100x1000 euk22wtv9i
PHPoC Blue
×1
Amazon echo dot
Amazon Alexa Echo Dot
×1
Micro stepper motor controller t type 4hz2ygod0g
PHPoC Stepper Motor Controller Ⅱ (T-type)
×2
Stepper motor SE-SM243
×2
Cocktail Machine DIY
×1
Software apps and online services:
Dp image kit 02
Amazon Alexa Alexa Skills Kit
Screen%20shot%202015 07 20%20at%206.10.26%20pm
Amazon Web Services AWS Lambda
Mqtt
MQTT

Custom parts and enclosures

Lift Closer
Lift Part
Slide Moving Part
Slider Bearing Side
Slider Motor Side

Code

PHPoC code (task0.php)PHP
<?php

include_once "/lib/sd_spc.php";
include_once "/lib/sn_dns.php";
include_once "/lib/vn_mqtt.php";

define("SID_X",				13);
define("SID_Y",				14);
define("COCKTAIL_FLOW_TIME",	3); // time for cocktail flow into cup in second
define("COCKTAIL_WAIT_TIME",	3);

function step_wait($sid)
{
	while((int)spc_request_dev($sid, "get state") > 1)
		usleep(1);
}

function spc_check_did($sid, $did)
{
	$resp = spc_request_csv($sid, 0, "get did");

	if($resp === false)
	{
		echo "spc_check_did: sid$sid - device not found\r\n";
		return false;
	}

	if($resp[1] != "40002405")
	{
		echo "spc_check_did: unknown device ", $resp[2], "\r\n";
		return false;
	}

	return true;
}

function cooktail_get_id($drink_name)
{
	global $names;
	
	for($i = 0; $i < 4; $i++)
	{
		if($names[$i] == $drink_name)
			return $i;
	}
	
	return -1;
}

function cocktail_get($recipe)
{
	global $pos;
	
	spc_request_dev(SID_X, "goto -sw1 20000 1000000");
	step_wait(SID_X);
	spc_request_dev(SID_X, "reset");
	
	for($step_motor = 0; $step_motor < 4; $step_motor++) // get component one by one
	{
		$amount = $recipe[$step_motor]; 
		if($amount > 0)
		{
			$ps = $pos[$step_motor];
			
			spc_request_dev(SID_X, "goto +$ps 20000 1000000");
			step_wait(SID_X);
			
			for($i = 1; $i <= $amount; $i++)
			{
				if($i != 1)
					sleep(COCKTAIL_WAIT_TIME);

				spc_request_dev(SID_Y, "goto -sw0 30000 1000000");
				step_wait(SID_Y);
				sleep(COCKTAIL_FLOW_TIME);
				spc_request_dev(SID_Y, "reset");
				spc_request_dev(SID_Y, "goto 90000 30000 1000000");
				step_wait(SID_Y);
			}
			
			spc_request_dev(SID_Y, "goto 140000 30000 1000000");
			step_wait(SID_Y);
		}
	}
}

function cocktail_init()
{
	spc_reset();
	spc_sync_baud(460800);

	if(!spc_check_did(SID_X, "40002405"))
		return;
	if(!spc_check_did(SID_Y, "40002405"))
		return;

	spc_request_dev(SID_X, "set vref stop 4");
	spc_request_dev(SID_X, "set vref drive 15");
	spc_request_dev(SID_X, "set mode 32");
	spc_request_dev(SID_X, "set rsnc 120 250");
	
	spc_request_dev(SID_Y, "set vref stop 4");
	spc_request_dev(SID_Y, "set vref drive 15");
	spc_request_dev(SID_Y, "set mode 32");
	spc_request_dev(SID_Y, "set rsnc 120 250");
	
	spc_request_dev(SID_X, "goto +sw0 20000 1000000");
	step_wait(SID_X);
	
	spc_request_dev(SID_Y, "goto -sw0 30000 1000000");
	step_wait(SID_Y);
	
	spc_request_dev(SID_X, "reset");
	spc_request_dev(SID_Y, "reset");
	
	spc_request_dev(SID_Y, "goto 140000 30000 1000000");
	step_wait(SID_Y);
	
	spc_request_dev(SID_X, "goto +sw0 20000 1000000");
	step_wait(SID_X);
	spc_request_dev(SID_X, "reset");
	spc_request_dev(SID_Y, "reset");
}

$host_name = "iot.eclipse.org";
$port = 1883;
$will = "";
$username = "";
$password = "";
$subc_topics = array(array("alexa/phpoc/cocktail", 0));
$topic = "";
$content = "";
$retain = 0;

$names = array("SUMMER_RAIN", "SCREW_DRIVER", "BLACK_RUSSIAN", "BLACK_RUSSIAN_2", "SWEET_MARTINI", "MARTINI");

$recipe_list = array(//MALIBU | VODKA | OGRANGE_JUICE | KAHLUA | GIN    ||
				array(   2,       1,          0,          0,      0), //||SUMMER_RAIN
				array(   0,       1,          2,          0,      0), //||SCREW_DRIVER
				array(   0,       1,          0,          2,      0), //||BLACK_RUSSIAN
				array(   0,       2,          0,          1,      0), //||BLACK_RUSSIAN_2
			);

// motor pos: //MALIBU | VODKA | OGRANGE_JUICE | KAHLUA  |  GIN  | 
$pos = array(   1000,    22000,      41000,       63000,   82000);

mqtt_setup(0, "PHPoC-MQTT Sub Example",  $host_name, $port);
mqtt_connect(true, $will, $username, $password);

if(mqtt_state() == MQTT_CONNECTED)
	mqtt_subscribe($subc_topics);

cocktail_init();

while(1)
{
	if(mqtt_state() == MQTT_DISCONNECTED)
		while(mqtt_reconnect() == false);
	
	if(mqtt_loop($topic, $content, $retain))
	{
		if($retain == 1)
			continue;// a stale message

		echo $content;
		$drink_name = $content;

		$id = cooktail_get_id($drink_name);

		if($id >= 0)
		{
			$recipe = $recipe_list[$id];
			cocktail_get($recipe);
		}
		else
			echo "cocktail: The drink is not found\r\n";

		spc_request_dev(SID_X, "goto -sw1 20000 1000000");
		step_wait(SID_X);
		spc_request_dev(SID_X, "reset");
	}
}
?>
Lambda function (index.js)JavaScript
'use strict';

var mqtt = require('mqtt');

// --------------- 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 createAttributes(cocktail) {
    return {
        cocktail: cocktail
    };
}

/**
 * Send data to mqtt and prepares the speech to reply to the user.
 */
function cocktailInSession(intent, session, callback) {
	const cardTitle = intent.name;
	const drinkNameRequest = intent.slots.drinkName;
	let repromptText = '';
	let sessionAttributes = {};
	const shouldEndSession = true;
	let speechOutput = "";

	var drinkName = "";
	var requestName = "";

	if(drinkNameRequest) 
	{
		requestName = drinkNameRequest.value;
		console.log("cocktail: " + requestName);

		drinkName = requestName.toUpperCase();
		drinkName = drinkName.replace(/ /g, "_");
		
		switch(drinkName)
		{
			case "SUMMER_RAIN":
			case "SCREW_DRIVER":
			case "BLACK_RUSSIAN":
			case "BLACK_RUSSIAN_2":
			case "SWEET_MARTINI":
			case "MARTINI":
				break;

			default:
				drinkName = "";
		}
	}
	
	if(drinkName !== "")
	{
		speechOutput = "Ok, I will tell cocktail machine make " + requestName + " for you";

		//Update 
		var mqttpromise = new Promise( function(resolve,reject){
			var client = mqtt.connect({port:1883,host:'iot.eclipse.org'})

			client.on('connect', function() { // When connected
				// publish a message to any mqtt topic
				client.publish('alexa/phpoc/cocktail', drinkName)
				client.end()
				resolve('Done Sending');
			});
		});
		mqttpromise.then(
			function(data) {
				console.log('Function called succesfully:', data);
				sessionAttributes = createAttributes(data);
				repromptText = speechOutput;
				callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
			},
			function(err) {
				console.log('An error occurred:', err);
			}
		);
	}else{
		speechOutput = "Please try again";
		repromptText = "Please try again";
		
		callback(sessionAttributes,buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
	}
}

// --------------- 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 === 'cocktail') {
        cocktailInSession(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);
    }
};

Credits

On uvdqjvxt6b
phpoc_man
3 projects • 81 followers
Contact
Hackster y9wdftit0f
hite000
0 projects • 3 followers
Contact

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Sign up / LoginProjectsPlatformsTopicsContestsLiveAppsBetaBlog