Demonstration




Things Used In This Project
  • 1 x PHPoC Blue
  • 2 x PHPoC Stepper Motor Controller Ⅱ (S-type)
  • 2 x Stepper motor SE-SM243
  • Cocktail Machine DIY
  • Jumper wires


How It Works

PHPoC board itself is also an embedded web server. We upload web UI on this board. When Web Browser makes an HTTP request to PHPoC Board. It returns this web UI to Web Brower.

When user chooses a cocktail from Web Browser, the cocktail name will be sent to PHPoC board via web-socket. The server side code in PHPoC board receives this cocktail name and control the cocktail machine to make that cocktail.

For detail how to wiring among PHPoC, Step motor controller and Step motor, refer to this manual: http://www.phpoc.com/support/manual/....php?id=layout

I have another project which uses Alexa to control cocktail machine here: https://www.hackster.io/56170/cockta...d-phpoc-9027c4



Source Code

User Interface <index.php>
PHP Code:
<?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>[/CODE]





Server Side <task0.php>
[code]<?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($sid0"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");
  }
 }
}
?>