AWS IoT1-Clickで家族へ「帰ります」通知を送信できるようにしてみました

# はじめに
先日、AWSを使ってインフラの構築作業を行ったのですが、AWSにとても興味を持てたので、実際に生活で使えそうな何かを作成しようと思い、色々と考えてみました。
私の友人に**「Lambda王」**というあだ名の人がおり、私はlambdaを触ったことがなかったので、どんな感じで使えるのかを確かめようと思い、今回はLambdaを取り入れることにしました。
私はいつも仕事から帰る時に奥さんに「今から帰ります」と通知をしているので、これを簡単に実行してくれるものを作ってみました。Lambda関数を実行するトリガーとして「AWS iot-1-click」で関数が実行される仕組みにしています。
すでに、色々な情報が溢れており、今さら感が否めませんが、自分の勉強も兼ねてやってみました。

# システム構成図
システム構成は以下の通りです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/d6b97586-0fba-cea0-15be-e9b66593e1aa.png)

**lambdaランタイム設定**
Ruby 2.7.0

# 使用したIotデバイス
SORACOM LTE-M Button

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/fab833cb-b4eb-0043-7bbb-14d65948bad0.png)


# 開発の流れ
１　SORACOM LTE-M BUttonのデバイス登録
２　LINENotifyでアクセストークンの発行
３　lambda関数の作成
４　コードのアップロード
５　実験・感想

#  SORACOM LTE-M Buttonのデバイス登録
今回仕様したデバイスは、[AWS IoT1-Click](https://ap-northeast-1.console.aws.amazon.com/iot1click/home?region=ap-northeast-1#/onboard)というAWSサービスにデバイスの登録を行わないと使用できません。

デバイス登録に関する流れは[こちら](https://docs.aws.amazon.com/ja_jp/iot-1-click/latest/developerguide/claiming-devices.html)を参考にしました。

デバイス登録をする際にDNSという番号を入力しないといけないのですが、その番号がどこにあるのか分からず、苦戦したのでそちらについてご紹介します。
写真を見てもらうと一目瞭然ですが、SORACOM LTE-M Buttonの裏側の電池パックを入れるところにDNS番号が記載されています。
そちらをAWS IoT1-Clickのコンソール画面上に登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/091de677-b063-40a7-0356-75584bfcf769.png)



# LINENotifyでアクセストークンの発行

[こちら](https://notify-bot.line.me/ja/)からLINENotifyのトップページにアクセスし、ログインした後に、「マイページ」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/08a918e7-2135-cdeb-92b3-1020359bd69f.png)

遷移した画面で「トークンを発行」をクリックすると、LINENotifyのアクセストークンが表示されるので、後で使うので忘れないようにコピーして保管しておきます。
このアクセストークンを使ってLINEの特定の通知先に通知を送ることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/45fe4fe2-a4e3-d694-77de-49d4a88525e4.png)


# AWS Lambda
AWS Lambdaは、サーバを構築することなく、Lamda関数と呼ばれるコードを実行することができるサービスで、Faas(Function as a Service)と呼ばれるものです。
サーバを構築、管理しなくていい上に、料金も、関数が実行される短い時間だけであり、EC2を構築して運用するよりもメリットが大きいサービスです。

**Lambda関数のトリガー**
Lambda関数を実行するためには、何かしらのきっかけ（トリガー）が必要です。
AWS iot-1-clickのイベントリソースの種類はプッシュ型の中の非同期呼び出し（処理の実行命令だけを送る）になり、今回はこちらがトリガーになります。

**Lambda関数のコーディング方法（３つ）**

- コンソール上で直接コードを書く
- ローカル環境でコードを書いて、zipファイルにしてアップする（容量は10MBまで）
- S３にアップしたzipファイルを参照する

## ruby 2.7.0での開発環境構築

lambda関数のRuby対応バージョンがruby2.7.0だったので、開発環境も統一させます。
普段使っているバージョンが異なっているので、今回の開発についてはruby 2.7.0で実現させたいので、バージョンを一時的に変更させます。

```shell
d@dMacBook-Pro ~ % rbenv versions

system

* 2.6.5 (set by /Users/xxxxxxx/.rbenv/version)

# rubyバージョンが2.6.5しかなかったので、2.7.0をインストールしていきます
d@dMacBook-Pro ~ % brew update

d@dMacBook-Pro ~ % rbenv install 2.7.0

d@dMacBook-Pro ~ % rbenv versions
system
* 2.6.5 (set by /Users/xxxxxxxx/.rbenv/version)
2.7.0

# 現在のディレクトリのプロジェクトのみに適用
$ rbenv local 2.7.0

# 開発環境のみruby 2.7.0になってるのを確認します
d@dMacBook-Pro lineNotify_ruby % rbenv local 2.7.0
d@dMacBook-Pro lineNotify_ruby % ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin20]

# ルートディレクトリではバージョンは元の状態です
d@dMacBook-Pro ~ % ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin20]
```

# lambda関数の作成

コードの作成は、こちらの公式を参考にさせていただきました。
https://notify-bot.line.me/doc/ja/

こちらも参考にしています。
https://docs.ruby-lang.org/ja/latest/library/net=2fhttp.html

```ruby
require 'net/http'
require 'uri'

class LineNotify
  NOTIFY_TOKEN = ENV["NOTIFY_TOKEN"]
  APIURI = URI.parse("https://notify-api.line.me/api/notify")

  def make_request(notify_message)
    # postリクエスト作成
    request = Net::HTTP::Post.new(APIURI)
    request["Authorization"] = "Bearer #{NOTIFY_TOKEN}"
    request.set_form_data({message: notify_message})
    return request
  end

  def send(notify_message)
    request = make_request(notify_message)
    response = Net::HTTP.start(APIURI.host, APIURI.port, use_ssl: APIURI.scheme == "https") do |https|
      https.request(request)
    end
  end
end

line = LineNotify.new
notify_message = "今から帰らせていただきます"

response = line.send(notify_message)
puts response.code
puts response.body

```

# AWSLambdaにコードをアップする 

まずは関数を作成します。
この時にランタイム設定のバージョンが開発環境と同じであることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/6f101ed5-4036-cc92-740b-782f6f5f3500.png)

