Help us understand the problem. What is going on with this article?

独身貴族のスマートホーム -スマートリモコンの課題解決-

More than 1 year has passed since last update.

はじめに

この記事は、弊社リンク情報システムが主催する「アドベントカレンダー」のリレー記事です。
アドベントカレンダーは 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をちゃんと書くの初めて。

やること

今回やること
予想フロー図2.png

 1.Alexaからnode-red経由でサーバーの<今回作るやつ>にエアコンをオンにするよう命令
 2.<今回作るやつ>MySQLからエアコンの状態(オン/オフ)を取得
 3.エアコンの状態により処理を分岐
  ⇒オンの場合:これ以降何もしない
  ⇒オフの場合:赤外線送信コマンドをスマートスピーカーに命令
 4.スマートスピーカーは赤外線でエアコンをオンにする
 5.<今回作るやつ>はエアコンの状態(オン)をMySQLに格納

これの<今回作るやつ>を作ります!

本番

ここまで前置きでした。長かったねぇ

環境構築

今の環境に足りないものをインストールしたりなんだり

MySQL Serverのインストール

家電情報を格納しておくデータベース

$ sudo apt-get install mysql-server

MySQLのGUIクライアントツールのインストール

Windows(筆者がメインで使っているPC)からMySQLにアクセスしてどーのこーのできるGUIのツール
heidisql.PNG
ついでにテーブルとレコードも作っちゃった。

image.png
今はリビングの照明とエアコンだけ入れてる状態ですね。

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ってやつに準拠してます。慣れないな~

main.py
#!/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()
remocon.py
#!/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')
mysqlutl.py
#!/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
remocon.conf
# ----- 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からの指示を解釈し、<今回作ったやつ>を実行するようにする。これも手順は省略。
デバイス登録
image.png
フロー作成
image.png

動作確認

できた~。このためだけにTwitterアカウント作った
※音出るので注意



アレクサちゃんかわええのう
でも、なんでもかんでも「はい」というのは良くないぞ。
(スマートスピーカーがエアコン付けたかどうかをスマートスピーカーは認知していない)

さいごに

今回は夢が広がった感があります。楽しかったなー
次は何をしよ~っていう構想が既にいくつか出てきてます。
・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を投げる

dein-vim

VimにPythonコードの補完機能を追加して簡単に編集できるようにする

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away