ネスカフェ バリスタを音声コントロール

ネスカフェ バリスタを使って、"ツイッター投稿"、"スマホでコントロール" に、続いて第3弾。
今度は、音声認識を使って、バリスタのスイッチをコントロールしてみた。

ネスカフェ バリスタを音声コントロール
ハードウェアの方は、USBマイクをつける以外は、"スマホでコントロール"の時と同じで、今回は、ソフトウェアの設定が主になる。
音声認識は、Juliusというシステムを使わせていただいた。
Juliusについてもたくさんの参考サイトが説明してくれているので、非常に助かる!

以下、その詳細。
では、まず、USBマイクを接続して、認識されていることと、優先順位が最初に来ているかを確認

$ sudo lsusb
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 005: ID 0d8c:013c C-Media Electronics, Inc. CM108 Audio Controller
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

$ sudo cat /proc/asound/modules
 0 snd_usb_audio
 1 snd_bcm2835

私の場合、USBには、BUFFALOのWiFIドングルのWLI-UC-GNM2 と、USBマイクのBSHSMO5BKというのが刺さっている。
上記リストのうちC-Media というのがマイクで、ちゃんと認識されていた。
優先順位のほうは、0のほうが優先順位が高いそうなのだが、そのままだと、SND_BCM2835のほうが優先になっていた。
で、順位を変更するのだけれど、ラズパイのOSのバージョンによって少し、動きが違っていた。
NOOBS v1.4.1 をインストールしたときは、"/etc/modprobe.d/alsa-base.conf" を編集すれば上記のようなったのだけど、NOOBS v1.5.0 をインストールしたときは、そもそも、この"alsa-base.conf"というファイル自体が見つからなかった。
で、いろいろググって見ると、こちらのサイトで助けられた。
簡単にできる!音声認識と音声合成を使ってRaspberrypiと会話 - Qiita

v1.4.1のときは、だいたい、以下のサイトに習って設定すればうまくいった。
Raspberry Piで音声認識 - Qiita

上記のサイトを参考にさせてもらって、Juliusのインストールとテストまでは、問題なく進んだ。
インストールできたら、自分に必要なワードの辞書を作成して辞書ファイルに変換。
以下のサイトも大変参考になる。
ラズパイで音声認識をしてみる | うしこlog
私の場合は、以下のように辞書ファイル作成

~$ nano word.yomi

ブラックにして  ぶらっくにして
ラテにして      らてにして
カプチーノにして        かぷちーのにして
エスプレッソにして      えすぷれっそにして
マグにして      まぐにして
コーヒーいれて  こーひーいれて
バリスタくん    ばりすたくん
おしまい        おしまい

$ cd ~/julius-4.3.1/gramtools/yomi2voca
$ iconv -f utf8 -t eucjp ~/word.yomi | ./yomi2voca.pl > ~/julius-kits/dictation-kit-v4.3.1-linux/word.dic

辞書ファイルができたら、上記サイトを参考に設定ファイルを作成

$ nano ~/julius-kits/dictation-kit-v4.3.1-linux/word.jconf

うまく認識されていることを確認。

認識できることが確認されたら、認識した文字でバリスタのスイッチをコントロールするプログラムをPythonで作成。
その前に、先ほどの”Word.jconf”のファイルの最後に "-module" という行を追加して、Julius をモジュールモードで実行するように設定
Pythonのプログラムは、以下のサイトを参考にさせていただいた。
Raspberry Pi

こちらのサイトの2015/08/30の記事のPythonプログラムをベースに下記のように、自分用にアレンジした。

~$ nano barista01.py

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

'''
  ファイル名 : barista01.py
  起動方法
  (1) Julius をモジュールモードで起動
      julius -C julius-kits/dictation-kit-v4.3.1-linux/word.jconf 

  Julius(フリーの高性能音声認識ソフトウェア)

  ・TCP/IP で認識結果を受信し認識結果を表す<RECOGOUT>...</RECOGOUT> 部分を抽出する

  参考 URL
    http://moosoft.jp/index.php?option=com_content&view=article&id=99&Itemid=134
    http://julius.osdn.jp/
    http://kuhjaeger.co.jp/laboratory/raspberrypi/julius/
'''

import threading
import RPi.GPIO as GPIO
import socket
import time
import sys

# モジュールトップレベル変数設定 Start
SOCK      = None      # TCP/IP ソケット
ENCODING  = 'utf-8'  # codec

