Watson AssistantでIoTやってみた

以前、[IBM Cloud FunctionsとWatson Assistantとの連携についての記事](https://qiita.com/K_M95/items/5182c9638936224e77b6)を作成してその流れでハンズオンを開催しました。その中で参加者の方から「**Watson Assistantだけで外部接続できるということはAssistantでIot連携もできるってことだよね？**」とお話をされてました。なるほど、それは面白そう！と思ったので、今回はWatson AssistantとWatson IoT Platformを使ったIot連携を試してみました。

# 今回作るもの
Watson Assistantのwebhookを使用し、Watson IoTで画像のESP32に接続したLEDをつけたり消したりするシンプルなデモです。

![title325763384.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/0087430e-e3a3-dcb4-c599-2b06a90846c9.png)

# デバイス側の設定
## Watson IoTの設定
まずはWatson Iot Platformのリソースを作成していきます。IBM Cloudのダッシュボードの中の「リソースの作成」からWatson IoT Platformを選択し、作成します。その後、IoT platformを起動し、左側のメニューから「アプリ（コンパスのアイコン）」を選択して、「APIキーの生成」からWatson IoT platformにデバイスがアクセスするためのAPIキーを生成します。説明は自分が分かりやすいものを自由に設定できます。

![コメント 2019-11-21 143510.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/a21601ab-c13c-9b6f-83a8-aef71166e3bf.png)

次の画面では、アプリケーションのアクセス権限を設定します。ここでは「標準アプリケーション」を選択します。

![コメント 2019-11-21 143543.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/8aa9645f-f006-fc77-711e-f8fbafee90a9.png)

キーの生成を押すと、APIキーと認証トークンが表示されます。この時、一度画面を閉じると認証トークンは2度と確認できなくなるので、忘れずに認証トークンをメモしておきましょう。

## ESP32をWatson IoT Platformに接続する
次にデバイスをWatson IoT Platformに接続する設定を行っていきます。使用するハードウェアはESP32、ファームウェアの書き込みにはmongoose osを使用します。パソコンにESP32を接続した後、[こちら](https://mongoose-os.com/docs/mongoose-os/quickstart/setup.md)の手順1から7を完了した後に、mongoose osのコマンドラインで以下のコマンドを実行し、Watson IoTを使えるようにプロビジョニングをします。

```shell-session
mos watson-iot-setup
```
その後以下のコマンドを実行し、Watson IoTの接続を完了させます。ここで先程生成したAPIキーと認証トークンを使います。

```shell
mos watson-iot-setup --watson-api-key your-api-key --watson-api-auth-token "yourtokenhere"
```

設定が完了すると、左側のデバッグ画面に以下のような結果が出力されます。コマンドを実行することで、今接続しているデバイスに自動的にデバイスIDが割り当てられます。

```shell
Using port /dev/ttyUSB0
Connecting to the device...
  esp8266 1AFE34A5930F running demo-c
Org ID: bcdefgh
Device ID: esp8266_A5930F
Checking device type "mos"...
Creating device "esp8266_A5930F"...

Updating config:
  device.id = esp8266_A5930F
  watson.client_id = d:bcdefgh:mos:esp8266_A5930F
  watson.enable = true
  watson.host_name = bcdefgh.messaging.internetofthings.ibmcloud.com
  watson.token = SECRET
Setting new configuration...
Saving and rebooting...
```

もう一度Watson IoT Platformの画面に戻り左のメニューからデバイス（CPUのようなアイコン）を選択して、追加したデバイスを確認すると、先程のmosコマンドで設定したデバイスIDが確認できるかと思います。これでESP32をWatson IoTに接続する設定が完了しました。

![コメント 2019-11-21 144714.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/4fe23d47-59bd-ce81-21d4-33344c15a8f7.png)

## ハードウェアのセットアップ
それでは、ハードウェアのセットアップをしていきます。まずはLEDを点灯する回路を作成していきます。配線は下図の通りです。LEDは＋側を25番のピンに接続しています。

![ESP_LED_ブレッドボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/8111ce9c-8486-8a6c-f6bf-8f029949215f.png)


次にESP32のプログラムを書き換えます。お好きなコードエディタでmongoose osのプロジェクトを保存しているフォルダの中にある```fs/init.js```を開きます。中のコードをすべて消して、以下のコードに書き換えます。

```javascript
// IoT subscriber
load('api_gpio.js');
load('api_mqtt.js');
load('api_sys.js');
 
let LEDpin = 25;
let topic = 'iot-2/cmd/cid/fmt/json';
let obj;
 
GPIO.set_mode(LEDpin, GPIO.MODE_OUTPUT);
GPIO.write(LEDpin, 0);
 
MQTT.sub(topic, function(conn, topic, msg) {
  print('Topic: ', topic, 'message:', msg);
  obj = JSON.parse(msg);
  print('ok');
  if (obj.d.on){
    GPIO.write(LEDpin, 1);
  }else{
    GPIO.write(LEDpin, 0);
  }
}, null);

```

書き換えたら、mongoose osのコマンドラインから以下のコマンドを順に実行します。

```shell-session
mos put fs/init.js
mos call Sys.reboot
```
これでデバイス側の設定は全て終わりました。

# Publisherの設定
今度はデバイスにPublishする設定を行います。今回はIBM CloudのNode-REDを使って設定します。IBM CloudでNode-REDのリソースを作成したら、まずはWatson IoT PlatformをAPIキーやトークンを使わずに実行できるようにNode-REDとの接続を作成します。Node-REDのリソース画面を開き、「接続の作成」をクリックします。「既存の互換性のあるサービスの接続」からWatson IoT Platformのリソースを選択して右端に出てくる「接続」をクリックします。

![コメント 2019-11-21 192621.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/4b916fd5-637c-3710-f04a-9404bf84f3f1.png)

すると、以下の画面が表示されるので、設定はそのままで「接続」をクリックします。その後再ステージングを要求されるので、そのまま「再ステージング」をクリックします。

![コメント 2019-11-21 194140.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/914ac95c-edba-90df-6f02-ea23490c21cf.png)

再ステージングをした後にNode-REDを起動してフローエディタを開きます。まずは、Webhookを使えるようにhttpノードをセットします。メソッドは```POST```、URLには```subdata```を設定します。

![コメント 2019-11-21 210805.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/195c69fe-17af-3b83-1a4f-9d150d4be551.png)

次にpostされたデータを変換してIBM IoTノードでプッシュします。jsonを変換するためにFunctionノードを追加します。

![コメント 2019-11-21 212428.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/bba97793-8ad5-b061-2b01-249ccb7469da.png)

Functionノードを開き、以下のコードに書き換えます。

```javascript
msg.payload = {
    "d":{
        "on":msg.payload.on
    }
}
return msg;
```

IBM IoTノードの設定は以下の通りです。デバイスIDはご自身が設定したものを記入します。

![コメント 2019-11-21 213550.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/95af2a0d-6a7b-adf0-3aa1-2cb23a976d54.png)

# Watson Assistantの設定
いよいよ最後のステップです。Watson Assistantを使ってLEDを制御する設定します。Watson Assistantのリソースを作成し、Skillsタブ（画面右上にある吹き出しマークではない方のアイコン）をクリックして、Create skillで新たにスキルを作成します。以下の画面が出てきたら、Dialog skillを選択して、Nextボタンをクリックします。

![コメント 2019-11-21 212428.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F170520%2Fd02c5312-3102-7281-1ae4-3d3cdcdfdb2e.png?ixlib=rb-1.2.2&auto=compress%2Cformat&gif-q=60&s=b3a739587a685d4ea97fc6a36ee356c3)

## インテントの設定
次にインテントを設定します。今回は、LEDをつけるか消すかの2種類のインテントを用意します。
![コメント 2019-11-21 225914.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/6e83811f-e534-72a3-9683-5312fd52cfa3.png)

今回はLEDのONとOFFが分かればいいので、インテントの中身は何でもいいですが、迷っている方は[こちら](https://gist.github.com/Miura55/9ddbed58ba0ddd7dedc36e56b4e4e4c0)
のCSVにサンプルを載せてあるのでダウンロードして、Asisstantにインポートして使ってください。インポートするには上の画像の中のアップロードアイコンをクリックしてダンロードしたCSVを読み込みます。

## webhookの設定
[こちら](https://qiita.com/K_M95/items/5182c9638936224e77b6#watson-assistant%E3%81%AE%E8%A8%AD%E5%AE%9A)を参考にwebhookの設定をしていきます。今回はIBM Cloud functionsを使っていないので、設定するURLは「（/redより前のNode-REDのURL）/subdata」の形式になります。

## フローの作成
それでは、フローを作成していきます。```Dialog```タブをクリックします。今回はLEDをつけるノードと消すノードを並べて設定します。送信するパラメータはブーリアン型なので、```VALUE```はダブルクオーテーションで囲みません。まずはLEDをつけるノードです。今回はNode-REDのレスポンスをちゃんと設定していないので、webhookのレスポンスに関係なく同じ返答を返すようにしました。

![コメント 2019-11-22 012219.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/8cd30635-94dc-08e5-eeb6-257cfc8076bf.png)
![コメント 2019-11-22 012635.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/9e64833a-3f3a-691b-6f14-b2cf8b00425c.png)

同様にLEDを消すアクションを設定します。

![コメント 2019-11-22 013251.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/e490a572-5dc6-0a4a-e6d5-d1202094738e.png)

![コメント 2019-11-22 013314.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/06c58dd2-41e1-e9f3-b3ab-e5f50a462a72.png)


# 動作確認
それでは、動作確認です。Assistantの```Try it```からメッセージを送信してLEDをつけたり消したり出来たら成功です。ちょっと見づらいですが、実際に動作させた時の動画です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Watson AssistantからLEDのON/OFFが出来た。詳しくは今年のIBM Cloudのアドベントカレンダーにてー<a href="https://twitter.com/hashtag/Watson?src=hash&amp;ref_src=twsrc%5Etfw">#Watson</a> <a href="https://twitter.com/hashtag/IBMCloud?src=hash&amp;ref_src=twsrc%5Etfw">#IBMCloud</a> <a href="https://t.co/pdyqA187Ze">pic.twitter.com/pdyqA187Ze</a></p>&mdash; K.Miura (@k_miura_io) <a href="https://twitter.com/k_miura_io/status/1197559386719154176?ref_src=twsrc%5Etfw">November 21, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>