Home AssistantでSwitchBotのエアコンをかっこよくコントロール!

  • Home AssistantでSwitchBotハブを通してエアコンをコントロールしたい
  • ついでにかっこよくコントロールしたい

こんなことを思っていませんか?

今回はHome AssistantでかっこよくSwitchBotと連携したエアコンを操作する方法を紹介します。

そんな私についてですが、スマートホームにはまってから、今では家中スマートホームデバイスが溢れています。遠隔操作、声で操作、GPSで操作、人が通ったら…などあらゆるシーンをスマート化しています。Home Assistantにも手を出して、色々なデバイスを連携させて、また、自分でコーディングをするくらいハマっています(笑)

そんな私がHome Assistantのノウハウをわかりやすく説明していきます。

この記事でわかること
  • Home AssistantでSwitchBotハブと連携しているエアコンの操作方法
  • Home Assistant上でかっこいいコントロールパネルで操作する方法

今回やりたいこと

今回やりたいことは、このようなコントロールパネルでSwitchBotと連携しているエアコンを操作します。

今回作成するシステムのしくみ

今回のシステムは以下のようなしくみで動作します。

  • MQTT HVACというプラットフォームでコントロールパネルを実装
  • MQTTをトリガーとしてPythonスクリプトを実行
  • PythonスクリプトでSwitchBot APIを叩いてエアコンを操作

詳しくは後ほど説明しますが、このしくみの実行と同時にエアコンの設定値をログファイル保存しておきます。

また、現在の室温はSwitchBot温湿度計の情報をMQTT経由で取得します。

事前準備

事前準備として以下が必要です。既にインストール済・準備済みであれば飛ばしてOKです。

  • File editorのインストール
  • Mosquitto brokerのインストール
  • SSH & Web Terminalのインストール
  • Pythonモジュールのインストール
  • SwitchBotハブとエアコンの連携
  • SwitchBotトークンとシークレットの確認
  • エアコンのDevice IDを確認する

File editorのインストール

Home Assistantのアドオンで、Pythonスクリプトを作成するために必要です。

Home Assistantの「設定」→「アドオン」→「アドオンストア」から「File editor」を選択しインストールします。

Mosquitto brokerのインストール

先ほどのしくみのところで書いた通り、今回はMQTTという通信プロトコルを使ってコントロールパネルとエアコンを繋ぎます。そのMQTTを使うためのアドオンです。

同じく、Home Assistantの「設定」→「アドオン」→「アドオンストア」から「Mosquitto broker」を選択してインストールします。

インストールはこちらを参考にしてみください。

SSH & Web Terminalのインストール

こちらもHome Assistantのアドオンです。次のPythonモジュールのインストールで使用します。

Home Assistantの「設定」→「アドオン」→「アドオンストア」から「SSH & Web Terminal」をインストールします。

似たようなアドオンに「Terminal & SSH」がありますが、これは別物ですので注意してください。

インストールについてはこちらでも紹介していますので参考にしてみてください。

Pythonモジュールのインストール

今回のPythonスクリプトでは以下のモジュールを使用します。

  • requests
  • paho-mqtt

インストールには以下のコマンドを先ほどインストールした「SSH & Web Terminal」で実行します。

pip3 install requests paho-mqtt

SwitchBotハブとエアコンの連携

PythonスクリプトでSwitchBot APIを叩いてエアコンを操作しますが、これをするためにはあらかじめSwitchBotとエアコンを連携しておく必要があります。

SwitchBotアプリからエアコンを登録していれば問題ありません。

もし、まだ登録をしていなければ、まずはSwitchBotアプリからエアコンの登録をしましょう。

SwitchBotトークンとシークレットの確認

SwitchBot APIを使うためにはトークンとシークレットという2つのコードが必要です。これらはSwitchBotアプリで確認できます。

この後の作業で使うので下記の手順で確認し、記録しておいてください。

「プロフィール」→「設定」に進みます。

「開発者向けオプション」に進むのですが、もし見当たらなければ、「アプリバージョン」を10回ほどタップしてください。タップすると開発者モードに入れ、「開発者向けオプション」が表示されます。

「開発者向けオプション」に進むと「トークン」と「シークレット」の2つのコードが表示されます。

また、この2つのコードが外部に漏れると、あなたのデバイスを誰でもコントロールできてしまうので、絶対に漏らさないように注意してください。

エアコンのDevice IDを確認する

SwitchBot APIでエアコンをコントロールするためにはDevice IDを調べておく必要があります。この後の設定で使うので事前に調べておきましょう。

Device IDを調べるためには以下のコマンドをTerminal で実行します。

