Alexaに買いたいものを伝えて共有の買い物リストに追加：文字化け対応編

# 前段
スキルアワードのお知らせが改めてメールで来てた。
http://alexaskillawards.jp/

審査や公開前のスキルでも構わないみたいなので
せっかくなのでスキル経由でwunderlistに追加できるようなスキルを作ってみることにした。
※完成しても自分用のベータのみにする予定。

Alexaとwunderlistとの連携の経緯については以下の過去を参照。
・[Alexaに買いたいものを伝えて共有の買い物リストに追加](https://qiita.com/ryo_naka/items/b6dc93c6f7c7fe94e8d0)
・[AlexaからIFTTT経由でショッピングリストの情報を取得すると文字化けするのをなんとかしたかった](https://qiita.com/ryo_naka/items/ae3b00a4c9be861c86d0)

# 今回のAlexaスキルの目的
以前[Alexaの買い物リストへ登録した際にIFTTT経由でwunderlistにも登録させるような仕組みを構築](ps://qiita.com/ryo_naka/items/b6dc93c6f7c7fe94e8d0)した。
が、ある日突然[文字化けしちゃう](https://qiita.com/ryo_naka/items/ae3b00a4c9be861c86d0)ようになった。
そこでAlexaの買い物リスト経由ではなく、カスタムスキル経由でダイレクトに登録させるようにしてみる。
イメージとしてはこんな感じ
Alexa→Lambda→IFTTT→wunderlist

# Alexa Skill作成
久々にAlexa Skillのコンソールをみたら、
最初に作ったときにはなかったような機能がいくつかできていて割と簡単にできるようになっている印象。
当時はこのコンソールはβ版としてあったような気はするが、その時よりも格段に使いやすくなってる。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/106639/625d69e4-2d7a-565f-b579-1df43db9c115.png)
・スキル名などを設定し「カスタム」を選択して次へ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106639/a8a472d7-da0c-7179-e491-2ae2664f4ee0.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106639/1621537b-3833-5377-e639-276b0d95c6c1.png)
・スキルのトリガー名を指定する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106639/f7a95e39-8353-39ff-81a3-f46dae3ce45c.png)
・インテントスロットなんてあった？

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106639/e9b9e182-117c-6a20-a7b7-1f230986500b.png)
・ここでLambda側のエンドポイントを指定する

AlexaSkillの基本的な仕組みさえわかっていれば、なんとなくでもスキルのガワは簡単に作れるレベルになっている気がする。
で、なんとなく作ってみた。

## 手間取った部分
### スキルID  
  よくわからなかったがLambda側にここのスキルIDを設定しておかないとダメだった。

### Lambda側でスロットのデータを取得する方法がわからない
しばし悩んだが、難しくはなかった。
こんな感じ。
`[intent.slots.add_item.value]`
.valueまで必要だった。
これはどちらというとNode.jsのお作法がわかってなかったからなのかもしれない。

### ベータテストまでできるようになったが、セッションが終了しない
これはLambda側のスキルの問題だった模様。
おそらくベースにしたサンプルがわるかったと思うのだが、どうやら**ask**で終わるとセッションを維持する模様。
シンプルなサンプルをベースに実装しなおしたら解消。


この時点でAlexaからカスタムスキルを使って、Lambdaに追加したいアイテム名を投げる処理が完成。
あとはこのアイテムをwunderlistに投げつけてあげればOKだ。

# ToWunderlist
[APIを使って直接登録することもできる](https://qiita.com/ryo_naka/items/595850c363de6c00ca6d)のだが、トークン取得処理などを書くのがめんどくさいので既存の処理のIFTTT経由にのっけてみる。
当初のイメージを少し変えてこんな感じにする。
Alexa→Lambda→IFTTT→Gmail→wunderlist
IFTTT→Gmail→wunderlistの部分はもうあるので、Lambda→IFTTTを作るのを目標にする。

## IFTTTのオフィシャルには載っていないのだが、webhookを使えばThat側で受けることもできそう。
https://ifttt.com/maker_webhooks
ここをみてみるとよくわからないのだが、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/106639/3cf19a92-cf9b-dcd3-875f-ed0c4f4bd58e.png)
[Documentation]をクリックしてみると
![image.png](https://qiita-image-store.s3.amazonaws.com/0/106639/8fea580c-8b50-8060-0cde-154501fc5382.png)
こんなページになる。ここに記載されているURLをトリガーにすることができる。
※データは3つまでしか送れないみたいだが。

ThatとなるAPIが作れたら、API経由でwunderlistで登録できることを確認しておく。

## Lambda→IFTTT
Webhook経由でメール登録はOKなことが確認できたら、IFTTTへのPOST処理をLambdaに埋め込む。

    var request = require('request');
    var options = {
    uri: "https://maker.ifttt.com/trigger/towunderlist/with/key/XXXXXXXXX",
    headers: {
        "Content-type": "application/json",
    },
    json: {
        "value1": "param1"
    }
    };
    request.post(options, function(error, response, body){});

単純に考えて、上記あたりの処理になるかと思ったのだが、標準ではrequestが入っていないのでエラーになる。
モジュールを追加したZIPを作ってアップロードしないといけないのだが、それもめんどくさい。

なのでhttpsモジュールでやることにする。
以下を参考にさせてもらった。
https://qiita.com/n0bisuke/items/33a6a6da1d6f455105f9

    const https = require("https")
    const HOST = `maker.ifttt.com`;
    const PATH = `/trigger/towunderlist/with/key/XXXXXXXXX`;

    let postData = {
        "value1": "param1"
    };

    let postDataStr = JSON.stringify(postData);
    let options = {
        host: HOST,
        path: PATH,
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        }
    };

    let req = https.request(options, (res) => {
    res.setEncoding('utf8');
    res.on('data', (chunk) => {
        console.log('BODY: ' + chunk);
    });
    });
    req.on('error', (e) => {
    console.log('problem with request: ' + e.message);
    });
    req.write(postDataStr);
    req.end();

こんな感じ。

# 完成
これで音声でwunderlistに追加することができるようになりました。
スキルに対するトリガーも必要になるので、
以前のように
「アレクサ、牛乳を買い物リストに追加して」
というような形式ではなく
「アレクサ、ワンダーリストを開いて、牛乳を追加して」
というように長くなってしまったのがちょっと難点。
これを一息で伝えるというのが意外にめんどくさい。
上手いトリガー名が思い浮かべばもう少し楽になるのかもしれない。

もう一つの目的にスキルアワードへの申請は別記事で。
どうやら動作しているところの動画も撮影＋Webで参照できるようにしないといけないっぽいのがちょっとめんどくさい。