読者です 読者をやめる 読者になる 読者になる

森川敬一 CTO ブログ

unimediaでCTOやってます森川敬一です。エンジニアブログ。IoT、ウエアブルとか書いていきます。

RaspberryPi B+でカメラモジュール使ってnode.jsとsocket.ioでストリーミング配信してみる

RaspberryPi B+でカメラモジュール使ってnode.jsとsocket.ioでストリーミング配信してみます。

純正カメラをつなげました。

f:id:m-kei1:20150220113541j:plainf:id:m-kei1:20150220113556j:plain

ついでにネットワークがつながってるので、シリアルログインが不要のためmicroUSBケーブルで接続してます。

カメラの有効化を行います
# sudo raspi-config
f:id:m-kei1:20150220113738p:plain
f:id:m-kei1:20150220113748p:plain

下記を参考にさせて頂きます

Raspberry Pi, Camera and Node.js - Live Streaming with Websockets #IoT | The Jackal of Javascript



liveStreamingフォルダを作って、expressをsocket.io付きでinitします。

http://thejackalofjavascript.com/rpi-live-streaming/


pi@raspberrypi ~ $ cd httpd/
pi@raspberrypi ~/httpd $ ls
sample
pi@raspberrypi ~/httpd $ mkdir liveStreaming && cd liveStreaming
pi@raspberrypi ~/httpd/liveStreaming $ ls
pi@raspberrypi ~/httpd/liveStreaming $ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (liveStreaming) liveStreaming
version: (0.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /home/pi/httpd/liveStreaming/package.json:

{
  "name": "liveStreaming",
  "version": "0.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes)

pi@raspberrypi ~/httpd/liveStreaming $ npm install express socket.io --save
npm WARN package.json liveStreaming@0.0.0 No description
npm WARN package.json liveStreaming@0.0.0 No repository field.
npm WARN package.json liveStreaming@0.0.0 No README data
npm http GET https://registry.npmjs.org/socket.io
npm http GET https://registry.npmjs.org/express
npm http 200 https://registry.npmjs.org/socket.io
npm http 200 https://registry.npmjs.org/express
npm http GET https://registry.npmjs.org/socket.io/-/socket.io-1.3.4.tgz
npm http 200 https://registry.npmjs.org/socket.io/-/socket.io-1.3.4.tgz
npm http GET https://registry.npmjs.org/engine.io
npm http GET https://registry.npmjs.org/socket.io-parser
npm http GET https://registry.npmjs.org/socket.io-client
npm http GET https://registry.npmjs.org/socket.io-adapter
npm http GET https://registry.npmjs.org/has-binary-data
npm http GET https://registry.npmjs.org/debug
npm http 200 https://registry.npmjs.org/has-binary-data
npm http 200 https://registry.npmjs.org/debug
npm http 200 https://registry.npmjs.org/socket.io-adapter
npm http 200 https://registry.npmjs.org/socket.io-parser
npm http 200 https://registry.npmjs.org/socket.io-client
npm http GET https://registry.npmjs.org/has-binary-data/-/has-binary-data-0.1.3.tgz
npm http GET https://registry.npmjs.org/debug/-/debug-2.1.0.tgz
npm http GET https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.3.1.tgz
npm http GET https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.3.tgz
npm http 200 https://registry.npmjs.org/has-binary-data/-/has-binary-data-0.1.3.tgz
npm http 200 https://registry.npmjs.org/engine.io
npm http 200 https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.3.1.tgz
npm http 200 https://registry.npmjs.org/debug/-/debug-2.1.0.tgz
npm http GET https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.3.4.tgz
npm http 200 https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.3.tgz
npm http 200 https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.3.4.tgz
npm http GET https://registry.npmjs.org/engine.io/-/engine.io-1.5.1.tgz
npm http 200 https://registry.npmjs.org/engine.io/-/engine.io-1.5.1.tgz
npm http GET https://registry.npmjs.org/methods
npm http GET https://registry.npmjs.org/fresh
npm http GET https://registry.npmjs.org/media-typer
npm http GET https://registry.npmjs.org/on-finished
npm http GET https://registry.npmjs.org/parseurl
npm http GET https://registry.npmjs.org/path-to-regexp
npm http GET https://registry.npmjs.org/proxy-addr
npm http GET https://registry.npmjs.org/qs
npm http GET https://registry.npmjs.org/range-parser
npm http GET https://registry.npmjs.org/send
npm http GET https://registry.npmjs.org/serve-static
npm http GET https://registry.npmjs.org/type-is
npm http GET https://registry.npmjs.org/vary
npm http GET https://registry.npmjs.org/cookie
npm http GET https://registry.npmjs.org/merge-descriptors
npm http GET https://registry.npmjs.org/utils-merge
npm http GET https://registry.npmjs.org/accepts
npm http GET https://registry.npmjs.org/content-disposition
npm http GET https://registry.npmjs.org/cookie-signature
npm http GET https://registry.npmjs.org/depd
npm http GET https://registry.npmjs.org/escape-html
npm http GET https://registry.npmjs.org/etag
npm http GET https://registry.npmjs.org/finalhandler
npm http 304 https://registry.npmjs.org/methods
npm http 304 https://registry.npmjs.org/on-finished
npm http 304 https://registry.npmjs.org/fresh
npm http 304 https://registry.npmjs.org/parseurl
npm http 304 https://registry.npmjs.org/path-to-regexp
npm http 304 https://registry.npmjs.org/range-parser
npm http 200 https://registry.npmjs.org/proxy-addr
npm http 200 https://registry.npmjs.org/qs
npm http 304 https://registry.npmjs.org/vary
npm http 304 https://registry.npmjs.org/media-typer
npm http 304 https://registry.npmjs.org/cookie
npm http 200 https://registry.npmjs.org/serve-static
npm http 200 https://registry.npmjs.org/send
npm http GET https://registry.npmjs.org/qs/-/qs-2.3.3.tgz
npm http 304 https://registry.npmjs.org/utils-merge
npm http 304 https://registry.npmjs.org/merge-descriptors
npm http 200 https://registry.npmjs.org/cookie-signature
npm http 304 https://registry.npmjs.org/content-disposition
npm http 200 https://registry.npmjs.org/accepts
npm http 200 https://registry.npmjs.org/qs/-/qs-2.3.3.tgz
npm http 200 https://registry.npmjs.org/type-is
npm http 304 https://registry.npmjs.org/depd
npm http 304 https://registry.npmjs.org/escape-html
npm http 304 https://registry.npmjs.org/etag
npm http GET https://registry.npmjs.org/send/-/send-0.11.1.tgz
npm http 304 https://registry.npmjs.org/finalhandler
npm http GET https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.5.tgz
npm http 200 https://registry.npmjs.org/send/-/send-0.11.1.tgz
npm http 200 https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.5.tgz
npm http GET https://registry.npmjs.org/accepts/-/accepts-1.2.4.tgz
npm http 200 https://registry.npmjs.org/accepts/-/accepts-1.2.4.tgz
npm http GET https://registry.npmjs.org/crc
npm http GET https://registry.npmjs.org/ee-first
npm http GET https://registry.npmjs.org/mime-types
npm http GET https://registry.npmjs.org/negotiator
npm http GET https://registry.npmjs.org/ipaddr.js
npm http GET https://registry.npmjs.org/forwarded
npm http 304 https://registry.npmjs.org/ee-first
npm http 304 https://registry.npmjs.org/crc
npm http 304 https://registry.npmjs.org/forwarded
npm http 304 https://registry.npmjs.org/mime-types
npm http 200 https://registry.npmjs.org/negotiator
npm http 304 https://registry.npmjs.org/ipaddr.js
npm http GET https://registry.npmjs.org/negotiator/-/negotiator-0.5.1.tgz
npm http GET https://registry.npmjs.org/object-keys
npm http 200 https://registry.npmjs.org/negotiator/-/negotiator-0.5.1.tgz
npm http GET https://registry.npmjs.org/debug
npm http GET https://registry.npmjs.org/socket.io-parser
npm http GET https://registry.npmjs.org/destroy
npm http GET https://registry.npmjs.org/mime
npm http GET https://registry.npmjs.org/ms
npm http 200 https://registry.npmjs.org/object-keys
npm http 304 https://registry.npmjs.org/debug
npm http 304 https://registry.npmjs.org/socket.io-parser
npm http 304 https://registry.npmjs.org/destroy
npm http 304 https://registry.npmjs.org/ms
npm http 200 https://registry.npmjs.org/mime
npm http GET https://registry.npmjs.org/object-keys/-/object-keys-1.0.1.tgz
npm http GET https://registry.npmjs.org/debug/-/debug-1.0.2.tgz
npm http GET https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.2.tgz
npm http GET https://registry.npmjs.org/mime/-/mime-1.2.11.tgz
npm http 200 https://registry.npmjs.org/object-keys/-/object-keys-1.0.1.tgz
npm http 200 https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.2.tgz
npm http 200 https://registry.npmjs.org/mime/-/mime-1.2.11.tgz
npm http 200 https://registry.npmjs.org/debug/-/debug-1.0.2.tgz
npm http GET https://registry.npmjs.org/json3
npm http GET https://registry.npmjs.org/component-emitter
npm http GET https://registry.npmjs.org/isarray
npm http GET https://registry.npmjs.org/benchmark
npm http 200 https://registry.npmjs.org/isarray
npm http GET https://registry.npmjs.org/debug/-/debug-0.7.4.tgz
npm http 200 https://registry.npmjs.org/component-emitter
npm http GET https://registry.npmjs.org/mime-db
npm http 200 https://registry.npmjs.org/json3
npm http 200 https://registry.npmjs.org/benchmark
npm http 200 https://registry.npmjs.org/debug/-/debug-0.7.4.tgz
npm http 304 https://registry.npmjs.org/mime-db
npm http GET https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz
npm http GET https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz
npm http GET https://registry.npmjs.org/json3/-/json3-3.2.6.tgz
npm http GET https://registry.npmjs.org/benchmark/-/benchmark-1.0.0.tgz
npm http 200 https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz
npm http 200 https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz
npm http 200 https://registry.npmjs.org/json3/-/json3-3.2.6.tgz
npm http 200 https://registry.npmjs.org/benchmark/-/benchmark-1.0.0.tgz
npm http GET https://registry.npmjs.org/ws
npm http GET https://registry.npmjs.org/engine.io-parser
npm http GET https://registry.npmjs.org/base64id
npm http GET https://registry.npmjs.org/debug
npm http 304 https://registry.npmjs.org/debug
npm http 200 https://registry.npmjs.org/engine.io-parser
npm http 200 https://registry.npmjs.org/ws
npm http 200 https://registry.npmjs.org/base64id
npm http GET https://registry.npmjs.org/debug/-/debug-1.0.3.tgz
npm http GET https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.2.1.tgz
npm http GET https://registry.npmjs.org/ws/-/ws-0.5.0.tgz
npm http GET https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz
npm http 200 https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.2.1.tgz
npm http 200 https://registry.npmjs.org/debug/-/debug-1.0.3.tgz
npm http 200 https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz
npm http 200 https://registry.npmjs.org/ws/-/ws-0.5.0.tgz
npm http GET https://registry.npmjs.org/ms
npm http 304 https://registry.npmjs.org/ms
npm http GET https://registry.npmjs.org/component-emitter
npm http GET https://registry.npmjs.org/isarray
npm http 304 https://registry.npmjs.org/isarray
npm http 304 https://registry.npmjs.org/component-emitter
npm http GET https://registry.npmjs.org/engine.io-client
npm http GET https://registry.npmjs.org/component-bind
npm http GET https://registry.npmjs.org/object-component
npm http GET https://registry.npmjs.org/has-binary
npm http GET https://registry.npmjs.org/indexof
npm http GET https://registry.npmjs.org/parseuri
npm http GET https://registry.npmjs.org/to-array
npm http GET https://registry.npmjs.org/backo2
npm http GET https://registry.npmjs.org/debug
npm http 200 https://registry.npmjs.org/object-component
npm http 200 https://registry.npmjs.org/component-bind
npm http 200 https://registry.npmjs.org/indexof
npm http 200 https://registry.npmjs.org/to-array
npm http 200 https://registry.npmjs.org/backo2
npm http 304 https://registry.npmjs.org/debug
npm http 200 https://registry.npmjs.org/has-binary
npm http 200 https://registry.npmjs.org/parseuri
npm http GET https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz
npm http GET https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz
npm http GET https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz
npm http 200 https://registry.npmjs.org/engine.io-client
npm http GET https://registry.npmjs.org/to-array/-/to-array-0.1.3.tgz
npm http GET https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz
npm http 200 https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz
npm http GET https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz
npm http 200 https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz
npm http 200 https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz
npm http GET https://registry.npmjs.org/parseuri/-/parseuri-0.0.2.tgz
npm http 200 https://registry.npmjs.org/to-array/-/to-array-0.1.3.tgz
npm http 200 https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz
npm http 200 https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz
npm http GET https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.5.1.tgz
npm http 200 https://registry.npmjs.org/parseuri/-/parseuri-0.0.2.tgz
npm http 200 https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.5.1.tgz
npm http GET https://registry.npmjs.org/ms
npm http 304 https://registry.npmjs.org/ms
npm http GET https://registry.npmjs.org/arraybuffer.slice
npm http GET https://registry.npmjs.org/after
npm http GET https://registry.npmjs.org/base64-arraybuffer
npm http GET https://registry.npmjs.org/blob
npm http GET https://registry.npmjs.org/utf8
npm http GET https://registry.npmjs.org/has-binary/-/has-binary-0.1.5.tgz
npm http 200 https://registry.npmjs.org/base64-arraybuffer
npm http 200 https://registry.npmjs.org/arraybuffer.slice
npm http 200 https://registry.npmjs.org/after
npm http 200 https://registry.npmjs.org/has-binary/-/has-binary-0.1.5.tgz
npm http GET https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.2.tgz
npm http GET https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz
npm http 200 https://registry.npmjs.org/blob
npm http GET https://registry.npmjs.org/after/-/after-0.8.1.tgz
npm http 200 https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.2.tgz
npm http 200 https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz
npm http 200 https://registry.npmjs.org/after/-/after-0.8.1.tgz
npm http GET https://registry.npmjs.org/blob/-/blob-0.0.2.tgz
npm http 200 https://registry.npmjs.org/utf8
npm http 200 https://registry.npmjs.org/blob/-/blob-0.0.2.tgz
npm http GET https://registry.npmjs.org/utf8/-/utf8-2.0.0.tgz
npm http 200 https://registry.npmjs.org/utf8/-/utf8-2.0.0.tgz
npm http GET https://registry.npmjs.org/better-assert
npm http 200 https://registry.npmjs.org/better-assert
npm http GET https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz
npm http 200 https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz
npm http GET https://registry.npmjs.org/nan
npm http GET https://registry.npmjs.org/options
npm http GET https://registry.npmjs.org/ultron
npm http 200 https://registry.npmjs.org/options
npm http GET https://registry.npmjs.org/options/-/options-0.0.6.tgz
npm http 200 https://registry.npmjs.org/ultron
npm http GET https://registry.npmjs.org/isarray
npm http 200 https://registry.npmjs.org/nan
npm http 200 https://registry.npmjs.org/options/-/options-0.0.6.tgz
npm http 304 https://registry.npmjs.org/isarray
npm http GET https://registry.npmjs.org/ultron/-/ultron-1.0.1.tgz
npm http GET https://registry.npmjs.org/nan/-/nan-1.4.3.tgz
npm http 200 https://registry.npmjs.org/ultron/-/ultron-1.0.1.tgz
npm http 200 https://registry.npmjs.org/nan/-/nan-1.4.3.tgz
npm http GET https://registry.npmjs.org/callsite
npm http 200 https://registry.npmjs.org/callsite
npm http GET https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz
npm http 200 https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz
npm http GET https://registry.npmjs.org/parsejson
npm http GET https://registry.npmjs.org/parseqs
npm http GET https://registry.npmjs.org/component-inherit
npm http GET https://registry.npmjs.org/has-cors
npm http GET https://github.com/rase-/node-XMLHttpRequest/archive/a6b6f2.tar.gz
npm http GET https://registry.npmjs.org/ws
npm http GET https://registry.npmjs.org/engine.io-parser
npm http GET https://registry.npmjs.org/debug
npm http GET https://registry.npmjs.org/parseuri
npm http 200 https://registry.npmjs.org/has-cors
npm http 200 https://registry.npmjs.org/parseqs
npm http 304 https://registry.npmjs.org/engine.io-parser
npm http 200 https://registry.npmjs.org/parsejson
npm http 304 https://registry.npmjs.org/ws
npm http 200 https://registry.npmjs.org/component-inherit
npm http 304 https://registry.npmjs.org/debug
npm http 304 https://registry.npmjs.org/parseuri
npm http GET https://registry.npmjs.org/has-cors/-/has-cors-1.0.3.tgz
npm http GET https://registry.npmjs.org/parseqs/-/parseqs-0.0.2.tgz
npm http GET https://registry.npmjs.org/parsejson/-/parsejson-0.0.1.tgz
npm http GET https://registry.npmjs.org/ws/-/ws-0.4.31.tgz
npm http GET https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz
npm http GET https://registry.npmjs.org/debug/-/debug-1.0.4.tgz
npm http GET https://registry.npmjs.org/parseuri/-/parseuri-0.0.4.tgz
npm http 200 https://registry.npmjs.org/parseqs/-/parseqs-0.0.2.tgz
npm http 200 https://registry.npmjs.org/debug/-/debug-1.0.4.tgz
npm http 200 https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz
npm http 200 https://registry.npmjs.org/ws/-/ws-0.4.31.tgz
npm http 200 https://registry.npmjs.org/parsejson/-/parsejson-0.0.1.tgz
npm http 200 https://registry.npmjs.org/parseuri/-/parseuri-0.0.4.tgz
npm http 200 https://registry.npmjs.org/has-cors/-/has-cors-1.0.3.tgz
npm http 200 https://github.com/rase-/node-XMLHttpRequest/archive/a6b6f2.tar.gz
npm http GET https://registry.npmjs.org/isarray
npm http 200 https://registry.npmjs.org/nan/-/nan-0.3.2.tgz

> ws@0.4.31 install /home/pi/httpd/liveStreaming/node_modules/socket.io/node_modules/socket.io-client/node_modules/engine.io-client/node_modules/ws
> (node-gyp rebuild 2> builderror.log) || (exit 0)

make: Entering directory '/home/pi/httpd/liveStreaming/node_modules/socket.io/node_modules/socket.io-client/node_modules/engine.io-client/node_modules/ws/build'
  CXX(target) Release/obj.target/bufferutil/src/bufferutil.o
  SOLINK_MODULE(target) Release/obj.target/bufferutil.node
  SOLINK_MODULE(target) Release/obj.target/bufferutil.node: Finished
  COPY Release/bufferutil.node
  CXX(target) Release/obj.target/validation/src/validation.o
  SOLINK_MODULE(target) Release/obj.target/validation.node
  SOLINK_MODULE(target) Release/obj.target/validation.node: Finished
  COPY Release/validation.node
make: Leaving directory '/home/pi/httpd/liveStreaming/node_modules/socket.io/node_modules/socket.io-client/node_modules/engine.io-client/node_modules/ws/build'
express@4.11.2 node_modules/express
├── utils-merge@1.0.0
├── merge-descriptors@0.0.2
├── methods@1.1.1
├── fresh@0.2.4
├── cookie@0.1.2
├── escape-html@1.0.1
├── range-parser@1.0.2
├── cookie-signature@1.0.5
├── finalhandler@0.3.3
├── vary@1.0.0
├── media-typer@0.3.0
├── parseurl@1.3.0
├── serve-static@1.8.1
├── content-disposition@0.5.0
├── path-to-regexp@0.1.3
├── depd@1.0.0
├── on-finished@2.2.0 (ee-first@1.1.0)
├── qs@2.3.3
├── debug@2.1.1 (ms@0.6.2)
├── proxy-addr@1.0.6 (forwarded@0.1.0, ipaddr.js@0.1.8)
├── etag@1.5.1 (crc@3.2.1)
├── send@0.11.1 (destroy@1.0.3, ms@0.7.0, mime@1.2.11)
├── type-is@1.5.7 (mime-types@2.0.9)
└── accepts@1.2.4 (negotiator@0.5.1, mime-types@2.0.9)

socket.io@1.3.4 node_modules/socket.io
├── debug@2.1.0 (ms@0.6.2)
├── has-binary-data@0.1.3 (isarray@0.0.1)
├── socket.io-parser@2.2.3 (isarray@0.0.1, debug@0.7.4, component-emitter@1.1.2, benchmark@1.0.0, json3@3.2.6)
├── socket.io-adapter@0.3.1 (object-keys@1.0.1, debug@1.0.2, socket.io-parser@2.2.2)
├── engine.io@1.5.1 (base64id@0.1.0, debug@1.0.3, engine.io-parser@1.2.1, ws@0.5.0)
└── socket.io-client@1.3.4 (to-array@0.1.3, indexof@0.0.1, component-bind@1.0.0, debug@0.7.4, backo2@1.0.2, object-component@0.0.3, component-emitter@1.1.2, has-binary@0.1.6, parseuri@0.0.2, engine.io-client@1.5.1)


準備完了したら、
index.js(サーバー側)とindex.html(クライアント側)を作成します。

index.js

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var fs = require('fs');
var path = require('path');

var spawn = require('child_process').spawn;
var proc;

var dateformat = require("dateformat");

app.use('/', express.static(path.join(__dirname, 'stream')));

app.get('/', function(req, res) {
	res.sendFile(__dirname + '/index.html');
});

var sockets = {};

io.on('connection', function(socket) {
	sockets[socket.id] = socket;
	console.log("Total clients connected : ", Object.keys(sockets).length);

	socket.on('disconnect', function() {

		delete sockets[socket.id];
		// no more sockets, kill the stream
		if (Object.keys(sockets).length == 0) {
			app.set('watchingFile', false);
			if (proc) proc.kill();
			fs.unwatchFile('./stream/image_stream.jpg');
		}
	});
	socket.on('start-stream', function() {
		startStreaming(io);
	});
});

http.listen(3000, function() {
	console.log('listening on *:3000');
});

function stopStreaming() {

	if (Object.keys(sockets).length == 0) {
		app.set('watchingFile', false);
		if (proc) proc.kill();
		fs.unwatchFile('./stream/image_stream.jpg');
	}
}

function startStreaming(io) {
	if (app.get('watchingFile')) {
		io.sockets.emit('liveStream', {url:'image_stream.jpg?_t=' + (Math.random() * 100000), time:dateformat(new Date(), "yyyy/mm/dd HH:MM:ss")});
		return;
	}

	var args = ["-bm", "-w", "320", "-h", "240", "-o", __dirname + "/stream/image_stream.jpg", "-t", "999999999", "-tl", "500", "--nopreview"];
	proc = spawn('raspistill', args);
	console.log('Watching for changes...');
	app.set('watchingFile', true);

	fs.watchFile(__dirname+'/stream/image_stream.jpg', function(current, previous) {
		console.log('emmit liveStewam');
		io.sockets.emit('liveStream', {url:'image_stream.jpg?_t=' + (Math.random() * 100000), time:dateformat(new Date(), "yyyy/mm/dd HH:MM:ss")});
	})

	proc.stdout.on('data', function(data) {
	  console.log('stdout: ' + data);
	})

	proc.stderr.on('data', function(data) {
	  console.log('stderr: ' + data);
	})

	proc.on('exit', function(code) {
	  console.log('exit code: ' + code);
	})

}

spawnでraspistillコマンドを実行してストリーミングします。

その後、fs.watchFileで、image_stream.jpgを監視。

変更があったら、io.sockets.emitで画像URLと更新時間を送付します。

	proc = spawn('raspistill', args);
	console.log('Watching for changes...');
	app.set('watchingFile', true);

	fs.watchFile(__dirname+'/stream/image_stream.jpg', function(current, previous) {
		console.log('emmit liveStewam');
		io.sockets.emit('liveStream', {url:'image_stream.jpg?_t=' + (Math.random() * 100000), time:dateformat(new Date(), "yyyy/mm/dd HH:MM:ss")});

raspistillコマンドの - tl 500 は電圧等の関係で値調整が必要ですのでご注意を。

次にindex.html(クライアント側)

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>the view from my office </title>
<!-- Bootstrap CSS -->
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<style type="text/css">
#stream {
height: 99%;
margin: 0px auto;
display: block;
margin-top: 20px;
}
</style>
<!-- jQuery -->
<script src="http://code.jquery.com/jquery.js"></script>
<!-- Bootstrap JavaScript -->
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
socket.on('liveStream', function(data) {
	$('#stream').attr('src', data.url);
	$('#timetext').text(data.time);
	$('.start').hide();
	});
function startStream() {
	socket.emit('start-stream');
	$('.start').hide();
}
</script>
</head>
<body class="container">
<h1 class="text-center">the view from my office
<small>Powered by PI</small>
</h1>
<hr>
<button type="button" id="" class="btn btn-info start" onclick="startStream()">Start Camera</button>
<div class="row">
<img src="" id="stream">
</div>
<div id="timetext" class="text-center"></div>
</body>
</html>

最初にstartStreamで、socket.emitで、"start-stream"を送付します。
後は、socket.onで、"liveStream"を受け取り画像と更新時間を再描画。

socket.on('liveStream', function(data) {
	$('#stream').attr('src', data.url);
	$('#timetext').text(data.time);
	$('.start').hide();
	});
function startStream() {
	socket.emit('start-stream');
	$('.start').hide();

node.jsってこんなに簡単にコーティング出来る。感動。

nohup node ./httpd/liveStreaming/index.js &
で起動します。

ターミナル閉じたいのでnohup にしました。

f:id:m-kei1:20150220133427p:plain

startCameraをクリック

f:id:m-kei1:20150220133433p:plain

オフィスというか僕のデスクからの外の景色です。
ちなみにカメラのびよ~んの奴がうまい事向きを調整できずに逆さカメラになっております

最後にgithubソースコード公開しました。


k1morikawa/RaspberryPI_LiveStreaming · GitHub

次回は、これをインターネットに公開しようと思います。

RaspberryPi

f:id:m-kei1:20150213124718j:plain
気がついたらRaspberryPi2が発売されてましたが、

RaspberryPi B+を購入しました。

RaspberryPi2では、Windows10も提供って事でIoT周りがドンドン盛り上がってきてます。


「Raspberry Pi 2」にWindows 10が無償提供されることが決定 - GIGAZINE


動かすに当たって、RaspberryPi だけではダメで色々と必要です。

・シリアル接続のコード
ディスプレイやキーボードを持ってればいいけど持ってなかったので。普通持ってないよね?
Amazon.co.jp: Raspberry Pi Arduino PL2303HX内蔵USBシリアル変換ケーブル: パソコン・周辺機器

・OSインストール済みSDカード
 普通、SDカードが読めるPCって持ってないよね。
Amazon.co.jp: debian OS for Raspberry Pi (Raspbian), OSインストール済み SDカード (microSDHC 32GB Class 6 (SDカードアダプタ付)): パソコン・周辺機器

wifiアダプター
 これも最近、ネットワークケーブルって周りに出てないでしょ
Amazon.co.jp: PLANEX 無線LAN子機 (USBアダプター型) 11n/g/b 150Mbps GW-USNANO2A (FFP): パソコン・周辺機器

って形で色々と揃える必要があります。

f:id:m-kei1:20150213115725j:plain
写真の様な形で接続して、下記からドライバーをDLしてインストールします。

http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=225&pcid=41

マニュアルに書いてある通り、自動でセットアップされたドライバーを削除して、このドライバーをインストールする必要がありました。

1.telnetで接続です。teratermを使いました。
f:id:m-kei1:20150213122221p:plain
接続後、シリアルのレートをraspberryPiに合わせて115200に変更します。

f:id:m-kei1:20150213122414p:plain
無事に接続されます!
こんな小さいのみ普通にLinuxが動いている事に感動です。

2.wifi設定
/etc/network/interfacesを編集

iface wlan0 inet dhcp
#iface wlan0 inet manual
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
#wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

/etc/wpa_supplicant/wpa_supplicant.confを編集

network={
ssid="YOUR_NETWORK_NAME"
psk="YOUR_NETWORK_PASSWORD"
proto=WPA2
key_mgmt=WPA-PSK
}

最後に
sudo ifdown wlan0
sudo ifup wlan0

で完了です。
ifconfigでwlan0 のIPを確認して、PCからsshも繋がりました。

3.node.jsを入れてみる

最初にnode.jsのバーション管理のnodebrewを入れます。

pi@raspberrypi:~$ curl -L git.io/nodebrew | perl - setup
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
100 22630  100 22630    0     0  10503      0  0:00:02  0:00:02 --:--:--  920k
fetching nodebrew...
install nodebrew in $HOME/.nodebrew

========================================
Add path:

export PATH=$HOME/.nodebrew/current/bin:$PATH
========================================

言われた通り環境変数追加

pi@raspberrypi:~$ vi ~/.bashrc
export PATH=$HOME/.nodebrew/current/bin:$PATH
pi@raspberrypi:~$ source ~/.bashrc

ということでnode.jsインストール

pi@raspberrypi:~$ nodebrew install-binary 0.10.28
fetch: http://nodejs.org/dist/v0.10.28/node-v0.10.28-linux-arm-pi.tar.gz
######################################################################## 100.0%                           36.9%
Install successful

pi@raspberrypi:~$ nodebrew use 0.10.28
use v0.10.28
pi@raspberrypi:~$ node -v
v0.10.28

expressでwebサーバー化

pi@raspberrypi ~ $ npm install -g express-generator
npm http GET https://registry.npmjs.org/express-generator
npm http 200 https://registry.npmjs.org/express-generator
npm http GET https://registry.npmjs.org/express-generator/-/express-generator-4.11.2.tgz
npm http 200 https://registry.npmjs.org/express-generator/-/express-generator-4.11.2.tgz
npm http GET https://registry.npmjs.org/commander
npm http GET https://registry.npmjs.org/mkdirp
npm http GET https://registry.npmjs.org/sorted-object
npm http 200 https://registry.npmjs.org/mkdirp
npm http 200 https://registry.npmjs.org/sorted-object
npm http 200 https://registry.npmjs.org/commander
npm http GET https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz
npm http GET https://registry.npmjs.org/sorted-object/-/sorted-object-1.0.0.tgz
npm http GET https://registry.npmjs.org/commander/-/commander-2.6.0.tgz
npm http 200 https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz
npm http 200 https://registry.npmjs.org/sorted-object/-/sorted-object-1.0.0.tgz
npm http 200 https://registry.npmjs.org/commander/-/commander-2.6.0.tgz
npm http GET https://registry.npmjs.org/minimist
npm http 200 https://registry.npmjs.org/minimist
npm http GET https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz
npm http 200 https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz
/home/pi/.nodebrew/current/bin/express -> /home/pi/.nodebrew/current/lib/node_modules/express-generator/bin/express
express-generator@4.11.2 /home/pi/.nodebrew/current/lib/node_modules/express-generator
├── sorted-object@1.0.0
├── commander@2.6.0
└── mkdirp@0.5.0 (minimist@0.0.8)
pi@raspberrypi ~ $

pi@raspberrypi:~$ vi ~/.bashrc
追加

export PATH=$HOME/.nodebrew/current/bin:$PATH
export PATH=$HOME/.nodebrew/node/v0.10.28/bin/express:$PATH
export NODE_PATH=$HOME/.nodebrew/node/v0.10.28/lib/node_modules

pi@raspberrypi:~$ source ~/.bashrc


pi@raspberrypi:~$ mkdir httpd
pi@raspberrypi:~$ cd httpd


pi@raspberrypi ~/httpd $ express -e sample

   create : sample
   create : sample/package.json
   create : sample/app.js
   create : sample/public
   create : sample/public/javascripts
   create : sample/public/images
   create : sample/public/stylesheets
   create : sample/public/stylesheets/style.css
   create : sample/routes
   create : sample/routes/index.js
   create : sample/routes/users.js
   create : sample/views
   create : sample/views/index.ejs
   create : sample/views/error.ejs
   create : sample/bin
   create : sample/bin/www

   install dependencies:
     $ cd sample && npm install

   run the app:
     $ DEBUG=sample:* ./bin/www

pi@raspberrypi ~/httpd $



pi@raspberrypi ~/httpd $ cd sample && npm install
npm http GET https://registry.npmjs.org/body-parser
npm http GET https://registry.npmjs.org/cookie-parser
npm http GET https://registry.npmjs.org/ejs
npm http GET https://registry.npmjs.org/morgan
npm http GET https://registry.npmjs.org/serve-favicon
npm http GET https://registry.npmjs.org/debug
npm http GET https://registry.npmjs.org/express
npm http 200 https://registry.npmjs.org/cookie-parser
npm http 200 https://registry.npmjs.org/serve-favicon
npm http 304 https://registry.npmjs.org/debug
npm http 304 https://registry.npmjs.org/express
npm http 200 https://registry.npmjs.org/morgan
npm http 200 https://registry.npmjs.org/ejs
npm http 200 https://registry.npmjs.org/body-parser
npm http GET https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.2.0.tgz
npm http GET https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.3.tgz
npm http GET https://registry.npmjs.org/morgan/-/morgan-1.5.1.tgz
npm http 200 https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.2.0.tgz
npm http GET https://registry.npmjs.org/ejs/-/ejs-2.2.4.tgz
npm http 200 https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.3.tgz
npm http GET https://registry.npmjs.org/body-parser/-/body-parser-1.10.2.tgz
npm http 200 https://registry.npmjs.org/ejs/-/ejs-2.2.4.tgz
npm http 200 https://registry.npmjs.org/morgan/-/morgan-1.5.1.tgz
npm http 200 https://registry.npmjs.org/body-parser/-/body-parser-1.10.2.tgz
npm http GET https://registry.npmjs.org/etag
npm http GET https://registry.npmjs.org/fresh
npm http GET https://registry.npmjs.org/ms
npm http GET https://registry.npmjs.org/parseurl
npm http GET https://registry.npmjs.org/cookie
npm http GET https://registry.npmjs.org/cookie-signature
npm http 304 https://registry.npmjs.org/fresh
npm http 304 https://registry.npmjs.org/etag
npm http 304 https://registry.npmjs.org/cookie-signature
npm http 304 https://registry.npmjs.org/ms
npm http 304 https://registry.npmjs.org/parseurl
npm http 304 https://registry.npmjs.org/cookie
npm http GET https://registry.npmjs.org/basic-auth
npm http GET https://registry.npmjs.org/depd
npm http GET https://registry.npmjs.org/on-finished
npm http 200 https://registry.npmjs.org/basic-auth
npm http 304 https://registry.npmjs.org/on-finished
npm http 304 https://registry.npmjs.org/depd
npm http GET https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.0.tgz
npm http 200 https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.0.tgz
npm http GET https://registry.npmjs.org/bytes
npm http GET https://registry.npmjs.org/iconv-lite
npm http GET https://registry.npmjs.org/raw-body
npm http GET https://registry.npmjs.org/media-typer
npm http GET https://registry.npmjs.org/qs
npm http GET https://registry.npmjs.org/type-is
npm http 200 https://registry.npmjs.org/raw-body
npm http 200 https://registry.npmjs.org/bytes
npm http 304 https://registry.npmjs.org/media-typer
npm http 304 https://registry.npmjs.org/type-is
npm http 200 https://registry.npmjs.org/iconv-lite
npm http 304 https://registry.npmjs.org/qs
npm http GET https://registry.npmjs.org/raw-body/-/raw-body-1.3.2.tgz
npm http GET https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz
npm http GET https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.6.tgz
npm http 200 https://registry.npmjs.org/raw-body/-/raw-body-1.3.2.tgz
npm http 200 https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz
npm http 200 https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.6.tgz
npm http GET https://registry.npmjs.org/crc
npm http 304 https://registry.npmjs.org/crc
npm http GET https://registry.npmjs.org/ee-first
npm http 304 https://registry.npmjs.org/ee-first
npm http GET https://registry.npmjs.org/on-finished
npm http GET https://registry.npmjs.org/parseurl
npm http GET https://registry.npmjs.org/methods
npm http GET https://registry.npmjs.org/range-parser
npm http GET https://registry.npmjs.org/type-is
npm http GET https://registry.npmjs.org/send
npm http GET https://registry.npmjs.org/cookie
npm http GET https://registry.npmjs.org/serve-static
npm http GET https://registry.npmjs.org/vary
npm http GET https://registry.npmjs.org/merge-descriptors
npm http GET https://registry.npmjs.org/utils-merge
npm http GET https://registry.npmjs.org/accepts
npm http GET https://registry.npmjs.org/cookie-signature
npm http GET https://registry.npmjs.org/content-disposition
npm http GET https://registry.npmjs.org/depd
npm http GET https://registry.npmjs.org/escape-html
npm http GET https://registry.npmjs.org/etag
npm http GET https://registry.npmjs.org/fresh
npm http GET https://registry.npmjs.org/finalhandler
npm http GET https://registry.npmjs.org/media-typer
npm http GET https://registry.npmjs.org/path-to-regexp
npm http GET https://registry.npmjs.org/proxy-addr
npm http 304 https://registry.npmjs.org/on-finished
npm http 304 https://registry.npmjs.org/parseurl
npm http 304 https://registry.npmjs.org/send
npm http 304 https://registry.npmjs.org/methods
npm http 304 https://registry.npmjs.org/cookie
npm http 304 https://registry.npmjs.org/range-parser
npm http 304 https://registry.npmjs.org/vary
npm http 304 https://registry.npmjs.org/serve-static
npm http 304 https://registry.npmjs.org/merge-descriptors
npm http 304 https://registry.npmjs.org/utils-merge
npm http 304 https://registry.npmjs.org/type-is
npm http 304 https://registry.npmjs.org/accepts
npm http 304 https://registry.npmjs.org/cookie-signature
npm http 304 https://registry.npmjs.org/content-disposition
npm http 304 https://registry.npmjs.org/depd
npm http 304 https://registry.npmjs.org/escape-html
npm http 304 https://registry.npmjs.org/etag
npm http 304 https://registry.npmjs.org/fresh
npm http 304 https://registry.npmjs.org/finalhandler
npm http 304 https://registry.npmjs.org/media-typer
npm http 304 https://registry.npmjs.org/path-to-regexp
npm http 304 https://registry.npmjs.org/proxy-addr
npm http GET https://registry.npmjs.org/crc
npm http GET https://registry.npmjs.org/ee-first
npm http GET https://registry.npmjs.org/mime-types
npm http GET https://registry.npmjs.org/negotiator
npm http GET https://registry.npmjs.org/mime-types
npm http GET https://registry.npmjs.org/forwarded
npm http GET https://registry.npmjs.org/ipaddr.js
npm http 304 https://registry.npmjs.org/crc
npm http 304 https://registry.npmjs.org/forwarded
npm http 304 https://registry.npmjs.org/ee-first
npm http 304 https://registry.npmjs.org/ipaddr.js
npm http 304 https://registry.npmjs.org/mime-types
npm http 304 https://registry.npmjs.org/negotiator
npm http 304 https://registry.npmjs.org/mime-types
npm http GET https://registry.npmjs.org/destroy
npm http GET https://registry.npmjs.org/ms
npm http GET https://registry.npmjs.org/mime
npm http 304 https://registry.npmjs.org/ms
npm http 304 https://registry.npmjs.org/destroy
npm http 304 https://registry.npmjs.org/mime
npm http GET https://registry.npmjs.org/mime-db
npm http 304 https://registry.npmjs.org/mime-db
npm http GET https://registry.npmjs.org/ee-first
npm http GET https://registry.npmjs.org/mime-types
npm http 304 https://registry.npmjs.org/ee-first
npm http 304 https://registry.npmjs.org/mime-types
cookie-parser@1.3.3 node_modules/cookie-parser
├── cookie@0.1.2
└── cookie-signature@1.0.5

debug@2.1.1 node_modules/debug
└── ms@0.6.2

morgan@1.5.1 node_modules/morgan
├── basic-auth@1.0.0
├── depd@1.0.0
└── on-finished@2.2.0 (ee-first@1.1.0)

serve-favicon@2.2.0 node_modules/serve-favicon
├── fresh@0.2.4
├── ms@0.7.0
├── parseurl@1.3.0
└── etag@1.5.1 (crc@3.2.1)

ejs@2.2.4 node_modules/ejs

express@4.11.2 node_modules/express
├── merge-descriptors@0.0.2
├── utils-merge@1.0.0
├── methods@1.1.1
├── cookie@0.1.2
├── fresh@0.2.4
├── escape-html@1.0.1
├── range-parser@1.0.2
├── cookie-signature@1.0.5
├── finalhandler@0.3.3
├── vary@1.0.0
├── media-typer@0.3.0
├── parseurl@1.3.0
├── serve-static@1.8.1
├── content-disposition@0.5.0
├── path-to-regexp@0.1.3
├── depd@1.0.0
├── on-finished@2.2.0 (ee-first@1.1.0)
├── qs@2.3.3
├── proxy-addr@1.0.6 (forwarded@0.1.0, ipaddr.js@0.1.8)
├── etag@1.5.1 (crc@3.2.1)
├── send@0.11.1 (destroy@1.0.3, ms@0.7.0, mime@1.2.11)
├── accepts@1.2.3 (negotiator@0.5.0, mime-types@2.0.9)
└── type-is@1.5.7 (mime-types@2.0.9)

body-parser@1.10.2 node_modules/body-parser
├── media-typer@0.3.0
├── bytes@1.0.0
├── raw-body@1.3.2
├── depd@1.0.0
├── on-finished@2.2.0 (ee-first@1.1.0)
├── qs@2.3.3
├── type-is@1.5.7 (mime-types@2.0.9)
└── iconv-lite@0.4.6
pi@raspberrypi ~/httpd/sample $
pi@raspberrypi ~/httpd/sample $ node app
依存モジュールを入れる

pi@raspberrypi ~/httpd/sample $ express -V
4.11.2
pi@raspberrypi ~/httpd/sample $ npm start

> sample@0.0.0 start /home/pi/httpd/sample
> node ./bin/www

無事動いた。パチパチ。
f:id:m-kei1:20150213123906p:plain

この後色々とやってみます。楽しみ。

VBAでWinHttp.WinHttpRequestで画面引き継ぐには、Keep-Aliveが必要だった

Web上のログイン画面とか色々とexcelVBAでちょちょいと調べたりする事あるじゃないですか。

で、WEBAPIを叩いてたですが、

1番目のapiでcodeを取得して、そのcodeで
2番目のapiを叩くみたいな処理をexcelVBAで作ってたら、何故かエラー。

    Dim url As String
    Const app_id = "AAA"
    Const secret = "BBB"
       
    url = "https://hoge.com/v1/oauth?app_id=" & app_id

    Dim xmlhttp As Object
    Dim xNode As Object
    Dim xNode2 As Object
    Dim retCd   As String
    Dim xdoc As Object
    Dim code As String
    Dim AccessToken As String
    
    Set xmlhttp = CreateObject("WinHttp.WinHttpRequest.5.1")
    xmlhttp.Open "GET", url, False
    xmlhttp.send (Null)

    retCd = xmlhttp.Status    '結果コード取得

    If retCd <> 200 Then
        Debug.Print "error:" & retCd
        Exit Sub
    Else
        Debug.Print xmlhttp.getAllResponseHeaders()
        'Debug.Print StrConv(xmlhttp.responsebody, vbUnicode)
        code = getValueFromXml(StrConv(xmlhttp.responsebody, vbUnicode), "Code")
    End If
    
    url = "https://hoge.com/v1/token"
    xmlhttp.Open "POST", url, False
    xmlhttp.SetRequestHeader "Content-Type", "application/x-www-form-urlencoded"
    
    Dim postData As Variant
    postData = "grant_type=oauth_code&app_id=" & app_id & "&secret=" & secret & "&code=" & code
    xmlhttp.send ("grant_type=oauth_code&app_id=" & app_id & "&secret=" & secret & "&code=" & code)

全くうまく行かない。
ブラウザでやるとうまくいきます。

最初cookieと思って、レスポンスヘッダーを調べてみたら何も入ってない!

なんだ!

と色々と悩んだ結果、Keep-Aliveを設定したら動いたというオチ。

    xmlhttp.SetRequestHeader "Connection", "Keep-Alive"

こんな事あるんだ。
2時間返せ

Unimedia モンゴルアプリコンテスト2014!

1月24日にUnimedia モンゴルアプリコンテスト2014!の決勝戦を行いました。

■Service/Tool部門

1-位 iLamp(D.Amartuvshin)f:id:m-kei1:20150128133523j:plain
buletoothでLEDとスマフォを繋いでコントロールするアプリです。
日本でもスピーカー付きが7000円とかで発売されてますが、安価に開発出来ればニーズはありそうです。
なにより自分でマイクロチップ使って、LEDと配線してるのを見て感動しました。

2-位 Happy Baby2.0(Happy Baby)f:id:m-kei1:20150128133526j:plain
この二人は昨年も応募してくれてて、しかも去年と同じくお子さんを授かってました。モンゴル人数増加で国安泰ですね(w
赤ちゃんの成長を記録するアプリです。
googleのmaterial designでUIが作られてて非常に綺麗でした。

3-位 Smart Hand Driver(S.Khangal)f:id:m-kei1:20150128133529j:plain
こちらは、入力が難しいモンゴルのキリル文字の入力アプリです。
タイプではなくてドラッグして文字入力できるアプリです。

■Game部門

1-位 Spelling Sheep(Batkholboo)f:id:m-kei1:20150128133715j:plain
タイピングゲーム。スペルを間違えたり、タイピングが遅かったら、フェンスの中の可愛い羊たちが狼にとらわれるゲーム。
キャラクターを写真から起こしてるという事で非常に綺麗なグラフィックでした。

2-位 Pill heals(Pill heals)f:id:m-kei1:20150128133517j:plain
薬が患部へ到着させる事をコンセプトにしたジャイロゲームです。途中さまざまなウィルスが邪魔をします。
結構はまります(w

3-位 Apipo(Usukhbayar)f:id:m-kei1:20150128133520j:plain
VR技術を使ったゲーム。画面から出てきた色に対して、同色の色のリアルカードで対応させます。

最後に記念撮影
f:id:m-kei1:20150128133511j:plain

IoTでbluetoothだったり、VR、3Dゲームや、material design等のアプリが沢山応募ありました。
昨年よりも格段レベルが高くなってきてます。
この中から幾つが製品化される物も出ると思います。今後も楽しみです。

次回は今年の11月頃を予定してますが、次回は大学でのunimediaラボからも応募が来ると思うので更にレベルアップが期待出来そうです。

littleBit

IoTという事でlittleBit入手しました。
f:id:m-kei1:20150127180908j:plain

磁石でブロックを組み立てる感じで出来るのが売りです。
Arduinoの様な配線は必要ありません。

サイトも用意されてます。
littleBits Cloud Control

ここでセットアップする事ができます。

f:id:m-kei1:20150127180927p:plain
アプリ名を入力



f:id:m-kei1:20150127180931p:plain
ランプが点灯するまで待ちます。
littleBitはLinuxが入ってるので起動まで時間が掛かります。



f:id:m-kei1:20150127180936p:plain
次にwifiでlittleBitに接続します。wifiまで最初から実装って凄いですね。
つなぐとwifi設定画面に移行します。
これでlittleBit自体がwifi接続可能になります。



f:id:m-kei1:20150127180940p:plain
完了すると管理画面みたいなのに遷移します。
これからテストです



f:id:m-kei1:20150127180944p:plain
次にボタンを繋ぎます。単純に磁石でくっつけるだけです。
その後グリーンになるまで待ちます



f:id:m-kei1:20150127180951p:plain
次は、LEDをつないで、同じでグリーンになるまで待ちます。



f:id:m-kei1:20150127180956p:plain
ここでWEB側でボタンを押すとLEDが点灯します!
littleBitがサイトにアクセスしてボタンの状態を取得してる様ですね。



f:id:m-kei1:20150127180959p:plain
次は、ボタン状態がメーター表示される。



f:id:m-kei1:20150127181003p:plain
押すとバーが動きました



f:id:m-kei1:20150127181006p:plain
これで一通り完了です。



f:id:m-kei1:20150127181010p:plain
f:id:m-kei1:20150127181014p:plain
f:id:m-kei1:20150127181017p:plain
IFTTTと連携出来るんですね。



f:id:m-kei1:20150127181021p:plain
littleBitチャンネルがあって沢山のアプリがあります。

f:id:m-kei1:20150127181026j:plain
最後に完成写真です。

littleBitはプログラミングは出来ないみたいですが、
IFTTT経由だったり、Arudinoもモジュールも発売されてます。


知育電子ブロック工作のlittleBitsに、プログラマブルArduinoモジュールが登場 - TechCrunch

米ドル為替チェックアプリ作成! by ArduinoとProcessing

昨年買ったArduinoで米ドル為替チェックアプリ作成してみました。

先ずはProcessingを入手します。
https://processing.org/download/
最新版は、processing-2.2.1でした。

これでproccesingがネット情報のデータを取得して、シリアルポート経由でArduinoと通信できる訳です。
proccesingはjavaで書けます。
シリアルポートの通信もこんな感じです。

  port = new Serial(this, arduinoPort, 9600); // connect to Arduino

yahooからUSDJPYのデータを取得して、その後パースします。

   String url = "http://info.finance.yahoo.co.jp/fx/detail/?code=USDJPY=FX";
   String[] lines = loadStrings(url);
    
   // Turn array into one long String
   String xml = join(lines, "" ); 

以下全ソースコード

import processing.serial.*;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

import processing.serial.*;

int interval = 10; // retrieve feed every 60 seconds;
int lastTime;      // the last time we fetched the content

int light = 0; // light level measured by the lamp

Serial port;
color c;
String cs;

String doll;
String doll_old;

String buffer = ""; // Accumulates characters coming from Arduino

PFont font;

void setup() {
  size(640, 480);
  frameRate(10); // we don't need fast updates

  font = loadFont("HelveticaNeue-Bold-32.vlw");
  fill(255);
  textFont(font, 32);

  // IMPORTANT NOTE:
  // The first serial port retrieved by Serial.list()
  // should be your Arduino. If not, uncomment the next
  // line by deleting the // before it, and re-run the
  // sketch to see a list of serial ports. Then, change
  // the 0 in between [ and ] to the number of the port
  // that your Arduino is connected to.
  //println(Serial.list());
  String arduinoPort = Serial.list()[0];

  port = new Serial(this, arduinoPort, 9600); // connect to Arduino
  lastTime = 0;
  fetchData();
}

void draw() {
  background( c );
  int n = (interval - ((millis()-lastTime)/1000));
  int up=0;
  int stay=0;
  int down=0;

  if(Float.parseFloat(doll) > Float.parseFloat(doll_old)){
     up = 255;
  }else if(Float.parseFloat(doll) < Float.parseFloat(doll_old)){
     down = 255;
  }else{
     stay = 255;
  }

  // Build a colour based on the 3 values
  c = color(up, stay, down);
  cs = "#" + hex(c, 6); // Prepare a string to be sent to Arduino

  text("Arduino Networked Lamp", 10, 40);
  text("Reading $doll:", 10, 100);
  text(doll, 10, 140);

  text("Next update in "+ n + " seconds", 10, 450);

  text("up", 10, 200);
  text(" " + up, 130, 200);
  rect(200, 172, up, 28);

  text("down ", 10, 240);
  text(" " + down, 130, 240);
  rect(200, 212, down, 28);

  text("stay ", 10, 280);
  text(" " + stay, 130, 280);
  rect(200, 252, stay, 28);

  // write the colour string to the screen
  text("sending", 10, 340);
  text(cs, 200, 340);
  text("light level", 10, 380);
  rect(200, 352, light/10.23, 28); // this turns 1023 into 100

  if (n <= 0) {
    fetchData();
    lastTime = millis();
  }

  port.write(cs); // send data to Arduino

  if (port.available() > 0) { // check if there is data waiting
    int inByte = port.read(); // read one byte
    if (inByte != 10) { // if byte is not newline
      buffer = buffer + char(inByte); // just add it to the buffer
    }
    else {

      // newline reached, let's process the data
      if (buffer.length() > 1) { // make sure there is enough data

        // chop off the last character, it's a carriage return
        // (a carriage return is the character at the end of a
        // line of text)
        buffer = buffer.substring(0, buffer.length() -1);

        // turn the buffer from string into an integer number
        light = int(buffer);

        // clean the buffer for the next read cycle
        buffer = "";

        // We're likely falling behind in taking readings
        // from Arduino. So let's clear the backlog of
        // incoming sensor readings so the next reading is
        // up-to-date.
        port.clear();
      }
    }
  }
}

void fetchData() {
  try {
		doll_old = doll;

	   // Get all the HTML/XML source code into an array of strings
	    // (each line is one element in the array)
	    String url = "http://info.finance.yahoo.co.jp/fx/detail/?code=USDJPY=FX";
	    String[] lines = loadStrings(url);
	    
	    // Turn array into one long String
	    String xml = join(lines, "" ); 
	    
	    String lookfor = "<dd id=\"USDJPY_detail_bid\">";
	    String end = "</span>";
	    doll = giveMeTextBetween(xml,lookfor,end);
	    doll = doll.replace("<span class=\"large\">", "");
		if(doll_old==null)
			doll_old = doll;

	    System.out.println(doll);

	} catch(Exception e){
	    e.printStackTrace();
        System.out.println("ERROR: "+e.getMessage());
	}
}

// A function that returns a substring between two substrings
String giveMeTextBetween(String s, String before, String after) {
	String found = "";
	int start = s.indexOf(before);    // Find the index of the beginning tag
	if (start == - 1) return"";       // If we don't find anything, send back a blank String
	start += before.length();         // Move to the end of the beginning tag
	int end = s.indexOf(after,start); // Find the index of the end tag
	if (end == -1) return"";          // If we don't find the end tag, send back a blank String
	return s.substring(start,end);    // Return the text in between
}

こちらは、Arduino側です。「Arduinoをはじめよう」のサンプルそのままです。

const int SENSOR = 0;
const int R_LED = 9;
const int G_LED = 10;
const int B_LED = 11;
const int BUTTON = 7;

int val = 0; // variable to store the value coming from the sensor

int btn = LOW;
int old_btn = LOW;
int state = 0;
char buffer[7] ;
int pointer = 0;
byte inByte = 0;

byte r = 0;
byte g = 0;
byte b = 0;

void setup() {
  Serial.begin(9600); // open the serial port
  pinMode(BUTTON, INPUT);
}

void loop() {
  val = analogRead(SENSOR); // read the value from the sensor
  Serial.println(val);      // print the value to
  // the serial port

  if (Serial.available() >0) {

    // read the incoming byte:
    inByte = Serial.read();

    // If the marker's found, next 6 characters are the colour
    if (inByte == '#') {

      while (pointer < 6) { // accumulate 6 chars
        buffer[pointer] = Serial.read(); // store in the buffer
        pointer++; // move the pointer forward by 1

      }

      // now we have the 3 numbers stored as hex numbers
      // we need to decode them into 3 bytes r, g and b
      r = hex2dec(buffer[1]) + hex2dec(buffer[0]) * 16;
      g = hex2dec(buffer[3]) + hex2dec(buffer[2]) * 16;
      b = hex2dec(buffer[5]) + hex2dec(buffer[4]) * 16;

      pointer = 0; // reset the pointer so we can reuse the buffer
    }
  }

  btn = digitalRead(BUTTON); // read input value and store it

  // Check if there was a transition
  if ((btn == HIGH) && (old_btn == LOW)){
    state = 1 - state;
  }

  old_btn = btn; // val is now old, let's store it

  if (state == 1) { // if the lamp is on

    analogWrite(R_LED, r); // turn the leds on
    analogWrite(G_LED, g); // at the colour
    analogWrite(B_LED, b); // sent by the computer
  } 
  else {

    analogWrite(R_LED, 0); // otherwise turn off
    analogWrite(G_LED, 0);
    analogWrite(B_LED, 0);
  }

  delay(100); // wait 100ms between each send
}

int hex2dec(byte c) { // converts one HEX character into a number
  if (c >= '0' && c <= '9') {
    return c - '0';
  } 
  else if (c >= 'A' && c <= 'F') {
    return c - 'A' + 10;
  }
}

後は、Arduinoを配線して完了です。
f:id:m-kei1:20150109110222j:plain
f:id:m-kei1:20150109110229j:plain

上昇したら赤、同じなら青、下がったら黄色が点灯します。
これは、processingの画面です。
f:id:m-kei1:20150109110023p:plain

これで安心して仕事が出来ますね(w

githubにソースを公開しときました!

k1morikawa/arduino_processing · GitHub

2015あけましておめでとうございます!!

昨年末、モンゴルでユニメディアのラボを設立しました!

モンゴル科学技術大学、モンゴル国立大学でオープニングセレモニーを行いました。

人生初の白手袋はめてリボンカットを行いました!!!


atモンゴル科学技術大学
f:id:m-kei1:20150101174512j:plain
モンゴル科学技術大学サイトhttp://www.sict.edu.mn/content/News/NewsDetail.aspx?m=1&newsID=298

atモンゴル国立大学
f:id:m-kei1:20150101174534j:plain
モンゴル国立大学サイトhttp://news.num.edu.mn/?p=22037

Google Glass、AndroidWearでGalaxy Gear2、iBeaconでStickFind、IoTでCloudBit等の研究開発を始めます!
モンゴルから世界へ未来へ!!

今年は1月24日には、モンゴルで2回目のアプリコンテストも行います!

ガートナーの2014ハイプ・サイクルの中で僕なりにポイント絞った戦略です。

http://www.gartner.co.jp/press/html/pr20140903-01.html
http://www.gartner.co.jp/press/html/img/pr20141029-01_img01.gif

やったります!ので!

2015もよろしくお願い致します!

森川敬一