HDE BLOG

コードもサーバも、雲の上

第20回 Monthly Technical Sessionが開催されました

3/18に第20回 Monthly Technical Session (MTS) が開催されました。MTSは月一回執り行われる、主に社内向けに現在どのような事を技術者が行っているのかという情報やその中で得られた知見を共有するための取り組みです。

司会のシー・ハンさんが開催をアナウンスしてくれました

f:id:lestrrat:20160318173001j:plain

今回のお題は二つです。最初はイスカンダルさんによる、現在旧アーキテクチャから新アーキテクチャにデータ移行中のサービスの概要についてです。データの整合性の取り方や考えられる問題点等についての説明をしていただきました。

f:id:lestrrat:20160318174551j:plain

次は牧によるJSON Schemaとその関連技術を使ってコードを自動生成するための道のりの話です。サーバーのスケルトン、バリデーション、クライアントコードなどが全てひとつのスキーマから生成されるまでの仮定やなぜ他のツールではなくJSON Schemaを使うのか等の話をしました。

f:id:lestrrat:20160318180115j:plain

トークの後は軽食とビールの時間です!

f:id:lestrrat:20160318190126j:plain

自作Let's EncryptクライアントをGoで書いた話

開発部たなべです。

Let's Encrypt (以下LE)が今年の1月についにDNSベースのドメイン認可をプロダクション環境で有効にしました。

これにより、証明書発行が完全自動化できるのを記念(?)して先月の社内勉強会で少し話しました。つまりは昨年のアドベントカレンダーの続きです。 スライドでも触れましたが、勉強会の当日(1/22)にAWSからACMが発表されるというちょっとしたハプニングがありました。

speakerdeck.com

AAA Updates

AAAとは私が開発しているACMEプロトコルのクライアント実装です。Goで実装しています。

github.com

主な特徴はAWS内で完結させていることです。つまり、

  • すべてのコードはLambda Functionとして実行
  • すべてのデータはサーバサイド暗号化を適用したS3へ保存

することでステートレスでサーバレスを実現しています。アドベントカレンダー以後のアップデートとしては、

  1. 証明書自動更新に対応しました。

    Goで実装したcliアプリをLambda向けにzipし、CloudWatch Eventsを使い、証明書の自動更新処理を行ないます。 Go製のcliをNodeでラップし、Lambda Functionとするのが私の中で王道になりつつあります。OS Xで開発・実行できるうえに、一瞬でLinux向けにビルドできるのでまさにLambda Functionにぴったりです。 早くLambdaのGo対応きてほしいですね。

  2. Slackインテグレーションに対応しました。

    ドメインの認可と証明書の発行がSlackからできます。こちらはAPI Gateway経由でLambda Functionを実行しているだけなので、他とのインテグレーションも難しくないと思います。

  3. ドメイン認可プロセスのDNSチャレンジに対応しました。

    こちらが目玉機能です。Route53環境があれば対象のサーバなしで証明書が発行できます。

今後はApexを利用してLambda Functionを管理できるようにする予定です(ただし、Apex自体ではCloudWatch Eventsには対応せず、Terraformに任せる予定のようです)

Let's EncryptとAmazon Certificate Manager (ACM)

スライドの最後でも触れましたが、改めてLEとACMについて触れます。

ACMはまだ出たばかりでus-eastのみです。現時点ではLEのほうが使い勝手がよさそうです。 リージョンの問題がなくなった場合、ELB連携は魅力的です。AWS内で完結できるのはとてもありがたいです。 また、ACMはワイルドカード証明書にも対応しているので一枚あれば事足りるのも魅力的です。

ACMEプロトコル側でもワイルドカードサポートの議論が始まっています。

github.com

一方で、ACMの証明書発行プロセスではメールでドメインを認可する必要があり、ここが自動化の障害となっています。 でも、証明書の期限は13ヶ月と長いのが幸い、というところでしょうか。

今後ACMEプロトコルの利用が進み、いい感じになったところでACMがACMEプロトコルに対応してくれればすべて丸く収まる…というのが私の妄想です。

ではまた!

