phpoc_man
Published © GPL3+

Cocktail Machine with PHPoC (Web Version)

Tell Cocktail Machine make what you want via web.

EasyShowcase (no instructions)924
Cocktail Machine with PHPoC (Web Version)

Things used in this project

Hardware components

PHPoC Blue
PHPoC Blue
×1
PHPoC Stepper Motor Controller Ⅱ (S-type)
PHPoC Stepper Motor Controller Ⅱ (S-type)
×2
Stepper motor SE-SM243
×2
Cocktail Machine DIY
×1

Story

Read more

Custom parts and enclosures

lift closer

lift part

slide movement part

slider bearing side

slider motor side

Code

Server side (task0.php)

PHP
This code runs in infinite loop to receives command (cocktail name) from web browser via web-socket and control step motors on the cocktail machine to make the cocktail
<?php

include_once "/lib/sd_spc.php";
include_once "/lib/sn_tcp_ws.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");
}

$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  | DRY_VERMOUTH 
$pos = array(   1000,    22000,      41000,       63000,   82000,    102000);

ws_setup(0, "cocktail", "text.phpoc");
cocktail_init();

$rbuf = "";

while(1)
{
	if(ws_state(0) == TCP_CONNECTED)
	{
		$rlen = ws_read_line(0, $rbuf);

		if($rlen)
		{
			$drink_name = rtrim($rbuf, "\r\n");

			$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");
		}
	}
}
?>

User Interface (index.php)

PHP
<?php
	$recipe_list = array("SUMMER_RAIN", "SCREW_DRIVER", "BLACK_RUSSIAN", "BLACK_RUSSIAN_2");
?>
<!DOCTYPE html>
<html>
<head>
<title>PHPoC - Cocktail Machine</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<style>
body {
	font-family:Helvetica;
	font-size: 200%;
	text-align: center;
	background-color: #33C7F2;
}
#container {
	position: relative;
	margin-right: auto;
	margin-left: auto;
}
#frame {
	margin-right: auto;
	margin-left: auto; 
	position: absolute;
	background: url(BACKGROUND.png) no-repeat;
	background-size: contain;
}
#confirm, #img_confirm, #btn_confirm{
	margin-right: auto;
	margin-left: auto;
	position: absolute;
}
#confirm { background-color: rgba(0, 0, 255, 0.5);}
#img_confirm { background-color: red;}

div[class='item'] {
	position: absolute; 
	border: 1px solid #d9d9d9;
}
#btn_confirm {
	background-color: white;
}
p { margin:15px; }
</style>
<script>
var ws = null;
var recipe_list = [];
var selected_item = "";

<?php
$num = count($recipe_list);
for($i = 0; $i < $num; $i++) 
	echo "recipe_list.push(\"", $recipe_list[$i] , "\");";
?>

