MESHで倉庫の出入りを確認&通知しよう

目次

はじめに

運用上、倉庫の出入りを管理したいことがあります。
○分前に人の出入りがあったか?を確認しようとすると、設置した監視カメラの映像を使うことが一般的かもしれませんが、確認に時間がかかります。
そんなとき、入退室の時間を何かのデータベースに登録しておき、その情報を簡単に確認できるとうれしいです。

そこで、kintoneと、MESHの人感ブロック・LEDブロック・ボタンブロックを組み合わせて、倉庫の出入り状況を確認できるしくみを作ってみました。

MESHについては MESH公式サイト (External link) を確認してください。

完成イメージ

このカスタマイズでは次のことを行います。

  • MESHの人感ブロックを使って、「エリア内に人がいるか?」をチェックします。チェック結果はkintoneのアプリに登録します。
  • MESHのボタンを押して、直近5分以内に人がいたか(該当するレコードがあるか)をkintoneに問い合わせします。
    • 人がいた場合:MESHのLEDブロックは赤に点灯します。
    • 人がいなかった場合:MESHのLEDブロックは緑に点灯します。

MESHとMESHを接続しているモバイルはBluetoothの範囲内としてください。

下準備

kintoneの設定

下記手順で作成するkintoneアプリのIDとAPIトークンは、MESHの設定で利用するので控えておいてください。

アプリIDは、アプリのURLで確認できます。
例:URLがhttps://sample.cybozu.com/k/10/の場合、「10」がアプリIDです。

kintoneアプリの作成

次のフィールドをフォームに設置します。

フィールド名 フィールドタイプ フィールドコード 初期値 備考
日時 日時 DateTime レコード登録時の時刻を初期値にする 人感センサで人を感知した時間です。
ステータス 数値 Status 人感センサの値です。
ただし登録するのみで、プログラム内で利用はしません。

APIトークンの生成

「レコード閲覧」「レコード追加」権限のあるAPIトークンを生成します。

APIトークンの生成方法は「 APIトークンを生成する (External link) 」を参照してください。

MESHの設定

MESH SDK

MESH SDKは、MESHアプリのレシピで利用するカスタムブロック(ソフトウェアブロック)を作成するツールです。
カスタムブロックでは、JavaScriptを使って、複雑な処理やさまざまなWebサービスとの連携ができます。

以下の手順にしたがって、MESHのカスタムブロックを2つ作成します。

作成するカスタムブロックは以下の「入退室(登録)ブロック」「入退室(取得)ブロック」です。

  • 入退室(登録)ブロック:人感センサのチェック結果をkintoneに登録するブロックです。
  • 入退室(取得)ブロック:kintoneに問い合わせしてLEDブロックを点灯させるブロック
  1. [Create New Block]をクリックし、新規ブロックを作成します。

  2. [Import]タブを選択します。

  3. エディタ部分に、後述する「 入退室(登録) 」および「 入退室(取得) 」のJSONの内容をそれぞれ貼り付けます。
    [Load JSON]をクリックすると、上書きの確認ダイアログが表示されるので[OK]ボタンをクリックし、インポートします。

  4. インポート後、下記PropertyのDafault Valueを書き換えます。

    プロパティ名
    ドメイン kintoneのドメインを指定してください
    アプリケーションID kintoneアプリの作成 で作成したアプリのアプリケーションID
    APIトークン APIトークンの生成 で発行したAPIトークン

    PropertyのDefault Valueは、レシピにブロックを配置する際、初期値として設定されます。
    Propertyの値は、MESHアプリのレシピからも変更できます。

  5. [Save]をクリックし、保存します。

MESHアプリ

MESHアプリでは、Bluetoothで接続したMESHブロックや、MESH SDKで作成したカスタムブロックを「レシピ」のキャンバス上に配置し、処理フローを作成します。

  1. [+新しいレシピ]をタップし、レシピを作成します。

  2. MESHブロックを接続します。

    • 人感ブロック
    • ボタンブロック
    • LEDブロック2つ。

    MESHブロックの接続

  3. 接続したMESHタグを、ドラッグ&ドロップでキャンバスに配置し、設定します。

    ブロック 設定
    人感センサ
    • 感知したら
    • 間隔(秒):60
    ボタンブロック
    • 1回押されたら
    LEDブロック 1つめのブロック
    • 点滅する
    • 色:オレンジ
    • 明るさ:1
    • 時間(秒):5秒
    • 周期(秒):1秒
    2つめのブロック
    • 点滅する
    • 色:ミント
    • 明るさ:1
    • 時間(秒):5秒
    • 周期(秒):1秒
  4. MESH SDKにサインインします。

    MESH SDKのサインイン

  5. カスタムの[追加]をタップし、MESH SDKで作った2つのカスタムブロックを追加します。

    • 入退室(登録)ブロック
    • 入退室(取得)ブロック

    カスタムブロックの追加

  6. 追加したカスタムブロックを、ドラッグ&ドロップでキャンバスに配置します。
    MESH SDKでブロックを作成したときのDefault Valueが初期値に設定されます。
    変更する場合は、対象のブロックをタップして表示される画面で変更してください。

  7. 配置したブロックをそれぞれ次のように接続します。
    「入退室(取得)」ブロックの出力コネクタについては、次のように接続してください。

    • 1つめのコネクタ(confusion):色をオレンジに設定したLEDブロック
    • 2つめのコネクタ(vacant):色をミントに設定したLEDブロック

