HaLaKeのドアの開閉を検知しよう!

  今回はセンサーを使って身の回りの物理現象を読み取って活用できるデータをとれるようにしていきたいと思います。 一つの例として今回はHaLaKeのドアの開閉を読み取って一日初めの開閉時間と開閉回数をSlackに投稿してくれるようにしていきたいと思います。

HaLaKeだけでなくお店や家のどこかしらのドアの開閉のデータをとることで何かに活用できるのではないでしょうか。
多様な条件でもなるべく運用できるように今回は超音波センサを使って距離で開閉を読み取っていきます。 SlackにIFTTTを経由して投稿する記事は以前投稿しているので今回はSlackのAPIを使って投稿する方法を紹介します。

前提条件

  • 書き込み方などがわからない方以前の記事を参照
  • arduinoやESP32の知識がある方は上記を無視してもOK

必要なもの

  1. ESP32-DevKitCなどのESP32開発ボード
  2. 書き込み用ケーブル(開発ボードに合う端子のケーブルを各自用意)
  3. 超音波センサ
  4. ブレッドボード
  5. ジャンパワイヤ
  6. 確認用LED(なくても大丈夫)
  7. 抵抗(LEDなしなら容易不要)330~1kΩぐらい
  8. コンデンサ0.1μF(自動書き込みができない場合)

Slackの設定

Slackの設定を行っていきます。
今回使う機能は最低限に絞っているので使わない機能は説明を省きます。 参考にさせて頂いたサイトはこちら

https://note.com/kawa1228/n/nb0811ed44792note.com

最初は下記のサイトにアクセス

Slack API: Applications | Slack サイトからサインインしたことがない方は以下のような画面が出てくるので赤枠をクリックしてサインインするワークスペースURLとメールアドレス、パスワードを入力しサインインする必要があります。
サインインしたことがある方はこちらの作業をスキップ  

サインインできたらもう一度こちらにアクセス Slack API: Applications | Slack

最初からサインインしてあった方はこちらからの作業になります。 初めにAppを作るの画像に従って操作します。 

  • 注意:Appを作ることによってSlack API利用規約に同意したことになるので利用規約を確認の上、各自の判断で行って下さい。

 ここからトークンの種類を設定していきます。     インストールボタンを押してワークスペースで利用できるようにします。    次にSlack自体の設定を行っていきます。
自動投稿したいチャンネルを作成、選択し次の操作を行ってください。    これでワークスペースに追加できました。  左のチャンネル選択画面から一番下App欄を見ると追加されているのがわかります。
これでSlackの下準備が完了しました。

ハードウェア

 必要なもので記入されているものすべてを使った場合の例です。
私の環境ではデバッグ用にLEDと抵抗,自動書き込みされないのでコンデンサを挟んでいます。必要としない場合は取り除いても構いません。
 私はこのような配線になってしまいわかりにくいので一つ目の画像のようにパーツ同士が配線されていればぐちゃぐちゃでも構わないません。
ところどころ配線が二つの画像で違っているので一つ目の画像を参考に組んでもらえれば楽だと思います。

配線をつなぐ場所が間違っていないかだけ確認してもらえればと思います。
 最低限↑のようにつながっていれば動作します。

ソフトウェア

#include <Arduino.h>
#include <HTTPClient.h>
#include <time.h>

#define TRG 12
#define ECH 13
#define HIGHTIME 10
#define threshold 70    //70m
#define judge_time 1000 //1秒

HTTPClient http;
const char* ssid = "";                                                       //Wi-FiのSSID
const char* password = "";                                              //Wi-Fiのpasword
String url = "https://slack.com/api/chat.postMessage";
String acces_token = "";                                                  //アクセストークン
String channel = "";                                                         //投稿したいチャンネル名
String acces_url;

unsigned int counter = 0;
unsigned long total_counter = 0;
unsigned long diff;
float dis;
bool result = false;
struct tm timeInfo;//時刻を格納するオブジェクト
int before_hour = 0;
int before_day = 0;
int open_per_hour_total = 0;
double hour_average;
int start_hour;

bool response_echo(){
    digitalWrite(TRG, HIGH);
    delayMicroseconds(HIGHTIME);
    digitalWrite(TRG, LOW);
    diff = pulseIn(ECH, HIGH);
    dis = (float)diff * 0.01715;//26度の場合0.017355室度によって音の伝わる速さが違うので変えるとより正確に距離を出すことが出来る
    //Serial.print(dis);//debug
    //Serial.println("cm");//debug
    if(dis < threshold){
      result = true;
    }else{
      result = false;
    }
    return result;
  }