Building AWS Lambda function in Rust

This post is a summary of my presentation on 18th Monthly Technical Session.

As I worked more on AWS Lambda for some feature of our service, I looked into developing AWS Lambda functions with languages not supported by Amazon. Recently, I'm working on some private project in Rust so it is worth a try to see whether it is possible to run Rust code on AWS Lambda.

How to run Rust code on AWS Lambda

According to the document of AWS Lambda, the function is run on Amazon Linux with some language runtime and library. It is also possible to spawn new process to run some executable. So there is really little limitation on how the function executes aside from the limitation on CPU, memory and network usage.

There are 2 possible ways to run code in languages not supported:

  • Spawn a new process to run some executable.

    With this way, some standalone executable that is runnable on Amazon Linux is built. The AWS Lambda function creates a new process to run it.

  • Build the code into dynamic load library and load the library with language supported and call the function. (Python or Javascript)

Code written in Rust can be easily compiled into dynamically linked (shared object) library which only depends on GNU libc on a Linux distribution. Also, Python supports loading this kind of library naturally. So the second option is quite adoptable.

Sample project

Here is the code of a sample project to build an AWS Lambda function in Rust with Python code as a loader.

https://github.com/yxd-hde/lambda-rust-demo

The Python loader

To implement handler function in Rust, some code in Python is required to load the library built from Rust and call the function in the library.

Python's cdll package is used to load the library built from Rust (which is named with libhandler.so and uses standard C calling convention) and then the code call the handler function with event and context serialized into json strings.

The code is quite simple and uses simplejson library to do json serialization.

from ctypes import cdll

import simplejson as json

lib = cdll.LoadLibrary('./libhandler.so')


def handler(event, context):
    ret = lib.handle(json.dumps(event),
                     json.dumps(context, default=encode_context))
    return ret


def encode_context(context):
    return {
        "function_name": context.function_name,
        "function_version": context.function_version,
        "invoked_function_arn": context.invoked_function_arn,
        "memory_limit_in_mb": context.memory_limit_in_mb,
        "aws_request_id": context.aws_request_id,
        "log_group_name": context.log_group_name,
        "log_stream_name": context.log_stream_name

        # add others if it is required.
    }

The handler in Rust

In Rust code, the event and context parameters are in C string and need to be converted into Rust strings for further processing. Some unsafe conversion is required to be done before handling them. After that, all things can be done in Rust safely.

Here, Rust's libc library is used for the type of C char pointer, which represents a string in C.

extern crate libc;

use std::ffi::CStr;
use libc::c_char;

#[no_mangle]
pub extern "C" fn handle(c_event: *const c_char,
                         c_context: *const c_char) -> i32 {
    let event = unsafe { CStr::from_ptr(c_event).to_string_lossy()
                         .into_owned() };
    let context = unsafe { CStr::from_ptr(c_context).to_string_lossy()
                           .into_owned() };

    real_handle(event, context)
}

fn real_handle(event: String, context: String) -> i32 {
    println!("Event: {}", event);
    println!("Context: {}", context);

    // Do the real handling

    return 0;
}

Wind them together

To wind them together, there are some extra work to do.

Build the Rust code into an .so file

In Cargo.toml, it is required to tell Rust's build tool cargo that the build target is a dynamic library.

...

[lib]
name = "handler"
crate-type = ["dylib"]

...

Add all the dependencies

The dependencies in Rust are managed by cargo, while requirements.txt is used for Python though there is only simplejson required.

Make the zip package to deploy

Python code, simplejson library and libhandler.so file built from Rust needs to be packaged together in one zip file to deploy.

The libhandler.so file should be binary compatible with Amazon Linux. It is recommended to build it on a distribution that is binary compatible with Amazon Linux.

AWS Lambda settings

An AWS Lambda function with Python environment is required and the handler needs to be set to Python's handler function.

Others

logs

Rust function can just output to stdout for logging as this is supported by AWS Lambda.

error handling

For the code above, the return value of Rust's handler can be used to decide whether the execution succeeded.

Finally

