Skip to content

Instantly share code, notes, and snippets.

@BobBurns
Last active August 29, 2015 14:17
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BobBurns/c5caa2fe70b059637382 to your computer and use it in GitHub Desktop.
Save BobBurns/c5caa2fe70b059637382 to your computer and use it in GitHub Desktop.
php websocket device server
#!/usr/bin/php
<?php
/* websocket/device server program for raspberry pi
* this program only deals with packets that are 125 bytes max
* currently only one client can connect at a time. Maybe not a bad thing.
* run as super user (for gpio access)
* check out https://gist.github.com/BobBurns/6f83930912da4094f014 for the client html code
* much of the juicy bits adapted from ghedipunk/PHP-Websockets
*
* commands to send to client:
* 0xA0 0x00 device A power state off
* 0xA0 0x01 power state on
* 0xA0 0x02 power state sleep
* 0xA1 0xXX 0xXX sensor 1 value
* 0xA2 0xXX 0xXX sensor 2 value
* 0xA3 0xXX 0xXX sensor 3 value
* 0xA4 0xXX 0xXX sensor 4 value
*
* 0xB0 0x00 device B power state off
* 0xB0 0x01 power state on
* 0xB0 0x02 power state sleep
* 0xB1 0xXX 0xXX sensor 1 value
* 0xB2 0xXX 0xXX sensor 2 value
* 0xB3 0xXX 0xXX sensor 3 value
* 0xB4 0xXX 0xXX sensor 4 value
* commands sent to server
* 0x00 disconnect
* 0x10 power off device A
* 0x11 power on device A
* 0x12 sleep device A
* 0x13 0xXX 0xXX inc by value bus 1 device A
* 0x14 0xXX 0xXX dec by value bus 1
* 0x15 0xXX 0xXX set value bus 1
* 0x16 0xXX 0xXX inc by value bus 2
* 0x17 0xXX 0xXX dec by value bus 2
* 0x18 0xXX 0xXX set value bus 2
*
* 0x20 power off device B
* 0x21 power on device B
* 0x22 sleep device B
* 0x23 0xXX 0xXX inc by value bus 1 device B
* 0x24 0xXX 0xXX dec by value bus 1
* 0x25 0xXX 0xXX set value bus 1
* 0x26 0xXX 0xXX inc by value bus 2
* 0x27 0xXX 0xXX dec by value bus 2
* 0x28 0xXX 0xXX set value bus 2
*/
$errno = 0; $errstr = '';
$resource = '';
$on = false;
$maxbuf = 4096;
// open gpio pin 23 to input 24 to output
// this program has led on gpio pin 24 and a button on pin 23
system ( "echo 23 > /sys/class/gpio/export" );
system ( "echo in > /sys/class/gpio/gpio23/direction" );
system ( "echo 24 > /sys/class/gpio/export" );
system ( "echo out > /sys/class/gpio/gpio24/direction" );
$server = @stream_socket_server("tcp://0.0.0.0:2342", $errno, $errstr);
if ($server === false) {
fwrite(STDERR, "Error: $errno: $errstr\n");
exit(1);
}
echo "listening for connection...\n";
$result = array();
for (;;) {
$conn = @stream_socket_accept($server, -1, $peer);
if ($conn !== false) {
// got connection now do handshake
wshandshake($conn);
$oventemp = 0x20;
$humidity = 50;
$on = false;
// main loop
for (;;) {
stream_set_blocking($conn, 0);
// get device values
$button = array();
exec ( "cat /sys/class/gpio/gpio23/value" , $button );
if ($button[0] == 1) {
printf("button pressed");
if ($on === false) $on = true;
else if ($on === true) $on = false;
}
if ($on === true)
system( "echo 1 > /sys/class/gpio/gpio24/value" );
else
system( "echo 0 > /sys/class/gpio/gpio24/value" );
if ($on === true) $message = 0x01;
else $message = 0x00;
// send some values
$cmd = 0xA0; // powerstate device A
$dataframe = setupState($cmd, $message);
fwrite($conn, $dataframe);
$oventemp += rand(-2,2);
if ($oventemp > 255) $oventemp = 255;
if ($oventemp < 0) $oventemp = 0;
$cmd = 0xA1; // sensor 1 device A
$dataframe = setupValue($cmd, 0x00, $oventemp);
fwrite($conn, $dataframe);
$cmd = 0xA2; // sensor 2 device A
$dataframe = setupValue($cmd, 0x00, $humidity);
fwrite($conn, $dataframe);
// echo 'message successful ';
// check for incomming
$recbuf = fread($conn, $maxbuf);
if ($recbuf != false) {
$result = getIncomming($recbuf);
if ($result[0] == 0) {
echo "Bye!";
break;
}
switch ($result[0]) { // check sent command and do something with it
case 0x10:
// power off
break;
case 0x11:
// power on
break;
case 0x12:
// sleep device A
break;
case 0x13:
$humidity += $result[2];
break;
case 0x14:
$humidity -= $result[2];
break;
case 0x15:
// etc
break;
}
}
usleep(500000);
}
fclose($conn);
}
}
function wshandshake($conn) {
global $resource;
$MAXLEN = 4096;
$magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
$headers = array();
if (!($buf = fread($conn, $MAXLEN))) printf("error: fread\n");
$lines = explode("\n", $buf);
print_r($lines);
foreach ($lines as $line) {
if (strpos($line, ":") !== false) {
$header = explode(":", $line, 2);
$headers[strtolower(trim($header[0]))] = trim($header[1]);
} elseif (stripos($line,"get ") !== false) {
preg_match("/GET (.*) HTTP/i", $line, $request);
$headers['get'] = trim($request[1]);
}
}
if (isset($headers['get']))
$resource = $headers['get'];
if (!isset($headers['sec-websocket-version']) || strtolower($headers['sec-websocket-version']) != 13) {
$handshakeResponse = "HTTP/1.1 426 Upgrade Required\r\nSec-WebSocketVersion: 13";
fwrite($conn, $handshakeResponse);
return false;
}
$webSocketKeyHash = sha1($headers['sec-websocket-key'] . $magicGUID);
$rawToken = "";
for ($i = 0; $i < 20; $i++) {
$rawToken .= chr(hexdec(substr($webSocketKeyHash,$i*2, 2)));
}
$handshakeToken = base64_encode($rawToken);
$handshakeResponse = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $handshakeToken\r\n\r\n";
fwrite($conn, $handshakeResponse);
return true;
}
function setupState($cmd, $state) {
$opcode = 0x82;
$len = 0x02;
return chr($opcode) . chr($len) . chr($cmd) . chr ($state);
}
function setupValue($cmd, $valH, $valL) {
$opcode = 0x82;
$len = 0x03;
return chr($opcode) . chr($len) . chr($cmd) . chr($valH) . chr($valL);
}
function setupPacket($message) {
$opcode = 0x81; // to send text
$length = strlen($message);
print_r($length);
$extendedLength = "";
if ($length < 126) {
$paylen = dechex($length);
}
return chr($opcode) . chr($paylen) . $message;
}
function getIncomming($inbuf) {
$decoded = array();
$arrayBuffer = unpack('C*', $inbuf);
$opcode = $arrayBuffer[1] & 0x0F;
$paylen = $arrayBuffer[2] & 0x7F;
$maskbit = $arrayBuffer[2] & 0x80;
if ($opcode == 0x08) {
$decoded[0] = 0;
return $decoded;
}
if ($maskbit > 0) {
$mask = array($arrayBuffer[3], $arrayBuffer[4], $arrayBuffer[5], $arrayBuffer[6]);
for ($i = 0; $i < $paylen; $i++) {
$decoded[$i] = $arrayBuffer[7+$i] ^ $mask[$i % 4];
}
}
return $decoded;
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment