PR

iPhoneで自作スマートロック。ESP32をスマホで操作

スポンサーリンク
iPhoneで自作スマートロック。ESP32をスマホで操作 3Dプリンター
記事内に広告が含まれています。
スポンサーリンク

今回はESP32を使ってガレージのシャッターを開閉するスマートロックを自作しました。

製作費用は2000円と激安でアルディーノのプログラムを少し勉強すれば誰でも作ることが可能です。

配線方法やサーボモーター動作原理、プログラムの解説も行っています。

ぜひ、最後までご覧ください。

スポンサーリンク

ESP32で自作スマートロックの製作理由

ESP32で自作スマートロックの製作理由

スマートロックを作った理由はガレージのリモコンを持ち歩くのが嫌だったからです。

ガレージのシャッターは電動で専用のリモコンで操作します。

バイクに乗る時はリモコンも一緒に持ち歩かないといけないので荷物が増えます。

荷物が増えると紛失の可能性も高くなるので、スマホからwifi経由で操作できるようにしてみました。

ESP32で自作スマートロック 準備したもの

ESP32で自作スマートロック 準備したもの

まずはスマートロックを自作するために用意したものを紹介します。

ESP32のマイコンモジュール

これはAmazonで800円ほどで売っています。

Arudinoのプログラム編集ソフトで、プログラムが編集できます。

さらにwifiとBluetoothのモジュールも入っています。

今回はESP32のwifiの機能を使ってスマホから操作できるようにしました。

SG90サーボモーター

ESP32の指令に対して動作するのはSG90のサーボモーターです。

これもAmazonで500円くらいで手に入ります。

動作用のアームも付属品を使います。単体で買うと入っていない可能性もあるので注意が必要です。

ちなみにこれはArudino勉強用に買ったセットに付属していたモーターです。

ジャンパー線

モーターとESP32を接続するための配線です。

ハンダつけをすれば必要ないですが、今後バージョンアップする可能性もあるため今回はジャンパー線で接続します。

ESP32、サーボモーター自作ホルダー

ESP32、サーボモーター自作ホルダー

サーボモーターとESP32を固定するためにホルダーを3Dプリンターで自作しました。

両面テープで固定する予定ですが、これは見栄えとしっかりと固定するために出来るだけシンプルに作りました。

なお、直接貼り付けできればこれは要らないです。

最後にスマホです。

最後にスマホです。

ESP32 スマートロックの配線図

ESP32 スマートロックの配線図

それでは早速、作っていきます。

まずは配線です。

配線は非常にシンプルです。

ESP32のP18番にサーボモーターのオレンジ色のPWM線を接続します。

ESP32の3.3V(一番上のオレンジ)にサーボモーターの赤色の電源を接続。

ESP32のGND(一番上の黒)にサーボモーターの茶色マイナスを接続します。

これで完成です。

ESP32 スマートロックのアルディーノプログラム

実際に作ったプログラムがこちらです。