$ curl "https://api.switch-bot.com/v1.0/devices" -H "Authorization: (あなたのトークン)" | jq .

(あなたのトークン)と書かれている箇所には先ほど取得したAPIのトークンを記載してください。

このコードを実行するとSwitchBotに登録しているすべてのデバイス情報が表示されます。

今回操作したいエアコンを探し、その中のdeviceIdの文字列を記録してください。

Configuration.yamlの編集(コントロールパネルの実装など)

さて、事前準備が済んだところで、ここからは具体的にエアコン操作の実装をしていきます。

File editorでConfiguration.yamlを開き、下記のコードを追加します。

Device IDやエンティティのIDは自身のデバイスのものに書き換えてください。

修正したら、Configuration.yamlを反映させるためにHome Assistantを再起動します。

#コントロールパネルの実装
mqtt:
  climate:
    - name: エアコン
      modes:
        - "off"
        - "cool"
        - "heat"
        - "dry"
        - "fan_only"
      current_temperature_template: "{{value_json}}"
      current_temperature_topic: "mqtt_statestream/sensor/wen_shi_du_ji_temperature/state" #wen_shi_du・・・は温湿度計のエンティティID。自分のものに書き換えてください。
      power_command_topic: "ac/living/power/set"
      mode_command_topic: "ac/living/mode/set"
      mode_state_topic: "ac/living/mode/set"
      temperature_command_topic: "ac/living/temperature/set"
      temperature_state_topic: "ac/living/temperature/set"
      fan_mode_command_topic: "ac/living/fan/set"
      fan_mode_state_topic: "ac/living/fan/set"
      swing_mode_command_topic: "ac/living/swing/set"
      swing_mode_state_topic: "ac/living/swing/set"

#Shellコマンド(MQTTトリガーでPythonスクリプトを実行するための記述)
shell_command:
    switchbot_ac: 'python3 ./python_scripts/switchbot_ac_control.py "(あなたのDevice ID)" {{states("climate.eakon")}} {{state_attr("climate.eakon", "temperature")}} {{state_attr("climate.eakon", "fan_mode")}} {{state_attr("climate.eakon", "swing_mode")}}' #SwitchBot APIでエアコンをコントロール
    read_ac_data: 'python3 ./python_scripts/read_ac_data.py' #ログファイルから設定値を読込MQTT Publishする(詳しくは後述)

#SwitchBot温湿度計のデータをMQTTでPublish(温湿度に変化があった場合にPublishされる)
#コントロールパネルに現在の温度を表示するため
mqtt_statestream:
  base_topic: "mqtt_statestream"
  include:
    domains:
      - sensor
    entities:
      - sensor.wen_shi_du_ji_temperature    #エンティティIDは自分のものに書き換えてください。

Pythonスクリプト

次にPythonスクリプトを準備します。

configフォルダ内にpython_scriptsフォルダを作成し、その中に下記のPythonスクリプトを作成します。

ファイル名は「switchbot_ac_control.py」です。(先ほどのConfiguration.yamlのswitchbot_acの行で書いた名前と同じにします。)

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# switchbot_ac_control.py
 
import requests
import json
import sys
import time
import hashlib
import hmac
import base64

#SwitchBot API v1.1を使うための認証
OPEN_TOKEN = '(あなたのトークン)'
SECRET = '(あなたのシークレット)'
API_HOST = 'https://api.switch-bot.com'

DEBIVELIST_URL = f"{API_HOST}/v1.1/devices"

nonce = ''
t = int(round(time.time() * 1000))
string_to_sign = '{}{}{}'.format(OPEN_TOKEN, t, nonce)

string_to_sign = bytes(string_to_sign, 'utf-8')
secret = bytes(SECRET, 'utf-8')

sign = base64.b64encode(hmac.new(secret, msg=string_to_sign, digestmod=hashlib.sha256).digest())

HEADERS = {
    'Authorization': OPEN_TOKEN,
    'sign': format(str(sign, 'utf-8')),
    't': format(t),
    'nonce': format(nonce)
}

#デバイスIDの取得
DEVICE_ID=sys.argv[1]

def post_request(url, params):
    res = requests.post(url, data=json.dumps(params), headers=HEADERS) 
    data = res.json()
    if data['message'] == 'success':
        return res.json()
    return {}

def send_air_condition(deviceId, temperature, mode, fanspeed, power_state):
    url = DEBIVELIST_URL+f"/{deviceId}/commands"
    params = {
        "command": "setAll",
        "parameter": f"{temperature},{mode},{fanspeed},{power_state}",
        "commandType": "command"
    }
    res = post_request(url, params)
    if res['message'] == 'success':
        return res
    return {}


