ラベル IR の投稿を表示しています。 すべての投稿を表示
ラベル IR の投稿を表示しています。 すべての投稿を表示

2016年9月20日

ミニマルなIRKitクローンを作ってiOSから家電を制御する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
どうも、お久しぶりです。生きてます。

さて、iOS 10が配信開始されて新たに登場した「ホーム」アプリのおかげで、日本ではあんまり注目されてなかったHomeKitが熱くなってるみたいです。(個人的感想)

HomeKitではPhilips Hueを操作できたりするのですが、そもそも対応していない家電を対応させるためのDIY的手法も色々存在しています。
例えば、HomebridgeとIRKitを組み合わせた方法。
Raspberry PiにHomebridgeを入れて、homebridge-irkitでIRKitを叩くみたいなお手軽スマートハウスのやり方は検索すれば山ほど出てきます。
そしてここで使われるIRKit、赤外線リモコンの信号を送受信できるオープンソースハードウェアなのですが、大人気なんですね。
在庫切れ入荷予定無しで手に入らないんだけど(キレ)という声も周囲にチラホラあったり。

というわけで、欲しいけど無いなら作りましょう。
自分で作ると安いし、面白いですし...

回路はこんな感じ。

必要な部品は以下の通り。
ESP-WROOM-02でミニマルなIRKitクローンを作る



もしESP-WROOM-02とかブレッドボードとか抵抗とか...持ってるなら、赤外線LEDと赤外線リモコン受信モジュールだけ買っちゃってください。

私はオリジナルのESP-WROOM-02搭載ボードとプロトタイプ・シールド基板を作っているので、これを使ってサクッと作りました。


中身のソフトウェアはIRremoteESP8266とaJSONを使って100行程度で実現しています。
コードはこちら。
9SQ/minIRum: A minimal implementation of infrared sender/receiver like IRKit by ESP8266

Arduino core for ESP8266をArduinoに入れて、コードをビルドしてESP-WROOM-02に書き込んであげてください。

あとは、IRKitみたいに GET /messages で最後に受信したリモコンのコードが取得できるので、これをメモしておいて...
POST /messages にこれを投げてあげれば、リモコンと同じように発光してくれます。
もし、エアコンなどの長めのコードを飛ばすリモコンの場合は、IRremoteESP8266/IRremoteESP8266.hの#define RAWBUF 100を200とかにしてあげれば取れるかも。

あとはHomebridgeと組み合わせれば、このようなことが出来ます。

Raspberry PiにHomebridge諸々を入れるのは、検索すればいっぱい記事が出てくると思います。
ただ、Raspbianはapt-getで取れるnodeが古かったりするので、楽をしたいならArch Linux(RasPi2/RasPi3)をお勧めします...
pacman -S git python2 nodejs npm nss-mdns avahi
systemctl enable avahi-daemon
systemctl start avahi-daemon
npm install -g homebridge
npm install -g homebridge-irkit
mkdir .homebridge
cd .homebridge
nano config.json
config.jsonは以下のような感じで。
irkit_hostは適宜変更してください。
{
    "bridge":
    {
       "name": "Homebridge",
       "username": "B8:27:EB:4D:31:D7",
       "port": 51826,
       "pin": "031-45-154"
    },

    "accessories": [
        {
            "accessory": "IRKit",
            "name": "ライト",
            "irkit_host": "minirum-a492cd.local",
            "on_form": {"format":"raw","freq":38,"data":[3550,1700,500,400,500,400,450,1300,500,1300,500,400,450,1300,500,400,500,400,450,450,450,1300,500,400,500,400,450,1300,450,450,450,1300,500,400,450,1300,500,450,500,400,500,1300,500,400,500,400,450,450,450,450,450,1300,500,400,500,1300,500,1300,450,450,500,1300,500,400,500,400,500,400,450,450,500,1300,500,400,500,450,450,1300,500,400,500,400,450]},
            "off_form": {"format":"raw","freq":38,"data":[3550,1700,500,400,500,400,450,1300,500,1300,450,450,500,1300,500,400,500,400,500,400,500,1300,500,400,500,400,500,1300,500,400,450,1300,500,400,500,1300,450,450,500,400,450,1300,500,400,500,400,450,450,450,450,500,1300,450,1300,450,1300,450,1300,450,450,500,1300,450,450,450,450,450,450,450,1300,500,1300,500,400,500,400,450,1300,500,400,500,400,500]}
        }
    ]
}
ちなみに、この赤外線コードはPanasonic製のシーリングライトのON/OFFです。

