クックパッドマートの生鮮食品を SORACOM の IoT デバイスで遠隔温度監視している話

クックパッドマートでサーバーサイドなどのソフトウェアエンジニアをしている石川です。

この記事では、クックパッドマートの物流の一部で SORACOM のサービスを活用して生鮮食品の遠隔温度監視を行っている話について、主にサーバーサイドの取り組みを紹介します。

クックパッドマートの物流

クックパッドマートの物流は、非常に大雑把に言うと以下のような手順になっています。

  1. 販売者さんが集荷場所に置いてあるコンテナへ商品を届ける。
  2. ドライバーさんが集荷場所からコンテナを集めて回る。
  3. 集めたコンテナを、商品の受け取り場所の冷蔵庫に届ける。
  4. 冷蔵庫に届いた商品をユーザーさんが受け取る。

まとめると、(販売者さん)→集荷場所→(ドライバーさん)→ステーション→(ユーザーさん)、という図式になっています。

ここでコンテナと言っているのは物理的な容器の方のコンテナです。以下のようなコンテナに食品を入れて運んでいます。

緑色の折り畳めるコンテナの写真です。
コンテナ

今回注目するのは、ドライバーさんが集荷場所から受け取り場所に届けるまでの間です。集荷場所から受け取り場所の間ではドライバーさんが車両でコンテナを移動させています。お肉やお魚などの生鮮食品を扱っているため移動の間も温度を低く保ちたいのですが、コンテナをそのまま運んでしまうと温度を低く保つのが難しいため、蓄冷剤の入った保冷用のボックスにコンテナを入れて運んでいます。

保冷用のボックスというのは次の写真のような、銀色の箱です。コンテナがいくつか入る程度の大きさになっています。

外側が銀色になっている、直方体の箱です。
保冷用ボックス

この保冷用ボックスの温度を遠隔監視しよう、というのがこの記事のテーマです。

GPS マルチユニット SORACOM Edition

2021 年 4 月現在、私たちはこの保冷ボックスの温度を「GPS マルチユニット SORACOM Edition」を使って計測しています。このセンサーは京セラさんのセンサー「GPS マルチユニット」をベースに SORACOM プラットフォームで利用しやすくするためのカスタムがなされているセンサーです。温度の他、湿度、加速度、位置情報を計測できます。

GPS マルチユニット SORACOM Edition の見た目は下のような感じです。後ろでコンテナの中に入っているものは食品サンプルです。

白くて薄い直方体の形をしたセンサーです。背景には保冷用ボックスが写り込んでいます。
GPS マルチユニット SORACOM Edition

GPS マルチユニット SORACOM Edition は、実装当初候補に挙がっていた他のセンサーと比較しても実装工数が少なく済みそうなことや、今回のユースケースに充分な測定精度があること、充分な数を入手できそうなことなどを理由に採用しました。

SORACOM プラットフォーム上でこの GPS マルチユニットを使う場合、SORACOM Lagoon を使ってダッシュボードを作れる他、SORACOM FunnelSORACOM Funk を使って他のクラウドサービスへデータを送ることができます。今回は SORACOM Funnel を使って AWS へデータを送っています。

温度データの利用

具体的な構成の説明に入る前に、私たちが温度データを使ってどのような機能を作ったかを説明します。

保冷用バッグの中には生鮮食品が入っているため、GPS マルチユニットの示す温度は低く保たれている必要があります。もし GPS マルチユニットの温度が高くなり始めた場合、その GPS マルチユニットの入った保冷用ボックスを運んでいるドライバーさんにご確認いただこうということになりました。

しかし GPS マルチユニット自体には温度を表示する液晶画面の類や異常を知らせるブザーなどはついていないため、何かしら別の方法でドライバーさんに異常を伝えなければいけません。そこで GPS マルチユニットの温度データを元にドライバーさんへ通知をする機能を作りました。