#main
#ログファイルから前回の設定値の読込
path = './python_scripts/ac_state.txt'
with open(path) as f:
    json_load=json.load(f)

#引数からSwitchBot APIが受け付ける値に変換
if sys.argv[2]!='unknown':
    if sys.argv[2]=='off':
        json_load['power']='off'
    else:
        json_load['power']='on'
        if sys.argv[2]=='heat':
            json_load['mode']=5
        elif sys.argv[2]=='cool':
            json_load['mode']=2
        elif sys.argv[2]=='dry':
            json_load['mode']=3
        elif sys.argv[2]=='fan_only':
            json_load['mode']=4
if sys.argv[3]!='unknown' and sys.argv[3]!='NONE':
    json_load['temp']=sys.argv[3]
if sys.argv[4]!='unknown':
    if sys.argv[4]=='auto':
        json_load['fan']=1
    elif sys.argv[4]=='low':
        json_load['fan']=2
    elif sys.argv[4]=='medium':
        json_load['fan']=3
    elif sys.argv[4]=='high':
        json_load['fan']=4
# if sys.argv[5]!='unknown':    #swingの方向操作はHome Assistantではできるが、SwitchBot APIではできないので書いても意味がない。コメントアウトしている
#     json_load['swing']=sys.argv[5]

#エアコンにコマンドを送信
status = send_air_condition(DEVICE_ID, json_load['temp'], json_load['mode'], json_load['fan'], json_load['power'])
print(status)

#今回の設定値をログファイルに書き込み
path = './python_scripts/ac_state.txt'
with open(path, mode='w') as f:
    json.dump(json_load, f)

オートメーション設定

コントロールパネルで操作をしたときにPythonスクリプトを実行するためのオートメーションを設定していきます。

下記のように設定します。

トリガー

  • MQTTトリガー(トピック:ac/living/power/set)
  • MQTTトリガー(トピック:ac/living/mode/set)
  • MQTTトリガー(トピック:ac/living/temperature/set)
  • MQTTトリガー(トピック:ac/living/fan/set)
  • MQTTトリガー(トピック:ac/living/swing/set)

条件はなし

アクション

  • Delay(1秒)
  • Shell Command (switchbot_ac)

コントロールパネルの操作によって送信されたMQTTをHome Assistant自身が受信して、それをトリガーとしてオートメーションを発動します。

アクションで1秒のDelayを入れているのは、コントロールパネルで押した設定値が反映されず、押す前の設定値で指示が送られてしまうためです。コントロールパネルで押した後、実際に設定値が反映されるのに少し時間がかかるようです。

アクションのShell CommandでPythonスクリプトを実行します。コマンドはConfiguration.yamlのshell_commandに記載した内容です。つまり、Terminal で下記を打ったのと同じことです。

python3 ./python_scripts/switchbot_ac_control.py "(あなたのDevice ID)" {{states("climate.eakon")}} {{state_attr("climate.eakon", "temperature")}} {{state_attr("climate.eakon", "fan_mode")}} {{state_attr("climate.eakon", "swing_mode")}}

