6-2-1.Scratch1.4用ESP32-DevKitC環境構築 インターネットなし
ESP32-DevKitC環境構築
Scratch1.4用にESP32-DevKitC環境構築します。
本ページで利用するスケッチはESP32-DevKitCがインターネットに接続できない環境でも利用できます。
ArduinoIDE環境構築
「ESP32-DevKitC」へスケッチ(プログラム)を書き込みにはArduinoIDEを利用します。
環境が準備できていない方はこちらを参照し構築して下さい。
また、必要なライブラリはこちらになりますので構築できていない方がインストールして下さい。
回路と配線
電子回路と配線図は全センサーが利用できるよう5-4「全センサー実装」を利用します。
【ESP32-DevKitCの入出力端子はこちらを参照下さい】
スケッチ(制御ソフトウェア)
Scrachと接続するための制御ソフトウェアは以下の2つとなります。
(1)SketchESP32Enkaku.ino
(2)irRecvSend.ino
こちら[2019.6.22版]からダウンロードして下さい。
(1)SketchESP32Enkaku.ino
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
// IoT電子工作キット // 6. Scratch遠隔センサー接続用 // ①ライブラリを読み込み #include <WiFi.h> #include <WiFiClient.h> #include <DHT.h> #include <FS.h> #include <SPIFFS.h> // ②環境設定 const char* Host = "192.168.x.x"; //ScratchPCのIPアドレス const int Port = 42001; //ScratchPCのPort番号(変更の必要なし) const char *ssid = "##### SSID #####"; const char *password = "### PASSWORD ###"; // ③ピン配置 const byte LED_PIN = 22; // LED緑 const byte IR_R_PIN = 36; // リモコン受信 const byte IR_S_PIN = 23; // リモコン送信 const byte LIGH_SNR = 39; // 照度センサ(A18) const byte TEMP_SNR = 21; // 温・湿度センサ // ④グローバル変数 bool ledFlag = true; // LED制御フラグ WiFiClient wifiClient; unsigned short irData[1500]; // ⑤SetUp処理(起動時に最初に処理) void setup(void) { // ⑥Serial/Port設定 Serial.begin(115200); Serial.println ( ); pinMode ( LED_PIN, OUTPUT ); pinMode(IR_S_PIN, OUTPUT); pinMode(IR_R_PIN, INPUT); if (!SPIFFS.begin()) { Serial.println(F("SPIFFS Failed")); // Failed mount delay(5000); ESP.restart(); } // ⑦無線Wi-Fi接続 WiFi.begin ( ssid, password ); while ( WiFi.status() != WL_CONNECTED ) { ledFlag = !ledFlag; digitalWrite(LED_PIN, ledFlag); delay ( 1000 ); Serial.print ( "." ); } Serial.print ( "Wi-Fi Connected! IP address: " ); Serial.println ( WiFi.localIP() ); digitalWrite ( LED_PIN, true ); // ⑧ScratchPCに接続(接続されるまでループ) while ( true ) { if (wifiClient.connect(Host, Port)) { Serial.print("Scratch PC Connection Success\n"); break; } else { Serial.print("Scratch PC Connecttion Failed\n"); } delay(1000); } // ⑨Scratch制御「を送る」のプルダウン表示及び、変数利用のためメッセージ送信 sendMessage("broadcast \"LED_ON\" "); sendMessage("broadcast \"LED_OFF\" "); sendMessage("broadcast \"SENSOR_UPDATE\" "); sendMessage("broadcast \"SEND1\" "); sendMessage("broadcast \"SEND2\" "); sendMessage("broadcast \"SEND3\" "); sendMessage("broadcast \"SEND4\" "); sendMessage("broadcast \"SEND5\" "); sendMessage("broadcast \"RECV1\" "); sendMessage("broadcast \"RECV2\" "); sendMessage("broadcast \"RECV3\" "); sendMessage("broadcast \"RECV4\" "); sendMessage("broadcast \"RECV5\" "); sendMessage("sensor-update \"ONDO\" 0 \"SITUDO\" 0 \"SYODO\" -1 "); delay ( 1000 ); } // ⑩ScratchPCにメッセージ送信 void sendMessage(String sMessage){ // ⑪送信メッセージ作成(最初3ByteのLengthなどを追加して作成) char scmd[128] = {0}; strcpy(scmd+4, sMessage.c_str()); // 4Byte目からコピー scmd[3]=(uint8_t)strlen(scmd+4);// 3Byte目はLength if(0!=strlen(scmd+4)) { // Message長が0で無かったら Serial.print("Send message:"); for(uint32_t i = 0; i < 4 + strlen(scmd + 4); i++) { Serial.print(scmd[i]); } Serial.println(); // ⑫メッセージ送信処理 if (wifiClient.write((const uint8_t*)scmd, 4 + strlen(scmd+4))) { Serial.println("Send Message Success"); } else { Serial.println("Send Message Failed"); } } delay(100); } // ⑭loop処理(起動中、繰り返し処理) void loop() { // ⑮メッセージ受信処理(Scratchからのメッセージを受信) uint8_t bufUint[128] = {0}; uint32_t len = wifiClient.readBytes(bufUint, sizeof(bufUint)); if (len > 0) { String rMessage; for(uint32_t i = 4; i < len; i++) { // Length情報を除いて4Byte目から取得 rMessage.concat(String((char)bufUint[i])); } Serial.print("Received:["); Serial.print(rMessage); Serial.print("]\r\n"); // ⑯メッセージ判定処理(受信したメッセージが自端末宛かチェックし処理) if(rMessage.startsWith("broadcast")){ if(rMessage.indexOf("LED") > -1){ if(rMessage.indexOf("ON") > -1){ Serial.println("LED_ON"); digitalWrite ( LED_PIN, true ); } else if(rMessage.indexOf("OFF") > -1){ Serial.println("LED_OFF"); digitalWrite ( LED_PIN, false ); } } else if(rMessage.indexOf("SENSOR_UPDATE") > -1){ Serial.println("SENSOR_UPDATE"); updateSensor(); } else if(rMessage.indexOf("RECV") > -1){ Serial.println("RECV"); digitalWrite ( LED_PIN, false ); setRemocon (getNumStr(rMessage)); digitalWrite ( LED_PIN, true ); } else if(rMessage.indexOf("SEND") > -1){ digitalWrite ( LED_PIN, false ); Serial.println("SEND"); contRemocon (getNumStr(rMessage)); digitalWrite ( LED_PIN, true ); } } } delay(10); } // ⑰センサー情報を送信しデータ更新 void updateSensor(){ DHT dht(TEMP_SNR, DHT11); float g_temperature = dht.readTemperature(); float g_humidity = dht.readHumidity(); unsigned short g_light = analogRead(LIGH_SNR) * 100 / 4095; String messageS = "sensor-update \"ONDO\" " + String(int(g_temperature)) + " \"SITUDO\" " + String(int(g_humidity)) + " \"SYODO\" " + String(g_light); sendMessage(messageS); } // ⑱番号情報のみ取得し返答 String getNumStr(String message) { message.replace("broadcast ", ""); message.replace("_", ""); message.replace("\"", ""); message.replace("SEND", ""); message.replace("RECV", ""); return message; } |
(2)irRecvSend.ino
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
// ①赤外線受信(信号受信 or 30秒間を処理) void setRemocon (String setNumStr) { // ②利用する変数を宣言 unsigned short irCount = 0; // HIGH,LOWの信号数 uint32_t lastt = 0; // 1つ前の経過時間を保持 uint32_t deltt = 0; // 1つ前の経過時間を保持 uint32_t sMilli; // 本処理の開始時間 uint32_t wMilli; // 赤外線の待ち開始時間 uint32_t sMicro; // 処理の開始時間 uint32_t cMicro; // 現在時間 bool rState = 0; // 赤外線受信モジュールの状態 0:LOW,1:HIGH // ③現在の時間をミリ秒で取得 sMilli = millis(); // ④特定条件(信号受信 or 30秒経過)するまで無限ループ while(1) { // ⑤Ir受信を待つ開始時間を取得 wMilli = millis(); // ⑥反転信号の受信待ち while (digitalRead(IR_R_PIN) == rState) { // ⑦待ち始めて0.5秒以上経過したら if (millis() - wMilli > 500) { // ⑧待ち始めて0.5秒以上経過したら if ( irCount > 10 ) { Serial.println(""); Serial.println("recvOK!"); delay(1); // ⑨ボタン名をEEPROMへ、リモコンデータをファイルへ保存 if (saveIr( (irCount - 1), setNumStr )) { // ⑩正常に終了 Serial.println("setRemocon OK"); } else { // ⑪信号受信に失敗 Serial.println("setRemocon NG"); } return; // ⑫正常に完了 } // ⑬0,1信号が10個以上ない場合は雑音のため再度ゼロから受信 irCount = 0; } // ⑭処理が15秒以上経過したらタイムアウト if ( millis() - sMilli > 15000 ) { Serial.println("setRemocon T.O."); return; // ⑮15秒経過で処理終了(受信なし) } } // ⑯信号受信開始時の現在の時間や経過時間を取得 if ( irCount == 0 ) { sMicro = micros(); lastt = 0; irCount++; Serial.print("ir:"); // ⑰信号受信処理開始後の処理(irCountが1以上) } else { // ⑱赤外線受信部の状態変化が最後に変化した時間からの経過時間を計算 cMicro = micros(); deltt = ( (cMicro - sMicro)/ 10 ) - lastt; irData[(irCount - 1 )] = deltt; // ⑲次回経過時間計算のため最後に変化した経過時間を保存 lastt = lastt + deltt; irCount++; Serial.print( deltt ); Serial.print(","); } // ⑳次回While内で状態変化を検知する値を変更 rState = !rState; } } // ㉑ボタン名をEEPROMへ、リモコンデータをファイルへ保存 bool saveIr(unsigned short irLength, String setNumStr){ // ㉒ボタン番号チェック if (setNumStr == "") { return false; } // ㉓リモコン信号を保存するためファイル名を作成(ファイル名はボタン番号) String t_file = "/" + setNumStr; Serial.println( "recvFile:" + t_file); // ㉔ファイルを書き込みモードで開く File fw = SPIFFS.open(t_file.c_str(), "w"); // ㉕リモコン信号の長さを最初に書き込み(最初の行) fw.println( String( irLength, HEX ) ); // ㉖リモコン信号の0,1の時間長さを書き込み(2行目以降) for (int i = 0; i < irLength; i++) { fw.println( String( irData[i], HEX ) ); } // ㉗書き込みが完了したのでファイルを閉じる fw.close(); // ㉘正常に処理が完了したのでtrueを返す return true; } // ㉙赤外線送信処理 bool contRemocon (String setNumStr) { // 送信番号保存 // ㉚変数宣言 unsigned short irCount = 0; // HIGH,LOWの信号数 unsigned long l_now = 0; // 送信開始時間を保持 unsigned long sndt = 0; // 送信開始からの経過時間 // ㉛リモコン信号をファイルから取得(ファイル名はボタン番号) String t_file = "/" + setNumStr; Serial.println( "sendFile:" + t_file); // ㉜ファイルを開く File fr = SPIFFS.open(t_file.c_str(), "r"); // ㉝ファイルを開く if(!fr || fr.isDirectory()){ Serial.println("FileOpen NG"); return false; } // ㉞最初の1行のみ読み出し信号長さ(0,1の数)を取得 String snum = fr.readStringUntil('\n'); // ㉟1行目の文字列を数値型に変換 irCount = strtol(snum.c_str(), NULL, 16); Serial.print( "sendData:" + String(irCount)); // ㊱一旦ファイルから変数irDataに読み出し保存 for (int i = 0; i < irCount; i++) { snum = fr.readStringUntil('\n'); irData[i] = strtol(snum.c_str(), NULL, 16); } fr.close(); // ㊲送信開始時間を取得 l_now = micros(); // ㊳0,1の信号回数分をFor文でループ for (int i = 0; i < irCount; i++) { // ㊴送信開始からの信号終了時間を計算 sndt += irData[i]; do { // ㊵iが偶数なら赤外線ON、奇数ならOFFのまま // キャリア周波数38kHz(約26μSec周期の半分)でON時間で送信 digitalWrite(IR_S_PIN, !(i&1)); microWait(13); // ㊶キャリア周波数38kHz(約26μSec周期の半分)でOFF時間で送信 digitalWrite(IR_S_PIN, 0); microWait(13); // ㊷送信開始からの信号終了時間が超えるまでループ } while (long(l_now + (sndt * 10) - micros()) > 0); } // ㊸正常に終了したので、trueを返答 Serial.println(":End"); return true; } // ㊹マイクロ秒単位で待つ void microWait(signed long waitTime) { unsigned long waitStartMicros = micros(); while (micros() - waitStartMicros < waitTime) {}; } |
環境設定
SketchESP32Enkaku.inoファイル内には以下の設定を実施しESP32-DevKitCにスケッチを書き込みして下さい。
(1)SSIDとパスワードの設定
以下の行を書き換えて自宅の接続するSSIDとパスワードを設定して下さい。
1 2 |
const char *ssid = "##### SSID #####"; const char *password = "### PASSWORD ###"; |
(2)ScratchPCのIPアドレス
以下の行を書き換えてScratchを利用するパソコンのIPアドレスを設定して下さい。
1 |
const char* Host = "192.168.x.x"; //ScratchPCのIPアドレス |
《ScratchパソコンのIPアドレス確認方法》
①左下の「Windowsマーク」と「R」キーを押して、表示された窓に「cmd」を入力しリターン
②コマンドプロンプトに「ipconfig」と入力しIPv4アドレス(ScratchパソコンのIPアドレス)を確認します。