室温をSiriでコントロール

ボストンに引っ越しました。


こちらのアパートは日本と違って各部屋のエアコンというものはなく、全室空調になっています。

その温度設定をするのがサーモスタットと言われているこういうコントローラ。

要するに、室温をセンサで読み取って、設定値より高く or 低くなると、暖房/冷房に繋がった線を短絡させて空調を作動させる装置です。


で、こいつは交換可能になっていて、時間によってプログラムした温度に調整してくれるとか、Wi-Fi経由でiPhoneから設定ができるとか、高機能なものに付け替えることができます。


そういうわけで、さっそくWi-Fi対応のものに交換してみました。Honeywellという会社のRTH6580WFというのを使いました。交換方法はメーカーがYouTubeで解説してくれています。

取り付けると最初はWi-Fiアクセスポイントとして機能して、そこに接続してWebページからWi-Fiルータへの接続設定を行います。すると、Honeywellのサーバに接続した状態になり、このサーバ経由でWebやiPhone/Androidアプリから各種設定ができるようになります。

ただ単に公式アプリを使って設定できるというだけでは面白くないので、iPhoneの音声アシスタント「Siri」を使って室温などを変更できるようにしてみました。

設定変更用のコマンドを用意する

まず、Webサイトを通じて温度設定や暖房/冷房/オフを切り替えるためのコマンドを用意します。
適当にWebサイトとの通信を眺めて、それをシェルスクリプトに切り出しました。*1
https://gist.github.com/NeoCat/5279143

SiriProxyをセットアップする

SiriProxyをインストールします。今回はMacをサーバにしました。インストール方法はREADMEにある通り、ruby1.9か2.0を入れて、gem install siriproxyする感じです。
適当に検索するとより細かいインストール方法も出てきます。
ただし、現在のSiriProxyはDNS機能を搭載したので、dnsmasqは不要になっている点に注意。


インストールしたら、設定ファイル ~/.siriproxy/config.yml に次のように記入します。pluginsについては後述します。

listen: 0.0.0.0
port: 443
log_level: 1
upstream_dns: [8.8.8.8, 8.8.4.4]
server_ip: 192.168.1.112          ← MacのIPアドレス
plugins:
    - name: 'RemoteControl'
      path: '/Users/NeoCat/Applications/SiriProxy/SiriProxy-RemoteControl'

上記のように、server_ip にMacの(iPhoneから見える)IPアドレスを書いてあげることで、DNS機能が有効になります。このDNSサーバでAppleのSiriサーバの代わりにSiriProxyに接続するように誘導する仕組みです。

SiriProxyのプラグインを書く

こちらの記事を参考に、サーモスタット制御用のプラグインを書きます。
SiriProxyのプラグインとしてSiriで家電を操作するSiriProxy-iRemocon - blog.katsuma.tv


SiriProxy/plugins/siriproxy-example を丸っとコピーして別のディレクト*2に移し、Gemfileを適当に変更し、lib/siriproxy-example.rb (適当に改名してもok) の内容を下記のように編集します。そして、設定ファイルに自分のプラグインのパスを書き加えておきます。

# -*- coding: utf-8 -*-
require 'cora'
require 'siri_objects'
require 'pp'
require 'json'
require 'net/http'

class SiriProxy::Plugin::RemoteControl < SiriProxy::Plugin
  def initialize(config)
  end

  listen_for /(?:部屋の温度|室温)?/ do |mode,temp|
    set_temp(nil, nil)
    request_completed
  end

  listen_for /(暖房|冷房)(?:設定)?温度を?(\d+)度に(?:設定)?/ do |mode,temp|
    say "#{mode}の温度を#{temp}度に設定します"
    mode = mode == "暖房" ? "-h" : "-c"
    set_temp(mode, temp)
    request_completed
  end

  listen_for /(暖房|冷房).*(?:(?:自動|オン)?(?:設定)?|つけて)?/ do |mode|
    say "#{mode}の温度を自動設定にします"
    mode = mode == "暖房" ? "-h" : "-c"
    set_temp(mode, nil)
    request_completed
  end

  listen_for /(暖房|冷房|空調|エアコン)?(?:停止|ストップ|オフに|止めて|切って)?/ do |mode|
    say "#{mode}をオフにします"
    set_temp('-o', nil)
    request_completed
  end

private
  def set_temp(mode, temp)
    ret = nil
    IO.popen "/Users/NeoCat/bin/honeywell_set_temp.sh #{mode||''} #{temp||(mode ? 'schedule' : '')}" do |result|
      while line = result.gets
        puts line
        ret = line
      end
      ret = JSON.parse ret
    end
    if ret['success']
      say "#{temp ? temp.to_s+'度に設定しました。' : mode == '-o' ? 'オフにしました。' : mode ? '自動に設定しました。' : ''}現在の室温は#{ret['latestData']['uiData']['DispTemperature'].to_i}度です"
    else
      say "設定に失敗しました"
    end
    ret
  end
end

iPhoneにCAルート証明書をインストー

SiriProxy用のCAルート証明書iPhoneに登録します。

% siriproxy gencerts

を実行すると、 ~/.siriproxy/ca.pem というファイルができるので、これをメールに添付してiPhoneに送り、インストールします。(アンインストールは設定のプロファイルから行えます。)

SiriProxyを起動

SiriProxyを起動します。

% sudo siriproxy server
[Info - Configuration] Loading plugins -- If any fail to load, run `siriproxy bundle` (not `bundle install`) to resolve.
[Info - Server] DNS Server started, tainting 'guzzoni.apple.com' with 192.168.1.112
[Notice - Server] ======================= WARNING: Running as root =============================
[Notice - Server] You should use -l or the config.yml to specify and non-root user to run under
[Notice - Server] Running the server as root is dangerous.
[Notice - Server] ==============================================================================
[Info - Server] Starting SiriProxy on 0.0.0.0:443...
[Info - Server] SiriProxy up and running.

rootで動かしてしまっているので警告が出ていますが、とりあえずこれで。。

iPhoneWi-Fi設定でDNSを変更

iPhoneWi-Fi設定で、DNSIPアドレスだけをMacIPアドレスに変更します。
これで準備完了。

Siriに向かってしゃべる

暖房の温度設定を変更してみます。ちなみに温度は華氏です。ほんとSIじゃない単位やめてほしいよね。
 
「暖房の温度を〜」ていってるつもりなんだけど「を」を拾ってくれない(--; でもこれくらいの揺らぎは正規表現でがんばって吸収しています。


あらかじめスケジュール登録した温度設定に戻すこともできます。
 

出来上がり

やってみたら意外と簡単にできました。
ただSiriProxyはこのままだとMacと同じWi-Fiの中でないと使えません。外から家のMacと通信するためには、たとえばVPNを張る必要があるでしょう。
そこまでする手間を考えると、外では公式アプリで十分かな…

*1:毎度おなじみのリバースエンジニアリング(?)

*2:最初 plugins/ の中で作業しようとしていましたが、プラグインは一つのgemになっていることが前提になっているため、siriproxy本体の外に移さないとうまく行きませんでした。