Cisco Webex Device で室内の密を検知してWebex に通知してみた

この記事はシスコの有志による Cisco Systems Japan Advent Calendar 2020 (2枚目）の23日目として投稿しています。

2017年版: https://qiita.com/advent-calendar/2017/cisco
2018年版: https://qiita.com/advent-calendar/2018/cisco
2019年版: https://qiita.com/advent-calendar/2019/cisco
2020年版: https://qiita.com/advent-calendar/2020/cisco
2020年版(2枚目): https://qiita.com/advent-calendar/2020/cisco2

今年初参加ですが、Advent Calender にWebex関連の記事も多くて嬉しいです。

##はじめに
以前、Cisco Japan のブログにて　[”Webex Device を活用してソーシャルディスタンスを保つ”](https://gblogs.cisco.com/jp/2020/09/keep-social-distance-by-webex-device/)というタイトルで記事を投稿しました。人数超過を検知した際に、通知がビデオ端末上に出力され、端末の利用者に密であると伝えるという内容です。

>シスコのビデオ端末、Webex Devices は個人利用から大規模会議室まで、オフィスの様々な場所にフィットするラインナップを取り揃えています。一貫性のあるタッチパネル方式での操作に加えて、AIの利用、またはシスコのアプリケーションを利用する事でタッチレスでリモートと接続する事ができます。簡単に接続ができることはもちろん、安全に考慮した利用が可能です。

>最新の Webex Device はカメラでとらえている人の顔を認識することで、会議室に何人いるかを認識する事ができます。また、端末上で各種機能を簡易なプログラムと組み合わせて利用することができる、マクロフレームワークをサポートしています。この２つの機能を組み合わせる事で、設定された人数の超過を検知した際に、端末および操作パネル上にアラートを出す事が可能です。

こちらを掲載した後に、管理者向けに通知する仕組みはないの？という声をいただきました。そこで今回、Cisco Advent Calender への参加を契機に、実際にWebex Devicie上へのマクロを改修し、人数の超過を検知した際にWebex （Aka Webex Teams) のMessagingに関するAPI機能と Node-REDを使って管理者に対してBotから通知する仕組みを作ってみました。

##管理者への通知方法概要

Webex Device はCLIもしくはMacro を組むことによってHTTPのPostメッセージを送ることが可能です。そこで、全体としては下記のフローで作ってみました。
1.Webex Device が室内の人数が超過を検知する。
2.Webex Device がHTTP Post をNode-REDに送る。
3.Node-REDは受け取った内容を解釈し、ポストするメッセージを作成する。
4.WebexのAPIとNode-REDから準備したBotを利用して、作成したメッセージをWebexにポストする。
5.管理者がWebex上で Messaging通知を受け取る。

この記事を書くにあたり利用した環境は以下の通りです。
- Cisco Webex Roomkit Mini （クラウド登録利用）
- Node−RED on IBM Cloud 環境 
- Cisco Webex アカウント(Botの作成、メッセージの受け取り）

##Webex アカウントを使ってBot の準備をする
Webex アカウントを取ることでWebex for Developer のページからBotの作成が可能です。
Bot の作成の基本については、今回同じCisco Advent Calendar にて説明をしてくれている記事があります。"[[初心者向け] built.io flow を使って Webex のボットを30分で作る](https://qiita.com/YasutakaTanabe/items/fa82d9d1b8b75b2db021)"を参考にしてください。

Bot を作成したらトークンをメモしておきます。
今回の目的である通知を送るスペースをWebex上で作成し、Botを追加します。
作成したスペースのID情報を取得するため[Webex for Developers](https://developer.webex.com/) のページから取得していきます。[Documentation](https://developer.webex.com/docs/platform-introduction) ページを開き、API Reference > [Rooms](https://developer.webex.com/docs/api/v1/rooms) > [List Rooms](https://developer.webex.com/docs/api/v1/rooms/list-rooms) を選択します。Authorization のBearerには自分のアカウントのトークンではなく、Botのトークンを入力します。Run ボタンを押します。Responseにはスペースのタイトルやタイプなどの情報が含まれます。そのなからBotを追加したスペースのID情報をメモしておきます。これも後ほどNode-REDで設定をする際に利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412449/24878d4c-b2cc-e6bc-cdd5-72d86983e7da.png)


今回は単一のスペースへの通知をするために簡略化していますが、Botを追加した各スペースに通知するなどの場合には、List Roomsで返ってくる複数のSpaceのIDを取得し、利用する仕組みを作る必要があります。


##Node-REDを使ってWebex DeviceとWebex Messaging をつなぐ

今回はIBM Cloud上に展開したNode-RED環境を利用しました。
Node-RED flow editor 上でシンプルに下記のようなフローを作成します。
<img width=80% alt="Node-RED_Flow.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412449/d00b8262-3f3f-3f2e-cbed-1cc2fa779b60.png">
フローの概要は下記の通りです。
1.HTTP Post受付
2.Webex DeviceからPost された"部屋の名前","部屋の許容人数","検知した人数" からWebex Messaging にPost するコンテンツを作成
3.Botのトークン情報からヘッダを作成し、取得したID情報から宛先Room情報を指定
4.Webex API を利用して作成した内容をPOST

フローの詳細は長いので展開して確認できるようにしています。\<WebexBotToken>,\<RoomId>は取得した値に読み替えてください。
<details><summary>フロー詳細はこちら</summary><div>
```
[
    {
        "id": "d2da6f34.546c1",
        "type": "tab",
        "label": "PeopleCountPostToWebexMessaging",
        "disabled": false,
        "info": ""
    },
    {
        "id": "c22e16cf.06d618",
        "type": "http in",
        "z": "d2da6f34.546c1",
        "name": "[post] /capover",
        "url": "/capover",
        "method": "post",
        "upload": false,
        "swaggerDoc": "",
        "x": 200,
        "y": 120,
        "wires": [
            [
                "c9bd8657.5075e8"
            ]
        ]
    },
    {
        "id": "a46e3417.f797e8",
        "type": "change",
        "z": "d2da6f34.546c1",
        "name": "[Set] headers + destination",
        "rules": [
            {
                "t": "set",
                "p": "headers",
                "pt": "msg",
                "to": "{\"Content-Type\":\"application/json\",\"Authorization\":\"Bearer <WebexBotToken>\"}",
                "tot": "json"
            },
            {
                "t": "set",
                "p": "payload.roomId",
                "pt": "msg",
                "to": "<RoomId>",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 300,
        "y": 220,
        "wires": [
            [
                "2f220e4f.be9ef2"
            ]
        ]
    },
    {
        "id": "2f220e4f.be9ef2",
        "type": "http request",
        "z": "d2da6f34.546c1",
        "name": "Post to Webex Teams",
        "method": "POST",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "https://api.ciscospark.com/v1/messages",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "x": 600,
        "y": 220,
        "wires": [
            []
        ]
    },
    {
        "id": "c9bd8657.5075e8",
        "type": "template",
        "z": "d2da6f34.546c1",
        "name": "[create] Contents",
        "field": "payload.text",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": " {{payload.roomname}}にて人数超過を検知しました。\n 最大{{payload.cap}}名の部屋に{{payload.number}}人が入室しました。",
        "output": "str",
        "x": 430,
        "y": 120,
        "wires": [
            [
                "a46e3417.f797e8"
            ]
        ]
    }
]
```　
</div></details>

##Webex Device上でマクロを動かす

Webex Device上でデバイス上で人数をカウントし、Node-REDに対してPostするマクロを作成していきます。
Webex Device 上のマクロではJavascript を利用してマクロを組むことでDevice上で利用できる設定やステータ取得、カスタマイズされたUIとの連携などなど、いろいろなユースケースで利用が可能です。
Webex Device上でのマクロの設定の基本に関しても、今回のCisco Advent Calendarに記載があります。"[Webex デバイスのマクロを使って朝から元気にお仕事](https://qiita.com/kazkaz_o3/items/92276ace86c140943d12) "を参考にしてください。
今回、ベースはGithubに公開されている[RoomCapacity.js](https://github.com/CiscoDevNet/roomdevices-macros-samples/tree/master/Room%20Capacity%20Alert)をベースに利用し、メッセージの日本語化、HTTP POSTの仕組みを追加しました。これにより、人数の超過を検知した際に、端末上にアラートを表示しつつ、Node-REDに対して"部屋の名前","部屋の許容人数","検知した人数"を含んだメッセージをPOSTします。

```Javascript
const xapi = require('xapi');

//Variables you are able to adjust as needed for the Room Capacity and Messaging
const maxPeople = 1;  //部屋の許容人数
const alertTime = 60; //アラート表示時間
const text2Display = '当会議室の使用制限人数は' + maxPeople + '人までです。'; //Alert Text
const roomname = '会議室名'; //RoomName
const targeturl= 'https://<Node-REDのURL>/capover'; //Node-REDtarget url 

//This enables the Room Analytics required for the Macro to function properly
function init() {
  xapi.config.set('RoomAnalytics PeopleCountOutOfCall', 'On')
    .catch((error) => { console.error(error); });
    console.log('RoomAnalytics PeopleCountOutOfCall Has been Enabled');
  xapi.config.set('HttpClient Mode', 'On');
    console.log('HTTPClient on')
}

function alertDisplay() {
  xapi.command(
      'UserInterface Message Alert Display',
      {Title : '室内の人数が超過しています。',
      Text : (text2Display),
      Duration : (alertTime) }
    )
}

//Webex Message HTTP Post with RoomName, Capacity, # of People
function sendWXT(count) {
  var payload = { 
    "cap": maxPeople,
    "number":count,
    "roomname": roomname,
  };
  xapi.command('HttpClient Post', 
  {
    Header: 
    ['Content-Type: application/json'],
    Url: targeturl
  },
  JSON.stringify(payload))
  .then((result) => {
    console.log('HTTP Post was success:' + result.StatusCode);
  }).catch((err) => {
    console.log('HTTP Post was failed:' + err.message);
  });
}

function checkCount(count) {
  if (count > maxPeople) {
    alertDisplay()
    sendWXT(count);
    console.log('*** There are too many people in the room. ',count)
  }
}

//Run init function to setup prerequisite configurations
init();
  

// Fetch current count and set feedback for change in peoplecount
xapi.status
    .get('RoomAnalytics PeopleCount')
    .then((count) => {
        console.log('Max occupancy for this room is: ' + maxPeople);
        console.log(`Initial people count is: ${count.Current}`);
        checkCount(count.Current);

        // Listen to events
        console.log('Adding feedback listener to: RoomAnalytics PeopleCount');
        xapi.feedback.on('/Status/RoomAnalytics/PeopleCount', (count) => {
            checkCount(count.Current);
            console.log(`Updated count to: ${count.Current}`);
        });

    })
    .catch((err) => {
        console.log(`Failed to fetch PeopleCount, err: ${err.message}`);
        console.log(`Are you interacting with a Room Series? exiting...`);
        xapi.close();
    });
```



##試験結果

実際に最大1人のキャパシティ設定を行った部屋で、2人検知させてみました。

デバイス上のアラート通知（画面と操作卓）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412449/fd0e4517-810e-0d47-61e8-4ca6d2709493.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412449/d5a047d3-975f-2949-c270-f8e9fc158bb4.png" width=50%>

Webexのスペースへの通知
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412449/7ed676dd-b868-bc8e-f070-e5d5305bcd06.png" width=50%>

##まとめ

本記事ではWebex Deviceで密の検知を元にWebexへの通知をする方法について紹介しました。
Ciscoのビデオ端末にはカスタマイズで使える項目が用意されており、今回ご紹介したマクロの機能に加えてUIの変更なども可能です。最近の端末には人の検知に加えて、温度、湿度、明るさ、ノイズなどを計測できるセンサーがあり、温度や湿度などはセンサーからの情報をAPIを用いて取得できます。
Webex自体にも豊富なAPIが存在しており、Bot以外にもSDKなども準備されています。
ご興味を持ちましたら[Cisco Devnet](https://developer.cisco.com/) や [Cisco Webex for Develper](https://developer.webex.com/) のページを覗いてみてください。
アイデア次第で色々なことができると思いますので、ぜひ作成していただけると有難いです。


##免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。