39Si

プログラミング関連の勉強した内容を簡単にまとめておきます

【Apple Watch と IoT】Apple Watch でエアコンを制御する【後編】

inner2.hatenablog.com

前編の続きです。

Raspberry PI で Twitter のつぶやきを読み取る

自宅に設置する Raspberry PI では主に2つのことを行います。 今回は、Python 3 系でプログラムを書くことにしました。

  1. Twitter でつぶやいたコマンドの読み取り
  2. Arduino への命令(Serial 通信)

Twitter の Timeline を取得

まず、Twitter のタイムラインの取得には以下の Module を使用しました。

また、Twitter の認証には OAuth 認証を使うため、あらかじめ設定をしておく必要があります。 私以外にたくさんの人が解説しているのでそちらを参考にしてください。 - OAuth 認証についての参考ページ

Arduino と Serial 通信

Serial で文字列を送信するのは大変そうだったので、 命令は文字1文字を送ることにし、 以下のようにした。

Twitter で heating とつぶやいた -> Arduino に "h" を送信
Twitter で cooling とつぶやいた -> Arduino に "c" を送信
Twitter で stop    とつぶやいた -> Arduino に "s" を送信

Code (Raspberry PI)

# import module pyserial twitter
from twitter import *
import serial
import time


# ------ Access key や 使用する Twitter アカウントの入力 --------
# Twitter Account
twitter_account = ""
# SETTING TWITTER ACCESS
token = ""
token_key = ""
con_secret = ""
con_secret_key = ""
# Arduino serial port
serial_port = '/dev/ttyACM0'  # mac /dev/tty.usbmodem1421
# ---------------------------------------------------------------

auth = OAuth(token, token_key, con_secret, con_secret_key)
t = Twitter(auth=OAuth(token, token_key, con_secret, con_secret_key))

# twitter read
def twitter_read():
    # init
    ser = serial.Serial(serial_port, 9600)
    mg = ser.read()
    print(mg)

    twitter_userstream = TwitterStream(auth=auth, domain='userstream.twitter.com')
    for msg in twitter_userstream.user():
        if 'user' in msg:
            # check user
            if msg['user']['screen_name'] == twitter_account:
                print(msg['text'])
                cmd = msg['text'].split('-')
                if cmd[0] == 'stop':
                    sends = "s".encode()
                    ser.write(sends)
                elif cmd[0] == 'heating':
                    sends = "h".encode()
                    ser.write(sends)
                elif cmd[0] == 'cooling':
                    sends = "c".encode()
                    ser.write(sends)


# Main
if __name__ == '__main__':
    time.sleep(10)
    try:
        twitter_read()
    except:
        print("error")

補足

  • Sleep 処理を入れているのはラズベリーパイのUSBポートが二つしかなく、キーボードと無線LANで埋まっており、Sleep 中にキーボードとArduinoを入れ替えるためです。

Arduino でエアコンを制御する

Arduino では、以下の三つのことをしました。

  1. あらかじめリモコンの信号の取得
  2. Serial 通信(Raspberry PI からの信号の読み取り)
  3. 赤外線LED から信号を送信

Arduino で赤外線LEDを利用する

Arduino の部分は下記のページを参考にしました。
リモコンの信号を取得する部分はそのまま利用しました。

Code (Arduino)

うまい具合に書けなかったので、かなりごり押しなコードになってます。

run.ino

// Arduino

// IR Signal Data
unsigned int airstop[] = {373,192,44,52,42,144,43,49,43,144,40,54,41,148,37,55,44,142,44,49,44,143,44,49,44,142,44,142,42,52,44,143,44,49,44,143,44,142,47,142,42,143,43,50,42,53,45,140,43,144,40,53,40,54,44,51,37,54,44,143,44,48,45,50,42,51,42,143,43,143,42,53,42,51,42,49,46,48,42,53,42,51,42,145,42,51,42,49,46,47,42,52,44,142,44,52,37,54,44,143,47,48,42,51,42,51,42,50,42,144,42,52,42,51,44,142,44,50,41,52,44,49,42,52,43,51,42,51,42,49,46,47,42,52,44,52,42,142,44,140,47,142,46,48,42,51,42,52,41,52,41,52,41,52,39,54,42,141,45,52,44,142,44,144,41,52,44,142,42,52,41,52,44,49,44,50,41,52,41,52,44,49,44,143,47,142,44,48,42,142,43,144,44,143,39,148,42,51,39,54,40,54,39,54,39,54,42,51,39,148,44};
unsigned int cool[] = {376,189,45,49,47,140,47,47,47,139,48,46,46,141,42,51,39,135,52,54,40,146,41,53,40,148,39,148,39,54,40,148,39,53,40,148,44,140,48,142,47,140,45,49,44,49,44,142,45,142,40,53,44,49,44,49,40,53,45,142,45,49,44,48,45,49,47,46,45,51,45,140,46,140,40,53,40,54,41,51,40,53,40,147,39,54,40,54,47,46,45,142,48,140,46,47,45,50,45,46,46,141,40,54,40,53,39,54,39,148,39,54,39,54,44,142,40,54,44,49,44,49,44,49,40,54,40,54,41,52,44,48,45,49,41,51,48,140,48,139,46,46,46,50,45,46,46,46,40,53,44,50,39,54,39,54,44,142,40,53,44,143,39,53,40,54,44,49,48,46,47,46,47,46,47,46,44,50,40,53,40,54,42,145,48,139,46,47,44,143,44,143,44,143,47,140,44,49,44,49,44,49,47,46,46,140,40,53,40,53,44};
unsigned int heat[] = {380,184,54,40,53,134,52,41,52,134,52,41,50,136,53,41,52,134,52,42,48,138,50,42,53,135,51,135,51,42,53,134,52,42,49,137,53,134,53,134,51,137,52,41,51,45,50,134,52,136,49,44,48,44,49,44,51,43,48,138,48,45,50,42,48,45,48,138,50,137,49,44,48,44,48,44,49,45,48,44,49,44,52,135,49,44,50,44,49,44,52,134,53,135,52,41,51,42,48,139,50,43,52,41,51,42,50,44,52,135,50,44,49,44,49,137,53,40,52,41,52,42,50,43,50,42,51,43,50,43,48,44,50,44,49,44,50,132,54,138,48,138,50,43,49,44,49,43,52,41,52,42,49,44,48,44,50,137,49,44,50,138,49,44,50,44,52,41,52,42,50,42,50,43,52,42,50,42,49,44,49,44,50,138,52,134,53,41,52,135,51,136,49,138,48,138,48,44,48,45,48,45,49,45,48,44,51,127,60,135,51};