# GPIO ピン番号設定
# GPIO.setmode(GPIO.BOARD) P1 ヘッダ上のピン番号を用いる
RELAY_1   = 24        # コーヒー   GPIO8 = 24 ピン
RELAY_2   = 11        # ブラック   GPIO17 = 11 ピン
RELAY_3   = 12        # マグ     GPIO18 = 12 ピン
RELAY_4   = 13        # エスプレッソ  GPIO27 = 13 ピン
RELAY_5   = 15        # カプチーノ    GPIO22 = 15 ピン
RELAY_6   = 16        # ラテ   2   GPIO23 = 16 ピン
P0 = 18               # Aques bit0
P1 = 22               # Aques bit1
P2 = 19               # Aques bit2

HOST_NAME = 'localhost'
PORT_NUM  = 10500
BUF_SIZE  = 4096
DELIM_STR = '.\n'
START_STR = '<RECOGOUT>'
END_STR   = '</RECOGOUT>'
FIND_STR0 = ['コーヒー'  , 'いれて']
FIND_STR1 = ['ブラック', 'にして']
FIND_STR2 = ['マグ', 'にして']
FIND_STR3 = ['エスプレッソ', 'にして']
FIND_STR4 = ['カプチーノ', 'にして']
FIND_STR5 = ['ラテ', 'にして']
FIND_STR6 = ['バリスタ','くん']
FIND_STR7 = ['おし', 'まい']

# モジュールトップレベル変数設定 End

# GPIO 初期化
def gpio_init():
    try:
        GPIO.setwarnings(False)                 # Warning 表示停止
        #GPIO.setmode(GPIO.BCM)                 # GPIO ピン番号を用いる
        GPIO.setmode(GPIO.BOARD)                # P1 ヘッダ上のピン番号を用いる
        GPIO.setup(RELAY_1,GPIO.OUT)
        GPIO.setup(RELAY_2,GPIO.OUT)
        GPIO.setup(RELAY_3,GPIO.OUT)
        GPIO.setup(RELAY_4,GPIO.OUT)
        GPIO.setup(RELAY_5,GPIO.OUT)
        GPIO.setup(RELAY_6,GPIO.OUT)
        GPIO.setup(P0,GPIO.OUT)
        GPIO.setup(P1,GPIO.OUT)
        GPIO.setup(P2,GPIO.OUT)
        GPIO.setup(RELAY_1,                     # SW 1
                   GPIO.OUT,
                   pull_up_down=GPIO.PUD_DOWN)
        GPIO.setup(RELAY_2,                     # SW 2
                   GPIO.OUT,
                   pull_up_down=GPIO.PUD_DOWN)
        GPIO.setup(RELAY_3,                     # SW 3
                   GPIO.OUT,
                   pull_up_down=GPIO.PUD_DOWN)
        GPIO.setup(RELAY_4,                     # SW 4
                   GPIO.OUT,
                   pull_up_down=GPIO.PUD_DOWN)
        GPIO.setup(RELAY_5,                     # SW 5
                   GPIO.OUT,
                   pull_up_down=GPIO.PUD_DOWN)
        GPIO.setup(RELAY_6,                     # SW 6
                   GPIO.OUT,
                   pull_up_down=GPIO.PUD_DOWN)
        GPIO.setup(P0,                     # Bit0
                   GPIO.OUT,
                   pull_up_down=GPIO.PUD_UP)
        GPIO.setup(P1,                     # Bit1
                   GPIO.OUT,
                   pull_up_down=GPIO.PUD_UP)
        GPIO.setup(P2,                     # Bit2
                   GPIO.OUT,
                   pull_up_down=GPIO.PUD_UP)
    except Exception as e:
        print('gpio_init:{0}'.format(e))

