リモートLED制御

リモートでブラウザからRaspberry PiのLEDを制御する。
同時にストリームでRaspberry piから動画をストリーミングする。

Raspberry pi上のHTTPサーバとして

1) node.js
2) MJPG-Streamer

を導入。
ポートがぶつからないように
それぞれの待ち受けポートを
1) 8088
2) 8080
とする。
node.js側をメインのHTTPサーバとして、MJPG-Streamerを動画ストリーミング用とする。

ブラウザで表示させた画面。
制御するLEDを写すようにカメラを向けている。

(1)ブラウザで表示するHTML
・imgタグで動画の表示を行う。
・ボタンが押されたらPOSTメッセージをXMLHttpRequestにて送信する。

<html>
 <head>
  <meta charset="UTF-8">
  <title>STREAM VIEW</title>
 </head>
 <body>
  <img src="http://192.168.11.200:8080/?action=stream" />
  <br>
  <form name="control">
   <input type="button" value="RED" onClick="button('red')">
   <input type="button" value="GREEN" onClick="button('green')">
   <input type="button" value="YELLOW" onClick="button('yellow')">
  </form>
  <script type="text/javascript">

    var color_red = 'off';
    var color_green = 'off';
    var color_yellow = 'off';

    function button(value){
      console.log(value);

      var request = false;
      request = new XMLHttpRequest();
      if(!request){
        alert("This browser does not support XMLHttpRequest");
        return false;
      }

      var led_value = 'off';
      switch(value){
      case 'red':
        color_red = (color_red == 'off') ? 'on' : 'off';
        led_value = color_red;
        break;
      case 'green':
        color_green = (color_green == 'off') ? 'on' : 'off';
        led_value = color_green;
        break;
      case 'yellow':
        color_yellow = (color_yellow == 'off') ? 'on' : 'off';
        led_value = color_yellow;
        break;
      }

      var send = 'color=' + value + '&' + 'set=' + led_value;
      request.open('POST', '/serial', true);

      request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
      request.send(send);
    }

  </script>
 </body>
</html>

(2)node.jsのスクリプト
・上記のHTMLを返す。
・LED制御のPOSTリクエストに応答する。

// controlLED.js

var http        = require('http');
var path        = require('path');
var fs          = require('fs');
var sys         = require('sys');
var fs          = require('fs');
var spawn       = require('child_process').spawn;
var url         = require('url');
var querystring = require('querystring');
var util        = require('util');

http.createServer(function (request, response){
    var lookup = path.basename(decodeURI(request.url));

    if(request.method == 'GET'){
	switch(lookup){
	case 'controlLED.html':
	    lookup = '/home/pi/RemoteControlLed/' + lookup;
	    fs.readFile(lookup, function(err, data){
		if(err){
		    response.writeHead(500);
		    response.end('Server Error!');
		    return;
		}

		var headers = {'Content-Type': 'text/html'};
		response.writeHead(200, headers);
		response.end(data);
	    });
	    break;
	default:
	    response.writeHead(404);
	    response.end('The page cannot be found');
	    console.log('file not found : ' + lookup);
	    break;
	}
    }
    else if (request.method == 'POST'){
	switch(lookup){
	case 'serial':

	    var postData = '';
	    request.on('data', function(chunk){
		postData += chunk;
	    }).on('end', function(){

		var postDataObject = querystring.parse(postData);
		if(postDataObject.hasOwnProperty('color') &&
		   postDataObject.hasOwnProperty('set')){

		    controlLED(postDataObject.color, postDataObject.set);
		}
		else{
		    console.log('connot found "color / set"');
		}

	    });

	    sendResponse(response);
	    break;

	}
    }

}).listen(8088);




function sendResponse(response)
{
    var headers = {'Content-Type': 'test/html'};
    response.writeHead(200, headers);
    response.end('OK');
}




function controlLED(color, set)
{
    var ctrl = spawn('./controlLED/controlLED', [color, set]);

    ctrl.stdout.on('data', function(data){
	sys.print('stdout:' + data);
    });

    ctrl.stderr.on('data', function(data){
	sys.print('stderr: ' + data);
    });

    ctrl.on('exit', function(code){
	sys.print('exit: ' + code);
    });
}


(3)LED制御のためのCプログラム
・GPIOを制御しLEDのON/OFFを行う。
・GPIOの制御はデバイスファイルへの1/0書き込み。

// controlLED.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

int gpio_write(int gpio_number, int value);
int writeValue(char *file, char *value);
int readValue(char *file, char *buff, int length);


#define PRINTLINE   printf("%s, %d\n", __FUNCTION__, __LINE__);

// GPIO PIN ASSIGN
#define GPIO_RED   23
#define GPIO_GREEN 24
#define GPIO_YELLOW  25


//------------------------------
// Expected command line is as below.
// ex.
// $ controlLED red on
// $ controlLED green off

int main(int argc, char *argv[])
{
  int i;
  int gpio;
  int value;

  for(i=0;i<argc;i++){
    printf("argv[%d] : %s\n", i, argv[i]);
  }

  if(argc < 3){
    PRINTLINE
    printf("illegal argument\n");
    return 0;
  }

  if(strcmp("red", argv[1]) == 0) {
    gpio = GPIO_RED;
  }
  else if(strcmp("green", argv[1]) == 0) {
    gpio = GPIO_GREEN;
  }
  else if(strcmp("yellow", argv[1]) == 0) {
    gpio = GPIO_YELLOW;
  }
  else {
    PRINTLINE
    printf("illegal argument\n");
    return 0;
  }

  if(strcmp("on", argv[2]) == 0){
    value = 1;
  }
  else if(strcmp("off", argv[2]) == 0){
    value = 0;
  }
  else{
    PRINTLINE
    printf("illegal argument\n");
    return 0;
  }

  gpio_write(gpio, value);
  return 0;
}







//------------------------------
int gpio_write(int gpio_number, int value)
{
  int ret;
  char wbuff[32];
  char str[128];

  PRINTLINE
  printf("gpio : %d , value : %d\n", gpio_number, value);

  sprintf(str, "%d", gpio_number);
  ret = writeValue("/sys/class/gpio/export", str);

  sprintf(str, "/sys/class/gpio/gpio%d/direction", gpio_number);
  ret = writeValue(str, "out");

  sprintf(str, "/sys/class/gpio/gpio%d/value", gpio_number);
  sprintf(wbuff, "%d", value);
  ret = writeValue(str, wbuff);

  return 0;
}


//------------------------------
int writeValue(char *file, char *value)
{
  int fd;
  int ret;

  printf("%s : %s\n",file, value);
//  return;

  fd = open(file, O_WRONLY);
  if(fd < 0){
    PRINTLINE
    perror("GPIO open error");
    return -1;
  }

  ret = write(fd, value, strlen(value));
  if(ret < 0){
    PRINTLINE
    perror("GPIO write error");
    return -1;
  }

  ret = close(fd);
  if(ret < 0){
    PRINTLINE
    perror("GPIO close error");
    return -1;
  }
  return 0;
}

//------------------------------
int readValue(char *file, char *buff, int length)
{
  int fd;
  int ret;

  fd = open(file, O_RDONLY);
  if(fd < 0){
    PRINTLINE
    perror("GPIO open error");
    return -1;
  }

  ret = read(fd, buff, length);
  if(ret < 0){
    PRINTLINE
    perror("GPIO read error");
    return -1;
  }

  ret = close(fd);
  if(ret < 0){
    PRINTLINE
    perror("GPIO close error");
    return -1;
  }

  printf("%s : %s\n",file, buff);
  return 0;
}