make the smart speaker smarter 8

09/15

take sumn control

さて、今回は趣旨を変える。

  1. When I Want(時間で)
  2. If She Felt Temp/Humidity(温湿度センサから)
  3. When She Saw(カメラから)
  4. If She Felt Someone(人感センサから)

ここではトリガーを挙げているが
ラズパイからの命令も実行してみたい。

ということでKURO-RSをセットアップしていく。

KURO-RS

徐にKURO-RSを挿してみる。
認識したかを確認してみる。

pi@raspberrypi:/srv/google-home-helper $ dmesg
・
・
・
[518932.548806] usb 1-1.5: new full-speed USB device number 4 using dwc_otg
[518932.684454] usb 1-1.5: New USB device found, idVendor=0411, idProduct=00b3
[518932.684475] usb 1-1.5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[518932.684489] usb 1-1.5: Product: BUFFALO RemoteStation PC-OP-RS1
[518932.684501] usb 1-1.5: Manufacturer: BUFFALO
[518932.684513] usb 1-1.5: SerialNumber: NNNNNNNNNN
pi@raspberrypi:/srv/google-home-helper $

ちゃんと認識しているようだ。
ただ/dev/ttyUSB0というデバイスファイルとして
アタッチされていない。

どうやらちょこっとゴニョゴニョしないといけないようだ。

pi@raspberrypi:/srv/google-home-helper $ sudo sh -c 'echo "0411 00b3" >/sys/bus/usb-serial/drivers/ftdi_sio/new_id'
pi@raspberrypi:/srv/google-home-helper $ sudo modprobe ftdi_sio
pi@raspberrypi:/srv/google-home-helper $ sudo sh -c 'echo "ftdi_sio" >>/etc/modules'
pi@raspberrypi:/srv/google-home-helper $ sudo vi /etc/rc.local
・
・
#added -->
modprobe ftdi-sio
echo "0411 00b3" > /sys/bus/usb-serial/drivers/ftdi_sio/new_id
#<-- added

exit 0
pi@raspberrypi:/srv/google-home-helper $ ls -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 0  9月 13 04:03 /dev/ttyUSB0

お、見えている。
準備OKのようだ。

KURO-RS Daemon

玄人志向から提供されているソースもあるのだが
siriusさんがこちらにデーモンとして
KURO-RSを管理するツールが公開されている。
Cで書かれていることとリモートで実行可能で
軽量かと思われるので試してみる。

pi@raspberrypi:/srv/google-home-helper $ mkdir -p src/kuro-rs && cd src
pi@raspberrypi:/srv/google-home-helper $ wget -O kuro-rs-1.00.tar.gz "http://sirius10.dip.jp/cgi-bin/download/download.cgi/kuro-rs-1.00.tar.gz?id=XXXXXXXXXX"
pi@raspberrypi:/srv/google-home-helper $ cd kuro-rs
pi@raspberrypi:/srv/google-home-helper $ tar zxvf ../kuro-rs-1.00.tar.gz -C ./
pi@raspberrypi:/srv/google-home-helper $ sed -i -e "s/\/etc\/rc\.d\/rc/\/etc\/rc/g" Makefile
pi@raspberrypi:/srv/google-home-helper $ sudo make install-all
pi@raspberrypi:/srv/google-home-helper $ sudo sed -i -e "s/eikbox01\.belldandy\.local/192.168.0.1/" /usr/local/etc/kuro-rsd.conf
pi@raspberrypi:/srv/google-home-helper $ sudo vi /etc/init.d/kuro-rsd
・
・
・
# 15行らへんに追加
#added -->
daemon () {
    kuro-rsd
}

killproc () {
    killall kuro-rsd
}
#<-- added
pi@raspberrypi:/srv/google-home-helper $ sudo /etc/init.d/kuro-rsd start

こんな感じかな。
これで再起動しても大丈夫なはず。

Evaluation

さて、テストをしてみる。

以下のコマンドを実行後
部屋の電気のリモコンをKURO-RSの受光部に向けて
電源ONボタンを押す。

pi@raspberrypi:/srv/google-home-helper $ sudo kuro-rs-rec /usr/local/share/kuro-rs/data/light-on
Hash: XXXXX
Create Rec File: /usr/local/share/kuro-rs/data/light-on
pi@raspberrypi:/srv/google-home-helper $ 