# 受信解析 SW ON 制御クラス
class tcp_recv(threading.Thread):

    # コンストラクタ
    def __init__(self):
        threading.Thread.__init__(self)
        self.daemon = True               # デーモンスレッド

    # 受信解析 SW ON 制御
    def run(self):
        global SOCK

        try:
            SOCK = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            SOCK.connect((HOST_NAME, PORT_NUM))
            rv_str = ''
            while SOCK is not None:
                rv = SOCK.recv(BUF_SIZE).decode(ENCODING)
                rv_str += rv
                if DELIM_STR in rv:                               # '.\n' : メッセージの区切り
                    s0 = rv_str.find(START_STR)                   # '<RECOGOUT>'
                    s1 = rv_str.find(END_STR)                     # '</RECOGOUT>'
                    if (s0 > -1) and (s1 > -1):
                        rec = rv_str[s0 : s1 + len(END_STR) + 1]  # 文字列抽出
                        print(rec)

                        if FIND_STR0[0] in rec:                   # Start SW
                            if FIND_STR0[1] in rec:
                                isON = "1.000" in rec
                            GPIO.output(P0, False)            # コーヒー入れて
                            GPIO.output(P1, False)            # Aques
                            GPIO.output(P2, False)
                            time.sleep(1)
                            GPIO.output(P0, True)
                            GPIO.output(P1, True)
                            GPIO.output(P2, True)
                            time.sleep(2)
                            GPIO.output(RELAY_1, isON)        #スイッチON
                            time.sleep(1)
                            GPIO.output(RELAY_1,False)

                        if FIND_STR1[0] in rec:               #ブラック
                            isON = FIND_STR1[1] in rec
                            GPIO.output(P1, False)            # Aques
                            GPIO.output(P2, False)
                            time.sleep(1)
                            GPIO.output(P1, True)
                            GPIO.output(P2, True)
                            GPIO.output(RELAY_2, isON)        # ブラックSet
                            time.sleep(1)
                            GPIO.output(RELAY_2,False)

                        if FIND_STR2[0] in rec:               # マグ
                            isON = FIND_STR2[1] in rec
                            GPIO.output(RELAY_3, isON)        # マグSet
                            GPIO.output(P0, False)            # Aques
                            GPIO.output(P2, False)
                            time.sleep(1)
                            GPIO.output(P0, True)            
                            GPIO.output(P2, True)            
                            GPIO.output(RELAY_3,False)

                        if FIND_STR3[0] in rec:               # エスプレッソ
                            isON = FIND_STR3[1] in rec
                            GPIO.output(P2, False)            # Aques
                            GPIO.output(RELAY_4, isON)        # エスプレッソSet
                            time.sleep(3)
                            GPIO.output(P2, True)
                            GPIO.output(RELAY_4,False)

                        if FIND_STR4[0] in rec:               # カプチーノ
                            isON = FIND_STR4[1] in rec
                            GPIO.output(RELAY_5, isON)        # カプチーノSet
                            GPIO.output(P0, False)            # Aques
                            GPIO.output(P1, False)            # Aques
                            time.sleep(1)
                            GPIO.output(RELAY_5,False)
                            GPIO.output(P0, True)            # Aques
                            GPIO.output(P1, True)            # Aques

                        if FIND_STR5[0] in rec:               # ラテ
                            isON = FIND_STR5[1] in rec
                            GPIO.output(RELAY_6, isON)        # ラテSet
                            GPIO.output(P1, False)            # Aquos
                            time.sleep(1)
                            GPIO.output(RELAY_6,False)
                            GPIO.output(P1, True)            # Aques

                        if FIND_STR6[0] in rec:               # バリスタくん
                            isON = FIND_STR6[1] in rec
                            GPIO.output(P0, False)            # Aques
                            time.sleep(1)
                            GPIO.output(P0,True)

                        if FIND_STR7[0] in rec:               # おしまい
                           # isON = FIND_STR7[1] in rec
                           if FIND_STR7[1] in rec:
                              if SOCK is not None:
                                   SOCK.shutdown(socket.SHUT_RDWR)
                                   SOCK.close()
                              GPIO.output(RELAY_1, GPIO.LOW)       # SW OFF
                              GPIO.output(RELAY_2, GPIO.LOW)       # SW OFF
                              GPIO.output(RELAY_3, GPIO.LOW)       # SW OFF
                              GPIO.output(RELAY_4, GPIO.LOW)       # SW OFF
                              GPIO.output(RELAY_5, GPIO.LOW)       # SW OFF
                              GPIO.output(RELAY_6, GPIO.LOW)       # SW OFF
                              GPIO.output(P0, GPIO.HIGH)       # Bit OFF
                              GPIO.output(P1, GPIO.HIGH)       # Bit OFF
                              GPIO.output(P2, GPIO.HIGH)       # Bit OFF
                              GPIO.cleanup()
                              sys.exit()                            # exit

                    rv_str = ''
        except Exception as e:
            if SOCK is not None:
                SOCK.shutdown(socket.SHUT_RDWR)
                SOCK.close()
                SOCK = None
            print('run:{0}'.format(e))