動作確認

  • 人感ブロックの前に立って感知されたら、kintoneにレコードが登録されます。
  • ボタンブロックのボタンを押して、LEDブロックが光ります。

サンプルコード

入退室(登録)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
  "formatVersion": "1.0",
  "tagData": {
    "name": "入退室(登録)",
    "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAADc0lEQVRoQ+2a3VEbMRCAd3UugFQAVIBTQUwHoQOoIPLp3jHv1nFUEFIBJWAqwB3EHcR5t24z65E85+MMuh+JhIlm/OCxfvbTrla7KyN8kIYfhAP+gwyhSSnlRAjxBREnAHBiPzz1GgCWiLjcbDY/iqJYvrXeu2iEAZIkuQYABvBpC2PMTVEUi0Odo4JIKY+EENeIKH2kr/dBxGKz2TAQa2yveYNIKcdCiG88uixLnmzVRhgp5cloNHogonGbcQ0wbG4X9fW9QbIsmxDRI09sjDl/Tc31xVkTo9HosS+Em9eeHZZhp5koIGma3nY1p4NnArGYz+fTHZyvmrtqpDrOdy3fflXLCK4RpRSbo6938mVw/RZa63P+EhSEHUSSJM9tpWvT32klKMh0Oi2cp2sjXJu+RHST5/lsD8S62Eb3KIQ4JqKZXeSOiBpv27Isl+4mDmxWe+a1B5Km6QwR+cbt3NwO8QRKqV8AcNR5Mr+BK631aWgQ8pOlXy+tNdZNi3evcQeFEBNE/G6XvDDGHArk1u6iUkq9D8hr+9LlHlFK/axEtP22/fDotdb6U1Cv9W6HfWiNZFk2I6JezsNDjXdaaxlUIyHDEwdojPnM7j4oiHXB/36IwiAhtdIpaLTZ3VcWrizLRZvESilVAMA2KRuwbc+Gm8/btPoIwJuQJAmbWK/ssCLD0mqjfWLVB4THcqqbJMnDADAM0T3V7QtiYVgzHHh2NbM7Y8ysV/FhCBA3h3UArcpBiHgzn8//jnJQfTNs4nUJAGfW5FycxxWaFSI+AcDiNYCoh72qCQC4JaIVET1x7sICH/KA9lyNiYirkGdckTTGXDVVcKJ4LQfyRsZYr5Ox8C8aEd3neX5V/yEqSJZlzwPUttbGmNP6gY8GYs2Ew/reralAGA0kTdPLSmLWF2ZXBop+2JVSfBluQ5wB2gvziqaRoQsRRHSV5/l9VI0EioD3zCuKRkIV6owxn5z3igIykNttulOmeZ5ziuBf++16QId0uw0ytC9idwUZ2O2+EMOZV3DTGtjtHjSvGCCh679b8woKEsjtNppXUJBQbrdOwi8AQUEi1X6ZaxEUxD0c2b9ouCywqwOsj+Ok7IkfnLg8FRSkvrJ9bx+XZTlGRE6cju0zRvV/KG4Yl3q2HxYWEX9boXcvYtX5o4IMpYqmeT4MyB+14EAP6Tq37QAAAABJRU5ErkJggg==",
    "description": "",
    "functions": [
      {
        "id": "function_0",
        "name": "postKintoneApp",
        "connector": { "inputs": [{ "label": "motion" }], "outputs": [] },
        "properties": [
          {
            "name": "ドメイン",
            "referenceName": "domain",
            "type": "string",
            "defaultValue": "example.cybozu.com"
          },
          {
            "name": "アプリケーションID",
            "referenceName": "appId",
            "type": "number",
            "defaultValue": "1"
          },
          {
            "name": "APIトークン",
            "referenceName": "apiToken",
            "type": "string",
            "defaultValue": "TOKEN"
          }
        ],
        "extension": {
          "initialize": "",
          "receive": "",
          "execute": "/*\n * MESH program\n * Copyright (c) 2019 Cybozu\n *\n * Licensed under the MIT License\n */\nconst url = `https://${properties.domain}/k/v1/record.json`;\nconst data = {\n  app: properties.appId,\n  record: {\n    DateTime: { value: new Date() },\n    Status: { value: messageValues.stateValue }\n  }\n};\n\najax ({\n  url: url,\n  data: JSON.stringify(data),\n  type: 'POST',\n  contentType: 'application/json',\n  dataType: 'json',\n  timeout: 5000,\n  headers: { 'X-Cybozu-API-Token': properties.apiToken },\n  success: (contents) => {\n    log('success');\n  },\n  error: (request, errorMessage ) => {\n    log('error');\n    log(request.responseText);\n    log(errorMessage);\n  }\n});\n\nreturn {\n  resultType: 'pause'\n};\n",
          "result": ""
        }
      }
    ]
  }
}

