phpoc_man
Published © GPL3+

PHPoC - Remotely Open Door via Web with Pattern Password

Remotely control door via web with pattern password protected. Your door is securely controlled from anywhere through Internet.

BeginnerFull instructions provided1 hour684
PHPoC - Remotely Open Door via Web with Pattern Password

Things used in this project

Story

Read more

Schematics

phpoc-_schematic_HRHkqLhERt.jpg

Code

task0.php

PHP
This is code run on system loop
<?php
include_once "/lib/sd_340.php";
include_once "/lib/sd_spc.php";
include_once "/lib/sn_tcp_ws.php";

define("CMD_AUTH",    0);
define("CMD_CTRL",    1);
define("ACCESS_ACCEPTED",		0);
define("ACCESS_UNAUTHORIZED",	1);
define("DOOR_STATE_OPEN",		2);
define("DOOR_STATE_CLOSE",		3);
define("DOOR_TIMEOUT_MS",		10000);

$rbuf = "";
$authenticated = false;
$pattern = "1,4,8,6,3";
$last_active_time = 0;

ws_setup(0, "web_pattern", "text.phpoc");

st_free_setup(0, "ms");
spc_reset();
spc_sync_baud(115200);
spc_request_dev(1, "set 0 output high");

while(1)
{
	if(ws_state(0) == TCP_CONNECTED)
	{
		$rlen = ws_read_line(0, $rbuf);
		
		if($rlen)
		{
			$array = explode(":",$rbuf);
			$cmd = (int) $array[0];
			$data = rtrim($array[1], "\r\n");
			
			if($cmd == CMD_AUTH)
			{
				if($pattern == $data)
				{
					$authenticated = true;
					$last_active_time = st_free_get_count(0);
					ws_write(0, (string)ACCESS_ACCEPTED . "\r\n");
				}
				else
				{
                    $authenticated = false;
					ws_write(0, (string)ACCESS_UNAUTHORIZED . "\r\n");
                }
            }
			else
            if($cmd == CMD_CTRL) {
                if($authenticated) {
                    $control = (int)$data;
                    
					if(!$control)
					{
						spc_request_dev(1, "set 0 output high");
						ws_write(0, (string)DOOR_STATE_CLOSE . "\r\n");
					}
					else
					{
						spc_request_dev(1, "set 0 output low");
						ws_write(0, (string)DOOR_STATE_OPEN . "\r\n");
					}

					$last_active_time = st_free_get_count(0);
                }
                else
				{
                    ws_write(0, (string)ACCESS_UNAUTHORIZED . "\r\n");
                }
            }
		}

		if ($authenticated && ((st_free_get_count(0) - $last_active_time) > DOOR_TIMEOUT_MS))
		{
			$authenticated = false;
			spc_request_dev(1, "set 0 output high");
			ws_write(0, (string)ACCESS_UNAUTHORIZED . "\r\n");
			usleep(500000);
			ws_write(0, (string)DOOR_STATE_CLOSE . "\r\n");
		}
	}
	else
	{
		$authenticated = false;
	}
}

index.php

PHP
This is Web User Interface
<!DOCTYPE html>
<html>
<head>
<title>PHPoC</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
<meta charset="utf-8">
<style>
body { text-align: center; font-size: width/2pt; }
h1 { font-weight: bold; font-size: width/2pt; }
h2 { font-weight: bold; font-size: width/2pt; }
button {font-weight: bold; font-size: width/2pt;}
</style>
<script>

var width = window.innerWidth - 10;
var ratio = width / 800;
if(ratio > 1)
	ratio = 1;

var CMD_AUTH = 0;
var CMD_CTRL = 1;
var ACCESS_ACCEPTED		= 0;
var ACCESS_UNAUTHORIZED	= 1;
var DOOR_STATE_OPEN		= 2;
var DOOR_STATE_CLOSE	= 3;
var ws;
var authorized = false;

/* lock variable */
var canvas_width = 800 * ratio;
var canvas_height = 1300 * ratio;
var lock_edge = 40 * ratio;
var pad = 50 * ratio;
var handle_width  = 500 * ratio;
var handle_height = 120 * ratio;
var lock_width  = (canvas_width  -  2 * lock_edge - handle_width) * 2;
var lock_height =  canvas_height -  2 * lock_edge;