# メインループ
def main():
    try:
        gpio_init()                          # GPIO 初期化
        tcp_recv().start()                   # 受信解析クラス
        while True: time.sleep(1000)
    except KeyboardInterrupt:
        if SOCK is not None:
            SOCK.shutdown(socket.SHUT_RDWR)
            SOCK.close()
        GPIO.output(RELAY_1, GPIO.LOW)       # SW OFF
        GPIO.output(RELAY_2, GPIO.LOW)       # SW OFF
        GPIO.output(RELAY_3, GPIO.LOW)       # SW OFF
        GPIO.output(RELAY_4, GPIO.LOW)       # SW OFF
        GPIO.output(RELAY_5, GPIO.LOW)       # SW OFF
        GPIO.output(RELAY_6, GPIO.LOW)       # SW OFF
        GPIO.output(P0, GPIO.HIGH)       # Bit OFF
        GPIO.output(P1, GPIO.HIGH)       # Bit OFF
        GPIO.output(P2, GPIO.HIGH)       # Bit OFF
        GPIO.cleanup()
        raise
    except Exception as e:
        print('main:{0}'.format(e))

# ============================================== #
if __name__ == '__main__':
    main()

続いて、音声認識コントロールを開始するためのスクリプトを作成

$ nano barista.sh

#!/bin/sh
amixer sset Mic 10
julius -C /home/pi/julius-kits/dictation-kit-v4.3.1-linux/word.jconf &
sleep 3
sudo python3 barista01.py &

exit 0

これで、実行するときは、

$ sudo bash barista.sh

と、やれば、音声認識コントロールが開始される。

誤認識もあるけど、期待した以上の精度でスイッチがコントロールできる。 ただ、音声合成で発声しているのだけど、この音をマイクがひろってしまい、ループしてしまうことがあるので、センテンスをひろったら、しばらくマイクのレベルをゼロにするとか何かの対策が必要かも・・・。
もう少し、改良のポイントは、あるかもね・・・。

ネスカフェ バリスタをスマホでコントロール

ネスカフェ バリスタラズベリーパイを接続して、Wifiネットワークからスマホタブレットなどのブラウザーからスイッチをコントロールできるようにしてみた。
とは、言うものの、これまた、先人の知恵の結集なのであります。 ・・・いつまでたってもゼロから自分でできるだけの実力がつかんなぁ~・・・。

ネスカフェ バリスタをスマホでコントロール

あ、スマホでコントロールとか言いながら、動画では、iPad使ってますが、Safariつかうから、結局おんなじですよね。
スマホだったら、Google Chromeでいけます。もちろん、IEでも。
たとえば、インターネットを介してもスイッチのコントロールができるので、遠くはなれたところからもコーヒーを入れたりすることができる。車を駐車場に入れたあたりで、コーヒーを入れておくと、部屋に入ったらすぐにコーヒーが飲めたり、留守中にうちにいる人にコーヒーを入れてあげたり・・・。と、いうシチュエーションがあるかどうかわからないが、なんか、まぁ、スマホでコーヒーが入れれたら、なんか、クールな感じがしない・・・?

以下その詳細
例によって、お約束!
以下の記事を参考にされて、何かされる場合は、すべて、自己責任でお願いしますね。何かが壊れたとか、感電したとか、さまざまなトラブルに見舞われるかもしれませんが、当方は、一切、責任とれませんので、そこんとこ、よろしく・・・。
で、
本当は、バリスタのスイッチのコントロールの通信やプロトコルをハックするのがスマートなんだろうけど、ここは、力まかせに、スイッチから線を引き出してきてフォトカプラでラズベリーパイからスイッチをいれている。フォトカプラでなくても、リレーとかでも同じだと思いますが、リレーの場合は、ラズパイから直接駆動するほど電流流せないので、別途、トランジスタを使って、電源から駆動しないといけないかと思うので、フォトカプラが簡単かと思います。
回路図を描くほどでもないけど、しいて描けば、こんな感じ。
f:id:manpukukoji:20160214223150j:plain
フォトカプラにつなぐ抵抗の値は、だいたい、200Ωくらいから、1kΩくらいでいけると思う。
f:id:manpukukoji:20160217203757j:plain

バリスタのスイッチのコントロールに加えて、音声合成ICで発声させているのでこちらのハードも作成しなければならない。
これは、以前に作成したものを流用している。
blog.goo.ne.jp
このときは、リモコンで発声する言葉をコントロールしていたが、この基板からPIC12F629を引っこ抜いて、出力PINのところにラズパイのGPIOの出力を接続してコントロールしている。 データーはあらかじめプリセットのメッセージを作っておいてラズパイの出力でメッセージを選択、発声させています。
AquesTalkのメッセージのビット0,1,2の順にそれぞれ、ラズパイのGPIOの24,25,10を使っています。

