Amazon DashでおとうさんDashボタンをつくる

th_come_father_3

Twitterの方ではちょいちょい呟いているのですが、四ヶ月ほど前に長男が生まれました。それはもう大変にかわいいのですが、生活は一変。これまでは休日になれば半田ごてを握るほどに自由奔放に生きてきたのですが、今ではテレビの音量を上げることすらままならなくなってしまいました。

当然、趣味の電子工作に割ける時間は激減してしまいました(←ここ三ヶ月ほどほぼ毎週更新できたのは、年末年始の間に記事をある程度ストックしていたからです)。少しは時間を捻出できるのですが、奥様が長男の世話をしてくれている横で自分一人趣味に耽るのもなんだか申し訳ない気がしましたので、せめて奥様の役に立つものを作ることにしました。

何を作ろうか考えていたところに、たまたまAmazon Dashの活用(ハック)例の記事が色々目に入ってきましたので、これを使って、奥様が自室にいる私を簡単に呼び出すことができるボタンを作ることにしました。長男を抱っこしていると両手が塞がってしまうので、ナースコールのように、ボタン一つでお父さん(=私)を呼び出すボタンがあれば便利かな、と考えたのです。

ということで、早速Amazon Dashを入手しまして、いざチャレンジ。

Amazon Dashボタンのハックについては、先人の方々がたくさんおられます。

 実現方法は色々あるみたいですが、自分的には

「Amazon Dashのボタン押下を検知してHTTPリクエストを発行」

という、自分のやりたいことをドンピシャで実現してくれているdasherを使いたいと思います。なお、Amazon Dashのボタン押下を監視するサーバマシンにはRaspberry Pi 3 Type Bを使います。

 

dasherでは、基本的にはHTTPリクエストの送り先としていろんなWeb APIを想定していると思いますが、ここでは簡単かつ実用的に、ローカルホストでサーバを動かして、それに対してHTTPリクエストを投げることにします。イメージとしては、こんな感じですね。

th_come_father_6

事前にRaspberry PiにはUSBオーディオデバイスとLEDを接続してるものとします。USBオーディオデバイスを認識させる方法は、こちらを参照ください。

ということで、個人的にお気に入りのPython Web Frameworkのbottleをインストールします。

$ sudo pip install bottle

ついでに、HTTPリクエストを受けたら音声が再生されるように、VoiceText Web APIを利用するためのパッケージもインストールしておきます。

$ sudo apt-get install python-pyaudio
$ sudo pip install python-voicetext

もちろん、dasherから直接VoiceText Web APIを叩きにいってもよいのかもしれませんが、VoiteText Web APIのベーシック認証とかをどう対応したら良いのかよくわかっていないので、ここでは一旦bottleをかましてから、パッケージを利用してVoiceText Web APIを利用するようにしています。

 

インストールが済んだら、適当なフォルダを作ってそこで待受用プログラムを作成します。

$ cd
$ mkdir python-server
$ cd python-server
$ vi controller.py

例えばこんな感じ。

# -*- coding: utf-8 -*-
from bottle import route,run,request,response,hook
from voicetext import VoiceText
import requests
import threading
import pigpio
import json
import time

vt = VoiceText('YOUR API KEY')
R_PIN = 18
G_PIN = 24
B_PIN = 23
pi = pigpio.pi()
pi.set_mode(R_PIN, pigpio.OUTPUT)
pi.set_mode(G_PIN, pigpio.OUTPUT)
pi.set_mode(B_PIN, pigpio.OUTPUT)

def led_off():
  pi.set_PWM_dutycycle(R_PIN, 0)
  pi.set_PWM_dutycycle(G_PIN, 0)
  pi.set_PWM_dutycycle(B_PIN, 0)

##########################################

class PapaDashThread(threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)

  def run(self):
    pi.set_PWM_dutycycle(R_PIN, 255)
    vt.speaker('haruka').emotion('happiness',3).speak('お父さん、お母さんがお呼びですよー')
    requests.get('http://maker.ifttt.com/trigger/papa_dash/with/key/xxxxxxxxxxxxxxxxxxxxxxx')
    time.sleep(60)
    led_off()

@hook('after_request')
def header_json():
  response.content_type = 'application/json'

##########################################

def control_response_json(value):
  obj = {'control':value}
  return json.dumps(obj)

@route('/call')
def control_call():
  th = PapaDashThread()
  th.start()
  return control_response_json("call")

##########################################