var pattern_width  = lock_width;
var pattern_height = lock_width;
var pattern_inner_radius  = 14 * ratio;
var pattern_middle_radius = 22 * ratio;
var pattern_outer_radius  = 34 * ratio;
var pattern_gap = lock_width / 3;

var body_width = lock_width;
var body_height = canvas_height - lock_edge * 2 - pattern_height - pad - (handle_width - lock_width / 2);
var knob_center_x = lock_edge + body_width / 2;
var knob_center_y = lock_edge + pattern_height + pad + body_height - body_width / 2;

var touch_x = 0, touch_y = 0;
var pattern_touch_state = 0;
var pattern_touch_list = new Array();
var handle_angle = 0;
var handle_last_angle = 0;
var handle_touch_state = 0;
var mouse_state = "MOUSE_UP";
var is_door_open = false;

function init()
{
	var lock = document.getElementById("lock");
	lock.width = canvas_width;
	lock.height = canvas_height;

	lock.addEventListener("touchstart", mouse_down);
	lock.addEventListener("touchend", mouse_up);
	lock.addEventListener("touchmove", mouse_move);
	lock.addEventListener("mousedown", mouse_down);
	lock.addEventListener("mouseup", mouse_up);
	lock.addEventListener("mousemove", mouse_move);

	var ctx = lock.getContext("2d");
	ctx.lineCap="round";
	ctx.lineJoin="round";

	update_view();

	var ws_host_addr = "<?echo _SERVER("HTTP_HOST")?>";
	if((navigator.platform.indexOf("Win") != -1) && (ws_host_addr.charAt(0) == "["))
	{
		// network resource identifier to UNC path name conversion
		ws_host_addr = ws_host_addr.replace(/[\[\]]/g, '');
		ws_host_addr = ws_host_addr.replace(/:/g, "-");
		ws_host_addr += ".ipv6-literal.net";
	}

	ws = new WebSocket("ws://" + ws_host_addr + "/web_pattern", "text.phpoc");
	ws.onopen = ws_onopen;
	ws.onclose = ws_onclose;
	ws.onmessage = ws_onmessage;
}