Rust code is safe and supposed to be as performant as C and C++. With this way of implementation, it is possible to use Rust as the language to develop AWS Lambda function easily. It is worth a try if there are requirements to develop performant AWS Lambda function, especially when the function is computation focused.

Developing with Vagrant and Docker

Hi, this is Shi Han from HDE Inc. Before joining HDE Inc. as a software engineer, I was involved in the field of computational physics mainly focusing on computational fluid dynamics and granular materials simulations. The simulations are commonly developed in a monolithic style where the whole simulation is treated/built as a single unit. As for setting up the development environment, usually it only requires the developer to deal the the makefile. As a newcomer in the field of software engineering, I found that things are not quite the same over here. The "recent" trend is that the application can be divided into several small services (microservice architecture) and communicating via HTTP resource API (API-centric architecture). This practice is often applied on applications that are being deployed on the cloud as it allows each services to be deployed and scaled independently.

続きを読む

Tool to help developing AWS Lambda function in Python on your local machine.

We are trying to migrate some part of our service from daemon on EC2 server to serverless function on Lambda. By doing this, we will be able to save some pennies on AWS service and save some time from server maintainence.

At first, we did some development in Javascript on Lambda. And the development went quite well with the awesome tool lambda-local developed by Ahmad Shiina san

ashiina.github.io

With this tool, we are able to develop and debug Javascript code on developer's machine without having to upload it to the cloud. With a shortened develop-deploy-test-fix cycle, we managed to develop features really fast.

We were just about to go all with Javascript when AWS enabled developing Lambda functions in Python2.7 at re:Invent 2015.

Using Python in an AWS Lambda Function | AWS Compute Blog

Since part of our stack is based on Python2 and most of our developers are more familiar with Python than Javascript. We decided to give it a try.

However, one problem is that there is no tool like lambda-local for Python right now. So we built one by ourselves and opensourced it on github.

github.com

We have also released it on PyPI

pypi.python.org

So you may try it our by installing it into a Python2.7 environment with just one command:

$ pip install python-lambda-local

Currently, it is quite feature complete except lacking enough support for the Context API. We will continue improving it.

The usage of the python-lambda-local command is quite similar with lambda-local. So there should be no hassle if you are familiar with lambda-local.

Ideas and pull requests are welcomed.

Happy hacking!

AWS re:Invent 2015行ってきました & 新サービスAmazon Snowballについて

■AWS re:Invent 2015行ってきました

f:id:miyamotokazuaki:20151022185547j:plain

 Amazon Web Serviceの巨大イベント、AWS re:Invent 2015に参加してきました。ラスベガスです。昼も夜も渋谷より騒がしい街があったことは衝撃的でした。うちの会社(HDE)は昔から渋谷にあり、私自身もかつて渋谷に住んでみたこともあって、"昼も夜も渋谷ほど騒がしい街は世界中どこにもないだろう"という確信を持っていて(あまりに落ち着かないので、さすがに自宅は半年で渋谷区じゃないところに転出したのですが)、まぁしかし、その数倍騒がしかったですね、ラスベガスは。Crazyです。

 というわけで、今日はラスベガスの若干の写真と、re:Inventの全体の雰囲気、今回Amazonから発表されたサービスの一つを紹介しつつ、最後にちょっとした宣伝(!)をさせていただく、という構成にしています。是非最後までお読みください。

 さて、まずはラスベガスらしい写真をいくつか上げておきます。

f:id:miyamotokazuaki:20151022185736j:plain
↑とりあえず肉は食っておこう、みたいな感じ

f:id:miyamotokazuaki:20151022185754j:plain
↑カジノに手を出すのはやめました

f:id:miyamotokazuaki:20151023103253j:plain
↑世界最大の観覧車High Rollerから見下ろすホテル群

f:id:miyamotokazuaki:20151022185829j:plain
↑ホテルでかすぎて、入り口入ってから迷う、迷う。ツアーメンバーがFacebookグループに「会場までの近道」を写真入りでアップしたらそれにたくさんいいね!がつくぐらい。

