SoracomでIPv6を使う

この記事はSORACOMさんのSoftware Design巻頭特集記念リレーブログ 5/4日の記事です。

何か面白い使い方を?というのを考えて、やはり自分と言ったらIPv6じゃん(w)ということで、SoracomのNW上でIPv6を使うことに。

なぜIPv6か

普通に使うとMVNOのNWで端末にはIPv4プライベートが降ってくるですね。まぁ、Global IPv4が降ってきたらちょっぴりビックリはするけど、プライベートIPということで、上位のNWから直接何か攻撃されるとかってリスクは防げている。
ただし、やっぱりあれだよね、IoTというかM2M的というか、はるか昔からそれ系のと言ったら…IPv6(藁)だーよーね。IPv6 Globalを降るとIPv6 NW側から直接端末にリーチする事が出来るようになる。これはこれで便利。ただし、Global IP直撃アタックのリスクも出てくる。その辺は、NWがNativeでIPv6に対応していて、上位のFWで選択的にACLを書けたら素敵だなーとは思うけど、とりあえずは端末に直撃で振って使う事に。

使うもの

使うものはRPi3、L-02C、soracom simです。
IMG_1127

ここで、端末にどーやってIPv6を振るか…というと、トンネル、VPNものですね。ただし、NAT越えか上位ルータでのプロトコル番号41番を通したりが必要になったりする。

1) Hurricane Electric IPv6ブローカを使ってみる
これはうまくいった。上位のNWで41番通してくれているのね(多分)。本当は6to4とか残っていたらなーとか思ったけど、見つけられなかった。もうこの手のトンネルものはIPv6の普及と共に少なくなってきたもんね。
このHurricane Electricのは適当にメアドで登録するとブローカが使えるようになる。ただし、1日にGlobal IPに対して2個の設定しか食わせられない…そう、仮に上位のNWのGlobal IPが変わると割り当てされるブローカ、IPv6が変わるというか再設定をするハメになるから、ちょっとなぁ…といった感じだった。

2) SoftEther IPv6割り当てサービスを使う
これはたまに使っているIPv6接続サービス。素晴らしいっす。これを使うと構成は次のようになる。

RPi用のARM SoftEtherクライアントでIPv6サーバに接続することで、IPv6のNWを引き込むことができる。これで別のIPv6 NW上のサーバから直撃でアクセスも可能になる。実際に接続した状態はこちら。

ppp0はsimで接続したもので、vpn_soracomはSoftEther VPN IPv6接続で作ったinterface。ちゃんと2001から始まるGlobal IPv6が振られてますね。(あ、もうこのIPにアクセスしてもムルポッス。止めてるから:)
これでやりたい事は出来た。次に実際データを流してみる。

パケット圧縮を使う

SoftEtherにはパケット圧縮という機能が付いていて、これを利用するとNW上に流れるパケットを事前に圧縮する事が出来る。もちろん、Plain Textとかだと効率がいいけど、バイナリだと効率が悪くなる。とわ言え、流したデータ量に対して従量課金が発生すると思うと、この辺はできるだけ抑えたくなる。
ということで、IPv6サーバから毎秒ping6を流して、圧縮、非圧縮じのデータ量比較を確認してみる。

結果はこちら。これはSoracomさんの時間毎データ量から見ることができる。

1) 一番右のもっともデータ量が大きい : 非圧縮
2) 右から2番目のもの : 圧縮
3) 右から3番目より左 : ping6も何も投げない定常接続

ということで、ping6のデータ(64byte文字)だと当然っちゃ当然の結果になった。何もしないで接続だけの場合だと1MByteくらいのデータ量で、毎秒ping6(64byte)の圧縮だと2MByte、非圧縮だと3.1Mbyteという結果に。SoftEtherのパケット圧縮が効いてますねー。
もちろん、圧縮処理をすると端末もパケットを投げる時に、圧縮/解凍が走るからその分重くなるけど、RPi3 quad-core ARMのハイスペックだと毎秒64byteなんて投げても負荷はもちろんゼロ。

まとめ

ということで、IoT/M2M的にはやっぱIPv6だーよーねー、というのは将来的な部分や可能性として6LoWPANという利用もあるから、何にしてもIPv6を引き込みたくなる(気がする)。
とりあえず、HurricaneとSoftEther IPv6を使ったけどSEの方が自分は便利だと思う。軽快に動くし、パケット圧縮という機能で流量を圧縮することができる。これは従量課金という部分にヒットする所だけど、IoT/M2M的なデータ流通ってそんなにサイズ的・頻度もあるかどうか…だし端末への圧縮/解凍負荷をどう考えるか?という部分にも効いてくる。全部が全部、RPi3ほどのハイスペックじゃないからね(と言っても、たまにデータを投げるくらいでテキストとかなら軽めの圧縮をした方が良いと思われ)。
こうやって、IPv6をトンネル/VPNで通さなくてもNativeでIPv6が使えるよーになったら、何かもっとテンションが上がるよーな気がする:-)

TMCN Intel RealSense USB 3.0 original board

Intel RealSense用のUSB 3.0基板がelecrowから届いた。TMCNロゴが光輝いてますね。

Windows10 RealSense SDKでバッチリ動いてます。


もちろんMac with librealsenseでも動作バッチリ。


この基板が作られたTMCNコミュニティ、kouさん、leeさんといった種々のノウハウの集合体でバッチリ動いて安定した基板が出来てきた。何か物や個人で…というのはあったりするけど、こういうコミュニティベースでノウハウが集まったできる、そしてバッチリ動いているというのは感動すら覚える。物、アプリ、カメラ、電気まわりのノウハウが自然に集まって、物ができるというのは素晴らしい!!!!の一言に尽きます。