ハードは、以上で、あとは、ラズパイ側のソフトの準備
Webを通して、GPIOをコントロールするのには、WebIOPiというソフトを使っています。
基本的には、ラズパイマガジンの2015年春号を参考にした(P.56 WebIOPiをカスタマイズしよう)ので、それとほぼ同じ構成になっています。
まず、WebIOPiのインストール 私がインストールしたときは、バージョンが0.7.1 でした。
WebIOPiのインストールに関しても、詳しく説明してくれているサイトがたくさんあるので、問題ないと思うけどまぁ、ざっくりと・・・。

$ wget http://sourceforge.net/projects/webiopi/files/WebIOPi-0.7.1.tor.gz/download
$ tar xvzf WebIOPi-0.7.1.tar.gz

これで、WebIOPiが展開されているはずだが、このままでは、ラズパイ2では、使えないようで、
少しファイルを編集する必要がある。
/WebIOPi-0.7.1/python/native/cpuinfo.c というファイルの40行目あたり
if(strcmp(hardware,"BCM2708")==0) という行の2708を2709に変更
それと、もう一つ
/WebIOPi-0.7.1/python/native/gpio.c というファイルの32行目あたり
#define BCM2708_PERI_BASE 0x20000000 と、いう行の0x20000000を0x3f000000に変更

変更したらインストール

~/WebIOPi-0.7.1$ sudo setup.sh

インストールしたら、次にコントロールのためのWebサイトを作成する。
webiopi_site というディレクトリを作成し、その下にさらに"htdocs" というディレクトリと"script"というディレクトリを作成。
htdocsにsample03.html と sample.css と sample03.js という3つのファイルをエディタで作成。(短いので、コピペしてね)

$ mkdir webiopi_site
$ cd webiopi_site
$ mkdir htdocs
$ mkdir script
$ cd htdocs
$ nano sample03.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.o$
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>01 | WebIOPi-Barista control</title>
  <script type="text/javascript" src="/webiopi.js"></script>
  <script type="text/javascript" src="./sample03.js"></script>
  <link rel="stylesheet" type="text/css" href="./sample.css">
</head>
<body>
  <div id="content"></div>
</body>
</html>
$nano sample.css
button {
  display: block;
  margin: 2px;
  width: 200px;
  height: 45px;
  font-size: 16pt;
  font-weight: bold;
  color: Black;
}
input[type="range"] {
  display: block;
  width: 200px;
  height: 45px;
}
.LOW {
  color: LightGray;
  background-color: Gray;
}
.HIGH {
  color: White;
  background-color: Red;
}
$ nano sample03.js
webiopi().ready(function() {
  var content, button;
  content = $("#content");
  button = webiopi().createMacroButton("btn_power","◎","PowerOn");
  content.append(button);
  button = webiopi().createMacroButton("btn_black", "Black(Cup)","CupOn");
  content.append(button);
  button = webiopi().createMacroButton("btn_Mag", "Mug Cup","MagOn");
  content.append(button);
  button = webiopi().createMacroButton("btn_esp", "Espresso","EspOn");
  content.append(button);
  button = webiopi().createMacroButton("btn_late", "Latte","LateOn");
  content.append(button);
  button = webiopi().createMacroButton("btn_cuppcino", "Cappuccino","CappOn");
  content.append(button);

  webiopi().refreshGPIO(true);
});

次に、script のディレクトリでPythonのマクロを作成

$ cd ../script
$ nano Sample02.py
import webiopi

GPIO = webiopi.GPIO
STRT = 8
CUP = 17
MAG = 18
ESP = 27
CAPP = 22
LATE = 23
P0 = 24
P1 = 25
P2 = 10