入退室(取得)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
{
  "formatVersion": "1.0",
  "tagData": {
    "name": "入退室(取得)",
    "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAD9klEQVRoQ+1a0VHbQBC9PbkAqCBQAVBBoINQQaCCyD79A9/4hKggpALoAFMB7iBOBXH+ddrMc04eWZbkO1sSDJOb8fDh9e2+3ber3RUkPsihD4JD/AfSRiTDMDyVUn4molMhxIH94Oq5EGJKRNM0TX8kSTLdpO9NIgIAQRBcCSEAwOVMjDE3SZJM6oSdgIRhuGe9hb9zFw9VKcQ9UsorIgpdrC/LEFGSpikAIWIrpxHIaDS6IKKvFZ7DRU/WSzMXo8IwPBgMBo/MfOwiX+v5f3Q7T5JkRW8lECgNguC7Q+hnxpiz8qVlIxCJwWDwvCuI/F6bO9C7jMwakBqlE2aeEdEejCEiJGZ+JlrrsyYvj0aju23p1BCZZDweD5fgarh8HAQBPDiXUl6Ox+NlkgFoEASPxWgZY/areIu7oyg6ZebnXehU91vLhoVttTkCekGgijZKqS9CCIDJz4HW+leVQqUUQLhWJ1+8SzY4Va3y7bYIIIcWR2tdl2uI7KuvdT7yeVS8gYRhCOMQjUXEmPkmjuPrKuXD4TCRUn7zMcxXNtfvBUQpBaNgNJ4njSDwfce0Wik2zkCiKLpi5tzzc2YexnH80ORBpdTvHLSvpz3kZ1rrQycgpZyYW15u7H+UUuxh0NaiyFEnIEWK2EgkLlrfK5BFchtjLpuatyJApdTPQkfrgn0bmbnWet8pItvc/m6TfRswURRdMzPa9S7PvdY6dIqIUgoPvwshxExKeX57e7sx0WF5l+1J7hljzAnGio1AKtqRjU1iKU/eR4tSbkcwgmqtT1y50mVUnJrG3FA71b0WWvdzrfWTKxCb9CjXbbcqi9zI7dhIrVwQnk3TdFrXrjcBs60/KLbTdFjQMbXRqB+sfDztI2unTjSbu4IBCLdR18dAH1kbGfRr29Ls3hhz7b188DHSR9YWAK91EBHdFCfVsj7nHPEx1FXWzjZ4Ph1Zyi3GAzyv8CGiFyHEpAmAd7K7Gtckh0gIIe6wyGDmlyzL8GCd1W1hbF4dMzP6vCNsJOt6vV4jsmFiLO/HipuapX+Y+SGO48s3pVYURa8t7LYwDx2WE763iFiaoK3f+RSf6L3nSEWrswugtX6vt4gopfAwxD6sjbNGrz6BtLqIYObL4vKjFyAddcAr9OoFSFeLuuLOuRcgLZXdtdwqbnQ6B9Jm2a2oErstsX3KTstld011Tq/OI9Jy2a2lVx9AWi27dfTqFEhHZbeSXp0C6arslpHgHUmnQHra/QLXpFMgmACllHgLjIEqnwJ9il6TLIayF2aeZlnWLZCyFfbV93GWZfkr7k/2RVDx/1Dyn2HVs/jAWCL6Y43GSmptZdtpRNpyvcs9HwbIXwb2Gg9ECfJDAAAAAElFTkSuQmCC",
    "description": "",
    "functions": [
      {
        "id": "function_0",
        "name": "getKintoneApp",
        "connector": {
          "inputs": [{ "label": "button" }],
          "outputs": [{ "label": "confusion" }, { "label": "vacant" }]
        },
        "properties": [
          {
            "name": "ドメイン",
            "referenceName": "domain",
            "type": "string",
            "defaultValue": "example.cybozu.com"
          },
          {
            "name": "アプリケーションID",
            "referenceName": "appId",
            "type": "number",
            "defaultValue": "1"
          },
          {
            "name": "APIトークン",
            "referenceName": "apiToken",
            "type": "string",
            "defaultValue": "TOKEN"
          },
          {
            "name": "間隔(分)",
            "referenceName": "interval",
            "type": "number",
            "defaultValue": "5"
          }
        ],
        "extension": {
          "initialize": "",
          "receive": "",
          "execute": "/*\n * MESH sample program\n * Copyright (c) 2019 Cybozu\n *\n * Licensed under the MIT License\n */\n\nconst query = 'order by 作成日時 desc limit 1';\nconst url = `https://${properties.domain}/k/v1/records.json?app=${properties.appId}&query=${encodeURIComponent(query)}`;\n\najax({\n  url: url,\n  type: 'GET',\n  dataType: 'json',\n  timeout: 5000,\n  headers: {\n    'X-Cybozu-API-Token': properties.apiToken\n  \t},\n  success: (contents) => {\n    log('get: success');\n    const records = contents.records;\n    let outputIndex = 1;\n    if(records.length > 0) {\n      const current = new Date();\n      const latest = new Date(records[0].DateTime.value);\n      const diff = current.getTime() - latest.getTime();\n      if(diff < (properties.interval * 60 *1000)) {\n        outputIndex = 0;\n      }\n    }\n    runtimeValues.outputIndex = outputIndex;\n    callbackSuccess({\n      resultType : 'continue',\n      runtimeValues : runtimeValues\n    });\n  },\n  error: (request, errorMessage) => {\n    log('get: error');\n    log(request.responseText);\n    log(errorMessage);\n    callbackSuccess({\n      resultType : 'continue',\n      runtimeValues : runtimeValues\n    });\n  }\n});\n\nreturn {\n    resultType : 'pause'\n};\n",
          "result": "return {\n  indexes: [ runtimeValues.outputIndex ],\n  resultType : 'continue'\n};"
        }
      }
    ]
  }
}

