Ola Kae Tode Tai

すべてのエンジニアに、追い風を祈る。

ショートメッセージサービス(SMS)を使ってLED制御する

この投稿は Electric Imp Advent Calendar 2015 の8日目の記事です。

f:id:kironono:20151201001226p:plain

まだLEDねた

前回はLEDをWebUIから制御してみました。

ola.kironono.com

今回は、携帯電話のSMSを使ってLEDを制御してみたいと思います。

Twilio

さて、ブログラムから電話が絡む操作をするにはTwilioというサービスが便利です。Twilioは専用の電話番号を発行してもらって、電話を受ける、かける、SMSを受信する、SMSを送信するといったことをAPIから行えるサービスです。

twilio.kddi-web.com

アメリカ発のサービスですが、KDDIが日本の代理店となっているようです。

今回はこのサービスをつかって、SMSを送るとLEDをON/OFFしてくれるものをElectric Impで作ってみたいと思います。

電話番号を取得する

まずはTwilioのアカウントが必要です。トライアルのアカウントは無料で作ることができるので、さくっと登録してしまいます。

Twilio | Try Twilio Free

アカウントができたら、SMSが使える電話番号を取得します。

f:id:kironono:20151209002047p:plain

"利用可能な機能"のSMSにマークがあるものを選びます。日本の電話番号はSMSが使えないみたいなのでアメリカ合衆国の番号にしました。

エージェントのコードを書く

Twilioで取得した番号にSMSを送る -> TwilioがSMS受信のコールバックURLを呼び出す -> Impエージェントが処理 -> Impデバイスに通知 -> LED制御 -> Twilioにレスポンス -> 結果をSMS送信元に返信

ということをやります。

TwilioからSMS受信したときにImpエージェントの特定のURLを呼び出してもらうようにTwilioを設定するので、まずはエージェント側を実装してしまいます。

#require "rocky.class.nut:1.2.3"

app <- Rocky();

app.post("/state", function(context) {
    try {
        if (!("state" in context.req.body)) throw "Missing param: state";
    } catch (e) {
        context.send(400, e);
        return;
    }
    try {
        if (!(context.req.body.state == "1" || context.req.body.state == "0")) throw "Invalid value: state";
    } catch (e) {
        context.send(400, e);
    }    
    
    local ledState = context.req.body.state.tointeger();
    device.send("set.led", ledState);
    context.send({state = ledState});
});


app.post("/sms/receive", function(context) {
    local body = context.req.body;
    
    // for debug
    if ("MessageSid" in body) {
        server.log("MessageSid: " + body.MessageSid);
    }
    if ("SmsSid" in body) {
        server.log("SmsSid: " + body.SmsSid);
    }
    if ("AccountSid" in body) {
        server.log("AccountSid: " + body.AccountSid);
    }
    if ("MessagingServiceSid" in body) {
        server.log("MessagingServiceSid: " + body.MessagingServiceSid);
    }
    if ("From" in body) {
        server.log("From: " + body.From);
    }
    if ("To" in body) {
        server.log("To: " + body.To);
    }
    if ("Body" in body) {
        server.log("Body: " + body.Body);
    }
    if ("NumMedia" in body) {
        server.log("NumMedia: " + body.NumMedia);
    }

    context.setHeader("Content-Type", "text/plain; charset=UTF-8");
    if (body.Body.find("ON") != null) {
        device.send("set.led", 1);
        context.send(200, "ONにしました");
    } else if (body.Body.find("OFF") != null) {
        device.send("set.led", 0);
        context.send(200, "OFFにしました");
    } else {
        context.send(200, "'ON'または'OFF'のキーワードでLEDを制御します");
    }
    
});

前回のコードに "/sms/receive" のリクエストに応答するハンドラを追加しました。SMSを受信すると送信元、送信先、本文などがTwilioから通知されます。どのようなパラメータが通知されるかは、https://jp.twilio.com/docs/api/twiml/sms/twilio_request で解説されています。

ここでは、受信したメッセージの中に ON または OFF のキーワードが含まれていたらデバイスのLEDを操作するようにしています。

また、レスポンスとしてテキストを返すことで、メッセージの送信元にテキストを返信しています。

SMSを受信したときに呼び出されるURLを設定する

エージェントのURLをTwilioの設定画面から設定します。

f:id:kironono:20151209003947p:plain

Twilioにログインして、製品一覧 -> プログラマブルSMS -> 電話番号とたどり、取得済みの電話番号を表示させます。電話番号をクリックするとメッセージの設定画面が開くので、 Configure withURLRequest URL にエージェントのURL + "/sms/receive" を入力し、 HTTP POST を選択します。

これで、SMSを受信すると設定したURLが呼び出されるようになりました。

Impをデプロイし、動作を確認してみます。

SMSを送信してみる

iPhoneから実際にSMSを送信してみました。

f:id:kironono:20151209005217p:plain

その時のImpのログはこんな感じです。

2015-12-09 00:46:11 UTC+9    [Agent] MessageSid: xxxx
2015-12-09 00:46:11 UTC+9   [Agent] SmsSid: xxxx
2015-12-09 00:46:11 UTC+9   [Agent] AccountSid: xxxx
2015-12-09 00:46:11 UTC+9   [Agent] From: +81xxxxxxxxxx
2015-12-09 00:46:11 UTC+9   [Agent] To: +1234567xxxx
2015-12-09 00:46:11 UTC+9   [Agent] Body: ONにしてちょ
2015-12-09 00:46:11 UTC+9   [Agent] NumMedia: 0
2015-12-09 00:46:11 UTC+9   [Device]    Set LED to state: 1
2015-12-09 00:47:00 UTC+9   [Agent] MessageSid: xxxx
2015-12-09 00:47:00 UTC+9   [Agent] SmsSid: xxxx
2015-12-09 00:47:00 UTC+9   [Agent] AccountSid: xxxx
2015-12-09 00:47:00 UTC+9   [Agent] From: +81xxxxxxxx
2015-12-09 00:47:00 UTC+9   [Agent] To: +1234567xxxx
2015-12-09 00:47:00 UTC+9   [Agent] Body: OFFってください!
2015-12-09 00:47:00 UTC+9   [Agent] NumMedia: 0
2015-12-09 00:47:00 UTC+9   [Device]    Set LED to state: 0

まとめ

というわけで今回はSMS経由でLED制御ってことにしてみましたが、正直ElectricImpあまり関係ないかもしれません。今回のケースではTwilioからのリクエストに応答する形でしたが、ElectricImpのエージェント等からTwilioのAPIを叩くこともできます。ElectricImpが提供するライブラリにTwilioのAPIを扱えるものがあるのでそれを使うとなにかイベントが起きた時に、SMSで通知とかできると思います。

ちなみに今回は海外の番号を取得したので、送るSMSも海外宛になり、送受信料は普通に1通50円から100円くらいかかるはずですのでもし試す場合はご注意ください。