homebridgeを立ち上げて、iPhoneとペアリングします。
homebridge
[Tue Sep 20 2016 03:31:29 GMT+0900 (JST)] Loaded plugin: homebridge-irkit
[Tue Sep 20 2016 03:31:29 GMT+0900 (JST)] Registering accessory 'homebridge-irkit.IRKit'
[Tue Sep 20 2016 03:31:29 GMT+0900 (JST)] ---
[Tue Sep 20 2016 03:31:29 GMT+0900 (JST)] Loaded config.json with 1 accessories and 0 platforms.
[Tue Sep 20 2016 03:31:29 GMT+0900 (JST)] ---
[Tue Sep 20 2016 03:31:29 GMT+0900 (JST)] Loading 1 accessories...
[Tue Sep 20 2016 03:31:29 GMT+0900 (JST)] [ライト] Initializing IRKit accessory...
Scan this code with your HomeKit App on your iOS device to pair with Homebridge:
                       
    ┌────────────┐     
    │ 031-45-154 │     
    └────────────┘     
                       
[Tue Sep 20 2016 03:31:29 GMT+0900 (JST)] Homebridge is running on port 51826.

iOS 10のデバイスで「ホーム」アプリを起動して「アクセサリを追加」、Homebridgeが表示されるのでコードを入力してペアリングを完了させます。
Homebridgeを追加したら、configに書いたアクセサリ(上記例では「ライト」)が表示されると思うので、これを追加すれば制御できるようになります。

Raspberry PiでのHomebridgeの自動起動は以下を読むと早いです。
Arch Linuxなら、Running Homebridge on Bootup (systemd)のセクションです。
https://github.com/nfarina/homebridge/wiki/Running-HomeBridge-on-a-Raspberry-Pi

homebridge-irkitではON/OFFの単純操作しかできないので、そのうち色々なコードを叩けるhomebridgeのプラグインでも書こうかな...
ちなみに、Raspberry Piにhomebridge-cmdを入れて、GPIOにSSRを繋いであげれば、リモコンの無いAC100Vの機器もON/OFFできます。

2014年7月31日

ATtiny85で赤外線シリアル通信

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回前々回の続き。
赤外線LED(OSI5FU5111C-40)とフォトトランジスタ(L-51ROPT1D1)を使ったシリアル通信をATtiny85で実現させます。
さらに、このATtiny85とArduinoをI2Cで接続し、I2C-赤外線通信コンバーター化します。

構成はこんな感じ。

ATtiny85の各ピンは以下の通り。

pin1 - RESET
pin2 - Serial RX (from フォトトランジスタ)
pin3 - Serial TX (to 赤外線LED)
pin4 - GND
pin5 - I2C SDA (Arduino A4)
pin7 - I2C SCL (Arduino A5)
pin6 - not used(D1)
pin8 - VCC

pin6が空いているので、更に何か追加することもできますが、今回は未使用。

ATtiny85をArduinoとして扱う方法は「Programming an ATtiny w/ Arduino 1.0」 を参考にしました。
書き込みはaitendoで購入し、以前の記事でファームウェアのアップデートを行ったUSBasp-Bを使用。
ATtiny85は内蔵RC 8MHz駆動です。

プログラムは以下の様な感じ。(たぶんもっとキレイに書けるはず...)

