あの公園にポケモンがどれ位いるかリアルタイムで教えてくれるHubot

先日ポケモンの出現を通知する投稿を拝見し（[オフィス周辺にポケモンが現れたら Slack チャンネルに通知するようにした](http://qiita.com/dongri/items/68b596e29a4d5cc6b9ee)）、「面白いことやる人がいるなあ。。」と思ったのですが、自分でも試してみたくなりました。

ただ、残念なことにライブラリ「[dgoguerra/pokego-scan] (https://github.com/dgoguerra/pokego-scan)」がクローズされてしまったようです。残念。

ライブラリをよく読んでみると代替ライブラリとして使えそうなものが紹介してありました。今回は「 [Armax/Pokemon-GO-node-api](https://github.com/Armax/Pokemon-GO-node-api)」を利用してみることにしました。

## あの公園に行った気になる

Slackに設置したHubotに「go 〇〇公園」みたいに話しかけると事前に登録した自分の
Pokémon GOアカウントに接続して、その近辺にいるモンスターを教えてくれます。

試しに話題になった愛知県の「鶴舞公園」に行ってみることにします。

![Slack 2016-07-27 22-29-24.png](https://qiita-image-store.s3.amazonaws.com/0/47128/fb5aad5e-24db-4f23-3b1b-e41eec5af3e4.png)

HubotはデフォルトでGoogle Map検索が出来るので一応キーワードが正しく反映されるか確認するのも良いかもしれません。

設定は変更出来るのですが、今回は「位置」「座標」「ユーザー名」「モンスターの最大値」「アイテムの最大値」「ポケコイン数」「スターダストの数」を表示させてみました。

モンスターは地図上の200m以内に出現したものを表示させます。ここでは5秒毎に5回検索をかけいます。

これは（恐らく）ルアーで出現したものは含まれないと思います。

ちょっと「新宿御苑」を覗いてみます

![Slack 2016-07-27 22-45-52.png](https://qiita-image-store.s3.amazonaws.com/0/47128/cade9a60-1106-7072-3fac-c990d7579d94.png)

なんかピカチュウ祭りっぽいですね。

こんな感じで楽しむことができます。

## 設置の仕方

[Armax/Pokemon-GO-node-api](https://github.com/Armax/Pokemon-GO-node-api)のドキュメントに沿ってやってみました。

通常通りHubotをSlackに設定します。その後必要なライブラリを導入します。

```ssh:terminal
npm install pokemon-go-node-api
```

~~それ以外の`pokemon-go-node-api`を利用するのに必要なライブラリは`npm install`して下さい。~~

（追記：2016/7/30 必要なさそうです）

```json:package.json
  "dependencies": {
    "events": "^1.1.1",
    "geocoder": "^0.2.2",
    "gpsoauthnode": "^0.0.5",
    "istanbul": "^0.4.4",
    "protobufjs": "^5.0.1",
    "request": "^2.74.0",
    "s2geometry-node": "^1.3.0",
    "tape": "^4.6.0"
  }
```

その他必要なjsファイルはhubot scriptと同じ階層に設置して下さい。

![package.json — pikachubot — :Users:pon_dad:pokemon:pikachubot 2016-07-27 22-56-06.png](https://qiita-image-store.s3.amazonaws.com/0/47128/ce04ea2f-4aaf-a4db-92d8-daa8886c51cf.png)

Hubot scriptはドキュメントのjsを利用しました。

```javascript:gogo.js
module.exports = function(robot) {
  robot.respond(/go (.*)/i, function(msg) {
    var PokemonGO = require('./poke.io.js');
    // using var so you can login with multiple users
    var a = new PokemonGO.Pokeio();
    var location = msg.match[1]

    //Set environment variables or replace placeholder text
    var location = {
        type: 'name',
        name: process.env.PGO_LOCATION || location
    };

    var username = process.env.PGO_USERNAME || 'アカウントのアドレス';
    var password = process.env.PGO_PASSWORD || 'アカウントのパスワード';
    var provider = process.env.PGO_PROVIDER || 'google';

    a.init(username, password, location, provider, function(err) {
        if (err) throw err;

        console.log('Current location: ' + a.playerInfo.locationName);
        console.log('lat/long/alt: : ' + a.playerInfo.latitude + ' ' + a.playerInfo.longitude + ' ' + a.playerInfo.altitude);
        msg.send('Current location: ' + a.playerInfo.locationName);
        msg.send('lat/long/alt: : ' + a.playerInfo.latitude + ' ' + a.playerInfo.longitude + ' ' + a.playerInfo.altitude);

        a.GetProfile(function(err, profile) {
            if (err) throw err;

            console.log('Username: ' + profile.username);
            console.log('Poke Storage: ' + profile.poke_storage);
            console.log('Item Storage: ' + profile.item_storage);

            msg.send('Username: ' + profile.username);
            msg.send('Poke Storage: ' + profile.poke_storage);
            msg.send('Item Storage: ' + profile.item_storage);

            var poke = 0;
            if (profile.currency[0].amount) {
                poke = profile.currency[0].amount;
            }

            console.log('Pokecoin: ' + poke);
            console.log('Stardust: ' + profile.currency[1].amount);
            msg.send('Pokecoin: ' + poke);
            msg.send('Stardust: ' + profile.currency[1].amount);

            var count = 0;
            var intervalID = setInterval(function(){
                a.Heartbeat(function(err,hb) {
                    if(err) {
                        console.log(err);
                    }

                    for (var i = hb.cells.length - 1; i >= 0; i--) {
                        if(hb.cells[i].NearbyPokemon[0]) {
                            //console.log(a.pokemonlist[0])
                            var pokemon = a.pokemonlist[parseInt(hb.cells[i].NearbyPokemon[0].PokedexNumber)-1];
                            console.log('There is a ' + pokemon.name + ' at ' + hb.cells[i].NearbyPokemon[0].DistanceMeters.toString() + ' meters');

                            msg.send(pokemon.name + ' at ' + hb.cells[i].NearbyPokemon[0].DistanceMeters.toString() + ' meters');

                        }
                    }

                });
                if (++count === 5) {
                     clearInterval(intervalID);
                 }
            }, 5000);

        });
    });

  });
};

```

アカウントのアドレスとパスワードはここでは直書きしてしまっていますが、環境変数に格納した方が良いと思われます。

ユーザー名とかステータスなどは必要なければ削除しても良いと思います。

## 気持ちだけ小旅行

気分だけ小旅行に。（５秒間検索をピックアップしてみました）

```text:新宿御苑
[10:45]  Pikachu at 200 meters
[10:45]  Tangela at 200 meters
[10:45]  Doduo at 200 meters
[10:45]  Pikachu at 200 meters
[10:45]  Pikachu at 200 meters
```

```text:江の島公園
[11:04]  Seadra at 200 meters
[11:04]  Krabby at 200 meters
[11:04]  Seadra at 200 meters
[11:04]  Krabby at 200 meters
[11:04]  Seadra at 200 meters
```

```text:大阪城
[11:10]  Cubone at 200 meters
[11:10]  Paras at 200 meters
[11:10]  Clefairy at 200 meters
[11:10]  Cubone at 200 meters
[11:10]  Paras at 200 meters
```

```text:CentralPark（アメリカ/セントラルパーク）
[11:12]  Rattata at 200 meters
[11:12]  Weedle at 200 meters
[11:12]  Pinsir at 200 meters
[11:12]  Rattata at 200 meters
[11:12]  Weedle at 200 meters
```

```text:TrafalgarSquare（イギリス/トラファルガー広場）
[11:16]  Paras at 200 meters
[11:16]  Spearow at 200 meters
```

```text:うちの近くの公園
[11:21]  Rattata at 200 meters
[11:21]  Magikarp at 200 meters
[11:21]  Pidgey at 200 meters
```

## まとめ

このAPIどうもアンドロイド用のAPIを利用しているようです。（最初「Android端末に接続しました」と通知がきます。）アカウントの接続不良が起きた際は`killall node`コマンドでHubotを一度リセットしてみると良いと思われます。

モンスター名を日本語に変換したかったのですが力及ばずでした...週末にちょっと挑戦してみたいと思います。

それでは皆様良いポケモンライフを。

## 追記：2016/7/30

日本語対応しました。[ポケモンの名前を英語から日本語に翻訳するスクリプト](http://qiita.com/PonDad/items/210cd6aed647e7d04450)この投稿で作った`json`ファイルを利用します。

Hubotのファイルは最上階より読み込まれるので、ここでは直下にファイルを設置しました。（`lib/pokemons-ja.json`）

Hubot scriptはこんな感じに書き換えました。

```javascript:gogo.js
module.exports = function(robot) {
  robot.respond(/go (.*)/i, function(msg) {
    var PokemonGO = require('./poke.io.js');
    var a = new PokemonGO.Pokeio();
    var fs = require("fs");
    var json = JSON.parse(fs.readFileSync('./lib/pokemons-ja.json', 'utf8'));
    var your_location = msg.match[1]

    var location = {
        type: 'name',
        name: process.env.PGO_LOCATION || your_location
    };

    var username = process.env.PGO_USERNAME || 'アカウントのアドレス';
    var password = process.env.PGO_PASSWORD || 'アカウントのパスワード';
    var provider = process.env.PGO_PROVIDER || 'google';

    a.init(username, password, location, provider, function(err) {
        if (err) throw err;

        console.log('Current location: ' + a.playerInfo.locationName);
        console.log('lat/long/alt: : ' + a.playerInfo.latitude + ' ' + a.playerInfo.longitude + ' ' + a.playerInfo.altitude);
        msg.send(a.playerInfo.locationName + 'に来たよ');

        a.GetProfile(function(err, profile) {
            if (err) throw err;

            var count = 0;
            var intervalID = setInterval(function(){
                a.Heartbeat(function(err,hb) {
                    if(err) {
                        console.log(err);
                    }

                    for (var i = hb.cells.length - 1; i >= 0; i--) {
                        if(hb.cells[i].NearbyPokemon[0]) {
                            //console.log(a.pokemonlist[0])
                            var pokemon = a.pokemonlist[parseInt(hb.cells[i].NearbyPokemon[0].PokedexNumber)-1];
                            console.log('There is a ' + pokemon.name + ' at ' + hb.cells[i].NearbyPokemon[0].DistanceMeters.toString() + ' meters');
                            for(var j = 0 ; j<json.length ; j++ ){
                              if(json[j].en === pokemon.name){
                                msg.send(json[j].ja + ' がいるよ');
                                msg.send(pokemon.img);
                              }
                            };
                        }
                    }

                });
                if (++count === 5) {
                     clearInterval(intervalID);
                 }
            }, 5000);

        });
    });

  });
};

```

よくコードを見てみると、ライブラリの`pokemons.json`の中に画像リンクコードも設置してあるので、そちらのリンクも合わせて投稿してみます。

![Slack 2016-07-30 08-57-17.png](https://qiita-image-store.s3.amazonaws.com/0/47128/0d639b80-e47e-73b1-6d14-7b141a39affd.png)

こんな感じで表示されました。

余談ですが、ライブラリが一部更新されており少し前にクローンしたものだと動作しませんでした。（最新版をクローンすれば大丈夫でした）こちらもいつまで利用出来るかは分かりませんが、使えるうちに楽しみましょう。

それでは、皆様マナーを守って良きポケモンライフを。