function ws_onopen()
{
	update_view();
}
function ws_onclose()
{
	alert("CANNOT connect to PHPoC!");
	ws.onopen = null;
	ws.onclose = null;
	ws.onmessage = null;
	ws = null;
	authorized = false;
	update_view();
}
function ws_onmessage(e_msg)
{
	e_msg = e_msg || window.event; // MessageEvent

	var resp = parseInt(e_msg.data);

	if(resp == ACCESS_ACCEPTED)
		authorized = true;
	else if(resp == ACCESS_UNAUTHORIZED)
		authorized = false;
	else if(resp == DOOR_STATE_OPEN)
		is_door_open = true;
	else if(resp == DOOR_STATE_CLOSE)
	{
		is_door_open = false;
		handle_last_angle = 0;
		handle_angle = 0;
	}
	else
		console.log("unknown:" + resp);

	update_view();
}
function update_view()
{
	var pattern_area = document.getElementById('pattern_area');
	var control_area = document.getElementById('control_area');

	var lock = document.getElementById("lock");
	var ctx = lock.getContext("2d");

	ctx.clearRect(0, 0, canvas_width,  canvas_height);

	// draw boder
	ctx.shadowBlur = 10;
	ctx.shadowColor = "LightGray";
	ctx.fillStyle = "#6A4439";
	ctx.beginPath();
	ctx.lineTo(0, 0);
	ctx.lineTo(body_width + 2 * lock_edge , 0);
	ctx.arc(knob_center_x, knob_center_y, body_width / 2 + lock_edge, 0, Math.PI);
	ctx.closePath();
	ctx.fill();

	// draw pattern password background
	ctx.fillStyle = "black";
	ctx.fillRect(lock_edge, lock_edge, pattern_width, pattern_height);

	// draw status indicator
	if(authorized)
		ctx.fillStyle = "Cyan";
	else
		ctx.fillStyle = "white";
	ctx.fillRect(lock_edge, lock_edge + pattern_height, pattern_width, pad);

	ctx.font = "22px Arial"
	ctx.textBaseline = "middle";
	ctx.textAlign = "center";
	ctx.fillStyle = "black";

	var text = "";
	if(is_door_open)
		text += "Openned, ";
	else
		text += "Closed, ";

	if(authorized)
		text += "Access permitted!";
	else
		text += "Access denied!";

	ctx.fillText(text, lock_edge + pattern_width / 2, lock_edge + pattern_height + pad / 2);

	// draw body background
	ctx.fillStyle = "#A07B72";
	ctx.beginPath();
	ctx.lineTo(lock_edge,				lock_edge + pattern_height + pad);
	ctx.lineTo(lock_edge + body_width ,	lock_edge + pattern_height + pad);
	ctx.arc(knob_center_x, knob_center_y, body_width / 2, 0, Math.PI);
	ctx.closePath();
	ctx.fill();

	// draw knob
	ctx.save();
	ctx.translate(knob_center_x, knob_center_y);
	if(authorized)
		ctx.fillStyle = "Cyan";
	else
		ctx.fillStyle = "white";
	ctx.shadowBlur = 1;
	ctx.shadowColor = "black";
	ctx.beginPath();
	ctx.arc(0, 0, body_width / 2 * 0.8, 0, 2 * Math.PI);
	ctx.fill();

	ctx.fillStyle = "black";
	ctx.shadowBlur = 1;
	ctx.shadowColor = "black";
	ctx.beginPath();
	ctx.arc(0, 0, body_width / 2 * 0.6, 0, 2 * Math.PI);
	ctx.fill();

	// draw handle
	ctx.rotate(handle_angle * Math.PI / 180);
	var grd = ctx.createLinearGradient(0, 0, handle_width, 0);
	grd.addColorStop(0, "#6A4439");
	grd.addColorStop(0.2, "#A07B72");
	grd.addColorStop(0.8, "#A07B72");
	grd.addColorStop(1, "#6A4439");

	ctx.fillStyle = grd;
	ctx.shadowBlur = 10;
	ctx.shadowColor = "black";
	ctx.beginPath();
	ctx.arc(0, 0, handle_height / 2, 0.5 * Math.PI, 1.5 * Math.PI);
	ctx.arc(handle_width - handle_height / 2 * 0.7, 0, handle_height / 2 * 0.78, 1.5 * Math.PI, 0.5 * Math.PI);
	ctx.closePath();
	ctx.fill();
	ctx.restore();

	// draw touched point and line
	ctx.save();
	ctx.shadowBlur = 20;
	ctx.shadowColor = "LightGray";
	ctx.lineWidth = 10;
	ctx.strokeStyle="white";
	ctx.globalAlpha=1;
	ctx.beginPath();

	ctx.translate(pattern_width/2 + lock_edge, pattern_height/2 + lock_edge);

	for (var i = 0; i < pattern_touch_list.length; i++) 
	{
		var temp = pattern_touch_list[i] - 1;
		var x =  temp % 3 - 1;
		var y = Math.floor(temp / 3) - 1;

		ctx.lineTo(x*pattern_gap, y*pattern_gap);
	}

	if(pattern_touch_state)
		ctx.lineTo(touch_x, touch_y);

	ctx.stroke();

	for (var i = 0; i < pattern_touch_list.length; i++) 
	{
		var temp = pattern_touch_list[i] - 1;
		var x =  temp % 3 - 1;
		var y = Math.floor(temp / 3) - 1;

		ctx.globalAlpha=0.2;
		ctx.fillStyle = "white";
		ctx.beginPath();
		ctx.arc(x*pattern_gap, y*pattern_gap, pattern_outer_radius, 0, 2 * Math.PI);
		ctx.fill();
	}

	// draw base
	for(var y = -1; y <= 1; y++)
	{
		for(var x = -1; x <= 1; x++)
		{
			ctx.globalAlpha=0.5;
			ctx.fillStyle = "white";
			ctx.beginPath();
			ctx.arc(x*pattern_gap, y*pattern_gap, pattern_middle_radius, 0, 2 * Math.PI);
			ctx.fill();

			ctx.globalAlpha=1;
			ctx.fillStyle = "Cyan";
			ctx.beginPath();
			ctx.arc(x*pattern_gap, y*pattern_gap, pattern_inner_radius, 0, 2 * Math.PI);
			ctx.fill();
		}
	}

	ctx.restore();
}