def setup():
        GPIO.setFunction(STRT,GPIO.OUT)
        GPIO.setFunction(CUP,GPIO.OUT)
        GPIO.setFunction(MAG,GPIO.OUT)
        GPIO.setFunction(ESP,GPIO.OUT)
        GPIO.setFunction(CAPP,GPIO.OUT)
        GPIO.setFunction(LATE,GPIO.OUT)
        GPIO.setFunction(P0,GPIO.OUT)
        GPIO.setFunction(P1,GPIO.OUT)
        GPIO.setFunction(P2,GPIO.OUT)

        GPIO.digitalWrite(STRT,GPIO.LOW)
        GPIO.digitalWrite(CUP,GPIO.LOW)
        GPIO.digitalWrite(MAG,GPIO.LOW)
        GPIO.digitalWrite(ESP,GPIO.LOW)
        GPIO.digitalWrite(CAPP,GPIO.LOW)
        GPIO.digitalWrite(LATE,GPIO.LOW)
        GPIO.digitalWrite(P0,GPIO.HIGH)
        GPIO.digitalWrite(P1,GPIO.HIGH)
        GPIO.digitalWrite(P2,GPIO.HIGH)

@webiopi.macro
def PowerOn():
        GPIO.digitalWrite(STRT,GPIO.HIGH)
        GPIO.digitalWrite(P0,GPIO.LOW)
        GPIO.digitalWrite(P1,GPIO.LOW)
        GPIO.digitalWrite(P2,GPIO.LOW)
        webiopi.sleep(1)
        GPIO.digitalWrite(STRT,GPIO.LOW)
        GPIO.digitalWrite(P0,GPIO.HIGH)
        GPIO.digitalWrite(P1,GPIO.HIGH)
        GPIO.digitalWrite(P2,GPIO.HIGH)

@webiopi.macro
def CupOn():
        GPIO.digitalWrite(CUP,GPIO.HIGH)
        GPIO.digitalWrite(P1,GPIO.LOW)
        GPIO.digitalWrite(P2,GPIO.LOW)
        webiopi.sleep(1)
        GPIO.digitalWrite(CUP,GPIO.LOW)
        GPIO.digitalWrite(P1,GPIO.HIGH)
        GPIO.digitalWrite(P2,GPIO.HIGH)

@webiopi.macro
def MagOn():
        GPIO.digitalWrite(MAG,GPIO.HIGH)
        GPIO.digitalWrite(P0,GPIO.LOW)
        GPIO.digitalWrite(P2,GPIO.LOW)
        webiopi.sleep(1)
        GPIO.digitalWrite(MAG,GPIO.LOW)
        GPIO.digitalWrite(P0,GPIO.HIGH)
        GPIO.digitalWrite(P2,GPIO.HIGH)

@webiopi.macro
def EspOn():
        GPIO.digitalWrite(ESP,GPIO.HIGH)
        GPIO.digitalWrite(P2,GPIO.LOW)
        webiopi.sleep(1)
        GPIO.digitalWrite(ESP,GPIO.LOW)
        GPIO.digitalWrite(P2,GPIO.HIGH)

@webiopi.macro
def CappOn():
        GPIO.digitalWrite(CAPP,GPIO.HIGH)
        GPIO.digitalWrite(P0,GPIO.LOW)
        GPIO.digitalWrite(P1,GPIO.LOW)
        webiopi.sleep(1)
        GPIO.digitalWrite(CAPP,GPIO.LOW)
        GPIO.digitalWrite(P0,GPIO.HIGH)
        GPIO.digitalWrite(P1,GPIO.HIGH)

@webiopi.macro
def LateOn():
        GPIO.digitalWrite(LATE,GPIO.HIGH)
        GPIO.digitalWrite(P1,GPIO.LOW)
        webiopi.sleep(1)
        GPIO.digitalWrite(LATE,GPIO.LOW)
        GPIO.digitalWrite(P1,GPIO.HIGH)

@webiopi.macro
def led1():
        GPIO.digitalWrite(LED,GPIO.HIGH)
        webiopi.sleep(1)
        GPIO.digitalWrite(LED,GPIO.LOW)
        webiopi.sleep(1)
        GPIO.digitalWrite(LED,GPIO.HIGH)
        webiopi.sleep(1)
        GPIO.digitalWrite(LED,GPIO.LOW)
        webiopi.sleep(1)

def destroy():
        GPIO.digitalWrite(STRT,GPIO.LOW)
        GPIO.digitalWrite(CUP,GPIO.LOW)
        GPIO.digitalWrite(MAG,GPIO.LOW)
        GPIO.digitalWrite(ESP,GPIO.LOW)
        GPIO.digitalWrite(CAPP,GPIO.LOW)
        GPIO.digitalWrite(LATE,GPIO.LOW)
        GPIO.digitalWrite(LED,GPIO.LOW)

これで、だいたい準備完了 (プログラムが長くなっちゃった。 ちょっと、書き方を考えないと・・・。)
あとは、以下のように、WebIOPiのドキュメントルートを指定して、サーバー用スクリプトファイルを指定