サンプルコードの解説

今回作成したMESHカスタムブロックのポイントを解説します。
MESH SDKの詳細は、 MESH SDKリファレンスマニュアル (External link) を参照してください。

入退室(登録)ブロック

人感センサの結果をkintoneに登録する

人感センサブロックは、人を感知したときに次のブロックへ信号を伝えるように設定しています。

Code
  • Executeメソッド
    人感センサブロックから伝わる結果はmessageValues.stateValueに格納されています。
    この値をkintoneに登録します。

入退室(取得)ブロック

レコードの取得結果に応じて出力先を変える

「5分以内に人がいたか?」に応じてLEDの色を変更させるため、2つのLEDブロックを配置しています。
カスタムブロックで、レコードがなければ1つめのコネクタに接続したブロックへ信号を送り、レコードがあれば2つめのコネクタに接続したブロックへ信号を送っています。

出力コネクタを分岐させるには、次のように設定します。

Connector
  • 2つのLEDブロックに出力するので、Output Connectorを2つ用意します。

Code
  • Initializeメソッド
    Function内で共有できる変数runtimeValuesを定義します。

  • Executeメソッド
    runtimeValuesのプロパティに、出力先コネクタの番号を指定します。
    1つめのコネクタのコネクタ番号は0、2つめのコネクタのコネクタ番号は1です。
    デフォルトでは、2つめのコネクタに出力するようにしています。
    所定の時間以内のレコードがなければ、1つめのコネクタに出力します。

    処理が終わったらcallbackSucces()メソッドでResultメソッドに渡します。

  • Resultメソッド
    Executeメソッドから渡されたruntimeValuesの値をindexesプロパティに設定することで、Output Connectorに出力します。

おわりに

今回の記事では、「5分以内に」人がいるか?をチェックしました。
チェックタイミングを「○時までに」とすると、指定時刻までに入室(または退室)が必要な業務において、入退室を管理できます。

また、cybozu developer networkでは、他にもkintoneとMESHを連携した記事を紹介しています。
ぜひこれらの記事も参照してみてください。

information

このTipsは、2019年6月版kintoneで動作を確認しています。