渋谷モノ系ミートアップやってみます

久々にイベントを立てた。

渋谷モノ系ミートアップ

モノ系主体のイベントとかミートアップはよくあるけど、Web、ネット側からモノ系にアプローチしてやっている所からの…といった感じで、モノ系な人とネット系な人とのミートアップになれば…と。前にやっていたSolr勉強会以来、かなり久々です。

別に渋谷が好きとか何とかじゃないけど、渋谷周辺にはアプリ、サービス、課金、ネット広告をやっている会社がゴロゴロしている。そして、システムもシステムの自動化、運用はもちろん、凄まじく膨大なデータを使った機械学習もノウハウがとってもあると思われ。(それはそうで、大量のサービスをやっている所に大量のデータが集まるというのも自然なので、データが大量にあればそれを生かす技術も発達するわけで)

自分が率直に感じているのは、IoTという言葉自体はそんなに好きじゃなく(顔文字にしか見えないw)、モノを使ったサービスの総称といった感じが。そこで、面白い、触ってみて楽しいモノというだけじゃなく、それを使ったサービスやアプリ、または課金/広告といった方法、超大規模システム、データの扱いを日常的にやっている所との繋がり、両輪が間違いなく必要になると思われ。dailyで数億のアクセスが一気に来るとか、多分モノ寄りの方は経験が無いと思われで、逆にネット寄りの方はこの端末・センサーが…とか扱う特性とかさっぱり分からないはず。

ただ、両方にちょっぴり顔を出している感じとしては…技術の下地(モノ寄り、Web寄り)が違うので、技術・サービスのミートアップでお互いが会う事がない、これに尽きる。
それぞれの技術が全く違うというのもあって、例えばネット寄りの人に「この回路でセンサーの値を取って…」とか簡単なものでも理解を得られる事がとっても少ない…(経験上)。もちろん逆もまた然りとは思ったりも。

ネット系の方は「このガジェット面白い!!」とか興味津々だったりするし、モノ寄りの方は機械学習(AI的な)とか広告、超大規模システムの作りとか興味津々かなと。例えば数億/dailyでガツンとアクセスが来るとか、モノが当たってシステムをスケール・自動化する時とかどーするか?だったりは、ネット系のノウハウが必要になると思われ。

どちらの分野でも、この人マジですげぇ!!と思う人は沢山いる中で、両輪が交わらないのは勿体なさすぎる!!という所が多分にあったりする。モノ系の方も、ネット系の方もぜひぜひ!!

現状のタイムラインはこちら。LTは絶賛募集です。

  • 場所 : 21cafe 東京都渋谷区道玄坂1-14-6 ヒューマックス渋谷ビル3F
  • 日時 : 2015/11/05(木) 18:30-(開場), 19:00-開始
  • 定員 : 80名sdf
  1. Beatrobo, Inc 浅枝大志さま
    レトロゲームをスマホ用に復活!ピコカセット
  2. フリービット株式会社 渡辺知男さま
    ドローン + IT + ウェアラブル(仮)
  3. GMOインターネット 宮尾 武裕さま
    O2O iBeaconを使ったサービスについて(仮)
  4. LT
    1. Web/ネット系からモノ系開発への関わりについて : hirotakaster
    2. レゴマインドストームのクラウド連携(Azure,AWS) : 渡辺 登 さま
    3. プログラマ向けハードウェア自動設計ツール ミルフィーユ Kou Yosinariさま

Raspberry PIとSensor Tag

Raspberry Pi2にBluetoothのドングルを指して、Broadcom WICED SenseとTI SensorTagに同時にBluetooth経由でNodeJSでアクセスする方法について、備忘録で残しておく。

– 現物
右 : Broadcom WICED Sense
左 : TI Sensor Tag
IMG_8841

Broadcom WICED Sense
搭載されているセンサーとしては、加速度、ジャイロ、電子コンパス、気圧、温度、湿度が取れますね。BluetoothはBCM20737S。スイッチサイエンスさん、マクニカオンラインさんとかでゲットできるですね。