$ cd /etc/webiopi/
$ nano config

[SCRIPTS] のセクションのおしまいのところに、
myscript = /home/pi/webiopi_site/script/Sample02.py

[HTTP}のセクションで
#doc-root = /home/pi/webiopi/examples/scripts/macros の下に
doc-root = /home/pi/webiopi_site/htdocs

と記入し、保存
これで、準備はできたので、WebIOPiをスタートして、スマホのブラウザから同じネットワークに接続して、上記で作成した、ラズパイのWebIOPiのサイトにアクセスすれば良い。

$ cd ~
$ sudo /etc/init.d/webiopi start

スマホのブラウザからアクセス
例えば、ラズパイのIPアドレスが 192.168.1.10 だったとすると、

http://192.168.1.10:8000/sample03.html

へアクセスすれば良い。 ・・・はず、・・・。

これで、うまくいっていれば、自動起動の設定をしておけば、ラズパイのスイッチを入れれば、立ち上げと同時にWebIOPi が起動するようになる。

$ sudo update -rc.d webiopi defaults

自動起動を解除するときは、

$ sudo update -rc.d webiopi remove

とやれば、良いようだ。

それでは、Good Luck!

ネスカフェ バリスタでコーヒーをいれるとツイッターに自動投稿

ネスカフェ バリスタラズベリーパイを接続して、コーヒーを入れると、自動的にツイッターに投稿されるようにしてみた。

実際の映像は、こちらから。(片手でビデオとりながらやっているので、ちょっと、かったるいけどね・・・。)

ネスカフェ・バリスタとラズパイでツイッターに自動投稿


技術的には、何もわかっていなくても、ほとんど先人の知恵でできてしまった。

ネットの知識は、やはり、すごい・・・。

以下、作成までの記録。

自分のための備忘録的なものですが、これ見て、自分もやってみようというかたは、くれぐれも、自己責任でお願いします。 バリスタは、100V電源つながっていますし、熱湯もでるし、間違えると、バリスタ壊したり、ラズパイ壊したりして、痛い出費になってしまいますので・・・。 当方は、責任取れませんので、あしからず・・・。

準備、

まず、ネスカフェ バリスタのサイドパネルをはずす。

バリスタは、すでに何度かモデルチェンジしているので、同じようには行かないかもしれません。私が使ったのは、初代のモデルです。型番でいくとPM9630だと思うのですが、同じ9630でも、初期のものと、後のものではボタンの位置とか少し異なっているようです。基板もかわっているのかもしれません。

サイドパネルのはずし方は、こちらのサイトが写真入りで詳しく解説されているので参考になります。

ネスカフェ バリスタの調子が悪いので分解清掃してみた | KUMA TYPE

ネジはトルクスねじが使われているので、専用ドライバが必要です。まぁ、通常のプラスドライバとかマイナスドライバを駆使して回しちゃう"つわもの"もいるでしょうけど・・・。

とりあえず、コーヒーパウダーのタンク下の4本のネジをはずすだけで用は足りると思います。上記の参考サイトにも書かれていますが、サイドパネルをはずすときには、かなりの確率で爪が折れます。 私の場合も4本中3本折れちゃいました。それなりの覚悟が必要かと・・・。

この4本のネジをはずすとポコッと頭の部分が外れます。 この頭の中にスイッチの基板が埋まっているので、内側からつめを押さえて外に向かって押し込んでやると、外側にスイッチパネルが外れると思います。

f:id:manpukukoji:20160212205822j:plain

スイッチパネルが外れたら、基板の真ん中にあるスタート/停止のスイッチから線を半田付けして引き出してきます。引っ張り出すのは、電圧の高い側で、私の場合、4.9Vくらいありました。低い側は、ほぼ、0V、実際には、100mV くらいありました。写真の矢印のところ

f:id:manpukukoji:20160212210034j:plain

このラインをラズベリーパイのGPIOピンのひとつにつなぐわけですが、前述のようにバリスタは、5VでラズベリーパイのI/Oは、3.3Vなので、このままつなぐと、ラズパイが壊れてしまいますので、何か方法を考えます。

やり方は、いくつか考えられますが、入力ひとつだけなので、ちゃんとした電圧変換モジュールを使うところまでしなくとも、抵抗で分圧したり、トランジスタとかFETをひとつ、かませたり、ダイオードで電圧を落としたり、どの方法でも良いと思います。