//アクセスするときはURLパラメーターの最後に&をつける。
    #include <WiFi.h>
     
    // 使用するWi-Fiとそのパスワードに書き換えてください
    const char* ssid     = "**********";
    const char* password = "***********";
     
    // ポート80番を使用
    WiFiServer server(80);
     
    // HTTPリクエストを格納する変数
    String header;
     
    // 値の設定に使用する変数
    String valueString = String(5);
    String delay_valueString = String(500);
    int pos1 = 0;
    int pos2 = 0;
     
    //pin
    const int servo_pin = 18;

  
     
    //サーボモーターの回転角
    //-90° 0.5ms  パルス0.5ms*1024(10ビットの値)/20ms=25.6
    //0°   1.45ms  パルス1.45ms*1024(10ビットの値)/20ms=74.24
    //90°  1.45ms  パルス2.4ms*1024(10ビットの値)/20ms=122.88
     
    const int servo_left   = 26;

    const int servo_center = 74;

    const int servo_right  = 123;

     

     
    void setup() {

     //シリアル通信開始
      Serial.begin(115200);

         //ledc setting
      ledcSetup(0, 50, 10);  // 0ch 50 Hz 10bit PWMの範囲は0~1023
      ledcAttachPin(servo_pin,0);  // 18pin, 0ch
      
      
      // Wi-Fiに接続
      Serial.print("Connecting to ");
      Serial.println(ssid);
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      // ローカルIPを表示(このIPにスマホなどからアクセスします)
      Serial.println("");
      Serial.println("WiFi connected.");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      server.begin();
    }
     
    void loop(){
      WiFiClient client = server.available();   // Listen for incoming clients
     
      if (client) {                             // If a new client connects,
        Serial.println("New Client.");          // print a message out in the serial port
        String currentLine = "";                // make a String to hold incoming data from the client
        while (client.connected()) {            // loop while the client's connected
          if (client.available()) {             // if there's bytes to read from the client,
            char c = client.read();             // read a byte, then
            Serial.write(c);                    // print it out the serial monitor
            header += c;
            if (c == '\n') {                    // if the byte is a newline character
              // if the current line is blank, you got two newline characters in a row.
              // that's the end of the client HTTP request, so send a response:
              if (currentLine.length() == 0) {
                // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
                // and a content-type so the client knows what's coming, then a blank line:
                client.println("HTTP/1.1 200 OK");
                client.println("Content-type:text/html");
                client.println("Connection: close");
                client.println();
                
     
                // Display the HTML web page
                client.println("<!DOCTYPE html><html>");
                client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" http-equiv=\"content-type\" charset=\"utf-8\"><title>ガレージの開閉</title>");
     
                // CSS to style the on/off buttons 
                // Feel free to change the background-color and font-size attributes to fit your preferences
                client.println("<style>body{ text-align: center;}");
                client.println(".btn{display: inline-block; width: 300px; height: 100px; text-decoration: none; background: #668ad8; color: #FFF; border-bottom: solid 4px #627295; border-radius: 3px; font-size: 30px;}");
                client.println(".btn:active {-webkit-transform: translateY(4px); transform: translateY(4px);  box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.2);  border-bottom: none;}");
                client.println("</style>");
                client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");
                
                // Web Page
                client.println("</head><body style='text-align: center;'><h1>ガレージのシャッター</h1>");
                //servo slide bar
                client.println("<div class='left block'> <a href='http://***.***.***/?angle=50&delay=500&'><button id='entrance_button' class='btn' type='button'>OPEN</button></a></div><p></p>");          
                client.println("<div class='right block'><a href='http://***.****.****/?angle=100&delay=500&'><button id='room_button' class='btn' type='button'>CLOSE</button></a></div>");
                client.println("</body></html>");     
     
     
                //HTTPリクエストの処理部分
                delay_valueString = "500";
                pos1 = header.indexOf('=',18);
                pos2 = header.indexOf('&',18);
                if(pos1!=-1 && pos2!=-1) {
                  delay_valueString = header.substring(pos1+1, pos2);
                  Serial.print("pos:");
                  Serial.println(pos1);
                  Serial.println(pos2);
     
                } else {
                  Serial.print("defaultサーボ待機時間:");
                  Serial.println(delay_valueString.toInt());
                }
                Serial.print("サーボ待機時間:");
                Serial.println(delay_valueString.toInt());
     
                
                pos1 = header.indexOf('=');
                pos2 = header.indexOf('&');
                valueString = header.substring(pos1+1, pos2);
                Serial.print("URLパラメーター:");
                Serial.println(valueString);
     
     
                if(valueString.toInt()>=26 && valueString.toInt()<=123) {
                 
                  //サーボモーターを回転
                  digitalWrite(4, HIGH);
                  delay(50);
                  digitalWrite(4, LOW);
     
                  
                  ledcWrite(0, servo_center);
                  delay(delay_valueString.toInt());
                  ledcWrite(0, valueString.toInt());
                  delay(delay_valueString.toInt());
                  ledcWrite(0, servo_center);
                  // バグ防止
                  delay(delay_valueString.toInt());
                  ledcWrite(0, 0);
                  
                  digitalWrite(4, HIGH);
                  delay(50);
                  digitalWrite(4, LOW);
                 
                  
                } else {
                  Serial.println("URLパラメーター エラー!");
                }
                
     
                // HTTPレスポンスの終了
                client.println();
                // Break out of the while loop
                break;
              } else {
                currentLine = "";
              }
            } else if (c != '\r') {
              currentLine += c;
            }
          }
        }
        // Clear the header variable
        header = "";
        // 接続を切断
        client.stop();
        Serial.println("Client disconnected.");
        Serial.println("");
      }
    }