おーでけた。
同じ要領で電源OFFボタンもlight-offというファイルで保存して
今度はIR送出部(今回は1番ポート)を電灯(IR受光部)に向けて固定して
以下のコマンドを発行する。

pi@raspberrypi:/srv/google-home-helper $ kuro-rs-send 1 /usr/local/share/kuro-rs/data/light-off

localhostの12000ポートに対してTCPセッション越しに
IRポート番号とファイルを送っているようだ。
受け取ったkuro-rsdがIR送出部にファイルのダンプを
送っているのかな?見事部屋が真っ暗になる。

kuro-rsdのすごいところは操作者に直接KURO-RS(/dev/ttyUSB0)を
操作させるのではなく、デーモンとして常駐して
TCP/IPのクライアントがコントロールするから
リモートからでも操作しやすくて、管理もしやすい。
light-onも実行してひとまず部屋を明るくする。

via HTTP

さらに使いやすいようにする。
この前作ったデーモンに追加でkuro-rs-sendコマンドを実行する
コードを追加。

const express = require('express');
//const ipfilter = require( 'express-ipfilter' ).IpFilter;
const morgan = require('morgan');
const bodyParser = require('body-parser');
const fs = require('fs');
const googleSpeak = require('./GoogleSpeak');

const exec=require('child_process').exec;

const app = express();
const serverPort = 8080;
const ips = [ '127.0.0.1', '192.168.0.1', '192.168.0.2' ];

//app.use( ipfilter( ips, {mode:'allow'} ) ); //なんかうまくいかないのでひとまずやめてみる

app.use(morgan());
if (app.get('env') == 'production' ){
    var stream = fs.createWriteStream(__dirname + '/log/access.log', { flags: 'a' });
    app.use(morgan({ stream: stream }));
};
const urlencodedParser = bodyParser.urlencoded({ extended: true });

// CORSを許可
app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});
app.use(bodyParser.json());

/**
 * 音声ファイルを取得 & 電気のON/OFF
 */
app.get('/googlehome/get/:audioName', (req, res) => {
    const audioName = req.params.audioName;
    if (!audioName) {
        res.status(400).send('Invalid Parameters.');
    }

    if (audioName=="light-on.txt"||audioName=="light-off.txt") {
        var filename=audioName.substring(0, audioName.length - 4);
        exec('/usr/local/bin/kuro-rs-send /usr/local/share/kuro-rs/data/'+filename+' 1',(err, stdout, stderr) => {
            console.log(stderr);
            console.error(err);
        });
        res.status(200).send('light');
        res.end();
    }else{
        const file = fs.readFileSync(__dirname + '/soundfile/' + audioName, 'binary');
        res.setHeader('Content-Length', file.length);
        res.write(file, 'binary');
        res.end();
    }
});

/**
 *
 * しゃべらせる
 *
 */
app.post('/googlehome/set/', (req, res) => {

    const textMessage = req.body.textMessage;
    if (!textMessage) {
        res.status(400).send('Invalid Parameters.');
    }

    const gs = new googleSpeak();

    gs.bowwow(textMessage, function(result){
        console.log(textMessage);
        console.log(result);
    });

    res.status(200).send('POST request accepted.');
    res.end();

});

app.listen(serverPort, () => {
    console.log(`Start api-server. Port is ${serverPort}`);
})

これで、

pi@raspberrypi:/srv/google-home-helper $ curl http://localhost:8080/googlehome/get/light-off.txt
pi@raspberrypi:/srv/google-home-helper $ curl http://localhost:8080/googlehome/get/light-on.txt

こんな感じで電気を消したり付けたりができた。
これによってNode.jsの中でもhttp clientから簡単に操作できる。
前回みつけたsync-requestモジュールを使えば超簡単。

const request=require('sync-request');
const lightOffURL='http://localhost:8080/googlehome/get/light-off.txt';
const lightOnURL='http://localhost:8080/googlehome/get/light-on.txt';

getBody=(url)=>{
    const response=request('GET', url);
    let body=JSON.parse(response.body);
    console.log(body);
}

goodnight=()=>{
	getBody(lightOffURL);
}
goodevening=()=>{
	getBody(lightOnURL);
}

goodnight();
goodevening();

人感センサと組み合わせると、部屋に誰かがいる時に限り
夕方以降暗くなってきたら勝手に部屋を明るくしたり
部屋を出たら電気を消したりといったことができる。はず。

Next

さて次は、人感センサをセットアップしてみたいと
思う。


コメント: