LoginSignup
5

More than 3 years have passed since last update.

「ボタンを押したらパトランプ点灯してブザーを鳴らす」を、すべてLTE-M回線で実現してみた。

Posted at

下記の投稿の後編です。

Wio LTE M1/NB1(BG96) でパケ死せずにデータを受け取る - Qiita

以前、SORACOM LTE-M ButtonからLINEにメッセージを送る - Qiita という記事を書きまして、その後も日々このボタンをポケットに入れ、機会あるたびに人にデモしていたのですが、ボタンを押したらLINEメッセージが届くだけでは、「すごい」と言われても、「それで?」「だから?」という気持ちが透けて見えてきました。

そのため、LTE-Mボタンを押したら、パトランプが光るようなデモができたらと考えました。そして、どうせなら、受信側も、LTE-M回線を経由して、Wio LTEを使えたら良いのではと考えました。

前回の投稿で、Wio LTE M1/NB1(BG96) を利用して、AWSからデータを受信するところまで実現したので、今回の投稿では、ボタンを押してパトランプを光らせるまでの全体を完成させようと思います。
スクリーンショット 2019-04-30 11.51.00.png

できたものがこちらです。

目次

  • IoTボタンをおしたらLINEメッセージを飛ばすLambda
  • IoTボタンを押したらDynamoDBに値を格納するLambda
  • 最新のDynamoDBの値を取得して返すLambda
  • 手軽なパトランプを探して購入
  • WioLTEとパトランプの接続
  • WioLTEのコード
  • ケースは100均で

IoTボタンをおしたらLINEメッセージを飛ばすLambda

一昔前に作った、 SORACOM LTE-M ButtonからLINEにメッセージを送る - Qiita のコードを適宜いじっています。ちょっとシンプルになったかも。

シングルクリックで、注意アラート、ダブルクリックで、警告アラート、長押しで、アラート解除という設定にしました。

const https = require('https');

exports.handler = async(event) => {
    var messagetext;
    switch (event.deviceEvent.buttonClicked.clickType) {
        case 'SINGLE':
            messagetext = "\u{26A0} 注意アラートが発砲されました。\u{26A0} ";
            break;
        case 'DOUBLE':
            messagetext = "\u{1F6A8} 警告アラートが発砲されました。\u{1F6A8} ";
            break;
        default:
            messagetext = "\u{2139} アラートが解除されました。\u{2139} ";
            break;
    }
    await linePush(messagetext);
};

function linePush(messagetext) {

    return new Promise((resolve, reject) => {
        var payload = {
            "to": [process.env.RECIPIENT_LINE_ID],
            "messages": [{
                "type": "text",
                "text": messagetext
            }]
        }
        var body = JSON.stringify(payload);
        var req = https.request({
            hostname: "api.line.me",
            port: 443,
            path: "/v2/bot/message/multicast",
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "Content-Length": Buffer.byteLength(body),
                "Authorization": "Bearer " + process.env.CHANNEL_ACCESS_TOKEN
            }
        }, function(res) {
            if (res.statusCode === 200) {
                console.log('Posted to LINE');
                resolve();
            }
            else {
                console.error('Failed to post to LINE ' + res.statusCode);
                reject();
            }
        });
        req.write(body);
        req.end();
    });
}

こんな感じで、かわいく絵文字も追加してみました。
スクリーンショット 2019-04-30 11.52.52.png

値を保存するためのDynamoDBの設定

前回の投稿で作ったWio-LTE側のコードは、数秒おきにAWSにステータスを問い合わせる作りになっています。つまり、AWSに直近のステータス(シングルクリックか、ダブルクリックか、長押しか)を保存しておく必要があります。
ちょっとオーバースペックではありますが、DynamoDBに保存することとします。

SORACOM Beam を使用して AWS と接続する | SORACOM Developers を参考にしながら進めようと思ったのですが、コードのバージョンが古いのかうまくいかなかったので、結局手で作りました。

DynamoDBを作る

実際、最新のステータスだけ取れればいいので、1カラム、1レコードのDBで問題ないのですが、どうせなので履歴を残しておくことにしましょう。
最新のステータスを取得できるよう、タイムスタンプをソートキーにしておきます。プライマリキー、ソートキーはDBの作成時にしか作成できないので、注意です。(私は4回ほど作り直しました。。。)
スクリーンショット 2019-04-28 13.13.20.png
キャパシティーモードは、デフォルト設定でも大丈夫だと思いますが、一応最小設定にしておきます。
スクリーンショット 2019-04-28 13.13.33.png

IoTボタンを押したらDynamoDBに値を格納するLambda

IoTボタンを押されたら、上で作成したDynamoDBに情報を格納するようにします。
IoTボタンとLambdaを接続する方法は、こちらを参照してください。
SORACOM LTE-M Button powered by AWS をクリックしてSlackに通知する | Getting Started with SORACOM LTE-M Button | SORACOM Developers


var AWS = require("aws-sdk");
const dynamo = new AWS.DynamoDB.DocumentClient({ region: "ap-northeast-1" });

exports.handler = async(event) => {
    var putItem = {};

    var d = new Date(event.deviceEvent.buttonClicked.reportedTime);

    putItem.timestamp = Math.floor(d.getTime() / 1000);
    putItem.deviceId = event.deviceInfo.deviceId;

    switch (event.deviceEvent.buttonClicked.clickType) {
        case 'SINGLE':
            putItem.buttonState = 1;
            break;
        case 'DOUBLE':
            putItem.buttonState = 2;
            break;
        default:
            putItem.buttonState = 0;
            break;
    }

    var params = {
        Item: putItem,
        TableName: 'BeamDemo'
    };

    try {
        await dynamo.put(params).promise();
    }
    catch (err) {
        console.error('DynamoDB error:', err);
    }
};

こんな感じで、データが保存できました。
スクリーンショット 2019-04-30 12.22.18.png

最新のDynamoDBの値を取得して返すLambda

前回の投稿 参照。最後に \n をつけないと、Beamがタイムアウトしてしまいます。


var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();

const dynamo = new AWS.DynamoDB.DocumentClient({ region: "ap-northeast-1" });

exports.handler = async(event) => {
    var retval;
    var params = {
        TableName: 'BeamDemo',
        KeyConditionExpression : "#k = :val",
        ExpressionAttributeNames  : {"#k" : "deviceId"},
        ExpressionAttributeValues : {":val" : "デバイスID" },
        ScanIndexForward: false,
        Limit: 1
    };
    await dynamo.query(params).promise().then((data) => {
        retval = data.Items[0].buttonState;
    }).catch((err) => {
        console.error(err);
    });
    return (retval + "\n");
};

手軽なパトランプを探して購入

最初は、本家純正のパトライトを使おうと思ったのですが、さすがに値段が高いのと、バッテリで駆動できないので。。。
ラジコンカー用のミニチュアパトランプをAmazonで購入。
スクリーンショット 2019-04-30 11.46.56.png
商品説明を見ると、電圧は4.8v-6vとあります。Wio-LTEは3.3v駆動なのでちょっと足りないですが、試してみてもし動かなかったらUSBの5vでなんとかすることにしましょう。安いし。
スクリーンショット 2019-04-30 12.30.41.png

WioLTEとパトランプの接続

LEDなので、そこまで消費電流多くないはずだし、もともとラジコンのバッテリとつなぐ前提のものなので、抵抗挟まずに直結してもきっと大丈夫でしょうということで、Groveコネクタをちょん切って、パトランプのコネクタもちょん切って、結線します。
パトランプは、3本線が生えていますが、これは、こちらのページによると、ラジコン用のコネクタでした。

茶色線が「-」赤色線が「+」オレンジ色の線が信号線

とのことなので、茶色とGND、赤色とDIGITALピンをつなぎます。 digitalWrite(PIN, HIGH) すれば、光るはず。オレンジ色の線は、信号線で、光るパターンを変更できるそうなのですが、今回は利用しません。

パトランプのコネクタはとても細くて、爪で被覆を剥けてしまうレベルでした。

せっかくなので、Grove IoT スターターキット for SORACOM(Wio LTE JP Version) についてきた、ブザーも接続します。

スクリーンショット 2019-04-30 11.44.46.png

WioLTEのコード

前回の投稿 で書いたコードに手を加えて、接続したパトランプとブザーを鳴らせるようにしました。

#include <WioCellLibforArduino.h>

#define INTERVAL        (10000)
#define RECEIVE_TIMEOUT (10000)

#define RED_PIN      (WIO_D19)
#define YELLOW_PIN      (WIO_D20)
#define BUZZER_PIN      (WIO_D38)

WioCellular Wio;
bool socketStatus;

void setup() {
  delay(200);

  pinMode(RED_PIN, OUTPUT);
  pinMode(YELLOW_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);

  SerialUSB.begin(115200);
  SerialUSB.println("");
  SerialUSB.println("--- START ---------------------------------------------------");

  SerialUSB.println("### I/O Initialize.");
  Wio.Init();

  SerialUSB.println("### Power supply ON.");
  Wio.PowerSupplyCellular(true);
  delay(500);

  SerialUSB.println("### Turn on or reset.");
#ifdef ARDUINO_WIO_LTE_M1NB1_BG96
  Wio.SetAccessTechnology(WioCellular::ACCESS_TECHNOLOGY_LTE_M1);
  Wio.SetSelectNetwork(WioCellular::SELECT_NETWORK_MODE_MANUAL_IMSI);
#endif
  if (!Wio.TurnOnOrReset()) {
    SerialUSB.println("### ERROR! ###");
    return;
  }

  SerialUSB.println("### Connecting to \"soracom.io\".");
  if (!Wio.Activate("soracom.io", "sora", "sora")) {
    SerialUSB.println("### ERROR! ###");
    return;
  }

  socketStatus = false;

  SerialUSB.println("### Setup completed.");
}

void loop() {
  char data[100];
  int v;
  int connectId;
  sprintf(data, "0");

  if(!socketStatus){
    SerialUSB.println("### Open.");
    //beam.soracom.io:23080
    connectId = Wio.SocketOpen("beam.soracom.io", 23080, WIO_UDP);
    if (connectId < 0) {
      SerialUSB.println("### ERROR! ###");
      goto err;
    }
    socketStatus = true;
  }

  SerialUSB.println("### Send.");
  SerialUSB.print("Send:");
  SerialUSB.print(data);
  SerialUSB.println("");
  if (!Wio.SocketSend(connectId, data)) {
    SerialUSB.println("### ERROR! ###");
    goto err_close;
  }

  SerialUSB.println("### Receive.");
  int length;
  length = Wio.SocketReceive(connectId, data, sizeof (data), RECEIVE_TIMEOUT);
  if (length < 0) {
    SerialUSB.println("### ERROR! ###");
    goto err_close;
  }
  if (length == 0) {
    SerialUSB.println("### RECEIVE TIMEOUT! ###");
    goto err_close;
  }
  SerialUSB.print("Receive:");
  SerialUSB.print(data);
  SerialUSB.println("");

  v = int(data[0]);

  if (v == '0'){
    digitalWrite(YELLOW_PIN, LOW);
    digitalWrite(RED_PIN, LOW);
    digitalWrite(BUZZER_PIN, LOW);
  }else if(v == '1'){
    digitalWrite(YELLOW_PIN, HIGH);
    digitalWrite(RED_PIN, LOW);
    digitalWrite(BUZZER_PIN, LOW);
  }else if(v == '2'){
    digitalWrite(YELLOW_PIN, LOW);
    digitalWrite(RED_PIN, HIGH);
    digitalWrite(BUZZER_PIN, HIGH);
  }
  goto err;

err_close:
  SerialUSB.println("### Close.");
  if (!Wio.SocketClose(connectId)) {
    SerialUSB.println("### ERROR! ###");
    goto err;
  }
  socketStatus = false;

err:
  delay(INTERVAL);
}

ケースは100均で

近くの100円ショップに行って、ゼムクリップのケースを買ってきて、穴を開けてミニチュアパトランプをつけました。

ブザーの基板部分にはテープを貼り、Wio-LTEの基板と当たってショートしないようにします。

IMG_4175.jpg
IMG_3545.jpg

これで、モバイルバッテリさえあれば準備不要でデモができるキットが完成しました。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5