"5V 3V 信号変換 " といったワードで検索すると、さまざまなやり方が見つかると思います。

私の場合は、手っ取り早くLEDと100kの抵抗を直列にかまして落としちゃいました。

このやり方は、正当なやり方ではないかと思いますが、電源ラインやGNDラインに落とさなくても良いので、接続先が増えなくて都合が良かったという理由です。

LEDは、Vfが2V くらいあれば良いと思います。ただし、光りません・・・。

とりあえず、これで、ラズパイが壊れることもなく、使えています。
私の場合、バリスタからの入力をGPIO23(Pin#16)に、LEDへの出力をGPIO24 (Pin#18)に接続しています。

あとは、GND側をラズパイのGNDとつなげば、ハードの方はOKです。

GNDは、本体側にそれっぽいピンが出ていたので、これを使いました。

f:id:manpukukoji:20160213080025j:plain

これで、ハード側は、おしまいですが、おまけでスイッチが入ったときにLEDが点滅するようにブレッドボード上に組んでみました。

ちなみに、バリスタのスタート/停止スイッチが入っていないときは、ラズパイのGPIOは、Highとなっていて、スイッチが入ったときにLowになりますので、そこで、スイッチが入ったことを検知します。

次に、ラズベリーパイにOSのインストール

これは、もう、山のように参考サイトがあるので、そちらで十分かと思いますが、今回、はまったのは、NOOBS v1.4.1をインストールしたときは、何もしないで日本語で表示されたのだけど、v1.5.0をインストールしたら、日本語が文字化けしてしまった。

いろいろ、調べてみたら、[$ sudo apt-get install fonts-vlgothic ] と、やったら、文字化けが解消されました。

次にPythonでツイートするための準備で、twython と、いうのを使います。

このあたりは、こちらのサイトを参考にさせてもらいました。

Raspberry PiのCPU温度をつぶやくTwitterBot | そう いう わけさ

上記参考サイトに習って、TwitterBotの環境を作成

$ mkdir TwitterBot
$ cd TwitterBot

twuthonをインストールして、Twitterのアカウントをとったら、Pythonのプログラムを作成。 これも、参考サイトのスクリプトを少し変更するだけでできてしまう。

以下のような感じで・・・。

 $ nano RaspiBot.py 
#!/usr/bin/env python
# coding: utf-8
import RPi.GPIO as GPIO
import time
import os
from twython import Twython
import datetime

COUNT = 3
LED = 24
Brst_SW = 23
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED,GPIO.OUT)
GPIO.setup(Brst_SW,GPIO.IN)
GPIO.output(LED,False)

def LCHIKA():
	global COUNT
	global LED
	for _ in xrange(COUNT):
		GPIO.output(LED,True)
		time.sleep(1.0)
		GPIO.output(LED,False)
		time.sleep(1.0)

def Tweet():
	#Twitterの認可情報を入力	
CONSUMER_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXX'
	CONSUMER_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXX'
	ACCESS_KEY = '1234567890-XXXXXXXXXXXXXXXXXXXXXXX'
	ACCESS_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
	api = Twython(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_KEY,ACCESS_SECRET)

	timestamp = 'date +%F_%H:%M:%S'
	current_time = os.popen(timestamp).readline().strip()

	api.update_status(status=current_time+' : コーヒーでくつろぎ中!!')

try:
	while True:
		if (GPIO.input(Brst_SW) == 0):
			Tweet()
			LCHIKA()
except(KeyboardInterrupt):
	print('KeyboardInterrupt!')

GPIO.cleanup()

実行権限を付与

$ chmod +x RaspiBot.py

これでほぼ完成。
あとは、

$ RaspiBot.py

と、やって実行し、バリスタでコーヒーを入れて、コーヒー飲みながらツイッターの再読み込みすると、ツイートされている・・・はず・・・。


ブログ再開

以前、書いていたブログにアクセスできなくなってしまい、何年かほったらかしにしていたけど、久しぶりにお引越しをして再開することにした。

以前のブログは、セキュリティに問題が発生したとかで、ほぼ、強制的にパスワードを変更させられたのだが、変更後のパスワードを記録していなかったので、わからなくなってしまい、なんか、キーワードみたいなのもわからず、お手上げ状態。

もう、そのまま、削除されるまで放っておくしかしかたなくなってしまった。

ちなみに、サイトは、まだ、生きているので興味のある方は、こちらから・・・。

 

 

blog.goo.ne.jp