TI Sensor Tag
こちらは、CC2650が搭載された激しめの端末。加速度、ジャイロ、3軸磁力計(というかMPU 9250)、照度、湿度、気圧、磁気、IRサーモパイルセンサといった感じで盛り積み。

– Raspberry PI2上での作業
NodeJSとbluezを入れるだけ。

uname -a 
# nodejsとbluezのインストール
# Linux raspberrypi 4.1.7-v7+ #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015 armv7l GNU/Linux
# RASPBIAN JESSIEを使っています。
# 
sudo wget http://node-arm.herokuapp.com/node_latest_armhf.deb
sudo dpkg -i node_latest_armhf.deb
node -v 
npm -v
sudo apt-get install bluez

– WICED Senseにつなぐ

npm install cylon
npm install cylon-ble
npm install cylon-wiced-sense

test.js

var Cylon = require('cylon');
// UUIDはhcitool lescanで見れるMacアドレス
// 00:10:18:01:4A:FA WICED Sense Kit
// こんな感じで
Cylon.robot({
  connections: {
    bluetooth: { adaptor: 'ble', uuid: '001018014afa' }
  },

  devices: [
    {name : 'wiced',  driver: 'wiced-sense' },
  ],

  display: function(err, data) {
    if (err) {
      console.log("Error:", err);
    } else {
      console.log("Data:", data);
    }
  },

  work: function(my) {
    my.wiced.getData(function(err, data) {
      if (!!err) {
        console.log("Error: ", err);
        return;
      }
      console.log("Data: ", data);
    });
  }
}).start();

結果

sudo node test.js     
2015-10-15T07:22:39.092Z : [Robot 1] - Starting connections.
2015-10-15T07:22:39.152Z : [Robot 1] - Starting connection 'bluetooth'.
2015-10-15T07:22:43.960Z : [Robot 1] - Starting devices.
2015-10-15T07:22:43.963Z : [Robot 1] - Starting device 'wiced'.
2015-10-15T07:22:43.963Z : [Robot 1] - Working.
Data:  { accelerometer: { x: 0, y: 0, z: 89 },
  gyroscope: { x: -50, y: -247, z: -222 },
  magnetometer: { x: 548, y: 653, z: -1464 } }
Data:  { accelerometer: { x: 1, y: 0, z: 88 },
  gyroscope: { x: 6, y: -249, z: -220 },
  magnetometer: { x: 535, y: 656, z: -1463 } }
Data:  { accelerometer: { x: 0, y: 0, z: 89 },
  gyroscope: { x: -19, y: -219, z: -217 },
  magnetometer: { x: 553, y: 651, z: -1460 } }
Data:  { accelerometer: { x: 0, y: 0, z: 88 },
  gyroscope: { x: 24, y: -250, z: -208 },
  magnetometer: { x: 558, y: 643, z: -1451 } }
Data:  { accelerometer: { x: 1, y: 0, z: 89 },
  gyroscope: { x: 30, y: -243, z: -215 },
  magnetometer: { x: 558, y: 648, z: -1448 } }
Data:  { accelerometer: { x: 0, y: 0, z: 89 },
  gyroscope: { x: -11, y: -243, z: -204 },
  magnetometer: { x: 565, y: 671, z: -1460 } }
Data:  { accelerometer: { x: 1, y: 0, z: 90 },
  gyroscope: { x: 9, y: -246, z: -225 },
  magnetometer: { x: 562, y: 646, z: -1440 } }
Data:  { accelerometer: { x: 0, y: 0, z: 89 },
  gyroscope: { x: 10, y: -227, z: -206 },
  magnetometer: { x: 557, y: 651, z: -1462 } }
Data:  { accelerometer: { x: 0, y: 0, z: 89 },
  gyroscope: { x: -12, y: -251, z: -223 },
  magnetometer: { x: 556, y: 642, z: -1451 } }
Data:  { humidity: 701, pressure: 10120, temperature: 285 }
Data:  { accelerometer: { x: 0, y: 0, z: 89 },
  gyroscope: { x: 3, y: -248, z: -196 },
  magnetometer: { x: 554, y: 655, z: -1455 } }

– Sensortagにつなぐ

npm install async
npm install bluebird
npm install sensortag 

test.js