function process_event(event)
{
	if(event.offsetX)
	{
		touch_x = event.offsetX;
		touch_y = event.offsetY;
	}
	else if(event.layerX)
	{
		touch_x = event.layerX;
		touch_y = event.layerY;
	}
	else
	{
		touch_x = (Math.round(event.touches[0].pageX - event.touches[0].target.offsetLeft));
		touch_y = (Math.round(event.touches[0].pageY - event.touches[0].target.offsetTop));
	}

	if(touch_x > lock_edge && touch_x < (lock_edge + pattern_width) && touch_y > lock_edge && touch_y < (lock_edge + pattern_height))
	{ // pattern password area
		touch_x -= (lock_edge + pattern_width / 2);
		touch_y -= (lock_edge + pattern_height / 2);
	
		for(var i = 1; i <= 9; i++)
		{
			if(i == pattern_touch_list[pattern_touch_list.length - 1])
				continue;

			var idx_x = (i-1)%3 - 1;
			var idx_y = Math.floor((i-1)/3) - 1;

			var knob_center_x = idx_x * pattern_gap;
			var knob_center_y = idx_y * pattern_gap;

			var dist = Math.sqrt( (touch_x - knob_center_x)*(touch_x - knob_center_x) + (touch_y - knob_center_y)*(touch_y - knob_center_y) );

			if(dist < pattern_outer_radius)
			{
				pattern_touch_list.push(i);
				break;
			}
		}

		pattern_touch_state = 1;
	}
	else
	{
		pattern_touch_state = 0;

		if(!authorized)
			return;

		var knob_center_x = lock_edge + body_width / 2;
		var knob_center_y = lock_edge + pattern_height + pad + body_height - body_width / 2;
		touch_x -= knob_center_x;
		touch_y -= knob_center_y;
		var current_angle = Math.atan2(touch_y, touch_x) * 180 / Math.PI;

		/* rotate coordinate */
		var radian = -handle_angle / 180 * Math.PI;
		var rc_x = touch_x * Math.cos(radian) - touch_y * Math.sin(radian);
		var rc_y = touch_x * Math.sin(radian) + touch_y * Math.cos(radian);

		if(mouse_state == "MOUSE_DOWN")
		{
			if(rc_x > (handle_width * 0.3) && rc_x < handle_width && rc_y > (-handle_height / 2) && rc_y < (handle_height / 2))
			{
				handle_last_angle = current_angle;
				handle_touch_state = 1;
			}
		}
		else
		if(mouse_state == "MOUSE_MOVE" && handle_touch_state == 1)
		{
			var angle = current_angle - handle_last_angle;
			if((handle_angle + angle) > 0 && (handle_angle + angle) <= 45)
			{
				handle_angle += angle;
				handle_last_angle = current_angle;
				if(handle_angle < 30)
					send_to_Arduino(CMD_CTRL, 1);
			}
		}
	}

	update_view();
}
function mouse_down()
{
	if(ws == null)
		return;

	event.preventDefault();
	mouse_state = "MOUSE_DOWN";
	process_event(event);
}
function mouse_up()
{
	if(ws == null)
		return;

	event.preventDefault();

	if(ws != null && pattern_touch_state)
		send_to_Arduino(CMD_AUTH, pattern_touch_list.toString());

	pattern_touch_state = 0;
	mouse_state = "MOUSE_UP";
	pattern_touch_list.splice(0, pattern_touch_list.length); 
	update_view();
}
function mouse_move()
{
	if(ws == null)
		return;

	event.preventDefault();
	mouse_state = "MOUSE_MOVE";
	process_event(event);
}

function send_to_Arduino(cmd, data)
{
	if(ws.readyState == 1)
	{
		ws.send(cmd + ":" + data + "\r\n");
	}
}

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

<body>
<div id="pattern_area" style="display:block;">
	<canvas id="lock"></canvas>
</div>
</body>
</html>

Credits

phpoc_man

phpoc_man

62 projects • 407 followers

Comments