この基板とコネクタがあると次の利点がある。
– RealSense R200/F200の形状に関わらず好きな形状を3Dプリンタとかで出力して、独自センサー(な物)を作れる。
– AR/VR向けの何か特殊デバイスや、組込み向けの物とかでも利用可能。
– ケーブル・足回りも独自のものが作れる。
…etc
といった面白い利用方法がある。fb/tw上にUSB 3.0の写真をアップしていたり、「何してんのwww」と言われたりしたのは、この実験をひたすらしていたという訳ですね。以下は自分のUSB 3.0、RealSenseハックの苦闘の歴史を。

元のRealSenseを分解

まずRealSenseを分解すると次のような構成要素になる。

カメラ、謎の基板、ケーブル、USB 3.0ケーブル。

次にUSB 3.0ケーブルを分解して実際に流れている電圧をチェック。

自分のノリだと、USB3.0ってもどーせUSB 2.0と同じノリでケーブルをちぎって繋ぎ変えて、電気まわりをハックすれば大丈夫だろう…と思ったら、USB 3.0との長い戦いが始まるとは思ってもみなかった。USB 3.0すげーよ。こんな線の中に最大5Gbps、2.4GHzとの電波干渉、TX(+/-)/RX(+/-)のGNDツイストとか…実体験としてわかったのは、「USB 3.0ケーブルは絶対にちぎるな!!」これに尽きる。TX(+/-)/RX(+/-)は電波干渉を避けるため被膜やツイスト、同軸と同じような作りといった、USB 2.0と同じような天真爛漫なノリで挑むと必ずハマる>< 2.4GHzのWiFiと干渉するって、もう剥いたら終了というのは後々知ったことで、この時点では天真爛漫になんとかなるだろと思っていたりしたwww
そして元のIntel RealSense基板の接続を見ながら結線を確認。3.0からの電気、信号線の並びを確認しつつ、5.0Vの電圧を3.3Vに変換してつなげればOKじゃん!!的な天真爛漫な気分でいたけど、地味にケーブルを処理するというのが切ない作業になるとは思っても見なかった。

超絶細い同軸ケーブルとの戦い

分解してUSB 3.0の5Vを3.3Vに変換して繋げばOKやろ!!と思ったものの、基板とカメラを繋げているこのケーブルの処理が超細かい作業だった。この写真、左は自分の髪の毛、そして右は接続ケーブル、ただしこの細さの同軸!!

見えるでしょか…この細さで、シールド、外部導体、内部導体、絶縁体、内部導体という作りをしていて、この内部導体を結線するという作業が超絶細かい。髪の毛の細さが0.1mm-0.06mmとした場合、髪の毛の細さ位の同軸で、導体の処理をする、絶縁の処理をしてあげるという処理が必要になる。構造的に、0.0xmm以下くらいオーダーの処理をするなんて初めてで、シールドに少し力を入れると、全部ちぎれちゃう!!とか何度食らったことか。まぁ、この位のサイズでも慣れちゃえば、1本剥くのに1分もかからないくらいの熟練度に上がっていく。ちなみに、ルーペとか使わないで指先の感覚だけで処理する感じ。まぁ、慣れれば何でも問題ない。

ケーブルをちぎって、USB 3.0側と接続実験してみた時はこんな感じ。

USB 3.0変換

USB 3.0ケーブルを剥いて使うと電波干渉や何が起こるか分からない…というのがあったから、千石さんでUSB 3.0変換基板をゲットしてきた。これで3.0ケーブルを剥かなくても信号線を取り出せることに。そして、3.0から5Vを3.3Vに変換するのは秋月さんでレギュレータ、TIのDC/DCを使って実験してみたり。

これで動いた時は感動でした。初動はこんな感じ。

この接続実験&検証の後、基板をデザインしてもらって、elecrowに発注&アセンブリして出来たのが一番最初の写真の基板。安定性バツグンです。Windows(RealSense SDK)/Mac(librealsense)のどちらで放置して動かしてもバッチリ安定稼働。素晴らしいっす。

色々と分かったこと

– コミュニティの力は凄い。元気になる。
– USB 2.0と3.0はスゲー!!のレベルが全然違う。
– USB 3.0ケーブルは絶対に剥くな。当然だけど変換使おう。
– どんなに小さいサイズでも感覚で慣れれば問題ない。
– 勝手基板だけど、これを活用して何か作れそう。

Intel RealSense USB 3.0 original board

Here is Intel RealSense R200 tear down.

And this is original(hacked) the Intel RealSense R200 USB 3.0 board and connector cable.

Running on Windows 10 with Intel RealSense SDK.



Following is Mac OS X EL Capitan with librealsense.



This original board for RealSense works very well on Windows/MacOS 🙂 Just USB 3.0 micro type B connector for this board/USB 3.0 Type A Male is needed. This RealSense board can use for special case/frame/housing, AR/VR original camera, and more different use for over the R200 case/connector restrictions.
Thanks for TMCN community, kou, lee!!

Following is 1st prototype version. Hack the USB 3.0 cable and power line on RealSense is very difficult. USB 3.0 SuperSpeed transmitter/receiver differential pair is sensitive, having a 2.4GHz radio interference. It was hard to hack:-P

This board BOM list and circuit design is here.
Intel RealSense R200 datasheet is here.

MQTT on ConoHa Cloud

