セミオート・スマートホームをつくる その2 XBeeドア開閉センサ

th_smart-home-xbee-5

前回述べたセミオート・スマートホームの実現を目標に、まずはXBeeのドア開閉センサから準備していきます。

作業に入る前に、おうちのレイアウトを確認しておきます。

semi-smart-home-1

リビングのドア・窓は全部で4つありますが、エアコン直下の窓は基本的に閉めっぱなしなので、①〜③の開閉状態を取得できればOKです。ということで、XBeeドア開閉センサを3つ作ります。

以前に一度作成していますが、あのときから少しだけ配線を変えたり、設定値を変えたりするので、改めて作り方を書いておきます。

必要になる主なパーツは、XBee、ピッチ変換基盤、電池ボックス、ミニブレッドボード、リードスイッチです。

アンテナのタイプによっていくつか種類がありますが、アンテナがどうしても邪魔になるということでなければ、ワイヤアンテナ型で良いと思います。

XBeeの変換基盤は、スイッチサイエンス製のものが 個人的には扱いやすいと思います。

電池ボックスは、ニッケル水素充電池を使うことを考えると、2本ではXBeeの駆動に必要な3V付近に届かないので、3本タイプを使います。小ささを優先するなら単四タイプ、電池の持ちを優先するなら単三タイプ、お好みで。

コンパクトさをつき詰めるなら、プリント基板上に配線していく方がよいのかもしれませんが、個人的にはブレッドボードのお手軽さが大好きなので、その中でできる限りコンパクトなものを使います。

ガラス管むき出しのタイプは結構簡単に割れてしまうので、取り扱いやすいケース入りタイプでもいいと思います。秋月とかで売っています。対となるマグネットがセットなのも良いです。ガラス管タイプを使う場合は、別途、対となるマグネットを用意しましょう。こんなのとか。

 

ではでは、配線していきます。まずはXBeeのピッチ変換基板から。スイッチサイエンス製のものを使う場合はこんな感じ。

th-smart-home-xbee-new-1

チップタイプのLED、抵抗、コンデンサを使えばもっとスマートになると思いますが、なければ(もしくは自分のように扱えなければ)普通のLED、抵抗、コンデンサで十分です。できる限り電力は消費させたくないので、点灯させる動作確認用のLEDはON/SLEEPのみにすることにします。

ブレッドボードの方はこんな感じです。

th_smart-home-xbee-2

XBeeの入出力端子として11番ピンを利用する想定です。11番ピンをプルアップにして、リードスイッチがOFF(=開状態のとき)に入力が1、リードスイッチがON(=閉状態のとき)に入力が0になるようにします。

th_smart-home-xbee-3

こんな感じです。一応、回路図も載せておきます。

NewXBeeDoorSensor

上の図では電池ボックスが単三×2本になっていますが、実際は単四×3本を使っています。

とりあえず2個作りました。

th_smart-home-xbee-5

XBeeの裏側にあるID(0013A200-xxxxxxxx)は、後でXBeeを識別するために必要になるので、この時点でメモっておきましょう。

あと1個開閉センサを作る必要がありますが、これには他のセンサもくっつけたいので、Arduino Fioと組み合わせる形で後で作ります。

 

では、シンプルなドア開閉センサの方のXBeeの設定です。以前書いたものとほぼ同内容ですが、こちらもパラメータを少し変えているので、改めて書いておきます。

今回設置予定の窓・ドアは、開いたら開きっぱなし、閉めたら閉まりっぱなしのタイプなので、そんなに頻繁に状態を通知してくれなくても大丈夫そうです。ということで、PM(スリープ・モード)を”Cyclic Sleep [4]“にして、ST(スリープまでの時間)を、ちょっと余裕を持たせて200msにするとして、あとはSP(スリープする時間)を長くすればするほど電池の持ちが良くなります。

SP単体で設定可能な値の範囲は0x20〜0xAF0(= 32〜2800)、この10倍がスリープ時間なので、SPだけで設定可能なスリープ時間は320〜28000ms(=0.32s〜28s)が限界です。これ以上のスリープ時間を実現したい場合は、SN(スリープ期間数)とSO(スリープオプション)を併用する必要がありますが、ちょっぴり面倒なので、今回はSP単体で設定可能な最大値である0xAF0(28s)に設定します。過去の経験から推定すると、この設定でも単四電池を使えば半年〜1年ぐらいはもってくれるハズ。

