はじめに
この記事は、弊社リンク情報システムが主催する「アドベントカレンダー」のリレー記事です。
アドベントカレンダーは engineer.hanzomon のグループメンバによってリレーされます。
7日目である本記事は私、阿部が書きました。よろしくどうぞ。
シリーズ方針
「独身貴族のスマートホーム -Alexaからローカルの音楽を再生する-」に引き続き、「独身貴族のスマートホーム」シリーズ第2弾です。(シリーズ化することにしたんだ)
本シリーズの方針は、スマートホームを世に広めることです。だって、間違いなく"一家に一台"の時代が来るじゃないですか。でも遅いんですよ。スマホの時もそう。スピード感って重要じゃない?流行ってくれないと技術が進歩しないし経済も良くならん。だから買おう!
背景
「スマートスピーカー(Alexa)からスマートリモコン(eRemote mini)を経由して家電の簡単な操作をする」はデフォルトの機能で出来ます。(オフィシャルサイトに載っている手順だけでめっちゃ簡単に出来ますよ)
しかし、私はもっと柔軟に家電を操作したい!
スマートリモコンというより赤外線リモコンの弱みになりますが、リモコン-家電間の信号のやり取りって一方通行なんですよね。家電からリモコンに対して応答がないんですよ。例を出します。
1.エアコンに向かってリモコンで"暖房"を押す
2.リモコンの表示が"暖房"になる
3.エアコン「ピッ」温風が出る
4.赤外線の届かなそうな場所(または角度)でリモコンで"冷房"を押す
5.リモコンの表示が"冷房"になる
6.エアコン「 … 」温風が出たまま
こんな経験ありません?
この4~6の現象は、リモコンからエアコンに対し出した命令に、エアコンがそれに気づいてなくてもリモコンは冷房にしたつもりになってるんですね。勝手なやつだ。
で、まぁそれは良いんですよ。
しかし、スマートスピーカー経由で家電を操作すると少し気持ち悪いことになるんです。例を出します。
1.テレビが付いていることを確認する
2.あべ「アレクサ、テレビ付けて」
3.アレクサ『はい』
4.テレビ「ピッ」 なんと、テレビが消える!!
テレビのリモコンって、オンとオフのボタン分かれてないじゃないですか。
オンもオフも同じボタンなんですよね。
アレクサさんもリモコンも、テレビが付いているのか知りもしないでオン/オフ信号を送ってるんですね。勝手なやつだ。
なので、このやり取りのどこかで家電の状態を持っておきたい。⇒じゃあ仕組みを作るか!そんな経緯です。
使う環境
まず今回使う環境とかツールを紹介です。
なにやつ | 名前とか | その他 |
---|---|---|
スマートスピーカー | Amazon Echo Spot | Alexaちゃん |
仲介やさん① | Node-red v0.19.4 | Node.js v8.11.4 |
サーバー | Raspberry Pi 2 Model B+ | Volumio(RaspbianベースのLinux) |
仲介やさん② | 今回作るやつ | Python2.7 |
ライブラリ | BlackBeanControl | - |
データベース | MySQL(サーバー) | HeidiSQL(クライアント) |
スマートリモコン | eRemote mini | - |
MySQLもPythonをちゃんと書くの初めて。
やること
1.Alexaからnode-red経由でサーバーの**<今回作るやつ>にエアコンをオンにするよう命令
2.<今回作るやつ>はMySQLからエアコンの状態(オン/オフ)を取得
3.エアコンの状態により処理を分岐
⇒オンの場合:これ以降何もしない
⇒オフの場合:赤外線送信コマンドをスマートスピーカーに命令
4.スマートスピーカーは赤外線でエアコンをオンにする
5.<今回作るやつ>はエアコンの状態(オン)をMySQL**に格納
これの**<今回作るやつ>**を作ります!
本番
ここまで前置きでした。長かったねぇ
環境構築
今の環境に足りないものをインストールしたりなんだり
MySQL Serverのインストール
家電情報を格納しておくデータベース
$ sudo apt-get install mysql-server
MySQLのGUIクライアントツールのインストール
Windows(筆者がメインで使っているPC)からMySQLにアクセスしてどーのこーのできるGUIのツール
ついでにテーブルとレコードも作っちゃった。
MySQL-Connector-Pythonのインストール
PythonからMySQLにアクセスしてどーのこーのできるパッケージ
$ sudo pip install mysql-connector-python
dein-vimのインストール
vim(筆者が使うエディタ)にPython補完機能を付けるためのプラグイン
インストール手順は長いので省略。
→実はvimのバージョンが古いせいでインストール失敗したが、コードに色付けはできたのでまぁ良しとする
BlackBeanControl関連のインストール
eRemoteをコマンドラインで扱うPythonのパッケージ
# 外部ライブラリ
$ sudo apt-get install python2.7-dev
$ sudo python2 -m pip install configparser
$ sudo python2 -m pip install netaddr
$ sudo python2 -m pip install pycrypto
# python-broadlink
$ git clone https://github.com/mjg59/python-broadlink.git
$ cd python-broadlink $ sudo python2 setup.py install
# BlackBeanControl
$ git clone https://github.com/davorf/BlackBeanControl.git
設定ファイルにeRemoteのIPアドレスとMACアドレスを設定する
赤外線登録すっるよー
自作プログラムから赤外線を送信するため、とりあえずエアコンのオンオフ操作を登録
$ cd BlackBeanControl
$ python2 BlackBeanControl.py -c ac-power-on
# ここでエアコンの電源ボタン押下
$ python2 BlackBeanControl.py -c ac-power-off
# ここでエアコンの電源ボタン押下
つくる
プログラムかっくよー
出来る限りPEP-8ってやつに準拠してます。慣れないな~
#!/usr/bin/env python
# coding: utf-8
import sys
import remocon
Args = sys.argv
# main Method
def main():
# Check Args
if len(Args) == 5:
# Create Instance
remoteController = remocon.RemoteController(Args[1], Args[2], Args[3], Args[4])
remoteController.rmt_ctl()
# Delete Instance
del remoteController
else:
return
# Enable Main Method
if __name__ == "__main__":
main()
#!/usr/bin/env python
# coding: utf-8
import sys
import ConfigParser
import mysqlutil
import subprocess
# Remote Controller Class
class RemoteController:
# Constructor
def __init__(self):
# Initialize
self.room = room
self.appliance = appliance
self.action = action
self.content = content
# Read Config
conf_path = "./config/remocon.conf"
self.read_config(conf_path)
# Destructor
def __del__(self):
# Create Instance
del self.mySQLUtil
# Remote Control Method
def rmt_ctl(self):
# Create Instance
self.mySQLUtil = mysqlutil.MySQLUtil(self.user, self.pswd, self.host, self.db)
# Check Velidity
aid = self.check_velidity()
# Create Command
if self.action == "power":
command = self.create_powercmd(aid)
elif self.action == "status":
command = self.create_statuscmd(aid)
elif self.action == "volume":
command = self.create_volumecmd(aid)
else:
return
# Infrared transmission Command
res = subprocess.call(command, shell=True)
# Create SQL String
sql = "UPDATE appliances_info SET {0}='{1}' WHERE id='{2}'"
sql = sql.format(self.action, str(self.content), aid)
# Write appliance Data
result = self.mySQLUtil.write_data(sql)
return
# Check Velidity Command Option
def check_velidity(self):
# Create SQL String
sql = "SELECT id FROM appliances_info WHERE room='{0}' AND name='{1}'"
sql = sql.format(self.room, self.appliance)
# Get appliance id
aid = self.mySQLUtil.read_data(sql)
if aid is None:
return aid
# Create Power Command
def create_powercmd(self, aid):
# Create SQL String
sql = "SELECT {0} FROM appliances_info WHERE id='{1}'"
sql = sql.format(self.action, aid)
# Get appliance Data
data = self.mySQLUtil.read_data(sql)
# Command
command = None
# Check Input and SQLData
if data == 0 and self.content == '1':
# Create Command
command = "python2 " + self.bean + " -c Ac-Power-on"
elif data == 1 and self.content == '0':
# Create Command
command = "python2 " + self.bean + " -c Ac-Power-off"
return command
# Create Status Command ※未実装
def create_statuscmd(self, aid):
return
# Create Volume Command ※未実装
def create_volumecmd(self, aid):
return
# Read Config Method
def read_config(self, conf_path):
method = sys._getframe().f_code.co_name
# Read Config
config = ConfigParser.SafeConfigParser()
config.read(conf_path)
# Get Config
self.user = config.get('DataBase', 'user_name')
self.pswd = config.get('DataBase', 'password')
self.host = config.get('DataBase', 'host_name')
self.db = config.get('DataBase', 'database')
self.bean = config.get('eRemote', 'black_been')
#!/usr/bin/env python
# coding: utf-8
import sys
import mysql.connector
# MySQL Utility Class
class MySQLUtil:
# Constructor
def __init__(self, username, password, hostname, database):
# Connecting MySQL
connect_conf = {
'user': username,
'password': password,
'host': hostname,
'database' : database,
}
self.conn = mysql.connector.connect(**connect_conf)
# Destructor
def __del__(self):
# Close Connection
self.conn.close()
# Read MySQL Data
def read_data(self, sql):
# MySQL:SELECT
cursor = self.conn.cursor()
cursor.execute(sql)
# Fetch SELECT result
result = cursor.fetchall()
if len(result) == 1 == len(result[0]):
ret = result[0][0]
else:
ret = None
# Close Cursor
cursor.close()
return ret
# Write MySQL Data
def write_data(self, sql):
# MySQL:UPDATE
cursor = self.conn.cursor()
try:
cursor.execute(sql)
# MySQL:Commit
self.conn.commit()
except:
# MySQL:RollBack
self.conn.rollback()
# Close Cursor
cursor.close()
return
# ----- eRemote Info -----
[eRemote]
# eRemote Command Path
black_been = /home/volumio/BlackBeanControl/BlackBeanControl.py
# ------- Log Info -------
[Log]
file_path = ./log/remocon.log
log_level = TRACE
# ----- DataBase Info -----
[DataBase]
# Host Name
host_name = localhost
# User Name
user_name = XXXXXXXX
# Password
password = XXXXXXXX
# DataBase
database = remote_control
# Charset Code
charset = 'utf8'
Node-Redのフローかっくよー
前回も使用したNode-Redで、Alexaからの指示を解釈し、**<今回作ったやつ>**を実行するようにする。これも手順は省略。
デバイス登録
フロー作成
動作確認
できた~。このためだけにTwitterアカウント作った
※音出るので注意
アレクサちゃんかわええのう でも、なんでもかんでも「はい」というのは良くないぞ。 (スマートスピーカーがエアコン付けたかどうかをスマートスピーカーは認知していない)動作確認用の動画 pic.twitter.com/HPQLfE3aYA
— r-abe (@r_abe_2014) 2018年12月4日
さいごに
今回は夢が広がった感があります。楽しかったなー
次は何をしよ~っていう構想が既にいくつか出てきてます。
・Alexaスキルを作って音声入力を柔軟にする
・GUIアプリ作って家のリアルタイムな家電状況をテレビに表示する
・サブマシン(Linux)にkodiを入れてブルーレイ&メディアプレイヤーにする
などなど
本日12/7はサイバーマンデー(Amazonのセール)です。なんと私が使ってるAmazon Echo Spotも出るらしい…!この記事を読んだあなたも、欲しくなってきたんじゃないんですか?よし、買おう!
次の記事は@k-tsukamotoによる「現在志向バイアスとキャッシュレス社会」です。ウチの新人が書いた記事ですが、とても面白い!読んでみてください~
参考
BlackBeanControl
・Raspberry PiからコマンドラインでRM mini3(スマートリモコン)を制御する
・スマートリモコン eRemote mini を Raspberry Pi から使う
MySQL-Connector
・MySQL Connector/PythonからSQLを投げる