/* WiFi_ESP8266_Socket_Servo_Command_Open_Campus_11_26_V3_debug.ino 2017.12.8 for UEC Open Campus "Micom Hand ..." LED Modulation from Smapho... LCD AQM1602 Akizuki Action command "1"...Goo, "2"...Choki, "3"...Pa- WiFi module WROOM-02(ESP8266) aitendo web ref. https://www.mgo-tec.com/blog-entry-websocket-wroom03.html http://www.geocities.jp/mtakapii/ */ #include #include #include #include #include "ESP8266WiFi.h" #define ADDR 0x3e #define C_Low 0x70 #define C_High 0x56 // 0x5c? #define AQM1602 #ifdef AQM1602 #define Cont 5 // Contrast AQM1602 Akizuki #else #define Cont 10 // Contrast 1602D1 Strawberry #endif /* ========= Trans Smapho http server ========= */ #define BUZZER 16 //#define debug // when debug ==> enable #define Office //#define Private //#define Home #ifdef Office #define WIFI_SSID "AirPortxxxxxx" #define WIFI_PSK "xxxxxxxxxxxxx" // Office #define local_ip "xxxxxxxxxx" #endif #ifdef Private #define WIFI_SSID "W01_xxxxxxxxxxxxxx" // 0 ==> O (Oh---) #define WIFI_PSK "xxxxxxxxxxxxxxxx" // Private #define local_ip "xxxxxxxxxxxxxxxx"; //const char* LocalIPaddress = "xxxxxxxxxxxxxx"; #endif #ifdef Home #define WIFI_SSID "xxxxxxxxxxxxx" // #define WIFI_PSK "xxxxxxxxxxxxx" // Home #define local_ip "192.168.xxxxxx"; //const char* LocalIPaddress = "xxxxxxxxxx"; #endif const char* LocalIPaddress = local_ip; #define DEST_HOST "api.fixer.io" #define DEST_PORT 80 #define DEST_URL "/latest?base=USD&symbols=JPY" const char* ssid ; const char* password ; boolean Ini_html_on = false; Servo servo;//サーボのインスタンス //ブラウザからの初回HTTPレスポンス完了したかどうかのフラグ boolean WS_on = false;//WebSocket設定が済んだかどうかのフラグ WiFiServer server(80); char Android_or_iPad; //スマホが Android か iPad かを判定するフラグ //WiFiClient client; //LED点灯用ピンアサイン GPIO 13 #define ledPin 13 //通信トラフィックをオーバーフローを起こさせないようにする変数。 //ミリセコンド単位でスマホからのスライダー値送信を間引く byte s_rate = 10; uint8_t cmd_cr[] = {0xc0}; // C/R uint8_t cmd_cl[] = {0x01}; // CLear Display int ID0 = 0; // = ID0 void setup() { uint8_t cmd_init1[] = {0x38, 0x39, 0x14}; uint8_t cmd_init2[] = {C_Low | (Cont & 0x0f), C_High | (Cont >> 4 & 3), 0x6c}; uint8_t cmd_init3[] = {0x38, 0x0d, 0x01}; // 0x0d => 0x0c ? //uint8_t mess_setup_done[] = "Setup done"; //uint8_t mess_select_APInten[] = "ON=AP, OFF=Inten"; uint8_t mess_start_server[] = "start HTT Server"; uint8_t mess_WiFi_connected[] = "WiFi connected "; uint8_t mess_Web_Socket_Test[] = "Web Socket Test"; uint8_t message[] = " "; uint8_t mess_point[] = {0x2e}; servo.attach(5); pinMode(BUZZER, OUTPUT); digitalWrite(BUZZER, LOW); pinMode(ID0, INPUT); // Serial.begin(115200); Serial.begin(38400); delay(10); //Wire.begin(4, 14); Wire.begin(4, 12); delay(40); // LCD Initialize LCD_command(cmd_init1, sizeof(cmd_init1)); LCD_command(cmd_init2, sizeof(cmd_init2)); delay(300); LCD_command(cmd_init3, sizeof(cmd_init3)); delay(1000); LCD_clear(); LCD_write(mess_Web_Socket_Test, sizeof(mess_Web_Socket_Test)); LCD_CR_LF(); ssid = WIFI_SSID; password = WIFI_PSK; WiFi.begin(ssid, password); #ifdef debug Serial.println(); Serial.println("Web socket '17324"); Serial.print("ssid==>"); Serial.println(ssid); Serial.print("KEY ==>"); Serial.println(password); Serial.print(" ==>"); Serial.println(LocalIPaddress); #endif int l_ep = 200; // End Point of Left int r_ep = 0; // End Point of Right int offset = 0; int delay_servo = 20 ; int step_servo = 6 ; int speed_servo = 20; servo.write( 90 + offset); // set zero position delay(1000); for (int i = 90 + offset ; i < l_ep;) { // Turn Left servo.write(i + offset); delay(delay_servo); i += step_servo; delay(speed_servo); } delay(1000); for (int i = l_ep; i > r_ep;) { // Turn Right servo.write(i + offset); delay(delay_servo); i -= step_servo; delay(speed_servo); } delay(1000); servo.write(90 + offset); delay(500); while (WiFi.status() != WL_CONNECTED) { delay(500); #ifdef debug Serial.print("."); #endif LCD_write(mess_point, sizeof(mess_point)); } #ifdef debug Serial.println(""); Serial.println("WiFi connected "); #endif LCD_clear(); LCD_write(mess_WiFi_connected, sizeof(mess_WiFi_connected)); server.begin(); #ifdef debug Serial.println("Websocket started ! "); Serial.println(WiFi.localIP()); #endif uint8_t ssid_[] = WIFI_SSID; uint8_t passwprd_[] = WIFI_PSK; uint8_t Set_ipadr_[] = "Set IP address "; uint8_t Get_ipadr_[] = "Get IP address "; uint8_t local_ip_address[] = local_ip; char s1[4], s2[4], s3[4], s4[4]; //char s[16]; int i; LCD_write(ssid_, sizeof(ssid_)); delay(2000); IPAddress ipadr = WiFi.localIP(); LCD_clear(); LCD_write(Set_ipadr_, sizeof(Set_ipadr_)); LCD_CR_LF(); LCD_write(local_ip_address, sizeof(local_ip_address)); delay(2000); LCD_clear(); LCD_write(Get_ipadr_, sizeof(Get_ipadr_)); LCD_CR_LF(); dtostrf(ipadr[0], 3, 0, s1); dtostrf(ipadr[1], 3, 0, s2); dtostrf(ipadr[2], 3, 0, s3); dtostrf(ipadr[3], 3, 0, s4); LCD_write_char(s1, sizeof(s1)); LCD_write_char(s2, sizeof(s2)); LCD_write_char(s3, sizeof(s3)); LCD_write_char(s4, sizeof(s4)); delay(2000); //HTTP_server(); } char pre_comannd; void loop() { LCD_CR_LF(); if (Ini_html_on == false) { pre_comannd = 0; Ini_HTTP_Response(); } if (Ini_html_on == true && WS_on == false) { WS_HTTP_Responce(); } delay(1);//これは重要かも。これがないと動作しないかも。 wdt_reset(); // mtakapii 2017.3.24 } //*****初回ブラウザからのGET要求によるJavaScript吐き出しHTTPレスポンス** ***** void Ini_HTTP_Response() { WiFiClient client = server.available();//クライアント生成は各関数内で しか実行できないので注意 String req; while (client) { req = client.readStringUntil('¥n'); #ifdef debug Serial.println(req); #endif if (req.indexOf("GET / HTTP") != -1) { //ブラウザからリクエストを受 信したらこの文字列を検知する #ifdef debug Serial.println("-----from Browser FirstTime HTTP Request---------") ; Serial.println(req); //ブラウザからのリクエストで空行(¥r¥nが先頭になる)まで読み込む #endif while (req.indexOf("¥r") != 0) { req = client.readStringUntil('¥n');//¥nまで読み込むが¥n自身は文 字列に含まれず、捨てられる //ここでブラウザがChromeかSafariかをリクエスト文字列から判定 if (req.indexOf("Android") != -1) { Android_or_iPad = 'A'; } else if (req.indexOf("iPad") != -1) { Android_or_iPad = 'i'; } #ifdef debug Serial.println(req); #endif } req = ""; delay(10);//10ms待ってレスポンスをブラウザに送信 //メモリ節約のため、Fマクロで文字列を囲う //普通のHTTPレスポンスヘッダ client.print(F("HTTP/1.1 200 OK¥r¥n")); client.print(F("Content-Type:text/html¥r¥n")); client.print(F("Connection:close¥r¥n¥r¥n"));//1行空行が必要 //ここからブラウザ表示のためのHTML JavaScript吐き出し client.println(F("")); client.println(F("")); client.println(F("")); client.println(F("")); client.println(F("WebSocket Test")); client.println(F("")); client.println(F("")); client.println(F("