それから、エンドデバイスが起きている間に1回サンプリングしてくれればよいので、IR(ST期間中のサンプリング周期)はST期間より1msだけ多い 201msに設定します。IRがゼロ以外に設定されていれば、スリープ復帰時に必ず1回、入力設定されているピンのサンプリングをしてくれるので、これで OKです。

以上で省電力関係の設定は終了です。あとは、入出力ピンの設定です。

今回は11番ピンを使うので、D4を”Digital Input [3]“に設定します。それから、11番ピンのプルアップを有効にしておく必要がありますが、デフォルトでプルアップは有効になっているので、PRは0x1FFFのままでOKです。

最終的に、以下のようにX-CTUで設定することになります。Function Setを”ZigBee End Device API”にしてファームウェアに書き込んでから、以下の項目を設定します。

  • ID … コーディネータと同じPAN ID
  • DH … 0(上位アドレス, コーディネータに送信)
  • DL … 0(下位アドレス, コーディネータに送信)
  • BD … 57600(自分の場合です)
  • AP … 2(よく分かっていませんが、2で統一しています)
  • SM … Cyclic Sleep [4]
  • ST … C8(200ms, ZigBeeが起きてデータを送信するための時間)
  • SP … AF0(2800ms、この10倍がスリープ時間)
  • SN … 1(デフォルト)
  • SO … 0(デフォルト)
  • D4 … Digital Input [3]
  • PR … 1FFF(デフォルト)
  • IR … C9(201ms)

 STを短く書き換えてしまうとX-CTUでの書き込みタイミングがシビアになってしまう(=リセットを押してから書き込みをクリックするまでの猶予がなくなる)ので、STは最後に設定することをオススメします。

 

さて、これでシンプルな方のXBee開閉センサは完成です。残る1個はシンプルじゃないです。

これについては、ドア開閉センサ以外に、温度センサ・湿度センサ・照度センサ・人感センサをくっつけます(*今回は全部使うわけではありませんが、将来を見越して)。XBeeだけで処理させるのはかなり厳しそうなので、Arduino Fioを使うことにします。

このXBeeは常時通電にして、Routerモードで動作させます。ウチでの設置場所では、これがちょうどCoordinator(Raspberry Piに接続したArduino Fio)とEnd Device(XBee開閉センサ)の間に位置するので、中継役も兼ねて。

th_smart-home-xbee-6

これについては、「センサステーション」という形で一度作成しているので、必要な方はそちらも合わせてご参考にしてください。ここでは、今回の用途向けに微修正したソースコードだけ載せておきます。

#include <XBee.h>
#include "DHT.h"

#define DHTTYPE DHT22   // DHT 22  (AM2302)

int TEMP_HUMID_PIN = 10;
int ILL_PIN        = A7;
int DOOR_PIN       =  4;
int MOTION_PIN     = 12;
int LED_PIN    = 13; 

int XBEE_SLEEP_PIN =  3; // 0 ... Enable XBEE / 1 ... Disable XBEE

DHT dht;

float temp_avg   = 0.0;
float humid_avg  = 0.0;
float ill_avg    = 0.0;
int   motion_avg = 0;
int   door       = 0;

// ドア(開閉)センサ以外のセンサは、過去1分間の出力値の平均値を送信する。
// (現在は、2秒に1回、1分間で30回のサンプリング)
// ただし、モーションセンサについては、平均値mによって以下の値を返す
//  m = 0          ... 0
//  0   < m <= 0.1 ... 1
//  0.1 < m <= 0.2 ... 2
//  0.2 < m <= 0.3 ... 3
//  0.3 < m <= 0.4 ... 4
//  0.4 < m <= 0.5 ... 5
//  0.5 < m <= 0.6 ... 6
//  0.6 < m <= 0.7 ... 7
//  0.7 < m <= 0.8 ... 8
//  0.8 < m        ... 9

const int SENSOR_LOG_NUM = 30; // 2秒で1ループなので
float temp_log[SENSOR_LOG_NUM];
float humid_log[SENSOR_LOG_NUM];
float ill_log[SENSOR_LOG_NUM];
float motion_log[SENSOR_LOG_NUM];

int loop_count = 0;