元々ドライバーさんには、当日の配送ルートの表示や集めるコンテナの指示などを行う目的でモバイルアプリを使っていただいていました。これはドライバーさん専用アプリで、販売者さんの商品を販売するアプリとは別のものです。社内では通称「ドライバーアプリ」と呼ばれています。

もし GPS マルチユニットの温度が高くなり始めた場合、このドライバーアプリ越しにプッシュ通知してお知らせするようにしています。以下のような感じです。

プッシュ通知のスクリーンショットです。内容には「シッパー内の温度が高くなっていませんか?」「タップして続ける」と書かれています。
プッシュ通知

※「シッパー」と書かれているのが保冷用ボックスのことです。

また、先述のように GPS マルチユニット自体を目で見ても温度は分からないため、ドライバーアプリから現在の温度が確認できるようにもしています。

ところでこの機能を実装するためには、それぞれの GPS マルチユニットをどのドライバーさんが持っているのか知らなければいけません。この紐付け登録もドライバーアプリを使って行っています。具体的には、それぞれの GPS マルチユニットに二次元コードを貼り付け、ドライバーさんにモバイルアプリで読み取ってもらうことで登録しています。

更にドライバーさん向けだけでなく、弊社の社内オペレーター向けにも温度データが見えるようにもしています。具体的には、Grafana を使ったダッシュボードで温度の時系列変化が確認できるようにしたり、GPS マルチユニットの温度が高い状態を維持した場合に Slack へ通知が来るようにしたりもしています。

構成

以上のような機能を作るため、サーバーサイドでは以下のような構成を採用しました。

各々のサービスを示すアイコンが矢印で結ばれています。まず GPS マルチユニット SORACOM Edition から SORACOM Funnel に矢印が伸びており、SORACOM Funnel から Amazon Kinesis Data Firehose に伸びています。そこから AWS Lambda に伸びており、AWS Lambda からは 2 本の矢印がそれぞれ Amazon CloudWatch と Amazon DynamoDB に伸びています。
構成図

まず、GPS マルチユニットから SORACOM へ送られてきたデータを SORACOM FunnelAmazon Kinesis Data Firehose に転送します。続いてそのデータを AWS Lambda を使って整形しつつ Amazon CloudWatchAmazon DynamoDB に流します。図からは省略していますがモバイルアプリからは API アプリを介して DynamoDB にある温度データにアクセスできるようになっています。なお、データの行き先が CloudWatch と DynamoDB の 2 つになっているのは開発事情の都合です。

構成自体はシンプルで、全体の実装にもそこまで長い時間はかかりませんでした。たとえば AWS Lambda の部分は AWS CDK を使って 1 日かからずに作れています。

なお、自分が不慣れだったこともあり、上記の構成に落ち着くまでには少し時間がかかりました。たとえば論点をひとつ取り上げると、SORACOM Funnel と SORACOM Funk のどちらを使うかというものがありました。

SORACOM Funnel と SORACOM Funk はどちらもクラウド間を結ぶ「アダプタ」であるという意味で似たサービスです。結果的に Lambda を実行するのであれば、SORACOM から別のクラウドへデータを運ぶ仕組みである SORACOM Funnel ではなく、SORACOM から別のクラウドの関数を実行する仕組みである SORACOM Funk を利用する選択肢もありました。しかし今回は SORACOM Funnel を採用しています。

これは、SORACOM Funnel の方がそれぞれの温度データのタイムスタンプをより正確に得られそうであったためです。GPS マルチユニット SORACOM Edition はデータ取得時の時刻を送らないため何かしらの時刻を使ってタイムスタンプを計算する必要があるのですが、SORACOM Funk を使った場合タイムスタンプの誤差が大きくなりうるという問題がありました。

というのも、今回の実装時点の SORACOM Funk は、GPS マルチユニットからのデータを受信した瞬間のタイムスタンプを保持していませんでした。このため SORACOM Funk を使った場合に温度データのタイムスタンプを得るには「SORACOM Funk 経由で実行された Lambda の内部で現在時刻を取得して温度データのタイムスタンプとする」ような実装が必要でした。しかし Lambda の実行が失敗してリトライされる可能性があることを考えると誤差が許容できないと判断しました。SORACOM Funnel ではデータを受信した瞬間のタイムスタンプが保持されており、この問題が起こりませんでした。