ESP-WROOM-02( ESP8266)
")); // client.println(F("WebSocket Test

")); client.println(F("WebSocket Test for Micom Hand")); // 2017.7.20 mtakapii client.println(F("from WROOM DATA = ")); client.println(F("")); client.println(F(""));//改行しない場合はを使う client.println(F("
JS-innerHTML=")); client.println(F("")); // client.println(F("

LED dimming ")); client.println(F("

Micom Hand Command ")); // 2017.7.20 mtakapii client.println(F("

Goo Choki Pa--- ")); // 2017. 7.20 mtakapii client.println(F("")); client.println(F("


")); client.println(F("

")); client.println(F("")); // client.println(F("
")); client.println(F("
")); // 2017.7.20 mtakapii client.println(F("¥r¥n")); delay(1);//これが重要!これが無いと切断できないかもしれない。 wdt_reset(); client.stop();//一旦ブラウザとコネクション切断する。 delay(1); #ifdef debug Serial.println("¥nGET HTTP client stop--------------------"); #endif req = ""; //スマホがiPadならばループを抜け出す if (Android_or_iPad == 'i') { Ini_html_on = true; //初回HTTPレスポンス終わったら trueにする。 break; } } else if (req.indexOf("favicon") != -1) { //ChromeはGetリクエストの直ぐ後のfaviconを投げかけてくるところの対 処 #ifdef debug Serial.println(); Serial.println("******GET favicon Request************"); Serial.print(req); #endif while (client.available()) { //ブラウザからデータが送られている間読み込む Serial.write(client.read()); } delay(1); client.stop(); //GET/faviconでも一旦ブラウザとコネクション切断す る必要あり。 delay(1); #ifdef debug Serial.println(); Serial.println("Client Stop--------------"); #endif Ini_html_on = true; //HTTPレスポンス終わったらtrueにする。 break; } } } //************HTTPレスポンスとデータ送受信関数************************** void WS_HTTP_Responce() { WiFiClient client = server.available();//クライアント生成は各関数内で しか実行できないので注意 String req; String hash_req_key; while (client) { req = client.readStringUntil('¥n'); #ifdef debug Serial.println(req); #endif if (req.indexOf("websocket") != -1) { //ブラウザからリクエストを受信 したらこの文字列を検知する #ifdef debug Serial.println("-----from Browser HTTP WebSocket Request---------") ; Serial.println(req); //ブラウザからのリクエストで空行(¥r¥nが先頭になる)まで読み込む #endif while (req.indexOf("¥r") != 0) { req = client.readStringUntil('¥n');//¥nまで読み込むが¥n自身は文 字列に含まれず、捨てられる #ifdef debug Serial.println(req); #endif if (req.indexOf("Sec-WebSocket-Key") >= 0) { hash_req_key = req.substring(req.indexOf(':') + 2, req.indexOf ('¥r')); #ifdef debug Serial.println(); Serial.print("hash_req_key ="); Serial.println(hash_req_key); #endif } } delay(10); req = ""; char h_resp_key[28]; //ハッシュ値、BASE64エンコード関数 Hash_Key(hash_req_key, h_resp_key); #ifdef debug Serial.print("h_resp_key = "); Serial.println(h_resp_key); #endif String str; //-------ここからHTTPレスポンスのHTMLとJavaScriptコード str = "HTTP/1.1 101 Switching Protocols¥r¥n"; str += "Upgrade: websocket¥r¥n"; str += "Connection: Upgrade¥r¥n"; str += "Sec-WebSocket-Accept: "; for (byte i = 0; i < 28; i++) { str += h_resp_key[i]; } //"Sec-WebSocket-Protocol: chat¥r¥n";これは不要。これを入れるとコ ネクションできない。 str += "¥r¥n¥r¥n";//空行は必須 #ifdef debug Serial.println("-----HTTP Respons start-------"); Serial.println(str); #endif client.print(str); str = ""; WS_on = true;//WebSocket 設定終了フラグ } else if (req.indexOf("favicon") != -1) { //Chromeでfaviconを2回連続で投げてきた時の対処 #ifdef debug Serial.println(); Serial.println("******GET favicon Request************"); Serial.print(req); #endif while (client.available()) { //ブラウザからデータが送られている間読み込む Serial.write(client.read()); } delay(1); client.stop(); //GET/faviconでも一旦ブラウザとコネクション切断す る必要あり。 delay(1); #ifdef debug Serial.println(); Serial.println("Client Stop--------------"); #endif Ini_html_on = true; //HTTPレスポンス終わったらtrueにする。 break; } delay(10); //ここからWebSocketデータ送受信。 if (WS_on == true) { byte b = 0; byte data_len; byte mask[4]; byte data_b; byte i; byte cnt = 0; long PingLastTime = millis(); long PongLastTime = millis(); long CountTestTime = millis(); uint8_t LED_Inten[] = " "; while (client) { //ブラウザがping受信して1秒後までにPongを受信しない場合、コネク ション切断する。 if (millis() - PongLastTime > 4000) break; // 2017.7.20 mtakapii //データ受信が無い時に3sec毎にping送信----------------------- if (millis() - PingLastTime > 3000) { client.write(B10001001); client.write(4); client.print("Ping"); //ブラウザにPing送信すると送信した文字そのものが返って来る。 #ifdef debug Serial.println("Ping Send-----------"); #endif PingLastTime = millis(); } //WROOMのカウンター数値を300ms毎にブラウザに送信 //あまり秒数が短いとエラーになりクローズするので注意 //if (millis() - CountTestTime > 300) { if (millis() - CountTestTime > 300) { // 2017.7.20 mtakapii client.write(B10000001);//データ送信ヘッダ client.write(1);//送信文字数 if (cnt > 9) { cnt = 0; } client.print(cnt); cnt++; CountTestTime = millis(); } if (client.available()) { b = client.read(); if (b == B10000001 || b == B10001010) { //B10001010はPongデータ受信 switch (b) { case B10000001: //ブラウザからデータ受信している時はPing送信しないように する。 PingLastTime = millis(); PongLastTime = millis(); break; case B10001010: PongLastTime = millis(); #ifdef debug Serial.println("Pong Receive**********"); #endif break; } b = client.read(); //マスクビットを削除 data_len = b - B10000000; //マスクキーを読み込む for (i = 0; i < 4; i++) { mask[i] = client.read(); } byte m_data[data_len]; char data_c[data_len]; #ifdef debug Serial.print("Receive Data = "); #endif for (i = 0; i < data_len; i++) { //マスクされたデータを読み込む m_data[i] = client.read(); //マスクキーとマスクデータをXOR演算すると実テキストデータ が得られる data_c[i] = mask[i % 4] ^ m_data[i]; #ifdef debug Serial.print(data_c[i]); #endif } #ifdef debug Serial.println(); #endif //テキストデータを数値に変換 switch (data_len) { case 1: data_b = data_c[0] - 0x30; //Char型を数値に変換 break; case 2: data_b = ((data_c[0] - 0x30) * 10) + (data_c[1] - 0x30); break; case 3: data_b = ((data_c[0] - 0x30) * 100) + ((data_c[1] - 0x30) * 10) + (data_c[2] - 0x30); break; } // ********** mtakapii 2017.3.15 ********** // ********** mtakapii 2017.7.19 ********** //LCD_CR_LF(); //for (int cntr = 0; cntr < 16; cntr++) { // LCD_space(); //} //LCD_CR_LF(); //for (int cntr = 0; cntr < 2; cntr++) { // LED_Inten[cntr] = data_c[cntr]; //} //write(LED_Inten, sizeof(LED_Inten) - 1); // // 0 < data_b < 100 // LED_analog(data_b); //LED analog 点灯関数 uint8_t micom_hand[] = " "; servo.write(data_b * 1.8); //0~180まで if ( 0 < data_b && data_b < 33) { micom_hand[0] = {0x31}; } if ( 33 < data_b && data_b < 66) { micom_hand[0] = {0x32}; } if ( 66 < data_b && data_b < 100) { micom_hand[0] = {0x33}; } LCD_write(micom_hand, sizeof(micom_hand)); LCD_space(); if (micom_hand[0] != pre_comannd) { Serial.println(char(micom_hand[0])); pre_comannd = micom_hand[0]; } // ***************************************** } else if (b == B10001000) { delay(1); client.write(B10001000); delay(1); #ifdef debug Serial.println("Close Send------------"); Serial.println(b, BIN); #endif break; } } delay(15); // mtakapii } delay(1); client.stop(); delay(1); #ifdef debug Serial.println(); Serial.println("Client.STOP-----------------"); #endif WS_on = false; Ini_html_on = false; break; } } } //************ハッシュ値、BASE64エンコード関数************************** void Hash_Key(String h_req_key, char* h_resp_key) { char Base64[65] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '=' }; byte hash_six[27]; byte dummy_h1, dummy_h2; byte bb; byte i, j; i = 0; j = 0; String GUID_str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; String merge_str; merge_str = h_req_key + GUID_str; #ifdef debug Serial.println(); Serial.print("merge_str ="); Serial.println(merge_str); Serial.print("SHA1:"); Serial.println(sha1(merge_str)); #endif byte hash[20]; sha1(merge_str, &hash[0]); #ifdef debug Serial.print("SHA1:"); for (uint16_t i = 0; i < 20; i++) { Serial.printf("%02x", hash[i]); Serial.print("-"); } Serial.println(); Serial.print("SHA1:"); for (uint16_t i = 0; i < 20; i++) { Serial.print(hash[i], BIN); Serial.print("-"); } Serial.println(); #endif for ( i = 0; i < 20; i++) { hash_six[j] = hash[i] >> 2; hash_six[j + 1] = hash[i + 1] >> 4; bitWrite(hash_six[j + 1], 4, bitRead(hash[i], 0)); bitWrite(hash_six[j + 1], 5, bitRead(hash[i], 1)); if (j + 2 < 26) { hash_six[j + 2] = hash[i + 2] >> 6; bitWrite(hash_six[j + 2], 2, bitRead(hash[i + 1], 0)); bitWrite(hash_six[j + 2], 3, bitRead(hash[i + 1], 1)); bitWrite(hash_six[j + 2], 4, bitRead(hash[i + 1], 2)); bitWrite(hash_six[j + 2], 5, bitRead(hash[i + 1], 3)); } else if (j + 2 == 26) { dummy_h1 = 0; dummy_h2 = 0; dummy_h2 = hash[i + 1] << 4; dummy_h2 = dummy_h2 >> 2; hash_six[j + 2] = dummy_h1 | dummy_h2; } if ( j + 3 < 27 ) { hash_six[j + 3] = hash[i + 2]; bitWrite(hash_six[j + 3], 6, 0); bitWrite(hash_six[j + 3], 7, 0); } else if (j + 3 == 27) { hash_six[j + 3] = '='; } h_resp_key[j] = Base64[hash_six[j]]; h_resp_key[j + 1] = Base64[hash_six[j + 1]]; h_resp_key[j + 2] = Base64[hash_six[j + 2]]; if (j + 3 == 27) { h_resp_key[j + 3] = Base64[64]; break; } else { h_resp_key[j + 3] = Base64[hash_six[j + 3]]; } i = i + 2; j = j + 4; } #ifdef debug Serial.print("hash_six = "); for (i = 0; i < 28; i++) { Serial.print(hash_six[i], BIN); Serial.print('_'); } Serial.println(); #endif } // 2017.3..---7.. mtakapii //************ LED_analog 出力関数 ************************** void LED_analog(byte data_b) { //analogWriteは 0-255 の値。 //analogWrite(ledPin, data_b * 2.5); analogWrite(ledPin, data_b * 10 - 50); // R=820 ohm } //************LCD制御関数************************** void LCD_space() { uint8_t LED_space[] = {0x20}; LCD_write(LED_space, sizeof(LED_space)); } void LCD_CR_LF() { LCD_command(cmd_cr, sizeof(cmd_cr)); delay(10); } void LCD_clear() { LCD_command(cmd_cl, sizeof(cmd_cl)); delay(10); } void LCD_command(uint8_t *cmd, size_t len) { size_t i; for (i = 0; i < len; i++) { Wire.beginTransmission(ADDR); delayMicroseconds(30); Wire.write(0x00); Wire.write(cmd[i]); delayMicroseconds(30); Wire.endTransmission(); delayMicroseconds(30); // 26.3us } } void LCD_write(uint8_t *cmd, size_t len) { size_t i; for (i = 0; i < len; i++) { Wire.beginTransmission(ADDR); delayMicroseconds(30); Wire.write(0x40); delayMicroseconds(30); Wire.write(cmd[i]); delayMicroseconds(30); Wire.endTransmission(); delayMicroseconds(30); // 26.3us } delay(1); } void LCD_write_char(char *cmd, size_t len) { int i; for (i = 0; i < len; i++) { Wire.beginTransmission(ADDR); delayMicroseconds(30); Wire.write(0x40); delayMicroseconds(30); Wire.write(cmd[i]); delayMicroseconds(30); Wire.endTransmission(); delayMicroseconds(30); // 26.3us } delay(1); }