//-----------------------------------------------------------------
#define XBEE_SEND_INTERVAL 60000 // 1分ごとに送出
XBee xbee = XBee();
// {温度下位バイト, 温度上位バイト, 湿度下位バイト, 湿度上位バイト, 照度下位バイト, 照度上位バイト, 
//  人感下位バイト, 人感上位バイト, 開閉下位バイト, 開閉上位バイト}
uint8_t payload[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// SH + SL Address of receiving XBee
XBeeAddress64 addr64 = XBeeAddress64(0x0013a200, 0x40c1a65a);
ZBTxRequest zbTx = ZBTxRequest(addr64, payload, sizeof(payload));
ZBTxStatusResponse txStatus = ZBTxStatusResponse();
unsigned long before = 0;
unsigned long now    = 0;
//-----------------------------------------------------------------

void updateTemperatureAvg(){
  float sum = 0.0;
  for(int i=0;i<SENSOR_LOG_NUM;i++){
    sum += temp_log[i];
  }
  temp_avg = sum/SENSOR_LOG_NUM;
}

void updateHumidityAvg(){
  float sum = 0.0;
  for(int i=0;i<SENSOR_LOG_NUM;i++){
    sum += humid_log[i];
  }
  humid_avg = sum/SENSOR_LOG_NUM;
}

float getIlluminance(){
  int AMS302_Value = analogRead(ILL_PIN);
  float lx = AMS302_Value*(3300.0/1024.0)/1000.0/(0.26/100);
  return lx;
}

void updateIlluminanceAvg(){
  float sum = 0.0;
  for(int i=0;i<SENSOR_LOG_NUM;i++){
    sum += ill_log[i];
  }
  ill_avg = sum/SENSOR_LOG_NUM;
}

void updateMotionAvg(){
  float sum = 0.0;
  for(int i=0;i<SENSOR_LOG_NUM;i++){
    sum += motion_log[i];
  }
  float avg = sum/SENSOR_LOG_NUM;
  if(avg > 0.8)       motion_avg = 9;
  else if(avg > 0.7)  motion_avg = 8;
  else if(avg > 0.6)  motion_avg = 7;
  else if(avg > 0.5)  motion_avg = 6;
  else if(avg > 0.4)  motion_avg = 5;
  else if(avg > 0.3)  motion_avg = 4;
  else if(avg > 0.2)  motion_avg = 3;
  else if(avg > 0.1)  motion_avg = 2;
  else if(avg > 0.0)  motion_avg = 1;
  else                motion_avg = 0;
}

void setup() {
  Serial.begin(57600);  // シリアル通信速度
  xbee.setSerial(Serial);

  pinMode(ILL_PIN, INPUT);
  pinMode(MOTION_PIN, INPUT);
  pinMode(DOOR_PIN, INPUT_PULLUP); // デフォルトの入力値を1(=開状態)、閉まるとGNDと通電して0になるようにする
  pinMode(LED_PIN, OUTPUT);
  pinMode(XBEE_SLEEP_PIN, OUTPUT);

  for(int i=0;i<SENSOR_LOG_NUM;i++){
    temp_log[i]   = 0.0;
    humid_log[i]  = 0.0;
    ill_log[i]    = 0.0;
    motion_log[i] = 0.0;
  }
  door = 0;

  digitalWrite(LED_PIN, LOW);
  digitalWrite(XBEE_SLEEP_PIN, LOW); // XBee Enable

  dht.setup(TEMP_HUMID_PIN);
}

void loop() {

  delay(2000);

  if(loop_count == SENSOR_LOG_NUM){
    loop_count = 0;
  }
  temp_log[loop_count]   = dht.getTemperature();
  humid_log[loop_count]  = dht.getHumidity();
  ill_log[loop_count]    = getIlluminance();
  motion_log[loop_count] = (float)digitalRead(MOTION_PIN);
  door                   = digitalRead(DOOR_PIN);

  // Check if any reads failed and exit early (to try again).
  if (isnan(temp_log[loop_count]) || isnan(humid_log[loop_count])) {
    //Serial.println("Failed to read from DHT sensor! Complement pre-measured value");
    if(loop_count > 0){
      temp_log[loop_count]  = temp_log[loop_count-1];
      humid_log[loop_count] = humid_log[loop_count-1];
    }else{
      temp_log[loop_count]  = temp_log[SENSOR_LOG_NUM-1];
      humid_log[loop_count] = humid_log[SENSOR_LOG_NUM-1];
    }
  }

  // あまり無線通信を発生させたくないので、送信するのは1分ごととする。 
  now = millis();
  if(now - before > XBEE_SEND_INTERVAL){
    updateTemperatureAvg();
    payload[0] = (uint8_t)(int(temp_avg*100));
    payload[1] = (uint8_t)(int(temp_avg*100) >> 8);
    updateHumidityAvg();
    payload[2] = (uint8_t)(int(humid_avg*100));
    payload[3] = (uint8_t)(int(humid_avg*100) >> 8);
    updateIlluminanceAvg();
    payload[4] = (uint8_t)(int(ill_avg));
    payload[5] = (uint8_t)(int(ill_avg) >> 8);
    updateMotionAvg();
    payload[6] = (uint8_t)motion_avg;
    payload[7] = (uint8_t)(motion_avg >> 8);     
    payload[8] = (uint8_t)door;
    payload[9] = (uint8_t)(door >> 8);
    xbee.send(zbTx);
    digitalWrite(LED_PIN, HIGH);
    delay(100);
    digitalWrite(LED_PIN, LOW);
    delay(100);
    digitalWrite(LED_PIN, HIGH);
    delay(100);
    digitalWrite(LED_PIN, LOW);

    before = now;

    // after sending a tx request, we expect a status response
    // wait up to half second for the status response
    if (xbee.readPacket(500)) {
      // got a response!
      // should be a znet tx status            	
      if (xbee.getResponse().getApiId() == ZB_TX_STATUS_RESPONSE) {
        xbee.getResponse().getZBTxStatusResponse(txStatus);

        // get the delivery status, the fifth byte
        if (txStatus.getDeliveryStatus() == SUCCESS) {
          // success.  time to celebrate

        } else {
          // the remote XBee did not receive our packet. is it powered on?       
        }
      }
    } else if (xbee.getResponse().isError()) {
      //nss.print("Error reading packet.  Error code: ");  
      //nss.println(xbee.getResponse().getErrorCode());
    } else {
      // local XBee did not provide a timely TX Status Response -- should not happen

    } 
  }

  loop_count++;
}

Arduino Fioでのサンプリング自体は2秒に1回行っていて、1分ごとに、サンプリング値の平均をCoordinatorに送る、というのが基本の動作です。ドア開閉センサについては、送信する瞬間の開閉状態しか見る動作で問題ないので、そうしています。

 

さ て、最後はこれら3つのXBeeからのデータを受信する、CoordinatorとなるXBeeを設定する必要があります。ここではArduino Fioで処理して、その結果をRaspberry PiにI2Cで渡すという変なやり方になっていますが、Raspberry PiとXBeeを直で繋げられる人は、必ずしもこのやり方じゃなくていいと思います。というか、それが普通だと思います。

こちらも過去にやっているので、XBeeの設定等については、そちらをご参照ください。ここでは、今回の用途向けに微修正したソースコードだけ載せておきます。

#include <XBee.h>
#include <Wire.h>
#define SLAVE_ADDRESS 0x21

const uint8_t HIGH_STATE = 1;
const uint8_t LOW_STATE  = 0;
const float SUPPLY_VOLT = 3.3;

uint8_t TEMP_PIN   = A2;
uint8_t HUMID_PIN  = A0;
uint8_t ILL_PIN    = A3;
uint8_t MIC_PIN    = A1;
uint8_t MOTION_PIN = 12;
uint8_t LED_PIN    = 11;

float temp_avg   = 0.0;
float humid_avg  = 0.0;
float ill_avg    = 0.0;
float mic_avg    = 0.0;
uint8_t motion_avg = 0;

uint8_t door_l_jp = 0;
uint8_t window_l  = 0;

// すべてのセンサは、問い合わせ時点から過去1分間の出力値の平均値を返す。
// ただし、モーションセンサについては、平均値mによって以下の値を返す
//  m = 0          ... 0
//  0   < m <= 0.1 ... 1
//  0.1 < m <= 0.2 ... 2
//  0.2 < m <= 0.3 ... 3
//  0.3 < m <= 0.4 ... 4
//  0.4 < m <= 0.5 ... 5
//  0.5 < m <= 0.6 ... 6
//  0.6 < m <= 0.7 ... 7
//  0.7 < m <= 0.8 ... 8
//  0.8 < m        ... 9

const int SAMPLING_INTERVAL = 2000; // ms
const int LOOP_INTERVAL = 100; //ms
const int SAMPLING_LOOP_COUNT = SAMPLING_INTERVAL/LOOP_INTERVAL;
const int SENSOR_LOG_NUM = 30;
float temp_log[SENSOR_LOG_NUM];
float humid_log[SENSOR_LOG_NUM];
float ill_log[SENSOR_LOG_NUM];
float mic_log[SENSOR_LOG_NUM];
float motion_log[SENSOR_LOG_NUM];

uint8_t loop_count = 0;
uint8_t data_index = 0;

byte sendByte;

//-----------------------------------------------------------------
XBee xbee = XBee();
XBeeResponse response = XBeeResponse();
// create reusable response objects for responses we expect to handle 
ZBRxResponse rx = ZBRxResponse();
ZBRxIoSampleResponse rxio = ZBRxIoSampleResponse();
ModemStatusResponse msr = ModemStatusResponse();
// {温度下位バイト, 温度上位バイト, 湿度下位バイト, 湿度上位バイト, 照度下位バイト, 照度上位バイト, 
//  人感下位バイト, 人感上位バイト, 開閉下位バイト, 開閉上位バイト}
const uint32_t XBEE_ADDRESS_LIVING = 0x40CA2F26;
uint8_t receiveXBeeData_living[] ={0,0,0,0,0,0,0,0,0,0};
const uint32_t XBEE_ADDRESS_LIVING_WINDOW  = 0x40ADD42D;
const uint32_t XBEE_ADDRESS_LIVING_JP_DOOR = 0x40ADD44B;
//-----------------------------------------------------------------

float getTemperature(){
  int LM35DZ_Value = analogRead(TEMP_PIN);
  return ((SUPPLY_VOLT * LM35DZ_Value) / 1024) * 100;
}

void updateTemperatureAvg(){
  float sum = 0.0;
  for(uint8_t i=0;i<SENSOR_LOG_NUM;i++){
    sum += temp_log[i];
  }
  temp_avg = sum/SENSOR_LOG_NUM;
}

float getHumidity(float temp){
  int HIH4030_Value = analogRead(HUMID_PIN);
  float voltage  = HIH4030_Value/1024.0 * SUPPLY_VOLT;
  float sensorRH = 161.0 * voltage / SUPPLY_VOLT - 35;
  float trueRH   = sensorRH / (1.0546 - 0.00216 * temp);
  return trueRH;
}

void updateHumidityAvg(){
  float sum = 0.0;
  for(uint8_t i=0;i<SENSOR_LOG_NUM;i++){
    sum += humid_log[i];
  }
  humid_avg = sum/SENSOR_LOG_NUM;
}

float getIlluminance(){
  int AMS302_Value = analogRead(ILL_PIN);
  float lx = AMS302_Value*(3300.0/1024.0)/1000.0/(0.26/100);
  return lx;
}

void updateIlluminanceAvg(){
  float sum = 0.0;
  for(uint8_t i=0;i<SENSOR_LOG_NUM;i++){
    sum += ill_log[i];
  }
  ill_avg = sum/SENSOR_LOG_NUM;
}

float getMic(){
  float ADMP401_Value = analogRead(MIC_PIN);
  return 3.3*ADMP401_Value/1024.0;
}

void updateMicAvg(){
  float sum = 0.0;
  for(uint8_t i=0;i<SENSOR_LOG_NUM;i++){
    sum += mic_log[i];
  }
  mic_avg = sum/SENSOR_LOG_NUM;
}

void updateMotionAvg(){
  float sum = 0.0;
  motion_avg = 0;
  for(uint8_t i=0;i<SENSOR_LOG_NUM;i++){
    sum += motion_log[i];
  }
  float avg = sum/SENSOR_LOG_NUM;
  if(avg > 0.8)       motion_avg = 9;
  else if(avg > 0.7)  motion_avg = 8;
  else if(avg > 0.6)  motion_avg = 7;
  else if(avg > 0.5)  motion_avg = 6;
  else if(avg > 0.4)  motion_avg = 5;
  else if(avg > 0.3)  motion_avg = 4;
  else if(avg > 0.2)  motion_avg = 3;
  else if(avg > 0.1)  motion_avg = 2;
  else if(avg > 0.0)  motion_avg = 1;
  else                motion_avg = 0;

}

void receiveData(int byteCount){
  uint8_t i2c_command = -1;
  while(Wire.available()){
    i2c_command = Wire.read();
    //Serial.print("i2c data received: ");
    //Serial.println(i2c_command);
    switch(i2c_command){
      case 0xF0: updateTemperatureAvg();
                 sendByte = (uint8_t)(int(temp_avg*100)); break;
      case 0xF1: sendByte = (uint8_t)(int(temp_avg*100) >> 8); break;
      case 0xF2: updateHumidityAvg();
                 sendByte = (uint8_t)(int(humid_avg*100)); break;
      case 0xF3: sendByte = (uint8_t)(int(humid_avg*100) >> 8); break;
      case 0xF4: updateIlluminanceAvg();
                 sendByte = (uint8_t)(int(ill_avg)); break;
      case 0xF5: sendByte = (uint8_t)(int(ill_avg) >> 8); break;
      case 0xF6: updateMicAvg();
                 sendByte = (uint8_t)(int(mic_avg*100)); break;
      case 0xF7: sendByte = (uint8_t)(int(mic_avg*100) >> 8); break;
      case 0xF8: updateMotionAvg();
                 sendByte = motion_avg; break;
      case 0xF9: sendByte = 0; break;
      // ------------------------------------------------------------------
      case 0xE0: sendByte = receiveXBeeData_living[0]; break;
      case 0xE1: sendByte = receiveXBeeData_living[1]; break;
      case 0xE2: sendByte = receiveXBeeData_living[2]; break;
      case 0xE3: sendByte = receiveXBeeData_living[3]; break;
      case 0xE4: sendByte = receiveXBeeData_living[4]; break;
      case 0xE5: sendByte = receiveXBeeData_living[5]; break;
      case 0xE6: sendByte = receiveXBeeData_living[6]; break;
      case 0xE7: sendByte = receiveXBeeData_living[7]; break;
      case 0xE8: sendByte = receiveXBeeData_living[8]; break;
      case 0xE9: sendByte = receiveXBeeData_living[9]; break;
      case 0xEA: sendByte = window_l; break;
      case 0xEB: sendByte = 0; break;
      case 0xEC: sendByte = door_l_jp; break;
      case 0xED: sendByte = 0; break;    
      // ------------------------------------------------------------------
    }
  }
}

void sendData(){
  Wire.write(sendByte);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(57600);  // シリアル通信速度
  xbee.begin(Serial);

  pinMode(TEMP_PIN, INPUT);
  pinMode(HUMID_PIN, INPUT);
  pinMode(ILL_PIN, INPUT);
  pinMode(MIC_PIN, INPUT);
  pinMode(MOTION_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(receiveData);
  Wire.onRequest(sendData);

  for(uint8_t i=0;i<SENSOR_LOG_NUM;i++){
    temp_log[i]   = 0.0;
    humid_log[i]  = 0.0;
    ill_log[i]    = 0.0;
    mic_log[i]    = 0.0;
    motion_log[i] = 0.0;
  }

  //Serial.println("Ready.");
}

void loop() {

  xbee.readPacket();

  if (xbee.getResponse().isAvailable()) {
    // got something
    digitalWrite(LED_PIN, HIGH);
    delay(50);
    digitalWrite(LED_PIN, LOW);
    //Serial.print("Recieve!");  

    if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE) { // APIモードフレームタイプ 0x90: RX受信
      // got a zb rx packet

      // now fill our zb rx class
      xbee.getResponse().getZBRxResponse(rx);

      // どこのXBeeからデータから送られてきたデータか確認
      XBeeAddress64 address64 = rx.getRemoteAddress64();
      uint32_t address64_lsb = address64.getLsb();// 上位バイトはXBeeで共通なので、下位バイトでアドレスを判断する
      if(address64_lsb == XBEE_ADDRESS_LIVING){
        // リビングのXBeeから送られてきたデータの場合
        //Serial.println("From Sensor Station!");  
        uint8_t payload_length = rx.getDataLength();
        //uint8_t offset = rx.getDataOffset();
        uint8_t* payload = rx.getData();
        for(int i=0;i<payload_length-1;i++){
          receiveXBeeData_living[i] = payload[i];
        }
      }

      if (rx.getOption() == ZB_PACKET_ACKNOWLEDGED) { // 受信オプション 0x01: パケットには確認応答が返された
          // the sender got an ACK
          //flashLed(statusLed, 10, 10);
      } else {
          // we got it (obviously) but sender didn't get an ACK
          //flashLed(errorLed, 2, 20);
      }
      // set dataLed PWM to value of the first byte in the data
      //analogWrite(dataLed, rx.getData(0));      
    } else if (xbee.getResponse().getApiId() == ZB_IO_SAMPLE_RESPONSE) { // APIモードフレームタイプ 0x92: 入出力データサンプル受信通知

      xbee.getResponse().getZBRxIoSampleResponse(rxio);
      // どこのXBeeからデータから送られてきたデータか確認
      XBeeAddress64 address64 = rxio.getRemoteAddress64();
      uint32_t address64_lsb = address64.getLsb();// 上位バイトはXBeeで共通なので、下位バイトでアドレスを判断する

      if(address64_lsb == XBEE_ADDRESS_LIVING_WINDOW){
        // リビングの窓用のXBeeから送られてきたデータの場合
        //Serial.println("From Window Sensor!");  
        if(rxio.isDigitalEnabled(4)){ // 開閉情報はDIO4を利用しているため
          window_l = (uint8_t)rxio.isDigitalOn(4);
        }
      }else if(address64_lsb == XBEE_ADDRESS_LIVING_JP_DOOR){
        // リビングの障子用のXBeeから送られてきたデータの場合
        //Serial.println("From Japanese Door Sensor!");  
        if(rxio.isDigitalEnabled(4)){ // 開閉情報はDIO4を利用しているため
          door_l_jp = (uint8_t)rxio.isDigitalOn(4);
        }
      }

    } else if (xbee.getResponse().getApiId() == MODEM_STATUS_RESPONSE) { // APIモードフレームタイプ 0x8a: モデムステータス
      xbee.getResponse().getModemStatusResponse(msr);
      // the local XBee sends this response on certain events, like association/dissociation

      if (msr.getStatus() == ASSOCIATED) {
        // yay this is great.  flash led
        //flashLed(statusLed, 10, 10);
      } else if (msr.getStatus() == DISASSOCIATED) {
        // this is awful.. flash led to show our discontent
        //flashLed(errorLed, 10, 10);
      } else {
        // another status
        //flashLed(statusLed, 5, 10);
      }
    } else {
    	// not something we were expecting
      //flashLed(errorLed, 1, 25);    
    }
  } else if (xbee.getResponse().isError()) {
    //Serial.print("Error reading packet.  Error code: ");  
    //Serial.println(xbee.getResponse().getErrorCode());
  }

  if(loop_count == SAMPLING_LOOP_COUNT){
    temp_log[data_index]   = getTemperature();
    humid_log[data_index]  = getHumidity(temp_log[loop_count]);
    ill_log[data_index]    = getIlluminance();
    mic_log[data_index]    = getMic();
    motion_log[data_index] = (float)digitalRead(MOTION_PIN);
    loop_count = 0;
    data_index++;
    if(data_index == SENSOR_LOG_NUM){
      data_index = 0;
    }
  }

  loop_count++; 

  delay(LOOP_INTERVAL);
}

他のXBeeからの情報を集約するだけならもう少しコンパクトにできるのですが、CoordinatorのXBeeが接続されているArduino Fio自身にもいろいろセンサを取り付けているため、こんなに長々としたコードになってしまっています。

 

さてさて、長かったですが、これでXBeeのソフトとハードの準備は完了です。早速設置してみます。

まずは窓。

smart-home-xbee-12th_smart-home-xbee-8

続いて和室に続く障子。

smart-home-xbee-13

th_smart-home-xbee-9

最後に廊下へ続くドア。ここにいろんなセンサがくっついたものを設置します。

smart-home-xbee-14

th_smart-home-xbee-10

これら3つのXBeeからデータを受け取る、CoorinatorとなるXBeeは、廊下の先の自室(寝室)に置いてあるArduino Fioに取り付けられています。そのArduino Fioが、さらに(ラピロの中の)Raspberry PiにI2Cで接続されている、という形です。

 semi-smart-home-2

というわけで、開閉状態情報を取得するためのセンサの準備はできました。後は、どのタイミングでセンサ情報を取得して、それをどう処理するかというのを、Raspberry Pi側で作っていきます。

長かった。。。