ConoHaにMQTT Mosquittoのテンプレートが追加された。このテンプレート、通常のMQTT 1883だけじゃなくWebSocketも11883で使える。つまり、ブラウザとMQTTを使う端末との接合点としても使える。端末とネットだけじゃなく、ブラウザ(WebSocket)というのも管理的な所やUI、使い勝手的な所では必要になってくると思われ。

まず使ってみる

サーバ追加でMosquittoテンプレを選んで起動するだけ。1.3円/hourで全然十分、サクッと試してみるだけだし。

そして追加したら、今度は端末側。Particle Photonを使うことに。Photonに温度センサ、照度センサを付けた状態がこんな感じ。ソースは下に書いてあるから、コピペすれば使える。もちろん、Photon以外にRaspberry Pi、Arduino Ethernetシールドとか、普通にMQTTが話せる端末だったら何でもOK。

そしたら、今度はWeb側。素敵な方がMQTT/WebSocketを公開されていて、それを使わせて頂くことに。Addressにさっき追加したMosquittoサーバのIPとWebSocket用のポート11883を指定して…こんな感じで。


ConnectしてSubscribeすると、温度と照度のセンサーデータが流れてくるのと、PublishもLEDの色を指定すると端末側の色が変わる。とっても簡単、MosquittoテンプレートにWebSocket付きなのもあって、サーバを追加してあげるとすぐWeb上で確認出来る。

 

Elastic/Kibanaと一緒に使ってみる

ちょっとクラウド的な真面目な構成を考えると次のような感じの図になる。これはセンサーデータをクラウド側でストア、可視化したり分析、そしてWebから端末コントロールをWebSocketで行うような時の構成。恐らく、多くのネットワークに繋がる端末が出てきたとき、このような構成になると考えられる。間にVIPが入って冗長化とかは抜いているけど、その辺も込みでこんな感じに。


ここで重要なパーツになるのがFluentdになる。MQTTを一旦、Fluentdで受けてバックエンドに流すことになる。
これは必ずしも多くのデバイスがMQTTを話す訳では無いという経験から。例えば、JSON、HTTP(GET)、バイナリ直接だったり、UDP(CoAP)という事もあり得る。「プロトコルを変えたいです」->「ファームの入れ替えが。。。」というのは全然ある事で、システム側にProtocol Translationを担う時が必ずやってくると思われ。そこで、実績もプラグインも豊富にあって機能追加も楽だし冗長化も簡単なfluentdは必然的に使った方が良い。多種のデバイス連携やオレオレプロトコルが入り込んで来ることはあり得るからね。

Elastic/Kibana

データの可視化でElatic/Kibanaを使う。センサーからのデータを検索、グラフ化して見るための物で、うまく動くとこんな感じでほぼリアルタイムで照度と温度がグラフで見れる。

以下は、Elastic/Kibanaのインストール。MQTTを入れたサーバでも良いし、別にサーバを立ててもどこでもOK。ただし環境はUbuntuを想定している。

# es install
wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
echo "deb http://packages.elastic.co/elasticsearch/2.x/debian stable main" | sudo tee -a /etc/apt/sources.list.d/elasticsearch-2.x.list
sudo apt-get update && sudo apt-get install elasticsearch

# センサーデータ用 mapping追加
curl -XPUT http://localhost:9200/_template/sensor-template_1 -d '
{
    "template": "sensor-log-*",
    "mappings": {
      "_default_": {
        "properties": {
          "temp": {
            "type": "float",
            "index": "analyzed"
          },
          "lux": {
            "type": "float",
            "index": "analyzed"
          }
        }
      }
    }
}
'
# kibanaダウンロード&起動
wget https://download.elastic.co/kibana/kibana/kibana-4.4.2-linux-x64.tar.gz
tar -zxvf kibana-4.4.2-linux-x64.tar.gz
kibana-4.4.2-linux-x64/bin/kibana 

Fluentd

次はFluentd。ここではMosquittoからデータを取得して、Elasticにメッセージをルーティングする感じになる。Mosquittoへの接続と、Elasticへのデータ送信部分を設定する。ここでもサーバはUbuntuを想定している。

# fluentd 
curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh
/opt/td-agent/embedded/bin/gem install fluent-plugin-mqtt-io

# 設定 /etc/td-agent/td-agent.conf に追加
<source>
 type mqtt
 # MosquittoサーバのIPを指定
 host XXX.XXX.XXX.XXX
 port 1883
 format json
 @label @MQTT_OUT
</source>

<label @MQTT_OUT>
 type copy
 <match sensor.**> 
 @type elasticsearch
 # ElasticのIP(localhostならそれでOK)を指定
 host localhost
 port 9200

 type_name sensor-log
 logstash_format true
 logstash_prefix sensor-log
 logstash_dateformat %Y%m

 buffer_type memory
 buffer_chunk_limit 10m
 buffer_queue_limit 10
 flush_interval 1s
 retry_limit 16
 retry_wait 1s
 </match>
</label>

# fluentdを再起動
/etc/init.d/td-agent restart

端末からデータを投げる

ここではParticle Photonを使う。別にPhotonじゃなくても、Raspbeerry PI、Arduino、iPhone/Android…別に何でも良いんだけど、手元にあったというだけの理由で。まぁ、あとParticle上でMQTT作ったりするというのもあったり。コードはこんな感じで、Arduinoとほぼ同じように書ける。
MosquittoへはMQTT(json形式のメッセージ)で送信する。