#include <SoftwareSerial.h>
#include "TinyWireS.h"

#define I2C_SLAVE_ADDR  13
#define IR_RX 3 // pin2
#define IR_TX 4 // pin3

SoftwareSerial irPort(IR_RX, IR_TX, false);

void receiveEvent(uint8_t a) {
  int i = 0;
  char c;
  char buf[100];
  if (TinyWireS.available()) {
    while(TinyWireS.available()){
      c = TinyWireS.receive();
      buf[i] = c;
      i++;
      buf[i] = '\0';
      delay(2);
    }
    irPort.write(buf);
  }
}

void requestEvent() {
  if(irPort.available()){
    char c = irPort.read();
    if(c!=255)
      TinyWireS.send(c);
  }
}

void setup() {
  TinyWireS.begin(I2C_SLAVE_ADDR);
  irPort.begin(1200);

  TinyWireS.onReceive(receiveEvent);
  TinyWireS.onRequest(requestEvent);
}

void loop() {

}

Arduino UNO側はこんな感じ。

#include <Wire.h>

void setup(){
  Serial.begin(9600);
  Wire.begin();
}

void loop(){
  if(Serial.available()){
    int i = 0;
    char c;
    char buf[100];
    while(Serial.available()){
      c = Serial.read();
      buf[i] = c;
      i++;
      buf[i] = '\0';
      delay(2);
    }
    Wire.beginTransmission(0); //broadcast
    Wire.write(buf);
    Wire.endTransmission();
  }

  Wire.requestFrom(13,1);
  if(Wire.available()){
    byte b = Wire.read();
    if(b!=0xff && b!=0x0a && b!=0x00)
      Serial.write(b);
  }
}

これで、一番上の写真のように向かい合わせにして赤外線通信ができます。
UNO側のコードでbroadcastにしているのは訳があって、このあとATtiny85を複数個ぶら下げる予定。

2014年6月1日

続・赤外線LEDとフォトトランジスタでシリアル通信

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回の続き。
赤外線LED(OSI5FU5111C-40)とフォトトランジスタ(L-51ROPT1D1)を使ったシリアル通信。
今回は、送受信×2で双方向(全二重)通信を実現させます。

構成は...
PC <---Serial---> Arduino <---赤外線---> Arduino <---Serial---> PC
こんな感じ。

前回のものを一体化して、以下のようにする。

これを2個用意し、互い違いになるように向かい合わせて配置。


プログラムは以下の通り。

#include <SoftwareSerial.h>

SoftwareSerial irPort(10, 11, false);

void setup() {
  irPort.begin(1200);
  Serial.begin(9600);
}

void loop() {
  int i = 0;
  char c;
  char buf[100];
  if(Serial.available()){
    while(Serial.available()){
      c = Serial.read();
      buf[i] = c;
      i++;
      buf[i] = '\0';
      delay(2);
    }
    irPort.print(buf);
  }

  if (irPort.available())
    Serial.write(irPort.read());
}

最初はSerialから赤外線へ渡す部分を
if (Serial.available()) {
    irPort.write(Serial.read());
}
こんな感じにしていたけど、これだとループの早さにSerial.readが追いつかないっぽい。
abcdefgと送るとabcgになる等、データが途中で抜けたりするので一旦バッファに全部溜めてからprintするようにしました。
ちなみに、上記コード中のdelay(2)を取ると、途中が抜けたり最初の3文字くらいしか取れない現象が発生するので、やはりSerial.readが原因の模様。
当初のコードのirPort.writeの前行にdelayを入れるのも試してみたが、10msくらいにしないとダメだったので、バッファに溜めた方が早いかなと。

上記写真のような配置で距離を離して双方同時に送信すると、互いが干渉して文字抜けや化けが発生するので、実際は間に遮蔽を入れるなどの工夫が必要。
試しに紙を1枚入れてみたら安定して通信できました。

2014年5月31日

赤外線LEDとフォトトランジスタでシリアル通信

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