関数を作成したら、秘匿情報を環境変数に定義して、関数実行時に読み込めるようにします。
AWSLambdaコンソール画面上の「設定」項目に「環境変数」の項目があるので、ここから設定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/76966582-1a4c-336c-b645-4c64a1e7bf6d.png)


**AWSLambdaにコードをアップする**

```shell
zipコマンドでファイルを圧縮する
d@dMacBook-Pro lineNotify_ruby % zip -r lineNotify_ruby.zip .
```
**詰まりポイント**
今回は、ローカルで作成したディレクトリをzipファイルで圧縮してlambdaにアップしました。
コードをアップする際は、作成したプロジェクトディレクトリ内でzipファイルを作成しないと、パスの読み込みがローカル上とlambda上で異なってしまい、エラーが発生するので、注意してください。
また、作成したコードが記載されているファイルは、zipファイルのルートに配置して圧縮するようにします。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/ruby-package.html


AWSLambdaコンソール画面に戻り、圧縮したファイルをアップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/96379dd8-f373-9721-d991-d7044a1153fa.png)


圧縮ファイルをアップすると、コンソール画面上にアップしたコード類が表示されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/a1b30559-6c0a-8371-d986-68935694b43e.png)

**詰まりポイント**
このままのコードでは、Lambda関数は実行できません。
Lambda関数が実行される際、コードが記載されているファイル名とランタイム設定に記載されているメソッド名が呼び出されて、関数が実行されます。
コード内には、Lambda関数を実行する際に、呼び出されるメソッドを定義しておく必要があります。
よって、作成したコードを以下のように修正します。

```ruby:send_iamgoinghome_notify.rb
require 'net/http'
require 'uri'

class LineNotify
  NOTIFY_TOKEN = ENV["NOTIFY_TOKEN"]
  APIURI = URI.parse("https://notify-api.line.me/api/notify")

  def make_request(notify_message)
    request = Net::HTTP::Post.new(APIURI)
    request["Authorization"] = "Bearer #{NOTIFY_TOKEN}"
    request.set_form_data({message: notify_message})
    return request
  end

  def send(notify_message)
    request = make_request(notify_message)
    response = Net::HTTP.start(APIURI.host, APIURI.port, use_ssl: APIURI.scheme == "https") do |https|
      https.request(request)
    end
  end
end

# ここを修正
def lambda_handler(event:, context:)

line = LineNotify.new
notify_message = "今から帰らせていただきます"

response = line.send(notify_message)
puts response.body

end
```

lambda_handlerメソッドを定義して、引数に`event:, context:`を渡せるようにします。
この引数を記載しないとエラーになります。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/ruby-handler.html

LineNotifyクラスを作成するメソッドを定義し、ラインタイムに記載されている呼び出しメソッドが`ファイル名.定義したメソッド名`になっていることを確認してください。
今回の場合は、`send_iamgoinghome_notify.lambda_handler`が実行されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/985d493e-c56a-8ed5-4bca-4e9bec34a4c0.png)

設定が異なっている場合は、編集して、呼び出されるメソッド名を統一させます。

#### Lambda関数のテスト

以上の手順でLambda関数を設定したら、テスト実行して、きちんとコードが実行されるか確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/2b2d16d3-17f6-6c6d-0d13-67dabb3b2752.png)


# デバイスにLambda関数を登録

AWS Iot1-Clickに登録したデバイスに作成したLambda関数を登録します。
まずは、プロジェクトを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/165255b7-a671-43ba-22a7-562000d0c3bd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/359c687c-b935-b2fe-3532-6b0eb673e477.png)

「プロジェクト名」と「説明」を適宜入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/79771fbe-6ae4-0204-7345-514ac7592b9d.png)

プロジェクトを作成した後は、デバイステンプレートを定義し、作成したLambda関数を登録します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/eddd8c10-40ad-3490-d328-8ce6a188f86c.png)

デバイステンプレートを定義したら、プレイスメントを作成して、完成です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/1fbcaa82-53eb-ba6a-9a97-ceda28054063.png)

# 実験
完成はこのような感じです。

![exec_iot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/938100/d1b9f6fa-dcc6-a447-c976-a61d59f7739d.gif)

**感想**
とても簡単に実生活で使えそうなものが完成しました。
いやー、とても面白かったです。
実際に何かを作って完成したら、おー！ってなります。色々と詰まりポイントもあり、自分の勉強にもなりました。
長文記事をご覧くださり、ありがとうございました。また、何か勉強がてら作ってみたいです。