ちなみにParticleのWeb IDEのビルド画面はこんな感じで、Web上(インターネット側)から端末にプログラムをFlashする。現時点でPhoton上のMQTTは1600アプリ、CoAPはたったの11だけ使われている。この差はLibraryで提供している側としては、わりと泣けるというかUDPの方が軽いのに…というのは常々思っていたりする。まぁ、好きな方をつかえば良い。

#include "MQTT/MQTT.h"

void callback(char* topic, byte* payload, unsigned int length);
MQTT client("XXX.XXX.XXX.XXX", 1883, callback);

// Subscribeしたメッセージのコールバック
void callback(char* topic, byte* payload, unsigned int length) {
    char p[length + 1];
    memcpy(p, payload, length);
    p[length] = NULL;
    String message(p);

    if (message.equals("RED"))    
        RGB.color(255, 0, 0);
    else if (message.equals("GREEN"))    
        RGB.color(0, 255, 0);
    else if (message.equals("BLUE"))    
        RGB.color(0, 0, 255);
    else    
        RGB.color(255, 255, 255);
    delay(1000);
}


void setup() {
    RGB.control(true);
    
    // connect to the server
    client.connect("sparkclient");

    // publish/subscribe
    if (client.isConnected()) {
        client.subscribe("led/");
    }
}

void loop() {
    // MQTT用
    if (client.isConnected())
        client.loop();
    
    // 温度取得
    int tempValue = 0;
    for (int i = 0; i < 100; i++) {
        tempValue += analogRead(0);
    }
    tempValue = tempValue / 100;
    float v = (float(tempValue)  / 1024) * 3.3;
    float temp = (v - 0.424) / 0.08725;
    
    // 照度取得
    int luxValue = 0;
    for (int i = 0; i < 100; i++) {
        luxValue += analogRead(1);
    }
    luxValue = luxValue / 100;
    
    // MQTTにjson形式で配信
    client.publish("sensor/", String("{\"temp\":\"") + String(temp) + String("\", \"lux\" : \"") + String(luxValue) + String("\"}"));

    delay(1000);
}

以上で全部おわり。端末が無くても手動でmosquitto_pub/subコマンドで、直接mosquittoに接続して確認できる。

# センサーデータの送信
mosquitto_pub -h XXX.XXX.XXX.XXX -t sensor/ -m '{"temp" : "22.0303", "lux" : "703" }'

# LEDの色を赤色に変えてみる
mosquitto_pub -h XXX.XXX.XXX.XXX -t led/ -m 'RED'

# 受信して確認してみる
mosquitto_sub -h XXX.XXX.XXX.XXX -t sensor/

ConoHaのmosquittoテンプレは身内なサービス(自分自身GMOな所に居るし)だけど、普通に使って内容を書いてみた。もちろんステマ的なあれじゃないからねw
他にもVIPやTLS/SSLを設定したりといった、冗長化、セキュリティの要素も入ってくる事にはなるんだけど、サクッと使ってまずは試してみてその次に、そういう要素を入れていく事になるかなと。普通にこんな構成で自分は使うと思われ。あと、プロトコル的な互換性の解決にfluentdを使ったりするにしても、サクッとMQTTを使って動確してみたりWebSocketでブラウザからも確認できたりできて、わりと良い感じのよーな気がする。

iOSのIPv4/v6 DNSの挙動

iOS9からIPv6対応との事で、こんな事が起きるようで。

Apple、iOS 9とOS X 10.11 El Capitan BetaでIPv6を優先し使用するよう「Happy Eyeballs」のアルゴリズムを変更。
IPv4接続で遅延が発生?!

これが本当なのか実験してみた。環境は以下の通り。

closedなLAN宅内環境で、IPv6にはAU光で実際に利用できるGlobal IPv6が/64で降ってきてそれを利用する。Raspberry Pi2にはbind9とiPhoneからアクセス用のNginXを立てて、IPv4/IPv6の名前解決はワイルドカードで行っておく。そして適当に作ったiPhone用のアプリからNginXのサーバにアクセスする際の名前は…

# IPv4はサフィックスにipv4と入れる
10001.ipv4.test.niisato.net
10002.ipv4.test.niisato.net
10003.ipv4.test.niisato.net

# IPv6はサフィックスにipv6と入れる
60001.ipv6.test.niisato.net
60002.ipv6.test.niisato.net
60003.ipv6.test.niisato.net

といった感じでプレフィックスを適当な数字でインクリメントする事で、都度DNSにアクセスを行うようにして、IPv4/v6のアクセスで常に名前解決を行いNginXにアクセスするように出来る。こうする事で、[DNSへの問い合わせ->HTTPアクセス]のループを1000回シーケンシャルにかまして両者の違いが分かるはず…だった。

だった…というのは、実際に試すそれ以前にRaspberry Pi上でDNSのパケットをキャプチャしたらもうそれ以前の問題だった。以下はIPv4へのアクセス時で、tcpdumpの結果をWireSharkで見たもの。

そう…25msの誤差もへったくれもなく、AAAA(IPv6)レコードを常に有線して名前解決が走る。そもそもね…AAAA(IPv6)優先で名前解決をしている以上、25ms分IPv4へのアクセスを遅くするもヘッタクレもなくIPv6があればそっちが早くなるというのは当然の帰結というわけですな。closedなLAN環境だとあれだけど、ベストエフォートなインターネット環境だったら、ネットワーク時間も影響してIPv6の方が早くなるのも理解できる。

ちなみにこれはIPv6の場合、