久々のArduinoネタ。
赤外線LED(OSI5FU5111C-40)とフォトトランジスタ(L-51ROPT1D1)を使ってシリアル通信をする。
最終的にATtiny85に載せる計画なので、SerialではなくSoftwareSerialを使っています。

送信側はこんな感じ。
普通のLEDと同様に抵抗1本を入れる。


受信側はこんな感じ。
トランジスタ(2SC1815)を入れてD10に接続。


これを向かい合わせにして、配置する。


プログラムは以下のような感じ。
送信側
#include <SoftwareSerial.h>

SoftwareSerial sender(10, 11);

void setup() {
  sender.begin(1200);
}

void loop() {
  sender.println("Hello World!");
  delay(1000); 
  sender.println("1234567890");
  delay(1000);
  sender.println("abcdefghijklmnopqrstuvwxyz");
  delay(1000); 
}

受信側
#include <SoftwareSerial.h>

SoftwareSerial receiver(10, 11, false);

void setup() {
  receiver.begin(1200);
  Serial.begin(9600);
}

void loop() {
  if (receiver.available()) {
    Serial.write(receiver.read());
  }
}

送信側のプログラムは、「Hello World!」→「1234567890」→「a〜z」を1s毎に出力、受信側は赤外線で受け取ったデータをSerialにそのままフォワーディングするような感じ。
仕組み的には独自のプロトコルではなく、Serial(SoftwareSerial)を使っているので特に複雑な訳でもなくサクッと使えるのが利点。

環境にもよると思いますが、この構成だと約20cmくらいまで離しても通信できました。
通信距離を伸ばすには赤外線LEDの球数を増やす、電圧を上げる(もちろん高出力タイプに置換した上で)等で出力を強くする必要あります。

次の記事では送受信×2で双方向(全二重)を実現させます。

2013年1月5日

ウォシュレット実況bot

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

お家のトイレからプライバシーが吹き飛ぶ日がやってきました。
事の発端は以下のツイート
このツイートに触発されて、Arduino + Ethernet Shield + 赤外線リモコン受信モジュールで作ってしまったのが上記写真。

実際のツイートはこんな感じ。(一部)
という具合。

我が家のTOTOのウォシュレット、そのリモコンから送信されるコードを赤外線受信モジュールでキャッチし、押されたボタンを判別してツイートします。

使用したのはArduino UNO、Ethernet Shield、赤外線リモコン受信モジュール (PL-IRM2121)の3つ。
配線を簡略化する為に、5番ピンを赤外線モジュールとの通信、6番ピンをGND、7番ピンをVccにしています。

まずは、リモコンが送信しているコードの取得。
6.1ミリ秒のON、2.9ミリ秒のOFFに続いて、0.6ミリ秒、0.5ミリ秒間隔でON、OFFを繰り返し、1.5ミリ秒のOFFが間に何回か入ります。
Excelに起こすとこんな感じ。

左上:流す(小)、左下:流す(大)、右上:おしり、右中:やわらか、右下:ビデ

最初の6.1ms、2.9msはリモコン毎に異なる送信開始の合図リーダ部で、その後がデータ部となっている。

ここで、ON時間を無視してOFF時間だけ抽出し、1.5ミリ秒以上のOFF時間を1、0.5ミリ秒のOFF時間を0とすると

010000000001000000000001011000010110000:大
010000000001000000000001000100010001000:小
010000000001000001011001000000010101100:おしり
010000000001000001011001010100010000100:やわらか
010000000001000001011000100000001101100:ビデ
010000000001000101010101101101001110000:ストップ

という風に表すことができる。
あとはこれを条件分岐し、それぞれにあったツイートをpostさせればOK。
プログラムは、こちらこちらこちらを参考にしつつ、以下のような感じで。
#include <SPI.h>
#include <Ethernet.h>
#include <Twitter.h>

#define IR_INPUT 5

byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //Ethernet ShieldのMACアドレス
byte ip[] = { 192, 168, 1, 123 }; //IPアドレス
Twitter twitter("/* 取得したトークン */");
char msg[256];

void setup()
{
  Ethernet.begin(mac, ip);   
  Serial.begin(9600);
  pinMode(IR_INPUT,INPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  digitalWrite(6,LOW);
  digitalWrite(7,HIGH);
}

void loop()
{
  unsigned long time = 0;
  int i , cnt;
  char buf[64];

  if (digitalRead(IR_INPUT) == LOW) {
    time = micros();
    while (digitalRead(IR_INPUT) == LOW) ;
    time = micros() - time;
  }
  if (time >= 6100) {
    i = 0 ;
    while(digitalRead(IR_INPUT) == HIGH) ;
    while (1) {
      while(digitalRead(IR_INPUT) == LOW) ;
      time = micros() ;
      cnt = 0 ;
      while(digitalRead(IR_INPUT) == HIGH) {
        delayMicroseconds(10) ;
        cnt++ ;
        if (cnt >= 1200) break ;
      }
      time = micros() - time ;
      if (time >= 10000) break ;
      if (time >= 1500)  buf[i] = (char)0x31 ;
      else               buf[i] = (char)0x30 ;
      i++ ;
    }
    if (i != 0) {
      buf[i] = 0 ;
      checkCode(buf) ;
    }
  }
}

void checkCode(String code)
{
  code = code.substring(15,37);

  Serial.println(code);
  if (code.equals("0000000010110000101100")){
    strcpy(msg,"トイレを流しました(大)");
    postTweet();
  }
  else if (code.equals("0000000010001000100010")){
    strcpy(msg,"トイレを流しました(小)");
    postTweet();
  }
  else if (code.equals("0010110010000000101011")){
    strcpy(msg,"おしり洗浄中( ´_ゝ`)");
    postTweet();
  }
  else if (code.equals("0010110010101000100001")){
    strcpy(msg,"おしりやわらか洗浄中(*´ω`*)");
    postTweet();
  }
  else if (code.equals("1010101011011010011100")){
    strcpy(msg,"洗浄ストップ(`・ω・´)");
    postTweet();
  }
  delay(100);
}

void postTweet()
{
  Serial.println("connecting ...");
  if (twitter.post(msg)) {
    int status = twitter.wait();
    if (status == 200) {
      Serial.println("OK.");
    } 
    else {
      Serial.print("failed : code ");
      Serial.println(status);
    }
  } 
  else {
    Serial.println("connection failed.");
  }
}
使用用途として、お通じの公開処刑記録、おじいちゃん・おばあちゃんの生存確認などが挙げられるようですが、流す度にプライバシーも流れていきます。

追記:噴射時間もツイートするようにしてみた。
unsigned long washTimeを宣言して、
   else if (code.equals("0010110010000000101011")){
    washTime = millis();
    strcpy(msg,"おしり洗浄中( ´_ゝ`)");
    postTweet();
  }
  else if (code.equals("0010110010101000100001")){
    washTime = millis();
    strcpy(msg,"おしりやわらか洗浄中(*´ω`*)");
    postTweet();
  }
  else if (code.equals("1010101011011010011100")){
    washTime = millis() - washTime;
    sprintf(msg,"洗浄ストップ(`・ω・´) 噴射時間%d秒",(int)(washTime/1000));
    postTweet();
  }
こんな感じで。

追記2:トイレットペーパーの使用量もツイートするようにしてみた。
トイレットペーパー使用量報告bot
http://eleclog.quitsq.com/2013/01/toilet-paper-bot.html

追記3:トイレットペーパー使用量botと合体させて、無線化しました。
ウォシュレット実況botの無線化
http://eleclog.quitsq.com/2013/01/toilet-tweet-bot-wireless.html


追記 2016.01.03 : 実際のツイートを開発用アカウントからメインアカウントのツイートに差し替えしました。