はじめに
この記事は古くなっています。Alexa-Cookieの最新版(v3.4.1)をご利用の場合は、以下を参照してください。
ちなみに、Alexa-cookieのバージョンは以下で確認できます。
$cd ~/.node-red
$npm list|grep alexa-cookie
│ ├─┬ alexa-cookie2@3.4.1
問題発生
「Alexaをしゃべらせる(Node-red編)」や「Raspberry Piで最強の防犯カメラを作ってみる(動画記録・配信、動体検知・Line通知、顔検知・顔認証、Alexa搭載)[6/6]」でご紹介したように、我が家のスマートホームシステムでは、node-red-contrib-alexa-remote2を使って、ID&Password認証でAlexaにログインして、Alexaをしゃべらせていました。
しかし、Alexa用のログインIDを新しいものに変えたところ、以下のようにログインができなくなってしまった😭 Node-redの画面には「Login unsuccessfull. Please check credentials.」というエラーが出ている。正常時は「Ready」。
原因:Amazon側の仕様変更
ネット上の情報を調査したところ、Amazon側の仕様変更によりユーザ&パスワードが動かなくなったとのこと。米国の「alexa.amazon.com」では、2019年夏頃から動かなくなったよう。。。日本の「alexa.amazon.co.jp」では、私の古いアカウントは使えていたので、アカウントによって、ログインできないアカウントがあるようです。
解決策:ログインをProxy認証に変更
私の調査結果では、node-red-contrib-alexa-remote2のログイン認証を「Email & Password」認証から「Proxy」認証に変更することで、解決できるらしい(後で分かるが、これだけでは解決できなかった)。
Alexa Accountノードの設定変更
Node-redのフロー上にある、Alexa Rutineノードをどれか一つ開きます。次に「Account」欄の鉛筆アイコンをクリックして「Alexa Accountノード」の設定画面を出し、以下のように設定します。
Auth Method:Proxy
This IP:※Node-redをインストールしているホストのIPアドレス
Port:3456 ※デフォルトでOK
Service Host:alexa.amazon.co.jp
Page:amazon.co.jp
Language:ja_JP
デプロイ
Proxy認証に変更したら「デプロイ」ボタンを押して、変更内容をデプロイしましょう。
デプロイが完了すると、Alexa Rutineノードの下に「Open 192.168.0.1:3456 in your browser」と表示されます。
ブラウザでアクセス
画面の指示通り、PCのWebブラウザで「http://192.168.0.1:3456/」にアクセスします。IPアドレスはnode-redホストのものに適宜変更してくださいね。すると、以下のようにAlexaのログイン画面が表示されるので、Amazonのユーザ名とパスワードを入力してログインします。ちなみに、2段階認証にしている人は、確認コードも入力が必要です。
ログイン
ログインが成功すると、以下の画面のようにCookieが取得できた旨が表示されます。
しかし、Node-redの画面に戻ってみると「Unexpected end of JSON input」とのエラーになってしまいます。。。ここからが長かった。。。。
Alexa-Cookie2(v3.2.1)のカスタマイズ
エラー原因を調べているとnode-red-contrib-alexa-remote2のCookie取得は、Alexa-cookie2というモジュールを利用していることが分かりました。
このモジュールのソースコードを読んでいくと、www.amazon.comにログインし、alexa.amazon.comからCookieを取得しているようです。日本語版のAlexaはalexa.amazon.co.jpでサービス提供されているので、alexa.amazon.comにはアカウントが無く、エラーとなっているようです。
そこで、このモジュールをamazon.co.jpに対応するようにカスタマイズして行きます。なお、Alexa-Cookie2のバージョン3.0.3をお使いの場合はこちらの記事を参照ください。この記事では、執筆時(2020年6月27日)の最新版である、3.2.1を対象に記載していきます。
ちなみに、Alexa-cookieのバージョンは以下で確認できます。
$cd ~/.node-red
$npm list|grep alexa-cookie
│ ├─┬ alexa-cookie2@3.2.1
alexa-cookie.jsの変更
alexa-cookie.jsに変更を加えていきます。
①alexa-cookie.jsを開く
Node-red起動ユーザのホームディレクトリの「.node-red/node_modules/node-red-contrib-alexa-remote2/node_modules/alexa-cookie2」にalexa-cookie.jsがあるので、これをバックアップ(コピー)して、開きます。
$cd ~/.node-red/node_modules/node-red-contrib-alexa-remote2/node_modules/alexa-cookie2
$cp alexa-cookie.js alexa-cookie.js.org
$vi alexa-cookie.js
②alexa-cookie.jsの変更
alexa-cookie.jsの247行目辺りにある「_options = __options;」の記載を探し、この下の行に「_options.baseAmazonPage=’amazon.co.jp’;」の行を追加します。
_options = __options;
_options.baseAmazonPage='amazon.co.jp'; //<--この行を追加
proxy.jsの変更
次に、proxy.jsに変更を加えて行きます。
①proxy.jsを開く
alexa-cookie.jsがあるディレクトリ内の「lib」ディレクトリにproxy.jsがあるのでこれを開きます。
$cd lib
$cp proxy.js proxy.js.org
$vi proxy.js
②initialUrlの変更
www.amazon.comとwww.amazon.co.jpは少し仕様が違うようで、140行目あたりにある初期ページのURLを以下のように変更します。
//const initialUrl = `https://www.${_options.baseAmazonPage}/ap/signin?openid.return_to=https%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fmaplandi\
ng&openid.assoc_handle=amzn_dp_project_dee_ios&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=amzn_dp_project_dee_ios&accountS\
tatusPolicy=P1&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns.oa2=http%3A%2F%2Fwww.${_options.b\
aseAmazonPage}%2Fap%2Fext%2Foauth%2F2&openid.oa2.client_id=device%3A${deviceId}&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.oa2.res\
ponse_type=token&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.pape.max_auth_age=0&openid.oa2.scope=device_auth_access&language=${_options.amazonPagePr\
oxyLanguage}`;
const initialUrl = `https://www.amazon.co.jp/ap/signin?showRmrMe=1&openid.return_to=https%3A%2F%2Falexa.amazon.co.jp%2F&openid.identity=http%3A%2F%2\
Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=amzn_dp_project_dee_jp&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.n\
et%2Fauth%2F2.0%2Fidentifier_select&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&`;
③終了条件の変更
また、Cookie取得を判定する終了条件の変更を行います。proxy.jsの258行目に「/spa/index.html」の記述を追加して、このページが開かれたら終了するようにします。
if (
(proxyRes.socket && proxyRes.socket._host === `www.${_options.baseAmazonPage}` && proxyRes.socket.parser.outgoing && proxyRes.socket.parser.outgoing.meth\
od === 'GET' && proxyRes.socket.parser.outgoing.path.startsWith('/ap/maplanding')) ||
(proxyRes.socket && proxyRes.socket.parser.outgoing && proxyRes.socket.parser.outgoing.getHeader('location') && proxyRes.socket.parser.outgoing.getHeader\
('location').includes('/ap/maplanding?')) ||
(proxyRes.headers.location && proxyRes.headers.location.includes('/ap/maplanding?'))
|| (proxyRes.headers.location && proxyRes.headers.location.includes('/spa/index.html')) //<--この行を追加
) {
変更は以上です。変更が完了したら、Node-redを再起動します。
ちなみに、proxy.jsのdiffは以下のようになります。
diff proxy.js proxy.js.org
140,142c140
< //const initialUrl = `https://www.${_options.baseAmazonPage}/ap/signin?openid.return_to=https%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fmaplanding&openid.assoc_handle=amzn_dp_project_dee_ios&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=amzn_dp_project_dee_ios&accountStatusPolicy=P1&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns.oa2=http%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fext%2Foauth%2F2&openid.oa2.client_id=device%3A${deviceId}&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.oa2.response_type=token&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.pape.max_auth_age=0&openid.oa2.scope=device_auth_access&language=${_options.amazonPageProxyLanguage}`;
< const initialUrl = `https://www.amazon.co.jp/ap/signin?showRmrMe=1&openid.return_to=https%3A%2F%2Falexa.amazon.co.jp%2F&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=amzn_dp_project_dee_jp&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&`;
<
---
> const initialUrl = `https://www.${_options.baseAmazonPage}/ap/signin?openid.return_to=https%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fmaplanding&openid.assoc_handle=amzn_dp_project_dee_ios&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=amzn_dp_project_dee_ios&accountStatusPolicy=P1&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns.oa2=http%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fext%2Foauth%2F2&openid.oa2.client_id=device%3A${deviceId}&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.oa2.response_type=token&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.pape.max_auth_age=0&openid.oa2.scope=device_auth_access&language=${_options.amazonPageProxyLanguage}`;
257,258c255
< (proxyRes.headers.location && proxyRes.headers.location.includes('/ap/maplanding?'))
< || (proxyRes.headers.location && proxyRes.headers.location.includes('/spa/index.html'))
---
> (proxyRes.headers.location && proxyRes.headers.location.includes('/ap/maplanding?'))
Cookieの取得
Cookieを取得しなおす前に、ブラウザのCookieを初期化しておきます。Safaiの場合は「Safari」メニュー→「履歴を消去」でOKです。
それではNode-redの画面に戻りCookieを取得しましょう。
①「デプロイ」ボタンのクリック
「デプロイ」ボタンを再度クリックします。
②Alexaにログイン
Webブラウザで「http://192.168.0.1:3456/」にアクセスしてAlexaにログインします。二段階認証が求められる場合には、二段階認証をしましょう。
また「Amazon Alexa Cookie successfully」の画面にならず、Alexaのサイトが表示されてしまった場合には、再度「http://192.168.0.1:3456/」にアクセスしてログインしてみてください。この場合「Amazon Alexa Cookie successfully」の画面は表示されず、白いエラーページとなりますが、Cookieは正常に取得され、ノードが「Ready」になっていると思われます。
③ノードの確認
Node-redの画面に戻って確認しましょう。今度は、ノードの下に「Ready」と表示されてノードが使えるようになりました。試しにちゃんと動作するか確認してみてください。
おわりに
今回はログインエラーが出るようになってしまったnode-red-contrib-alexa-remote2の対処方としてalexa-cookie v3.2.1のソースコードを変更するご紹介しました。
前回の記事作成時に、alexa-cookieの開発者にalexa.amazon.co.jpへの対応を依頼し、baseAmazonPageのパラメータを新しく作ってくれたのですが、初期ページの違いや終了条件の違いを取り込んで貰えなかったので再度依頼してみます。
コメント
早々のご対応ありがとうござます。
ローカルエリア環境でwindows→ラズパイのnode-redに接続するとリダイレクトせず最終的にステータスがno JSONとなり繋がりませんでした。
外部ネットワークからポートフォワーディング(1880と3456ポートをlocalhostで、node-redの設定もIPからlocalhostで)で同じように繋ぐとステータスはredeyになり喋らすことは可能ですが、クッキーの保存は出来ませんでした。
また外部で設定完了していればローカルからも喋らすことは可能でした。
繋がらない人のヒントになればと思います。
ありがとうございます。ローカル環境では試してませんでしたが、Alexaをしゃべらすためには、alexa.amazon.co.jpへの通信が必要ですね。
初めまして、Alexa-remote2でAlexaにログインできず、こちらのページにたどり着きました。
為になる情報ありがとうございます。
cookieのバージョンが3.4.1だったのですが、この場合のproxy.jsのソースコードの変更の仕方をご存知でしたら
教えて頂けないでしょうか?
状況は↑のページと同じ、Alexa-remote2でAlexaにログインできず、ログイン方法をproxyに変更した所、
node-redでUnexpected end of JSON inputというエラーになっています。
手順に沿ってalexa-cookie.jsを書き換え、次にproxy.jsを変更しようとinitialUrlを探しましたが、
バージョン3.4.1だと見つかりませんでした…。
代わりにproxy.jsの165行目にconst urlという行を見つけたので、ここを書き換えるのでしょうか…?
function router(req) {
const url = (req.originalUrl || req.url);
_options.logger && _options.logger(‘Router: ‘ + url + ‘ / ‘ + req.method + ‘ / ‘ + JSON.stringify(req.headers));
if (req.headers.host === `${_options.proxyOwnIp}:${_options.proxyPort}`) {
if (url.startsWith(`/www.${_options.baseAmazonPage}/`)) {
return `https://www.${_options.baseAmazonPage}`;
} else if (url.startsWith(`/alexa.${_options.baseAmazonPage}/`)) {
return `https://alexa.${_options.baseAmazonPage}`;
} else if (req.headers.referer) {
if (req.headers.referer.startsWith(`http://${_options.proxyOwnIp}:${_options.proxyPort}/www.${_options.baseAmazonPage}/`)) {
return `https://www.${_options.baseAmazonPage}`;
} else if (req.headers.referer.startsWith(`http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.${_options.baseAmazonPage}/`)) {
return `https://alexa.${_options.baseAmazonPage}`;
}
}
if (url === ‘/’) { // initial redirect
returnedInitUrl = `https://www.${_options.baseAmazonPage}/ap/signin?openid.return_to=https%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fmaplanding&openid.assoc_handle=amzn_dp_project_dee_ios${_options.baseAmazonPageHandle}&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=amzn_dp_project_dee_ios${_options.baseAmazonPageHandle}&accountStatusPolicy=P1&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns.oa2=http%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fext%2Foauth%2F2&openid.oa2.client_id=device%3A${deviceId}&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.oa2.response_type=token&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.pape.max_auth_age=0&openid.oa2.scope=device_auth_access&language=${_options.amazonPageProxyLanguage}`;
_options.logger && _options.logger(‘Alexa-Cookie: Initial Page Request: ‘ + returnedInitUrl);
return returnedInitUrl;
}
else {
return `https://www.${_options.baseAmazonPage}`;
}
}
return `https://alexa.${_options.baseAmazonPage}`;
}
お返事いただけますと幸いです。
連投失礼します。
先ほどproxyでのログイン方法について質問したものです。
ログイン方法をcookieに変えて試したところ、うまくできました!
Alexaをしゃべらせる(Node-red編)を参考にさせて貰いました。
お礼を言わせてください、ありがとうございました。
問題解決とのこと、よかったです!
[…] 参考にしたのは下記のページ。https://codelife.cafe/entry/nodo-red-alexa-rainfall-notifierAlexa連携がアメリカアマゾンに向けたサービスになっていたので、このページを参考にコードの変更。https://www.smarthome-diy.info/blog/developper/smarthome/2020/06/1699/やっとしゃべるようになった!はず。。まだ自分が家にいるときに雨が降ってきたことがないので試せていない。雨が15分以上降り続いたときに永遠に降ります、と喋り続けないかがちょっと心配。コードを見る限りだと大丈夫そうではあるけれど。 […]