まだIPv4/v6と名前解決のリクエストは関係ないから、当然こっちでもAAAAが優先して問い合わせが行われる。ぶっちゃけ、これで大きな時間的な差が生まれるとは考えにくい。というのは、こんなオモシロユニークな名前解決を連発するという事は通常は殆どない&キャッシュされるのと、最初の問い合わせで25msの遅延が挿入されると言っても…分からんべ(w)とは思うし。さらに国内のiPhoneでIPv6使ってるぜヒャッハーな人とかって…一般ユースだと無いもん(キャリア対応してないし)。ただ、AAAAが優先されて一発送られているというのは気に止めておいた方が良いと思われ。

CoAP library 0.2.0

CoAP simple client/server library 0.2.0 now available. Some bug fixed, add Arduino platform. And now, this library sample source run same sourcode on Particle Photon, Core, severals Arduino Platform(UNO with Ethernet Shield…others).

Particle Photon, Core version.
Arduino Platform version.

– How to use sample
In this exmples run with CoAP server libcoap or microcoap server for check. This is setting the libcoap on Ubuntu Linux. But if there don’t use CoAP server(request/reseponse), following setting don’t be needed.

libcoap server.

git clone https://github.com/obgm/libcoap 
cd libcoap/
./autogen.sh 
./configure --disable-examples 
gcc -o coap-server examples/coap-server.c -I./include/coap/ -I. -L.libs -lcoap-1 -DWITH_POSIX
gcc -o coap-client examples/client.c examples/coap_list.c -I./include/coap/ -I. -I./examples/ -L.libs -lcoap-1 -DWITH_POSIX
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.libs
# run coap-server
./coap-server
# next start Arduino and check the request/response.
# if you need check the coap server, use coap-client.

microcoap

git clone https://github.com/1248/microcoap
cd microcoap
make
# run CoAP server
./coap

On Arduino Platform, download this source code branch zip file and extract to the Arduino libraries directory or checkout repository. Here is checkout on MacOS X.

cd $HOME/Documents/Arduino/libraries/
git clone -b arduino https://github.com/hirotakaster/CoAP CoAP_library
# restart Arduino IDE, you can find CoAP_library examples.

here is coaptest.ino sample source code for Arduino

#include <SPI.h>
#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <coap.h>

byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };

// CoAP client response callback
// This function is called when application send packet to the server and next get response.
void callback_response(CoapPacket &packet, IPAddress ip, int port);

// CoAP server endpoint url callback.
// This function is called when application get request packet from client.
void callback_light(CoapPacket &packet, IPAddress ip, int port);

// UDP and CoAP class
EthernetUDP Udp;
Coap coap(Udp);

// LED STATE
// Change color CaAP request.
bool LEDSTATE;

// CoAP server endpoint URL callback.
void callback_light(CoapPacket &packet, IPAddress ip, int port) {
  Serial.println("[Light] ON/OFF");
  
  // send response
  char p[packet.payloadlen + 1];
  memcpy(p, packet.payload, packet.payloadlen);
  p[packet.payloadlen] = NULL;
  
  String message(p);

  if (message.equals("0"))
    LEDSTATE = false;
  else if(message.equals("1"))
    LEDSTATE = true;
  
  // CoAP server have to response message to the client with same messageid.
  if (LEDSTATE) {
    digitalWrite(9, HIGH) ; 
    coap.sendResponse(ip, port, packet.messageid, "1");
  } else { 
    digitalWrite(9, LOW) ; 
    coap.sendResponse(ip, port, packet.messageid, "0");
  }
}

// CoAP client response callback
void callback_response(CoapPacket &packet, IPAddress ip, int port) {
  Serial.println("[Coap Response got]");
  
  char p[packet.payloadlen + 1];
  memcpy(p, packet.payload, packet.payloadlen);
  p[packet.payloadlen] = NULL;
  
  Serial.println(p);
}