function init()
{
	document.getElementById("frame").addEventListener("click", item_click);
	document.getElementById("option").addEventListener("click", option_click);

	resize();
	
	ws = new WebSocket("ws://<?echo _SERVER("HTTP_HOST")?>/cocktail", "text.phpoc");
}
function ws_onmessage(e_msg)
{
}
function ws_onclose()
{
	ws.onclose = null;
	ws.onmessage = null;
	ws = null;
}
function wc_onclick()
{
	if(ws == null)
	{
		ws = new WebSocket("ws://<?echo _SERVER("HTTP_HOST")?>/cocktail", "text.phpoc");
		document.getElementById("ws_state").innerHTML = "CONNECTING";

		ws.onclose = ws_onclose;
		ws.onmessage = ws_onmessage;  
	}
	else
		ws.close();
}
function item_click(event)
{
	if(ws == null || ws.readyState != 1)
		return;

	if (event.target !== event.currentTarget) 
	{
		selected_item = event.target.id;
		
		var confirm_item = document.getElementById("img_confirm");
		confirm_item.style.backgroundImage = "url('" + event.target.id + ".jpg')";
		confirm_item.style.backgroundRepeat = "no-repeat";
		confirm_item.style.backgroundSize = "contain";
		
		var frame = document.getElementById("frame");
		var confirm = document.getElementById("confirm");
		confirm.style.display = 'block';
	}

	event.stopPropagation();
	event.preventDefault();
}
function option_click(event)
{
	if (event.target !== event.currentTarget) 
	{
		var frame = document.getElementById("frame");
		var confirm = document.getElementById("confirm");
		confirm.style.display = 'none';
		
		if(event.target.id != "btn_yes")
			return;
		
		if(ws == null || ws.readyState != 1)
			return;

		ws.send(selected_item + "\r\n");
	}

	event.stopPropagation();
	event.preventDefault();
}
function resize()
{
	var width = window.innerWidth - 20;
	var height = window.innerHeight - 20;

	if(width > height)
		width = height;
	else
		height = width;
	
	var offset_x =  0.19 * width;
	var offset_y =  0.19 * height;
	
	var container = document.getElementById("container");
	var frame = document.getElementById("frame");
	var confirm = document.getElementById("confirm");
	container.style.width = frame.style.width = confirm.style.width = width + "px";
	container.style.height = frame.style.height = confirm.style.height = height + "px";
	
	confirm.style.display = 'none';
	
	var item_width = Math.floor(width * 0.375);
	var item_height = Math.floor(height * 0.375);
	
	
	for(var i = 0; i < recipe_list.length; i++)
	{
		//two recipe in a row
		var top = offset_y + Math.floor(i/2) * (item_height + 10);
		var left = offset_x + (i%2) * (item_width + 10);
		var item = document.getElementById(recipe_list[i]);
		item.style.width = (item_width - 12)+ "px";
		item.style.height = (item_height - 12)+ "px";
		item.style.top = top + "px";
		item.style.left = left + "px";
		item.style.backgroundImage = "url('" + recipe_list[i] + ".jpg')";
		item.style.backgroundRepeat = "no-repeat";
		item.style.backgroundSize = "contain";
	}
	
	var img_confirm = document.getElementById("img_confirm");
	var btn_confirm = document.getElementById("btn_confirm");
	
	var btn_height = 60;
	item_width = Math.floor(item_width *1.5);
	item_height = Math.floor(item_height *1.5);
	
	img_confirm.style.width = item_width + "px";
	img_confirm.style.height = item_height + "px";
	img_confirm.style.top = Math.floor((height - item_height) / 2) + "px";
	img_confirm.style.left = Math.floor((width - item_width) / 2) + "px";
	
	btn_confirm.style.width = item_width + "px";
	btn_confirm.style.top = Math.floor((height - item_height) / 2 + item_height) + "px";
	btn_confirm.style.left = Math.floor((width - item_width) / 2) + "px";
}

window.onload = init;
</script>
</head>

<body onresize="resize()">
<div id="container">
	<div id="frame">
		<!--<div id="SUMMER_RAIN"></div>
		<div id="SCREW_DRIVER"></div>
		<div id="BLACK_RUSSIAN"></div>
		<div id="BLACK_RUSSIAN_2"></div>-->
		<?php
		$num = count($recipe_list);
		for($i = 0; $i < $num; $i++) 
			echo "<div class=\"item\" id=\"", $recipe_list[$i] , "\"></div>";
		?>
	</div>

	<div id="confirm">
		<div id="img_confirm"></div>
		<div id="btn_confirm">
			<p style="margin:15px" id="message">Would you like to drink it?</p>
			<p id="option" style="color:blue; font-weight: bold;"> 
				<span id="btn_no">&nbsp;&nbsp;&nbspCancel&nbsp;&nbsp;&nbsp;</span>&nbsp;&nbsp;
				<span id="btn_yes">&nbsp;&nbsp;&nbsp;OK&nbsp;&nbsp;&nbsp</span>
			</p>
		</div>
	</div>
</div>
</body>
</html>

Credits

phpoc_man

phpoc_man

35 projects • 103 followers
Contact

Comments