■会場の様子

 上の写真にある、一番繁華街のストリップ通りに面したベネチアンっていうところが会場でした。

 AWS re:Inventでは毎年、Amazon Web Serviceの様々な新機能発表がされます。今年もたくさん発表がありました。簡単にデータ分析ができる、Amazon QuickSight, 大量のデータ移行につかえる、Amazon Snowball, そしてKinesis Firehose, AWS Config Rules, Amazon Inspector, AWS Database Migration Service, AWS Schema Conversion Tool, Kinesis analytics, 新しいEC2インスタンスファミリーX1や、コンテナをより使いやすくする新サービスAmazon EC2 Container Registry, Python for Lambda, AWS Mobile Hubおよび、とどめAWS IoT。小さいものを含めるともっとたくさんあります。

 個々のサービスの内容は、数百人に登る日本からの参加者の皆さんがblog等で紹介されているので、このあたりから辿ってもらえればと思います。

aws.typepad.com

 全般的にはAmazonの「ビジネス面」の勢いを感じさせるものが多かったです。私の記憶では、数年前には、「システムのテストフェーズとかで使うと便利だからどんどん使ってくださいね」というトーンでした。今年は、「製造業や金融のミッションクリティカルかつ巨大なデータを扱う実環境としていけますよ!」と。データベース、データ分析のツール、IoT関連、いずれも出てくる事例は大企業、時代が変わっていっていることが見てとれます。

f:id:miyamotokazuaki:20151022185945j:plain ←BMWの事例

f:id:miyamotokazuaki:20151022185953j:plain ←工場でのIoT利用モデル

■個人的に一番印象的だったのはAmazon Snowballというサービス

 個々の新サービスの紹介をしはじめるとキリがないので、個人的に象徴的だと思ったものを一つ上げたいと思います。それはAmazon Snowball。これはなんとアプライアンスです。

f:id:miyamotokazuaki:20151022190008j:plain

 メジャーなクラウドベンダーがアプライアンス的なものを出すのは初めてじゃないでしょうか。

 これ、何の目的に使われるかというと、オンプレミスのデータをAmazonのS3に引っ越すためのものです。Amazon Snowballをオンプレミスのサーバに繋いでデータを吸い出して、それをAmazonに送るとAWSのS3にセキュアにアップロードしてくれるというもの。1台で50TBのデータを扱えます。

 我々も、エンドユーザ様から過去のメールを弊社サービス(HDE One)に入れてくれ、みたいな要望をいただいたり、そのアップロードの際に、転送速度をうまくコントロールしないと翌月の請求額が跳ね上がったり、そういう経験をしているので、こういうの必要だよね、と改めて感じました。データを引っ越す時に気になること、たとえば物理的破損だったり、セキュリティだったり、予想外の請求額だったり、そういったエンジニアや担当者が留意すべきところを全部考えなくていいよ、という隙間ソリューションです。例え、「フルスタックエンジニア」であっても、HDDが破損しない梱包の仕方とかっていうノウハウは持ってないですからね。  そして、そういう足回りのベタなところを(周りのサードパーティーがやるのではなくて)Amazon自身がやるんだということに少し驚きましたし、ここまで徹底してやるから伸びているのか、とある種の納得を感じました。

■実物見てみると

 このSnowball、そばでみるとごっついです。アメリカンサイズ。床に落とすと床の方が壊れるんじゃないかと(Keynoteでは床に落としてみせてましたが)。最近の超小型HDDとか見ていると、ちょっとびっくりするぐらいゴツい。

 ちなみに、何でsnowballっていう名前かっていうのを会場で聞いてみたところ、雪の球を投げつける=物理的なものを移動する=アプライアンスを搬送する、というようなことでした。加えて、帰国してからネットで調べると、「Cerro Torre(邦題:クライマー パタゴニアの彼方へ)」っていう2013年の映画の副題が a snowball's chance in hellっていって、ここから取ったのかも、というニュアンスの記事を見つけたので、これが(も)ビンゴかもしれません。

f:id:miyamotokazuaki:20151022190030j:plain

f:id:miyamotokazuaki:20151022190037j:plain