void setup() {
  Serial.begin(9600);

  Ethernet.begin(mac);
  Serial.print("My IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println();

  // LED State
  pinMode(9, OUTPUT);
  digitalWrite(9, HIGH);
  LEDSTATE = true;
  
  // add server url endpoints.
  // can add multiple endpoint urls.
  // this endpoint url is called by client.
  // exp) coap.server(callback_switch, "switch");
  //      coap.server(callback_env, "env/temp");
  //      coap.server(callback_env, "env/humidity");
  Serial.println("Setup Callback Light");
  coap.server(callback_light, "light");

  // client response callback.
  // this endpoint is single callback.
  Serial.println("Setup Response Callback");
  coap.response(callback_response);

  // start coap server/client
  coap.start();
}

void loop() {
  // send GET or PUT coap request to CoAP server.
  // To test, use libcoap, microcoap server...etc
  // int msgid = coap.put(IPAddress(10, 0, 0, 1), 5683, "light", "1");
  // "time"(libcoap sample server endpoint) is set.
  Serial.println("Send Request");
  int msgid = coap.get(IPAddress(XXX, XXX, XXX, XXX), 5683, "time");

  delay(1000);
  coap.loop();
}
/*
if you change LED, req/res test with coap-client(libcoap), run following.
coap-client -m get coap://(arduino ip addr)/light
coap-client -e "1" -m put coap://(arduino ip addr)/light
coap-client -e "0" -m put coap://(arduino ip addr)/light
*/

next, there is Particle Photon, Core sample sourcode. Difference point with the Arduino is only Udp class, include files and IP address setting only.

#include "coap/coap.h"

void callback_light(CoapPacket &packet, IPAddress ip, int port);
void callback_response(CoapPacket &packet, IPAddress ip, int port);

Coap coap;
bool LEDSTATE;

void callback_light(CoapPacket &packet, IPAddress ip, int port) {
    Serial.println("[Light] ON/OFF");
    
    // send response
    char p[packet.payloadlen + 1];
    memcpy(p, packet.payload, packet.payloadlen);
    p[packet.payloadlen] = NULL;
    
    String message(p);

    if (message.equals("0"))
        LEDSTATE = false;
    else if(message.equals("1"))
        LEDSTATE = true;
        
    if (LEDSTATE) {
        coap.sendResponse(ip, port, packet.messageid, "1");
        RGB.color(255, 255, 255);
    } else { 
        coap.sendResponse(ip, port, packet.messageid, "0");
        RGB.color(0, 0, 0);
    }
}

void callback_response(CoapPacket &packet, IPAddress ip, int port) {
    Serial.println("[Coap Response got]");

    char p[packet.payloadlen + 1];
    memcpy(p, packet.payload, packet.payloadlen);
    p[packet.payloadlen] = NULL;

    Serial.println(p);
}

void setup() {
    Serial.begin(9600);
    
    // LED Controll
    RGB.control(true);
    RGB.color(255, 255, 255);
    LEDSTATE = true;

    Serial.println("Setup Callback Light");
    coap.server(callback_light, "light");

    Serial.println("Setup Response Callback");
    coap.response(callback_response);

    // start coap server/client
    coap.start();
}

void loop() {
    Serial.println("Send Request");
    int msgid = coap.get(IPAddress(XXX, XXX, XXX, XXX), 5683, "time");

    delay(1000);
    coap.loop();
}

MQTT pub/sub library 0.3.4

MQTT library 0.3.4 now available. On this release add Arduino platform, and this client library can use nearly same source code on Particle Photon, Core, severals Arduino Platform(UNO with Ethernet Shield…others).

Particle Photon, Core MQTT is here, and for Arduino branches is here.
BTW, Particle Photon, Core version MQTT library is used over 1,200 apps on the Particle now.

– How to use on Arduino
Particle have Web IDE with community libraries application developer easy to use several latest libraies without notifying. But on Arduino, developer have to add library by your self. here is from github readme.
Download this source code branch zip file and extract to the Arduino libraries directory or checkout MQTT repository. Here is checkout on MacOS X.

cd $HOME/Documents/Arduino/libraries/
git clone -b arduino https://github.com/hirotakaster/MQTT MQTTCilent
# restart Arduino IDE, you can find MQTTCilent examples.

here is SimplePubSub Arduino source code.

#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <SPI.h>
#include <MQTT.h>

byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };

void callback(char* topic, byte* payload, unsigned int length);

/**
 * if want to use IP address,
 * byte server[] = { XXX,XXX,XXX,XXX };
 * MQTT client(server, 1883, callback);
 * want to use domain name,
 * MQTT client("www.sample.com", 1883, callback);
 * change "server_name".
 **/
EthernetClient ethclient;
MQTT client("server_name", 1883, callback, ethclient);

// recieve message
void callback(char* topic, byte* payload, unsigned int length) {
  char p[length + 1];
  memcpy(p, payload, length);
  p[length] = NULL;
  String message(p);

  Serial.println(message);
  delay(1000);
}