ただし SORACOM Funnel にも、GPS マルチユニットがデータを取得するタイミングと Funnel がデータを受信するタイミングにズレがあるという別の問題はあります。

この問題については、今回は温度について秒単位でのリアルタイム性は要求されておらず、またデータ取得時刻とデータ受信時刻のズレは充分小さいらしいことが分かったため、許容することにしています。実際私たちが気にしているのは「温度の低い状態が維持されているか」であり、特定時刻の温度を正確に知りたい訳ではないため、これで充分と判断しました。

このようにいくつかの論点を考えた上で今回の構成に至りました。そして実際今のところサービスが成長しドライバーさんが増えていく中でもこの構成のまま運用を進められており、ベターな選択であったと考えています。

最後に

以上のように、この記事では、GPS マルチユニット SORACOM Edition を使って生鮮食品の温度を遠隔監視している話を紹介しました。

ところで、実際にこの仕組みを使って温度を計測してみると、たとえば車がトンネルに入ると少しのあいだ温度が上手く取得できないことがあるなどの問題が分かっています。現状は安全側に倒してデータ取得失敗時も通知を行い、人力で判断している状態です。このような状況をどうしていくか、ハードウェアとソフトウェアの両面から改善を進めています。

このようにクックパッドマートでは実世界にまつわる様々な課題にハードからもソフトからも切り込み、スピード感のある開発を続けています。弊社ではただいま絶賛エンジニア募集中ですので、ぜひ採用情報をご覧くださいませ。

cookpad-mart-careers.studio.site

info.cookpad.com

※SORACOM は、株式会社ソラコムの登録商標または商標です。

/* */ @import "/css/theme/report/report.css"; /* */ /* */ body{ background-image: url('https://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527163350.png'); background-repeat: repeat-x; background-color:transparent; background-attachment: scroll; background-position: left top;} /* */ body{ border-top: 3px solid orange; color: #3c3c3c; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; line-height: 1.8; font-size: 16px; } a { text-decoration: underline; color: #693e1c; } a:hover { color: #80400e; text-decoration: underline; } .entry-title a{ color: rgb(176, 108, 28); cursor: auto; display: inline; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; font-size: 30px; font-weight: bold; height: auto; line-height: 40.5px; text-decoration: underline solid rgb(176, 108, 28); width: auto; line-height: 1.35; } .date a { color: #9b8b6c; font-size: 14px; text-decoration: none; font-weight: normal; } .urllist-title-link { font-size: 14px; } /* Recent Entries */ .recent-entries a{ color: #693e1c; } .recent-entries a:visited { color: #4d2200; text-decoration: none; } .hatena-module-recent-entries li { padding-bottom: 8px; border-bottom-width: 0px; } /*Widget*/ .hatena-module-body li { list-style-type: circle; } .hatena-module-body a{ text-decoration: none; } .hatena-module-body a:hover{ text-decoration: underline; } /* Widget name */ .hatena-module-title, .hatena-module-title a{ color: #b06c1c; margin-top: 20px; margin-bottom: 7px; } /* work frame*/ #container { width: 970px; text-align: center; margin: 0 auto; background: transparent; padding: 0 30px; } #wrapper { float: left; overflow: hidden; width: 660px; } #box2 { width: 240px; float: right; font-size: 14px; word-wrap: break-word; } /*#blog-title-inner{*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-position: left 0px;*/ /*}*/ /*.header-image-only #blog-title-inner {*/ /*background-repeat: no-repeat;*/ /*position: relative;*/ /*height: 200px;*/ /*display: none;*/ /*}*/ /*#blog-title {*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-image: url('https://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527172848.png');*/ /*background-repeat: no-repeat;*/ /*background-position: left 0px;*/ /*}*/