{{states(“climate.eakon")}}などはConfiguration.yamlのテンプレートを使用した書き方で、エンティティID(climate.eakon)の状態の値を取得しています。(つまり、オン/オフやモード、温度など)

もしエンティティIDを変更した場合は、この部分も修正する必要があります。

以上で、設定は完了です。

オーバービュー画面などからコントロールパネルのモードと温度の両方を操作するとエアコンが動くと思います。

起動したときに設定値を読み込まない対策

ここまできたら一度Home Assistantを再起動してみましょう。

ところが、本来であれば前回の設定値を保持してほしいのですが、保持されていないことがわかります。例えば、赤枠の部分には温度の設定値が表示されるはずですが、空欄になっています。

この状態でエアコンをONにしてもエアコンは起動しません。

そこで、起動時に前回の設定値を読み込むように変更を加えていきます。

改良版のしくみ

改良版は以下のしくみになります。

  • コントロールパネルで操作したときに、その設定値をログファイルに保存
  • Home Assistantの起動をトリガーとして、ログファイルに保存した設定値を読み込む
  • MQTTを使ってその設定値をコントロールパネルに送信

図の赤点線のところを作っていきます。

Pythonスクリプト

以下のPythonスクリプトを先ほどと同じpython_scriptsフォルダに作成します。

ファイル名は「read_ac_data.py」です。(こちらもConfiguration.yamlに書いたファイル名と同じにしてください)

import json
import paho.mqtt.client as mqtt
from collections import defaultdict

#SETTING DATA
POWER_TOPIC="ac/living/power/set"
MODE_TOPIC="ac/living/mode/set"
TEMP_TOPIC="ac/living/temperature/set"
FAN_TOPIC="ac/living/fan/set"
SWING_TOPIC="ac/living/swing/set"

MQTT_HOST="127.0.0.1"
MQTT_PORT=1883
MQTT_USER="(あなたのユーザー名)"
MQTT_PASS="(あなたのパスワード)"
MQTT_CLIENT="ac_data_pub"

class ACdata():
    def __init__( self, readData):
        nested_dict = lambda: defaultdict(nested_dict)
        self.data = nested_dict()
        self.data['power']['topic']=POWER_TOPIC
        self.data['power']['value']=readData['power']
        self.data['mode']['topic']=MODE_TOPIC
        self.data['mode']['value']=readData['mode']
        self.data['temp']['topic']=TEMP_TOPIC
        self.data['temp']['value']=readData['temp']
        self.data['fan']['topic']=FAN_TOPIC
        self.data['fan']['value']=readData['fan']
        self.data['swing']['topic']=SWING_TOPIC
        self.data['swing']['value']=readData['swing']

def readACdata():
    path = './python_scripts/ac_state.txt'
    with open(path) as f:
        json_load=json.load(f)

    return json_load

def publishMQTT(data):
    # MQTT publish as JSON
    print(data)
    msg_data = str(data['value'])
    print(
        "\n  Publishing MQTT payload to "
        + data['topic']
        + " ...\n\n    "
        + msg_data
    )
    mqttc = mqtt.Client(MQTT_CLIENT)
    mqttc.username_pw_set(MQTT_USER, MQTT_PASS)
    mqttc.connect(MQTT_HOST, MQTT_PORT)
    mqttc.publish(data['topic'], msg_data, 1)

#main
readData=readACdata() #ログファイル読込

#読み取り値をHome Assistantで認識可能な値に変換
if readData['mode']==1:
    readData['mode']='auto'
elif readData['mode']==2:
    readData['mode']='cool'
elif readData['mode']==3:
    readData['mode']='dry'
elif readData['mode']==4:
    readData['mode']='fan_only'
elif readData['mode']==5:
    readData['mode']='heat'
else:
    readData['mode']='unknown'
    
if readData['power']=='off':
    readData['mode']='off'

if readData['fan']==1:
    readData['fan']='auto'
elif readData['fan']==2:
    readData['fan']='low'
elif readData['fan']==3:
    readData['fan']='medium'
elif readData['fan']==4:
    readData['fan']='high'
else:
    readData['fan']='unknown'

ac_data=ACdata(readData)

#MQTT Publish
for data in ac_data.data.items():
    publishMQTT(data[1])

オートメーション設定

下記のようにオートメーションを作成します。

トリガーはHome Assistantの起動

条件はなし

アクション

  • Shell Command (read_ac_data)
  • Delay 3秒
  • Shell Command (read_ac_data)

Delay3秒を挟んでread_ac_dataを2回実行しています。1回だけだとコントロールパネルに正しく反映されないことがあるためです。

おそらくPythonスクリプトで各項目をPublishするときにDelayを入れてあげても良いかもしれません。(未確認)

これで起動直後も前回の設定値が反映されるようになります。

まとめ

いかがだったでしょうか?

Home Assistantでエアコンをコントロールする方法を紹介しました。

Configuration.yamlやPythonの作成など少し難しく感じる部分もあるかもしれませんが、もしわからないかしょがありましたら、問い合わせフォームやTwitterよりお気軽にご連絡ください。

問い合わせ

Twitter

今回はPythonを使ってコードを書いています。Pythonを知らなくてもほぼコピペするだけで動くように頑張って紹介していくつもりですが、Pythonの基本は知っておくことで、理解も深まりますし、アレンジもできるようになります。少し不安を感じる人は、以下の参考書を使って勉強してみることをおすすめします。

↓超入門書

↓初級本

また、Home Assistantやスマートホーム関連の記事はこちらにまとめていますので、ぜひこちらも読んでみてください。

この記事を書いた人
author

ユキヒト

家電大好き+子育て真っ只中のブロガーです。
スマートホームを始めとする家電関連の記事や子育て・知育関連の記事を書いています。
質問や相談はいつでも受け付けています。お問い合わせフォームやTwitterからお待ちしております。(もちろん無料です)
どんなことでも構いません。
これまでにあった例としては、
「SwitchBotハブの設定ができないので教えてもらえませんか?」
「ベビーカメラの安いやつないですか?」
などです。全く記事と関係ない質問もOKです。
できる限り答えていきたいと思いますので、お気軽にどうぞ。
お問い合わせ
Twitter