■いずれは消えるサービスだが、時代を象徴しているサービス

 このサービス、世の中のデータがことごとくクラウドに移行されちゃったら消えるサービス(?)ではないかと思います。オンプレミスからクラウドへの移行期ならではの象徴的なサービスかと。

 とはいえ、クラウドへのインポートだけではなく、export/importの両方をうたっています。説明ではImportの話が印象的だったので、てっきり、「Amazonにロックオンするone wayなサービスキター」と思ってたんですが、後からサイトを見ると「緊急時の復旧等の目的でexport使えるよ」って書いてありました。

 値段もお手頃。

 デバイス処理 $80.00〜$99.00(リージョンによって異なる) : 処理されるストレージデバイスあたり  データ読み込み時間 $2.49〜$2.99(リージョンによって異なる) : データ読み込み時間あたり。(2015/10/23時点)

 ただし、東京リージョンでは現時点(2015/10/23時点)ではまだやってません。アクセスすると、

Import/Export Snowball is not available in アジアパシフィック (東京). Please select another region.

 って表示が出ちゃいます。

 あと、「SnowballをAmazonに送る時にGPS付けてたらデータセンターの場所がバレちゃったりしないのかな?」というのは、re:Inventツアー参加メンバーの中で少し話題になっていましたが、さすがに会場では訊けずじまいでした。

■ペタバイトは今年のre:Inventのキーワードの一つ

 さて、このSnowballの説明には、”to transfer petabytes of data into or out of AWS(ペタバイトのデータを出し入れできるよ)"って書いてあります。この「ペタバイト」っていうのは、今年のre:Inventの隠れたキーワードのような気がしました。  キーノートの前日に開催されたパートナーサミットでもAndyがもうデータのサイズがペタバイトを超えるのは普通だ、って発言してました。私が聞きに言ったセッションの中にも、”Security and Compliance at Petabyte Scale”っていうゲノム解析データの事例が出ていました。  Amazon Japan様によれば、日本ではまだペタバイトのデータをAWSに預けているところって数社のようですが、これから増えていくでしょうね。

f:id:miyamotokazuaki:20151023103529j:plain ←パートナーサミットの様子

■宣伝!ペタバイト祭りやるよ

 さて、ここから宣伝です(笑)。

 HDEでもついに、AWSに預けているデータがペタバイトを超えました。そこで、これを記念するとともにAWS技術者に感謝するために、「ペタバイト祭り」なるものを催すことにしました。

 YAPC主催の牧大輔さん(@lestrrat)、AWS界隈で有名なMichael H. Oshitaさん(@ijin)を迎えて、「ペタバイト級データを支えるクラウドサービスの表と裏」〜ペタバイトまでの道のりと障害、そして、開発と運用のチームをどのように融合するかについて〜というテーマでパネルディスカッションやります。  モデレータは、なんと今話題のソラコムの玉川 憲さん!豪華な布陣ですが、無料です。場所はみなさんの大好きな渋谷です。面白そうだと思ったエンジニアの方は是非おいでください。

 f:id:miyamotokazuaki:20151023102707j:plain  f:id:miyamotokazuaki:20151023102502j:plain

 参加希望はFacebookイベントページ「ペタバイト祭り」

 https://www.facebook.com/events/1496829413966727/

 にて、「参加希望」ボタンをポチッと押してください。

 どうぞよろしくお願いいたします。

 以上です。

SORACOM Air/Beamはどんな問題を解決するのか、IoT素人の目線で考えてみる

こんにちは。HDEの小椋です。SORACOM リリース記念リレーブログ に参加させていただいております。

僕は機械・電気系はまったくの音痴、IoTも素人です。でも、クラウドは一応素人ではないので、オンプレミス機器をどんどんクラウドに移行したように、物理的な機器もどんどんクラウドのパワーを活用して、現実世界を豊かにすることができるんじゃないか、ということをよく妄想します。しかし、その時にいつも壁として立ちはだかるのが、物理セキュリティの問題です。

SORACOM Air/Beamが、それらの問題をエレガントに解決してくれたことに、とても興奮しています。うまく説明できるかどうかわからないのですが、以下チャレンジしてみます。

たとえば、家の玄関のチャイムを、クラウドとRaspberry Piのような安価な機器で実現することを考えてみましょう。面倒くさいので、とりあえず通話機能とかその他の機能とかはのぞいて、チャイム機能だけ考えることにします。

要件:玄関に来た人がボタンを押したときに、スマホに通知したい

という単純な問題を考えてみます。

f:id:goura:20151006023827p:plain

ボタンの部分はRaspberry PiとかEdisonとかにして、家の無線LAN経由でクラウドに接続し、クラウド側の何かのAPIを呼び出して、スマホに通知を送る。こうすれば、Raspberry Pi以外に特別な機器も要らないし、良さそうですよね。クラウドが得意な人なら、ちょっと電子工作するだけでできちゃいそうなので、一瞬ワクワクします。

でも、よく考えるとそう簡単でも無いんです。この時、Raspberry Pi側には、少なくとも二つの大事な情報が格納されています。一つは無線LANの認証情報、もう一つはクラウドのAPIの認証情報です。もしRaspberry Piだったら、実機を盗まれたら簡単に読み取れてしまう情報ですよね。

もし悪意を持った人が、玄関先にあるRaspberry Piを盗んだらどうなるか。無線LANの認証情報は、もし盗まれたら家の無線LANにタダ乗りされてしまったり、家のLANに侵入されてしまうかもしれない大事な情報です。クラウドのAPIの認証情報のほうは、万が一盗まれたら、いつでもどこでもピンポンが鳴らせる、無制限完全ピンポンダッシュが成立してしまいます。

  • 無線LANの認証情報は、家で普段使っている無線LANと別の無線LANにしておけばいいじゃないか
  • クラウドのAPIは、盗まれたことがわかった時点で認証情報を無効化すればいいじゃないか

と思うかもしれませんが、家で普段使っている無線LANと別の情報にしたとしても、タダ乗りは防げません。また、認証情報の無効化については、盗まれたことが検知できるならばそれでもどうにかなるかもしれませんが、検知に失敗し、盗まれたことに気づかないとどうしようもありません。たとえば、物理的にRaspberry Piを盗むのではなくて、盗んで素早くSDカードの中身をコピーして、また元に戻したらとしたらどうでしょうか。情報が盗まれたこと自体に気づかないかもしれません。

ちょっと考えただけでも「安心できる状況」を作るのは結構面倒くさいということがわかります。

SORACOM Air/Beamを使えば、こうした問題を解消できる可能性があります。

SORACOM Beamは、「SIM単位の認証と通信経路の保護をSORACOMが代わりに引き受ける」機能だと表現することができます。SORACOM Beamを使うと、SIMそのもの以外、Raspberry Pi側にはなにも認証情報を置かずに、そのSIM経由での通信が来た時のみ、SORACOMが代理で、あらかじめ登録してある認証情報を付加して第三者のクラウドAPIを呼び出すようなことが可能になります。クラウドAPIを呼び出すにあたっては、IMSIと呼ばれるSIMの識別番号の情報も付加することができます。

つまり、Raspberry Piは、SORACOMのSIM、SORACOM Airを使って通信さえすれば、無線LANの接続情報も、クラウドのAPIキーも、Raspberry Piには置かなくていいのです。証明書ストアの更新とか、そうしたことも忘れていい。大事な情報は全部、第三者に手の届かないクラウド側に置くことができます。

いわゆる「クローン携帯」が存在していないことを鑑みても、SIMを複製したりすることは相当に難しそうなので、SORACOM Beamは、問題をだいぶ単純化してくれる現実的な解であることがわかると思います。

上では触れませんでしたが、「100台置きたかったらどうするか問題」もあります。100台それぞれに別々の認証情報を設定することを考えると面倒ですし、一方全部同じ認証情報を設定してしまうと、万が一盗まれたときの被害が大きくなりますし、機器の入れ替え等で、数台だけアクセスを取り消したい、というような状況も面倒臭そうです。SORACOM Air/Beamを活用すれば、認証情報を各機器に格納する必要が無いため、100台全部に同じソフトウェアをデプロイした上で、どの機器にどのSIMカードを刺したかだけを記録しておけば良く、アクセス許可や、認証情報についてはクラウド側で集中管理することができます。

