GPSマルチユニットとAWS IoT Eventsで作業記録システムを作った話

# 作業記録を付けよう

作業記録を付けるのは大事なことです。原価管理はもちろんですが、自分の作業を見える化することで自宅作業であまり効率的に動けてない部分や思った以上に自分が働きすぎている部分を確認することが出来ます。

とはいえ、慣れないうちはExcelシートなりにマメにログを付けるというのはついつい忘れがちです。せめて作業を切り替えた時間だけでも簡単に記録できないかと考えたのが今回の記事になります。

# ボタンでやる？

最初に思いついたのは[SORACOM LTE-M Button](https://soracom.jp/products/gadgets/)を使うことです。
以前[「LTE-M Buttonで子育て支援するシステムを作ったお話」](https://qiita.com/kkimura/items/c13fc9ad14896c6c1430)というのを作っていますので、これを持ってきて各作業開始時にポチッと押すことでGoogle Spreadsheetに時間を記録することが出来ます。

ただ、これにはいくつか欠点があります。

- ボタンを押したかが思い出せない<BR/>
後からボタンを見ても、状態の変かが目に見えないので「さっき押したっけ？」というのが不安になります。もちろん、通知等を使えば解決は出来ますが、何か目に見えて変化があると安心できます。
- ちゃんと通信できたかが分かりにくい<BR/>
LTE-Mの通信は時々失敗します。このとき、ボタンだとLEDの色で教えてくれるのですが、通信成功/失敗が分かるまで10秒程度の時間がかかり、それを待つ必要があります。また、私は赤緑色弱なのでLEDの色の判別がとても難しく、結局通信が成功したかは通知やSpreadsheetを見て判断することになります。<BR/>
さらに、失敗していればまた自身でボタンを押さないといけません。

1つめは通知や、それを受けて表示するデバイスなどで工夫できそうですが、2つめについてはできれば自動でリトライしてくれると楽ちんだなと思って一旦保留しました。

# GPSマルチユニットでやる？

次に考えたのは[GPSマルチユニットSORACOM Edition](https://soracom.jp/products/kit/gps_multiunit/)を使うことです。

SORACOMさんのIoT DIYレシピの一つ、[「【IoT DIY レシピ】GPS マルチユニット SORACOM Edition で作る「在席状況の自動更新デバイス」」](https://soracom.github.io/iot-recipes/status-changer-by-gps-multiunit/#0)を参考にすると出来そうな気がします。GPSマルチユニットを裏返すというのは比較的大きい動作ですし、目で見て状態が変わってるので作業漏れにもボタンよりは気づきやすそうですし、通信に失敗したときも最短1分でリトライする(というか次の通信をする)ので良さそうです。

ただ、こちらのレシピだと「裏返ってる/表になってる状態」というのは取れるのですが、今回は「アクションした時間を取りたい」というのが目的です。どうにかして「裏表が変わった瞬間」というのを記録する必要があります。

つまり、「状態が変わった」と言うことを検知したいわけです。ボタンだと「ボタンを押した」というのが「状態が変わった」に当たるわけですが・・。

# 状態を持つ = ステートマシン

状態を持って判断して処理をするわけですが、ぱっと思いつくのはSORACOM FunkやBeamを使ってAWS Lambdaに送り、DynamoDBなどで前回のデータを覚えておいてそれと比較するという方法です。しかし、DynamoDBは目的の割にちょっと牛刀な気がします。

そこでふと思い出したのが、ソラコムのテクニカルエヴァンジェリスト maxの[「AWS IoT Events は IoT デバイスの「ステートマシン」」](https://qiita.com/ma2shita/items/66ecfdb34cdb16d345d3)という記事です。そう、このくらいのステートであればAWS IoT Eventsで持たせてやればいいのです。

# AWS IoT Events

[AWS IoT Events](https://aws.amazon.com/jp/iot-events/)については先述のmaxのブログを読んでいただくのがいいかと思いますので説明省略します(相変わらず人の記事におんぶに抱っこ)。

ここでは、以下のような状態を設定します。

- スタート直後の状態(init)、上向き(up)、下向き(down)の3つの状態を作る
- 入力の定義は、GPSマルチユニットのデータを使えるように以下のJSONを読み込ませ、名前を「gps_multiunit」としておく

```json
{
  "payloads":{
   "lat":null,
   "lon":null,
   "bat":3,
   "rs":4,
   "temp":29.3,
   "humi":54.3,
   "x":0.0,
   "y":64.0,
   "z":-960.0,
   "type":0
  }
}
```

- init/upからdownに向けて矢印を引き、遷移の条件に`$input.gps_multiunit.payload.z < 0`と入れる
- init/downからupに向けて矢印を引き、遷移の条件に`$input.gps_multiunit.payload.z > 0`と入れる
- up/downのonEnterイベントにLambda関数を指定する
- Lambda関数は、起動したらGoogle Spreadsheetに記録する([こちら](https://qiita.com/kkimura/items/c13fc9ad14896c6c1430)を参照)

実際の画面で見るとこんな感じですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59415/1dd99ee7-59f5-dd52-216a-97089e312f6c.png)


# AWS IoT CoreとSORACOM Funnelの設定

[こちら](https://dev.soracom.io/jp/start/funnel_aws_iot/)のドキュメントを参考に、AWS IoT CoreとSORACOM Funnelを設定します。

ルールは`SELECT payloads as value FROM '#'`とし、アクションを「IoT Events入力にメッセージを送信する」とします。Funnelで送信すると、GPSマルチユニットからのデータはJSONの中の`payloads`というキーに入っていますので、ルールでその部分だけを取り出して(`SELECT payloads`の所)、IoT Eventsに渡すようにします。

IoT Events側でも受け取るときに名前がズレないよう、上記の通り「payloads」と名前を合わせておきましょう。私はうっかり最初にIoT Eventsで入力の設定でJSONを読み込ませる際に「value」なんて名前にしてたのでうまく動かないで悩んだのですが、そんなときは慌てずIoT Coreのルール側で

`SELECT payloads AS value FROM '#'`

と名前を付け替えてあげると動きます。

# 動作検証

GPSマルチユニットを「平日の業務時間中は1分おきに送信」としておき、裏返してみて様子を見ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59415/543b0b3b-6eed-7d60-2546-bebeb3927d45.png)

無事取れてますね！

# まとめ

- GPSマルチユニットを裏返したり表にしたりすることで、作業の切り替わり時間を記録してみた
- 「前回の入力から変わったら」というようなステートを持つ作業はLambdaだけでやらずにIoT Eventsを挟むと楽ちん
- IoT Eventsの入力のパラメータ名と、IoT Coreから飛んでくるデータのパラメータ名はちゃんと合わせよう
- もしうっかり違う名前を付けたらIoT Coreのルールで「SELECT x AS y」と名前を付け替えればOK