var SensorTag = require('sensortag');

// UUIDはhcitool lescanで見れるMacアドレス
// 68:C9:0B:06:E4:8D CC2650 SensorTag
// こんな感じで
SensorTag.discoverByAddress("68:C9:0B:06:E4:8D", function(tag) {
    tag.on('disconnect', function() {
        console.log('disconnected!');
        process.exit(0);
    });

    function connectAndSetUpMe() {
        console.log('connectAndSetUp');
        tag.connectAndSetUp(enableTempMe);
    }

    function enableTempMe() {
        console.log('enableSensor');
        tag.enableHumidity(notifyMe);
        tag.enableLuxometer(notifyLux);
    }

    function notifyLux() {
    }

    function notifyMe() {
        tag.notifyHumidity(listenForHumidity);

        tag.setHumidityPeriod(10000, function(error) {
            if (error != null)
                console.log(error);
        });
    }

    function listenForHumidity() {
        tag.on('humidityChange', function(temperature, humidity) {
            tag.readLuxometer(function(error, lux) {
                console.log('\tlux = %d', lux.toFixed(1));
                console.log('\thumidity Temp = %d deg. C', temperature.toFixed(1));
                console.log('\tthumidity  = %d', humidity.toFixed(1));
            });
        });
    }

    connectAndSetUpMe();
});

結果

sudo node test.js 
connectAndSetUp
enableSensor
	lux = 134185
	humidity Temp = 27.2 deg. C
	thumidity  = 64.9
	lux = 140.2
	humidity Temp = 27.2 deg. C
	thumidity  = 64.9
	lux = 140.6
	humidity Temp = 27.2 deg. C
	thumidity  = 64.9

めちゃ簡単。

KoshianとFluent, Elasticsearch/Kibanaでリアルタイム可視化

Koshianを使ってセンサーデータのリアルタイム可視化・分析可能な構成を考えて作ってみたメモ。全体構成はこんな感じ。

全体構成
全体図.001
MQTTを使っても大丈夫で、MQTTでもOK。ただ、敢えて使わない。使わない理由は以下にて。

可視化の様子(Kibana)
pic
温度のグラフ、device_id(データを送ってきたデバイス毎のID)、接続元IPを使った位置情報を表示している。

やってみたいこと
1. センサーデータを可視化 -> es/kibana
2. リアルタイムが良い、センサーデータのストリームにも耐性がある -> fluentd
3. 大規模、並列化/スケールする -> es/fluentd/AP(golang)
4. 解析/分析も可能 -> fluentdからhadoopとかに流し込みでも可

使うもの
fluentd : ログ集約配送
elasticsearch : 検索用DB
kibana : 可視化
golang : gwとのやりとり用
ConoHA : クラウドのサーバ

KoshianはWeb系の人にはさーっぱり馴染みも無いと思うけど、安くてBTもサクッと使えるという素敵な端末。逆にモノをいじる方には、es(elasticsearch)、fluentd、kibanaとかナニソレ的な感じもするけど、かなり使われている感がする。特に可視化、リアルタイム、スケールするといった所では、導入検討はするはず。

なぜMQTTを使わないか?
自分がよく使うMQTTは使いません。サーバはUbuntuで立てているから、mosquittoとか使えば簡単なんだけど。その場合、golangの口をMQTTに入れ替えればOK、それでも動くですね。GW(iphone)がpublisherで間にMQTT Brokerが挟まったgolang(subscriber)で取得といった感じで。まぁ簡単に動かせる。

ただ、なぜにMQTTでセンサーデータの配送をしないか?というと、MQTT broker経由でsubscriber側で取得するともちろんpub側のIPが分からない。pub/subでのメッセージ配送物なのでそういうもんだけど。

インターネット上を流れてくるなら発信者のIPは知りたいし、データ発信者(デバイス)の発信者情報(IP)を受け取り手側で処理はしたくなるというか、これみたいに簡単に地図上に表示したくなった時とかでも。まぁ、IPと位置情報は正確には関連性が無いんだけどね。
デバイス/GW側でGPS情報を送信データに付与すれば…というのはそうだけど、別に位置が知りたい訳ではなくIPが知りたい。逆にMQTT BrokerでIPをメッセージに付与…は無いし、Brokerだけで動くならそもそもpub/subの意味は無い。