チャイム程度なら、他の無線テクノロジーでどうにかできるかもしれませんが、例えばドローンとか、デジタルサイネージとか、ロボットとか、クラウドから機器をコントロールするものの応用範囲は無限にありそうです。可能性が一気に拡がった感じで、ワクワクしませんか。そもそも3Gモジュールの値段がまだ高すぎたり、まだSORACOMが日本でしかサービスしていなかったり、まだまだ解決すべき課題はたくさんありますが、少なくとも大きな前進であることは間違いないですよね。

少し前に、うちの会社のインターン生がRaspberry Piで作った、クラウドベースのデジタルサイネージの社内導入を検討した際、上記のような話が問題になり「金属製のケースを作って南京錠でロックしてはどうか」などと議論した挙句面倒くさくなって話が立ち消えになるのを経験した私としては、例えば一般企業で、社内で実験的にIoT機器を導入したりするにあたっては、リスク受容できるところまでだいぶハードルが下がったのではないかと感じました。

さて、僕の文章は必要以上に長く、退屈なことで有名です。ここまで読んでいただき、ありがとうございました。ここで終わりと言いたいところなのですが、せっかくなので上記の話を実感するために、玄関チャイム的なものを試しに作ってから終わりたいと思います。

実際に作ってみる

用意するもの

  • Slack
  • SORACOMのSIMで通信可能な、Raspbian jessieが入ったRaspberry Pi
  • プッシュスイッチ、ブレッドボード、ジャンパ線

「SORACOMのSIMで通信可能なRaspberry Pi」が現在若干ハードル高めですが、このリレーブログシリーズが終わるころには、きっといろんな選択肢が説明されていることと思います。僕は @j3tm0t0 さんの

を参考にFS01BU(SORACOM自身が販売している)を使いました。

難しければ、とりあえず今回はあくまでもproof of conceptですので、SORACOM Airを刺したWiFiルーターとかスマホ(への無線LAN経由でのテザリング)とかの普通の接続で代用して、あとは心の中でPPP接続をしましょう。とにかくRaspberry PiがインターネットにアクセスするときにSORACOM Air経由で行くようにすれば以下の実験は可能です。

通知には、一番簡単なSlackを使います。Raspberry Piにつながったボタンを押すとSlackに通知が飛ぶようにしてみましょう。スマホにSlackのアプリを入れておけば、スマホ宛に通知を送ることもできますよね。

f:id:goura:20151006150145p:plain

こんな感じで、Raspberry PiはSORACOM Beamに対し、SORACOMの内部ネットワークを通じてHTTPでリクエストを送り、それを受けたSORACOM Beamが(特定のグループに入っているSIMからの通信の場合に限り)Raspberry Piの代わりに認証情報(APIトークン)を付加して、インターネット経由でHTTPSでSlackにAPIリクエストを送ります。

Raspberry Pi側には、SIMカード以外の認証情報は置きません。

今回は、SlackのWeb APIのうち、「chat.postMessage」 を使います。

このAPI呼び出しに必須となる引数は

  • token
    • 認証情報
  • channel
    • 宛先
  • text
    • メッセージの内容

の三つです。今回の試みでは、メッセージの内容はRaspberry Piから送り、SORACOM Beamで認証情報と宛先を付加します。

Slack Web APIの引数は "can be passed as GET or POST params, or a mix" という仕様なので、今回は行儀悪くmixする方向で行きます。

Raspberry PiはPOST paramでtextを送信し、そのリクエストに対し、SORACOM BeamがGET paramsとしてtokenchannelを追加します。

Beam側の設定を変えれば、Raspberry Piに変更を加えずに宛先や投稿するSlackのチームを変えることも可能な例を考えてみました。

SlackのAPIトークンの取得