プログラムを0からプログラムを作るには初心者にはハードルが高いです。

自分は初心者なので、まずは人が作ったプログラムを丸コピーして、アレンジしたいところのコードを調べながら追加と修正をしました。

ESP32でWifiの接続

ESP32をwifiに接続するためには無線LANのssidとパスワードが必要です。

こちらは無線LANの本体に記載されているのであらかじめ控えておき、プログラムに入力します。

ESP32でWifiの接続

プログラムのconst char*にwifiのssidとパスワードを入力。

ESP32でサーボモーター

ESP32でサーボモーター

サーボPINは18番にサーボの信号線を接続します。

サーボ角度の変更ですが、-OPENで-90度、COLSEで90度動くように設定

サーボ角度の変更ですが、-OPENで-90度、COLSEで90度動くように設定しています。

もし角度を変更したい場合は、26や123の数字を変更します。

26、123の数字はどっから出てきたのか?

少し詳しく解説していきます。

Void setup内にledSetup関数で、pwmの設定

まずはプログラムで角度を指令するために Void setup内にledSetup関数で、pwmの設定をします。

ledSetup関数

左の0がチャンネルの設定

真ん中の50が周波数の設定。ここではサーボの周期が50HZなので50に設定。

右の10が解像度の設定。今回は10bitに設定。10^10なのでPWMの範囲は0から1023になります。

ledcAttachPin関数

次にledcAttachPin関数で、先ほどのチャンネルのピン番号を設定します。

今回はピン番号18に設定しました。

サーボモーターのPWM制御

サーボモーターのPWM制御

いよいよ本題です。

これはSG90のデータシートです。

サーボへの信号はデジタル信号です。

デジタル信号はONとOFFしか出力することができません。

ONの時間を調整することでモーターの回転角度を制御することができます。

これがデューティーサイクルですね。

SG90のサーボモーターの場合、PWMの周期は50HZ。秒に換算すると20msです。

-90°に回転する場合は次のようになります。

パルスが0.5msの時に-90度サーボが動きます。

パルスとは1周期に対するONが締める時間の割合。

パルス0.5(mmsec)×10(ビットの値は1024)÷20(mmsec)=25.6

同じように計算することで、0°は75、+90°は123になります。

26から123の間の数字を変えると任意の角度に変わります。

ESP32のウェブページのデザインを変更する

ウェブページのボタンの配置やデザインはclient.println関数でHTMLとCSSでデザインしました。

ウェブページのタイトル

ウェブページのタイトルを変更したい場合はh1タグの中身を変更します。

ボタンの表示はリンク内の中身を変更

ボタンの表示はリンク内の中身を変更します。

ESP32のプログラムの書き込み

ESP32のプログラムの書き込み

プログラムが出来たら検証(コンパイル)を押してプログラムに間違いがないか確認します。

検証が出来たらESP32とパソコンをつないで、プログラムを書き込みします。

ここでひとつ注意が必要です。

マイクロUSBが安物だとパソコンがESP32を認識してくれませんでした。

もし認識しない場合はスマホの純正ケーブルを使うなど通信ができるケーブルに変更します。

書き込み中も通信がCONNECTING中と表示がでたらESP32のブートボタンを押し続けます。

これしないと書き込みができません。

書き込みが出来たらツールのシリアルモニターからIPアドレス

書き込みが出来たらツールのシリアルモニターからIPアドレスをメモします。

メニューの「ツール」→「シリアルモニタ」からシリアルモニターを開きます。

表示されていない場合は、ESP32をリセットします。

文字化けしている場合は、右下のbpsを115200に変更してみます。

このIPアドレスがウェブページのURLになります。

スマホのブラウザからIPアドレス入力するとシャッター開閉ページが表示されるはずです。

iPhoneで自作スマートロック動作確認

iPhoneで自作スマートロック動作確認

まずは机上で動作確認します。

動きに問題がないことが確認できたら、いよいよガレージに取り付けします。

ガレージに取り付け

給電は100V電源からUSBケーブルで確保。

取り付けはすべて両面テープで取り付けです。

両面テープは3Mの両面テープが強力でおすすめ!!

スマホから遠隔操作

無事にスマホから遠隔操作することができました。

【動画】iPhoneで自作スマートロック。ESP32をスマホで操作

コメント

タイトルとURLをコピーしました