int ir_out = 2;
char str='n';

// Init
void setup() {
  Serial.begin(9600);
  pinMode(ir_out, OUTPUT);
}

/* ---------- Send ir signal ---------- */

// 冷房
void cooling() {
  int dataSize = sizeof(cool) / sizeof(cool[0]);
  for (int cnt = 0; cnt < dataSize; cnt++) {
    unsigned long len = cool[cnt]*10;  // dataは10us単位でON/OFF時間を記録している
    unsigned long us = micros();
    do {
      digitalWrite(ir_out, 1 - (cnt&1)); // cntが偶数なら赤外線ON、奇数ならOFFのまま
      delayMicroseconds(8);  // キャリア周波数38kHzでON/OFFするよう時間調整
      digitalWrite(ir_out, 0);
      delayMicroseconds(7);
    } while (long(us + len - micros()) > 0); // 送信時間に達するまでループ
  }
}
// 暖房
void heating() {
  int dataSize = sizeof(heat) / sizeof(heat[0]);
  for (int cnt = 0; cnt < dataSize; cnt++) {
    unsigned long len = heat[cnt]*10;  // dataは10us単位でON/OFF時間を記録している
    unsigned long us = micros();
    do {
      digitalWrite(ir_out, 1 - (cnt&1)); // cntが偶数なら赤外線ON、奇数ならOFFのまま
      delayMicroseconds(8);  // キャリア周波数38kHzでON/OFFするよう時間調整
      digitalWrite(ir_out, 0);
      delayMicroseconds(7);
    } while (long(us + len - micros()) > 0); // 送信時間に達するまでループ
  }
}
// エアコンストップ
void air_stop() {
  int dataSize = sizeof(airstop) / sizeof(airstop[0]);
  for (int cnt = 0; cnt < dataSize; cnt++) {
    unsigned long len = airstop[cnt]*10;  // dataは10us単位でON/OFF時間を記録している
    unsigned long us = micros();
    do {
      digitalWrite(ir_out, 1 - (cnt&1)); // cntが偶数なら赤外線ON、奇数ならOFFのまま
      delayMicroseconds(8);  // キャリア周波数38kHzでON/OFFするよう時間調整
      digitalWrite(ir_out, 0);
      delayMicroseconds(7);
    } while (long(us + len - micros()) > 0); // 送信時間に達するまでループ
  }
}

/* ---------- Send ir signal ---------- */

void loop() {
  str='n';
  Serial.write(str);
  if(Serial.available()>0){
    str =Serial.read();
    Serial.write(str);
    if(str=='s'){
      air_stop();
      delay(3000);
    }else if(str=='c'){
      cooling();
      delay(3000);
    }else if(str=='h'){
      heating();
      delay(3000);
    }
  }
  delay(250);
}

PC から家電を制御する

MacWindows から直接家電制御したい場合は、PCから直接つぶやく
(Python Module を使うと簡単なのでコードは省略)

おわりに

ここまで、おつきあいいただきありがとうございます。長文になってしまい、すみませんでした。
普段しょうもない記事ばかり書いてますが、今回の内容は覚えることも多く大変でした。
Apple watch はもちろん iPhone アプリも初挑戦だったので、覚えることが多かったです。
特に、Apple watch は情報も少なかったので大変でした。

今回の内容で「Arduino いらないんじゃないか?」とか「Raspberry PI で LIRC 使ったら?」とか思っている人がいるかもしれませんが、
全くその通りで、昔使ったことがあるという理由だけで赤外線LEDの制御はArduino でやりました。
今後は、部屋の温度などの情報を取得できるようになどどんどん拡張していきたいです。

お世話になった本

iPhone アプリは初めてだったので、入門書のお世話になりました。
xcode の使い方と Label と Button ぐらいしかちゃんと見てないですが、
また今度しっかりと勉強したいです。

ほんきで学ぶSwift+iOSアプリ開発入門 Swift2,Xcode7,iOS9対応

ほんきで学ぶSwift+iOSアプリ開発入門 Swift2,Xcode7,iOS9対応

お世話になったページ 、Link

特に、Apple watch 関連は大変感謝してます。
ありがとうございます。