https://api.slack.com/web の下の方に、簡易的な、全権を持ったトークンを発行するボタンがあります。今回はこれで試してみましょう。

f:id:goura:20151006031443p:plain

ボタンを押すと、上の図のボタンの左「none」と書いてあるところにAPIトークンが入りますので、控えておきましょう。

SORACOM Beamの設定

Beamの設定はユーザーコンソール「グループ」から行います。適当なグループを作った後、そのグループの「SORACOM Beam設定」から「HTTPエントリポイント」を追加します。

f:id:goura:20151006031602p:plain

「エントリポイント」のパスに/を、「転送先」のホスト名に「slack.com」を入れます。「転送先」のパスには、

/api/chat.postMessage?token=<<APIトークン>>&channel=@kazuhiro

を登録します。 <<APIトークン>> は上記で発行したAPIトークン、@kazuhiroのところは自分のSlackの@IDに置き換えてください。(画像では途中で切れていますのでご注意ください。&channel=@kazuhiroを忘れずに)

f:id:goura:20151006113048p:plain

このグループに、Raspberry PiからアクセスするSIMを登録します。SIM管理画面からSIMを選んで「詳細」です。

f:id:goura:20151006113858p:plain

この状態で、このグループに登録されているSIMが刺してあるRaspberry Piから http://soracom.io:8888/ にHTTP POSTすると、SORACOM Beamが https://slack.com/api/chat.postMessage?token=<<APIトークン>>&channel=@kazuhiro に同じ内容をPOSTしてくれるはずです。

Raspberry Pi上のcurlから、試しにリクエストを投げてみましょう。

設定が間違っていなければ、

$ curl -X POST -d 'text=hello' http://beam.soracom.io:8888/
{"ok":true,"channel":"D0BSL33EX","ts":"1444063662.167012","message":{"text":"hello","username":"bot","type":"message","subtype":"bot_message","ts":"1444063662.167012"}}

のような応答が帰ってきて、slackbotから "hello" という内容のDMが届くはずです。 (僕の環境だと、スマホにプッシュ通知が来るのは30秒後ぐらいだったので、玄関チャイムとしてはちょっと実用性に難あり)

プッシュスイッチの結線

ここまでできれば、後は押しボタンを付けるだけです。……とはいえ僕は電気はまったくの素人です。 押しボタンの結線、押しボタンを押したことの検知は、以下の記事を参考にしました。

O'Reilly Raspberry Pi Cookbook http://razzpisampler.oreilly.com/ch07.html

記事を参考に、GPIO 18番とGNDにプッシュスイッチをつなぎます。

Raspberry Pi 2の場合は、ピン配置が少し違いますので注意しましょう。

www.raspberry-pi-geek.com

そして、以下のPythonプログラムをどうにかして、Raspberry Pi上にswitch.py として保存します。

短縮URL作りました。curl -L https://goo.gl/4ijyJi > switch.py等で取得できます)

で、そのswitch.py を、同じくRaspberry Pi上で

$ sudo python switch.py

として起動すると、ボタンを押すたびに画面に

button pressed
text=hello%21

のような文字が表示されて、SlackにDMが届くはずです。

ということで、完成!

f:id:goura:20151006032159j:plain

Lチカから先に進んだことが無かったド文系の僕でもIoTできました。感動です。

Raspberry Piは、単に http://beam.soracom.io:8888/ にアクセスしているだけで、何の認証情報も設定していません。仮にこれをプロダクトにして100台、それぞれ全く違う家庭に販売することになったとしても、SDカードの中身は全部同じでいいはずです。SIMの所属するグループが異なれば、異なるSORACOM Beam設定が適用可能なので、機器毎に違うSlackに投稿させることもできます。SORACOM Beam、便利ですね。

後片付け

遊び終わったら、ここで使ったAPIトークンは忘れずに無効化しておきましょう https://api.slack.com/web の右上の "My Auths" をクリックした後の画面のゴミ箱マークから無効化が可能です。 f:id:goura:20151006114711p:plain f:id:goura:20151006114724p:plain

まとめ

図をノートPCのトラックパッドだけで描こうとするのは無謀