ちなみに、IPのログとしての意味では、MQTT Broker側ではログとしてID/IP/配送先のID/IPは残しておく必要はあるはず。そうしないと、怪しいメッセージの配送、不正ID・ユーザの混入といった時にかなり厄介なことになるし、追跡手段として残しておくことになるかと。

そこまでしてMQTTか?といったらちょっと別の用途で使った方が好いと思われ。例えば、閉じた(宅内)NWとかバックエンドの配送では良いかなと。セキュリティ的に閉じていれば、その辺のことはある程度すっ飛ばして考えらえるから。
要はインターネット、Globalで利用する時、実際の運用・管理でどーするか?。MQTT Brokerも自分の管理で全て把握できるならそれでも良い気はするけど、この辺の解を持っている人がいたら教えて欲しい。

td-agentの設定
ここではIPアドレスを追記している。センサーデータの増減には全く影響を受けないから素敵。

# GEOIPで位置情報・国コードの追加
<match debug.temp>
  type geoip
  geoip_lookup_key ipaddr
  <record>
    lat   ${latitude["ipaddr"]}
    lon   ${longitude["ipaddr"]}
    location_properties  '{ "lat" : ${latitude["ipaddr"]}, "lon" : ${longitude["ipaddr"]} }'
    country ${country_code['ipaddr']}
  </record>
  tag store.${tag}
</match>

# elasticsearchに登録
<match store.debug.temp>
  type copy
  <store>
    type stdout
  </store>
  <store>
    type elasticsearch
    host localhost
    port 9200
    logstash_format true
    logstash_prefix temp

    tag_key @log_name
    include_tag_key true
    flush_interval 10s
  </store>
</match>

golang側
golangはこんな感じ。サクッと書いて、すぐ使えるから好き。スケールさせたかったら並べればOK。

package main
import (
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/ant0ine/go-json-rest/rest"
	"github.com/t-k/fluent-logger-golang/fluent"
)

// 受信データ用のstruct
type SensorData struct {
	DeviceId string
	Temp     string
}

func main() {
	logger, err := fluent.New(fluent.Config{FluentPort: 24224, FluentHost: "ip addr"})

	if err != nil {
		fmt.Println(err)
	}
	defer logger.Close()

        // GW(iphone)からは、RESTで/put/を叩く。
	api := rest.NewApi()
	api.Use(rest.DefaultDevStack...)
	router, err := rest.MakeRouter(
		rest.Post("/put/", func(w rest.ResponseWriter, req *rest.Request) {
			SensorData := SensorData{}
			err := req.DecodeJsonPayload(&SensorData)
			log.Println(req.Body)
			if err != nil {
				rest.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

                        // このtagはfluentの方と合わせておく
			tag := "debug.temp"
			t := time.Now()

                        // 温度, 接続元IP, device-id(端末からくる)を送信
                        // センサーデータが増えた時はこの辺で追加。ここでは温度のみ。
			data := map[string]string{
				"temp":      SensorData.Temp,
				"ipaddr":    strings.Split(req.RemoteAddr, ":")[0],
				"device-id": SensorData.DeviceId,
			}

                        // fluentd行き
			logger.PostWithTime(tag, t, data)

			w.WriteJson("OK")
		}),
	)
	if err != nil {
		log.Fatal(err)
	}
	api.SetApp(router)
	log.Fatal(http.ListenAndServe(":8080", api.MakeHandler()))
}

その他
es/kibanaの設定方法はググれば書いてある。GW(iphone)からはBLEでKoshianから値を取得して、RESTで叩くだけでOK。とっても簡単。MQTTを使う時は、PodでMQTTKitを入れてすぐ使えるから、それも問題ないでしょう。あと認証をしたくなったらMariaDBでも立てて、そこで管理してあげる感じ。暗号化はTLSで証明書でも突っ込んでおいて。
若干身内感はするけど、ConoHaイケてる。客観視で使ってみて、性能(CPU/SSD)、価格的にもこれは良いと普通に思った。