void setup() {
  Serial.begin(9600);

  // Get IP address from DHCP Server
  Ethernet.begin(mac);

  Serial.print("My IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println();
    
  // connect to the server
  client.connect("mqttclient");

  // publish/subscribe
  if (client.isConnected()) {
    client.publish("/outTopic","hello world");
    client.subscribe("/inTopic");
  }
}

void loop() {
  if (client.isConnected())
    client.loop();
}

Following is Particle Photon, Core same version. Difference points with Arduino are include files and Ethernet connection implementation only.

#include "MQTT/MQTT.h"

void callback(char* topic, byte* payload, unsigned int length);

/**
 * if want to use IP address,
 * byte server[] = { XXX,XXX,XXX,XXX };
 * MQTT client(server, 1883, callback);
 * want to use domain name,
 * MQTT client("www.sample.com", 1883, callback);
 * change "server_name".
 **/
MQTT client("server_name", 1883, callback);

// recieve message
void callback(char* topic, byte* payload, unsigned int length) {
  char p[length + 1];
  memcpy(p, payload, length);
  p[length] = NULL;
  String message(p);

  Serial.println(message);
  delay(1000);
}


void setup() {
  Serial.begin(9600);
    
  // connect to the server
  client.connect("mqttclient");

  // publish/subscribe
  if (client.isConnected()) {
    client.publish("/outTopic","hello world");
    client.subscribe("/inTopic");
  }
}

void loop() {
  if (client.isConnected())
    client.loop();
}

lost Blog data memo

I lost my blog data(my server operation miss…) at 2014/03, but Internet Archive save my lost blog data. Followinig entry for my memo from Internet Archive.

TreasureHunter Robotics equipments

Kinect Skeleton-tracking data search with Solr

Multi Layer Amid Screen

Android 4.2(Jelly Bean) and OpenNI 2.1 beta
Raspberry Pi and OpenNI2

SONY Smart Watch2 and HeartBeat, ball led cube

OpenNI User Tracking on Android

Recognize human robot on OpenNI

How to build OpenNI and Sensor Driver(PrimeSense and Kinect) with Android NDK r7

コロコロハック

Extreme Home Hackというイベントがあって、そこで作った物=コロコロについて書こうと思って、放置していたから書くことに。

まずはコロコロはニトムズさんが1983年から販売している物ですね。殆どの人が目にした事があると思われる、掃除でコロコロと床を粘着シートでゴミを取って綺麗にする物。

1. コロコロ Specifications

取手がついて、このままコロコロと…枝の部分は緩めて長さを調整できる。コロコロの用途としての基本機能としては、

1. 掃除で使う物
2. 粘着シートで床をコロコロして綺麗にする
3. 枝の部分を緩めて伸ばせる
4. 取手(グリップ)が付いている
5. コロコロの粘着ロールは取り外して交換可能

この辺でしょうか。お掃除で毎日使われますね。
コロコロの粘着ロールを外すと、次のように分解されます。まずは中の支柱(?)部分。

そしてロールはモチロン空洞ですね。

この5×2(裏表)の計20個に区画された空洞は、耐久性と軽量化、回した時の使いやすさを考えた結果の物と思われるですが、この部分は「仕込める!!」かなり熱いポイントです。
この空洞部分にセンサーやら電力、マイコンやら通信部分を仕込むと、このコロコロを激しく活用できるようになる。実際、他のハックでは、コロコロを回して床のどの部分が掃除できているか?といったネタが出ていた。この中空部分は割と広くて、ぶっちゃけ何でも仕込み放題という。
また枝の部分も中空になっていて、中にケーブルを通して利用できます。

コロコロのhackableな要素としては次のようになります。

1. コロコロは分解するとロールと支柱に分かれる。
   -> 5x2(裏表)の20個の区画の中に何でも仕込めそう。
   -> 耐久性との兼ね合いだが、区画の部分を切って広く使える。
2. 枝の中は中空になっている。
   -> ケーブルを通したり中に何か仕込める。
   -> 枝の伸び縮みも利用可能。
3. グリップの部分も取り外して仕込める。
   -> 取手に静電容量センサやスチッチ・ボタンを仕込んで握ると何か反応するような事ができる。
   -> 枝の中に線を通すor何か仕込んで枝を握ったら何かできるような。

2. コロコロ Hack idea

基本機能だけでぶっちゃけゾクゾクしてくる魅力があります。掃除で(毎日)使う生活に密着した物。これをハックするぜ!!という事で最初に上がったのは、

1. コロコロすると充電される
2. 充電した電気を取り出して利用できる

といったアイディアに合流して、これはイケる!!と。例えば電気のない地域で、お昼はコロコロと持って歩いて発電、そして夜は光って照明になるという使い方や、災害時の発電用途としても良さそう。ただ、実際に出来上がったものは全く違う物になっちゃいました。
この他に出来そうなのとかネタが以下です。

1. コロコロの中にLEDを仕込んで転がすと光る。
2. 色センサーを枝の部分からロールに向けて使って、汚れたら(色の変化)何かブブっとする。
3. グリップの部分に静電容量センサを仕込んで、握ると光る or etc…
4. コロコロの中にスピーカ・マイクを仕込んで、コロコロとの対話(モノとの対話)。

とかです。時間と労力とのバランスでこれまた全く違うモノになったですが、機会を見てやってみようかと。実際に作ったのは、コロコロすると音が出るモノですね。

3. コロコロ Hack

ここからは実際に加工します。作るものは以下です。

1. コロコロの中空部分にMPU 6050(加速度・ジャイロ)を仕込む
2. センサーの値をKonashi(BLE)で取得する
3. iPhoneアプリで取得した値によって音がなる
4. APIで音をリモートで変えたり流しこめるSDKもおまけで作る

実際の物とアプリを1日ちょいで一気にスクラッチから作るので、ちょっとした勢いが必要でした。出来上がったものはこちらです。

チーム名がコロコロ革命だったので、そのままタイトルもコロコロ革命です。動きに合わせて再生する音のピッチを変えているので、お掃除する時の流れでいろんな音が流せますね。加工した状態はこちら。

ビックリしたのが「ミニブレッドボードがピッタリ収まるサイズ!!!!」。ちょっと作ってみる用途にはピッタリでしょう。電源にはLipoを使ってますが、普通の電池でも楽勝で収まります。この空間は素晴らしい!!!!
構成としては次の通りです。コントローラとして中華Prominiを使っているのは、ここからLEDを出して中から光らせたり、何か制御を挟もうとした名残です。MPU 6050のLibraryが使えて、ここで終端&何かできるという所もあったりしますが。
普通のコロコロと並べると、次のようになります。

よく見ると穴が開いている方が”Hack済みコロコロ”です。中から光らせて、暗いとキラキラしてよく見えるように穴を開けてもらいました。このハッカソンではおかげでニトムズ賞を頂きました。ありがとうございます。

4. おまけ

作る時に気をつけたのが、

普通のコロコロとして使える

これに尽きます。上記の写真の通り、普通のコロコロと見た目も使い勝手も一緒です。「普通に生活している状態を損なう事なく、今まで通りの物として使える」これを意識しました。偶然、コロコロの中に何でも仕込めたので、完全に同一の物として使えます。
何か事前準備や環境条件をしなくても(まぁ、スマホにアプリは入れる必要がありますがw)、普段通りの物として使えるというのは一つのポイントかなと。IoT的な物とかは、何かプラスアルファのデザインや物といった他にも、今まで通りの物として生活に溶け込んで使えるという部分は、見た目のインパクト外の所で必要でしょう。

次に中の区画に仕込む時の注意として、耐久性とのバランスを考えて区画をカットしたりしました。恐らく凄く検討&試験を重ねて、今の2×5(裏表)の20区画に切られていますが、ここに手を入れるのでコロコロする時の耐久性が失われます。自分の力でゴリゴリして動かしてとりあえず大丈夫ですが、連続運転(連続コロコロ)するとかなりこの部分は心配になります。まぁ、この点は1-day hackなので…
区画を使いやすいようにカットする時は、この耐久性とのバランスを考えて行った方が良いです。

あ、もう一つ大切なのが、

実際に使ってもらったら、別に掃除している時に音とか要らないし、ウザイ

と言われたことです。ただし、子供ウケは良かったです(オモチャとして見ている)。よくアイディアでオモシロネタや、見た目のインパクトがあったりする物がありますが、実際に生活で使っている人の感想というのは大切なものです。これsuge-!!と思って作るのも大切ですが、フィールドテスト(アイディア段階でも)を行ってみると、また違った感想が出てきます。それを持ってフィードバックとして改良していくといった感じですね。ギークだけじゃなく、普通の人に使ってもらったりしてどうか?という所は、ハッカソンだと期間が短いのであれですが…大切なポイントかなーと。

他にやってみたい事は、コロコロさせて正転・逆転で違った音を出せたり遊べたので、コロコロを持って100人くらい体育館で並べて、一斉に歩くとメロディーが出来るとか楽しそうだなーと。まったく掃除と関係ないですが。

MQTTについて少し

ParticleでQoS1|2を実装しれ!!みたいに言われて、それっぽく使いやすいように実装してみたりして思ったりする所。Spark/Photonを持っている人なら一度は使ったと思われるMQTT、なぜかIoT(的)な物で使われるMQTT…に対してQoSを意識して実装する時の注意点を少し。

MQTT QoS0|1|2のシーケンスは以下の通り。

ここではよく利用すると思われるPUBLISHを例にする。MQTTはQoSのレベルによって接続するMQTTサーバとの通信が変わる。レベルが上がる毎に、応答確認(ACK)メッセージのやり取りが増える感じ。このACKを利用すると、次のような実装が期待されると思う。

これはQoS1の場合について。timer処理を入れて、ACKが来なかった時に同じメッセージを再送するといった事ができるようになる。実際MQTT 3.1のプロトコル定義にもDUPフラグを付けて再送信処理を行うと記載されている。(MQTT V3.1 Protocol Specification, 4.1. Quality of Service levels and flows, QoS level 1: At least once deliveryから)
NWの一般的なQoS(流量制御や遅延への保証)とは違って、メッセージの到達保証にかかるシーケンスが変わる感じですね。ここで、自分的にはこのtimer処理を入れて再送するという実装をしている場合は、それは止めた方が良いと思われ。そう言ったクライアントを利用しているなら、ちょっと危ない気はする。ちなみに、サーバ側はACKを送って、その再送処理を行わないのが殆どだと思われ(その必要がない)。

というのはTCP over TCP問題(Why TCP Over TCP Is A Bad Idea)という、よくある問題がベースになる。短い資料だけど、遅い&遅延が発生するようなNW(特にIoT的な端末だと、低帯域なNWを利用すると思われるので、このケースがよく合う)で発生する問題で一度は目を通した事がある人も多いはず。ザックリだと、TCPの上に信頼性(再送を行うような)のあるプロトコルを載せた場合、そのNWは破綻するといった感じ。

MQTTは足回りにTCPを利用していて、QoS1|2のケースでメッセージの到達性の確認(ACK)を利用した再送処理を行う場合、同様の問題(輻輳)が発生する可能性がある。上位(MQTT)の再送処理が、足回りTCPの再送を更に増加させて、輻輳により結果として止まってしまう現象が起きる。条件としては。

1. QoS1|2を利用
2. 到達性の保証からACK待ちのタイマーでの再送を行う

この場合に発生する現象です。これを回避するには、

1. タイマーによる再送を行わない
2. QoS0を利用する
3. 必要な時だけ接続断

このくらいかしら。MQTTのプロトコル的にはQoS1|2を利用するとき、ACKを受け取れない場合、Sender(クライアント)はDUPフラグを付けて再送信する。これは足回りにTCPを利用するケース(MQTT-SN: UDP/non-IPの実装をしている場合は別)では止めた方が良い。再送信が1回だけならOK…な感じも少しするけど、送信する頻度、TCP接続の維持(は止めた方が良い気がする)などで、どういった実装をするか不明なので再送信が1回も10回も変わらない。結果としてタイマー処理を行うようあるにも関わらず使わない方が良いという事になる。これは違和感もあると思うけど、プロトコル定義と発生する現象は別なので。
ちなみにTCPを利用するのはNWの信頼性のためで、上位MQTTメッセージングの信頼性はMQTTとして保証する必要があるため、別々のレイヤーとして考えられる。そのため、MQTTとしてはACKが必要になるというのも理解が出来る。ただ、どちらかと言えば、HTTP(リクエスト・レスポンス、トランザクションレス)のようなACKとして考えた方が良いと思われる。MQTTとHTTPで比較がたまにあるように、HTTPのように再送信を意識したり期待はしない方が良い。

経験的にだけど、回線業者と専用線で帯域保証を付けているNWでない限り、インターネットはベストエフォートな世界なので、遅延や低帯域になる事は普通にあり得る。そういった所で、足回りがTCPで再送処理を行う時の注意点としても、一つ考えておいた方が良いと思われ。
同様にIoT的なプロトコルの一つにCoAPがあるけど、そっちは足回りがUDPでこのような事は考える必要がない。あと、Google Chromeに実装されているQUICなんかも足回りはUDPで、その上に独自に信頼性のあるプロトコルを構築する形になっている。上位と下位のNWで何を利用して、どういう実装をするか?と言うのは、その後に発生するであろう問題点の回避として、一考しておいて良いでしょう。

モバイルバージョンを終了