void setup() {
  Serial.begin(115200);
  pinMode(TRG, OUTPUT);
  pinMode(ECH, INPUT);
  ledcAttachPin(A18,1);
  ledcSetup(1,12000,8);

  WiFi.begin(ssid, password);
  Serial.print("connecting to WiFi.");
  int i = 0;
  while(WiFi.status() != WL_CONNECTED){
    delay(100);
    Serial.print(".");
    i++;
    if(i == 100){
        i = 0 ;
        Serial.println("Retry!!! please check your ssid and passpword");
        }
    }
    Serial.println("connected! & timeset!");
    configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");//NTPの設定
    getLocalTime(&timeInfo);
    before_hour = timeInfo.tm_hour;
    before_day = timeInfo.tm_mday;

    bool first_time = true;
    Serial.println("not_first_time");
    while(first_time){
      if(response_echo()){
        ledcWrite(1,0);
        delay(judge_time);
        if(response_echo()){
          getLocalTime(&timeInfo);
          acces_url = url + "?token=" + acces_token + "&channel="+ channel + "&text=" + "HaLaKe_Door_Open_Notification" + "&attachments=" + "[{\"text\":\"First_Open->" + timeInfo.tm_hour + ":" + timeInfo.tm_min + "\"}]";
          http.begin(acces_url);
          http.GET();
          http.end();
          first_time = false;
          Serial.println(acces_url);
          start_hour = timeInfo.tm_hour;
        }
      }else{
        ledcWrite(1,255);
      }
    delay(100);
  }
}

void loop(){
  getLocalTime(&timeInfo);

  if(timeInfo.tm_mday != before_day){
    Serial.println("reset!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    Serial.print("before_day:");
    Serial.println(before_day);//debug
    Serial.print("now_day:");
    Serial.println(timeInfo.tm_mday);//debug
    ESP.restart();
  }
  if(timeInfo.tm_hour > 18){
    return;
  }else{
    if((timeInfo.tm_hour - before_hour) == 1){
      open_per_hour_total += counter;
      hour_average = (double)open_per_hour_total / (double)(timeInfo.tm_hour - start_hour);
      acces_url = url + "?token=" + acces_token + "&channel="+ channel + "&text=" + "HaLaKe_Door_Open_Notification" + "&attachments=" + "[{\"text\":\"Open_per_Hour:" + counter + "\\n" +  "Hour_Average:" + hour_average + "\"}]";
      http.begin(acces_url);
      Serial.println("GET!!!!!!!!!!!!!!!!!!!!!!!!");
      http.GET();
      http.end();
      counter = 0;
      before_hour = timeInfo.tm_hour;
    }
    if(response_echo()){
      ledcWrite(1,0);
      delay(judge_time);
      if(response_echo()){
        counter++;
        Serial.println(counter);
      }
    }else{
      ledcWrite(1,255);
    }
    delay(100);
  }
}
  • 注意:上記プログラムの一部を書き換える必要があります。

プログラム上部の
ssidWi-FiSSID(名前)
passwordWi-Fiのパスワード
acces_tokenを前章でメモをお勧めしたアクセストーク
channelをSlackの自動投稿してほしいチャンネル名 にそれぞれ書き換えておきましょう。
一つ例としてSSIDを書き換えてみましょう。SSIDhogehogだとしましょう。

const char* ssid = "hogehoge";

こうなります。これと同様にほかの項目も書き換えておきましょう。

プログラムの流れとしては
1. 起動直後はインターネットに接続しドアの初開閉がされるまで待つ
2. 最初の開閉を検知したら投稿
3. 随時開閉を検知してカウントしておく
4. 一時間おきに一時間の開閉回数と一日のその時点までの開閉回数の時間平均を投稿 5. 18時以降はカウントをストップ
6. 日付が変わると同時に再起動を行い起動直後の動作1.に戻る といった内容になっています。

  • 注意:このプログラムは特に作りこんでいないのである程度の動作はしますが、サンプル程度と認識していただきたい。各環境に合わせてプログラムを変える必要があります。このプログラムをそのまま利用する場合や何か問題が起きた場合、自己責任でよろしくお願いします。随時問題が見つかり改善出来次第追記していきたいと考えています。

動作確認

  HaLakeのドアにはこんな感じにおいてみてました。
起動したときはこんな感じに通知されます。 
初開閉から区切りの良い一時間置き(9時、10時、11時のような時間刻みで18時まで)に通知します。
運用はじめはわざと最初の開閉を誤認識させておく必要があります。
次の日の開店時には自動で一日の初開閉を認識するようになります。

まとめ

今回は多様な条件下でも運用できるようにと超音波センサを使って一つの例を紹介しましたが、それぞれの運用条件に合ったセンサを使うことによってもっと効率と精度を上げることが出来ます。
そのため紹介したプログラムは(経験が未熟なことも含め)無駄が多いような気がしますがご了承ください。
ドアノブが鉄などの導体でできているならタッチセンサ、運用場所の周りに人がいることが少なければ開閉でなく人を検知する人感センサ、ドアが頑丈で風などで動かないものならドアの加速度を測る加速度センサなど、開閉を検知できるセンサはたくさんあります。使うものによっては簡単なプログラムでも動くので私のような初心者でも運用ができると思います。長期運用の場合、消費電力なども考慮してプログラムやパーツ選びも重要になってくるので掘り下げてみるのも面白いかもしれません。

コメント

このブログの人気の投稿

Phaser3 + Typescriptを使ってRPGゲームの基礎を作ろう!その2

M5Stackで、においセンサー(TGS2450)を使ってみる。(LCDに表示編)

Phaser3 + Typescriptを使ってRPGゲームの基礎を作ろう!その1