run(host='192.168.xxx.xxx', port=10080, debug=True)

上記のソースコードについて、いくつか補足です。

  • フルカラーLEDはGPIO経由で制御していて、ライブラリとしてpigpioを使っています。もちろん、フルカラーでなくて単色のLEDでもOKです。
  • HTTPリクエストを受け取った後は、別にスレッド(PapaDashThread)を起動するようにして、すぐにHTTPレスポンスを返すようにしています。時間のかかるLED ON/OFFや音声再生の処理はスレッドの方で処理するようにしています。
  • スレッドの中で、ついでにIFTTTのMaker Channelを使って、スマホの方にも通知が来るようにしています。

試しに、これを以下のように実行します。一つめのコマンドはpigpioを有効にするためのデーモン起動コマンドなので、一度デーモンが起動した後は不要です。

$ sudo pigpiod
$ python controller.py

ブラウザで”http://192.168.xxx.xxx:10080/call”を入力すると、「お父さん、お母さんがお呼びですよー」という音声が再生されるハズです。確認できたら、Ctrl+Cで一旦サーバプログラムを終了させます。

 

これで、HTTPリクエストの受け側の準備はできました。いよいよAmazon Dash側の方の設定に入ります。

Amazon Dash本体の設定については、こちらの方の記事が詳しいので、こちらの内容に従ってセットアップしてください。最後の「3. 注文する商品を選択する」で、商品を選択せずに右上の×で終了させることだけ注意が必要です。この作業については、こちらの方の記事が詳しいです。

サーバプログラムのdasherのRaspberry Piへのインストールについては、githubのページに詳細が記載されているので、それをそっくりそのまま実行します。

$ cd
$ sudo apt-get install libpcap-dev
$ sudo apt-get install npm

$ sudo apt-get install node
$ wget http://node-arm.herokuapp.com/node_latest_armhf.deb 
$ sudo dpkg -i node_latest_armhf.deb

$ git clone https://github.com/maddox/dasher.git
$ cd dasher
$ sudo npm install

これで最初のセットアップは完了。次に、Amazon DashのMacアドレスを確認します。

$ sudo ./script/find_button
Watching for arp & udp requests on your local network, please try to press your dash now
Dash buttons should appear as manufactured by 'Amazon Technologies Inc.' 
Possible dash hardware address detected: 34:d2:70:xx:xx:xx Manufacturer: unknown Protocol: udp
Possible dash hardware address detected: 34:d2:70:xx:xx:xx Manufacturer: unknown Protocol: arp

Macアドレスが確認できたら、設定用ファイルを作成します。URLには、先ほど作成したPythonサーバのURLを指定します。

$ cp config/config.example.json config/config.json 
$ vi config/config.json

{"buttons":[
  {
    "name": "Papa Dash Button",
    "address": "34:d2:70:xx:xx:xx",
    "url": "http://192.168.xxx.xxx:10080/call",
    "method": "GET"
  }
]}

 

以上で準備完了です。早速実行してみましょう。

まずは、HTTPリクエストの受け側のPythonサーバを起動。

$ cd ~/python-server
$ sudo pigpiod
$ python controller.py &

“$ sudo pigipod”コマンドは、すでにpigpioのデーモンを起動中であれば不要です。それから、dasherを起動。

$ cd ~/dasher
$ sudo npm run start

この状態でAmazon Dashのボタンを押せば、LEDが光って先ほど設定した音声が鳴る!。。。ハズ。ちなみに自分の環境ではボタンを押してから5〜6秒後に音声が再生されました。

 

上の動画では、前に作ったコミュニケーション向けロボを使用していますので、ついでにLEDマトリクスでロボットが目覚めるような表情付けを行っています。表情付けのコードは、上のコードに対してこちらのコードを組み合わせてもらえば実現できます。

(以下、2017/8/14 追記)

この段階でAmazon Dashのボタンを押しても何が反応がない、という人は、改めて”$ sudo ./script/find_button”のコマンドを使って、Amazon DashのMACアドレスとプロトコルを確認してみてください。MACアドレスが見えているときのプロトコルが”udp”のみの場合(=”arp”プロトコルのリクエストが見えない場合)、config.jsonに以下のようにptorocolのパラメータを追加してください。

{"buttons":[
  {
    "name": "Papa Dash Button",
    "address": "34:d2:70:xx:xx:xx",
    "url": "http://192.168.xxx.xxx:10080/call",
    "method": "GET",
    "protocol": "udp"
  }
]}

これを指定しないと、デフォルトでは”arp”プロトコルをチェックするようになっているため、udpリクエストに反応することができません。こちらを見る限り、最近のAmazon Dashは”udp”プロトコルを指定しておいた方が確実そうです。

(以上、2017/8/14 追記)

 

最後に、Raspberry Piの電源を入れたときに、これらのプログラムが自動的に起動するようにしておきます。

dasherの方の設定の仕方はこちらに手順が書かれていますので、その設定の仕方に従っていきます。ファイル”/etc/init.d/dasher”を新規に作成し、こちらのページのinit scriptの全文をコピーして貼り付けます。

$ sudo vi /etc/init.d/dasher

#!/bin/sh
### BEGIN INIT INFO
# Provides:
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start daemon at boot time
# Description:       Enable service provided by daemon.
### END INIT INFO

dir=""
cmd=""
user=""

name=`basename $0`
pid_file="/var/run/$name.pid"
stdout_log="/var/log/$name.log"
stderr_log="/var/log/$name.err"

get_pid() {
    cat "$pid_file"
}

is_running() {
    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
}

case "$1" in
    start)
    if is_running; then
        echo "Already started"
    else
        echo "Starting $name"
        cd "$dir"
        if [ -z "$user" ]; then
            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
        else
            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
        fi
        echo $! > "$pid_file"
        if ! is_running; then
            echo "Unable to start, see $stdout_log and $stderr_log"
            exit 1
        fi
    fi
    ;;
    stop)
    if is_running; then
        echo -n "Stopping $name.."
        kill `get_pid`
        for i in {1..10}
        do
            if ! is_running; then
                break
            fi

            echo -n "."
            sleep 1
        done
        echo

        if is_running; then
            echo "Not stopped; may still be shutting down or shutdown may have failed"
            exit 1
        else
            echo "Stopped"
            if [ -f "$pid_file" ]; then
                rm "$pid_file"
            fi
        fi
    else
        echo "Not running"
    fi
    ;;
    restart)
    $0 stop
    if is_running; then
        echo "Unable to stop, will not attempt to start"
        exit 1
    fi
    $0 start
    ;;
    status)
    if is_running; then
        echo "Running"
    else
        echo "Stopped"
        exit 1
    fi
    ;;
    *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac

exit 0

そして、冒頭の以下の部分を記述します。

...
# Provides: Dasher
...
dir="/home/pi/dasher"
cmd="DEBUG=* node app.js"
user="root"
...

作成したら、

$ sudo chmod 755 /etc/init.d/dasher
$ sudo update-rc.d dasher defaults 

これで再起動後に自動でdasherプログラムが立ち上がるようになりますが、手動で立ち上げて動作確認したい場合は、以下を実行します。

$ sudo /etc/init.d/dasher start

 

次に、Pythonサーバの方の自動起動の設定です。こちらは、サーバプログラムの実行前に、”$ sudo pigpiod”コマンドが確実に実行されていないといけないので、dasherとは別の方法で起動設定をします。

$ sudo vi /etc/rc.local 

ファイル末尾のexitの手前で、以下を追記します。

...
fi

sudo pigpiod
sudo -u pi /usr/bin/python /home/pi/python-server/controller.py &

exit 0

ここまで出来たら一度再起動して、先ほどと同様にAmaon Dashのボタンに対して反応があればOKです。おつかれさまでした。ちなみに、今回は二種類の方法でRaspberry Pi起動時のプログラム実行を行っていますが、このあたりのことを詳しく知りたい方は、こちらの方の記事が参考になると思います。

 

というわけで、おとうさんDashボタン無事完成です。

th_come_father_3

せっかくなので、ラベルも変えてみました。こちらの方が用意してくださったラベルのテンプレートを使ってデザインをして、ラベル用用紙にインクジェットプリンタで印刷してみました。ちょっと雑ですみません。

ちなみに、デザインには以下の素材を使わせてもらいました。本業の方のお仕事でも大変お世話になっています。

一部はこちらで無料で利用できます。便利。

 

th_come_father_4

おとうさんDashボタンは、写真のような感じで、ベビーベッドの横のラックに結びつけています。そんなに頻繁に出番があるわけではないのですが、奥様的には「結構便利」だそうなので、まあとりあえずは良かったかなと思います。

 

にしても、Amazon Dashはなかなか楽しいですね。他にも色々遊べそうです。Amazonから怒られるまで遊ぼう。