2016年8月3日 星期三

利用網頁控制 Arduino (四) : 使用 Radio

晚上寫完 "利用網頁控制 Arduino (三)" 後, 在趙英傑寫的 "超圖解 Arduino 互動設計入門 2" 這本書的 16-3 節看到用 Radio 元素做 ON/OFF 介面的呈現方式, 在此做個補充測試, 也趁這個機會複習一下網頁設計.

測試 1 :

#include <SoftwareSerial.h>
#define DEBUG true

SoftwareSerial esp8266(7,8); //(RX,TX)
const String ssid="EDIMAX-tony";
const String pwd="1234567890";
const int MAX_PAGE_NAME_LEN=8;  //buffer size
char buffer[MAX_PAGE_NAME_LEN + 1]; //store page_name

void setup() {
  Serial.begin(9600);
  esp8266.begin(9600);
  sendData(F("AT+RST\r\n"),2000,DEBUG); // reset ESP8266
  sendData(F("AT+CWMODE=1\r\n"),1000,DEBUG); //configure as station
  sendData(F("AT+CIPMUX=1\r\n"),1000,DEBUG); //enable multiple connections
  sendData(F("AT+CIPSERVER=1,80\r\n"),2000,DEBUG); //turn on server 80 port
  while (!connectWifi(ssid, pwd)) {
    Serial.println(F("Connecting WiFi ... failed"));
    delay(2000);
    }
  sendData(F("AT+GMR\r\n"),1000,DEBUG);
  delay(3000); //wait for wifi connection to get local ip
  sendData(F("AT+CIFSR\r\n"),1000,DEBUG); //get ip address
  }

void loop() {
  if (esp8266.available()) { // check if esp8266 is sending message
    if (esp8266.find("+IPD,")) {
      delay(1000); //waiting for response: 0,234:GET /?pinD2=1
      int connectionId=esp8266.read()-48;  //turn ASCII to number
      bool on=false;
      if (esp8266.find("GET /?pin")) { //retrieve page name (router)
        char type=(char)esp8266.read(); //read char after ?pin
        int pin=esp8266.parseInt(); //get first int number from serial
        int val=esp8266.parseInt(); //get first int number from serial
        if (val==1) {on=true;}
        if (type=='D') { //update output status
          Serial.print(F("Digital pin "));
          Serial.print(pin);
          Serial.print(F(" is changed to "));
          Serial.println(val);          
          pinMode(pin, OUTPUT); //set pin as ouput
          digitalWrite(pin, val);
          }
        }
      String webpage=F("<html><body>");
      webpage += F("<h3>Click update button to turn D2 pin ON or OFF</h3>");
      webpage += F("<form action='/' method='GET'>"); 
      webpage += F("<input type='radio' name='pinD2' value='1'"); 
      if (digitalRead(2)) {webpage += F(" checked>");}
      else {webpage += F(">");}
      webpage += F("ON");
      webpage += F("<input type='radio' name='pinD2' value='0'");
      if (digitalRead(2)) {webpage += F(">");}
      else {webpage += F(" checked>");}  
      webpage += F("OFF");    
      webpage += F(" State : "); 
      if (digitalRead(2) == HIGH) {webpage += F(" ON");}
      else if (digitalRead(2) == LOW) {webpage += F(" OFF");}
      webpage += F(" <input type='submit' value='Update'>");
      webpage += F("</form>");    
      webpage += F("</body></html>");
      String cipSend=F("AT+CIPSEND=");
      cipSend += connectionId;
      cipSend += ",";
      cipSend += webpage.length();
      cipSend += F("\r\n");
      sendData(cipSend,1000,DEBUG);
      sendData(webpage,1000,DEBUG);
      delay(1);
      sendData("AT+CIPCLOSE=" + (String)connectionId + "\r\n",1000,DEBUG);      
      }
    }
  }

boolean connectWifi(String ssid, String pwd) {
  String res=sendData("AT+CWJAP=\"" + ssid + F("\",\"") + pwd + F("\"\r\n"),8000,DEBUG);
  res.replace("\r\n",""); //remove all line terminator
  if (res.indexOf("OK") != -1) {return true;}
  else {return false;}
  }

String sendData(String command, const int timeout, boolean debug) {
  String res=F("");
  esp8266.print(command);
  long int time=millis();
  while ((time + timeout) > millis()) {
    while(esp8266.available()) {res.concat((char)esp8266.read());}
    }
  if (debug) {Serial.print(res);}
  return res;
  }

這裡利用圓鈕元素 Radio 來選擇所要的狀態,  並透過讀取 D2 腳的目前狀態, 將 checked 這個屬性放到 ON 或 OFF 兩個圓鈕其中一個, 其實這就不需要 State 這個文字標示了. 但因為 Radio 可以選來選去, 在還沒按下 Update 之前就會搞不清楚現在到底是哪個狀態, 所以我還是保留 State 標示.  注意, 這兩個圓鈕必須取相同名稱, name 屬性值必須相同才會有二選一的效果, 這裡必須取名為 pinD2, 因為 Radio 的名稱就是要傳遞的參數名稱.

瀏覽器連線結果如下 :


而經過排版的網頁原始碼如下 :


上面程式裡我把 timeout 計時器都設為 1 秒, 反應速度變快了, 但運作仍正常.

如果把 D2 改成 D13, 就可以利用 Nano 板子上的 LED 來看到開啟與關閉的效果了, 程式如下 :

測試 2 :

#include <SoftwareSerial.h>
#define DEBUG true

SoftwareSerial esp8266(7,8); //(RX,TX)
const String ssid="EDIMAX-tony";
const String pwd="6628005572056";
const int MAX_PAGE_NAME_LEN=8;  //buffer size
char buffer[MAX_PAGE_NAME_LEN + 1]; //store page_name

void setup() {
  Serial.begin(9600);
  esp8266.begin(9600);
  sendData(F("AT+RST\r\n"),2000,DEBUG); // reset ESP8266
  sendData(F("AT+CWMODE=1\r\n"),1000,DEBUG); //configure as station
  sendData(F("AT+CIPMUX=1\r\n"),1000,DEBUG); //enable multiple connections
  sendData(F("AT+CIPSERVER=1,80\r\n"),2000,DEBUG); //turn on server 80 port
  while (!connectWifi(ssid, pwd)) {
    Serial.println(F("Connecting WiFi ... failed"));
    delay(2000);
    }
  sendData(F("AT+GMR\r\n"),1000,DEBUG);
  delay(3000); //wait for wifi connection to get local ip
  sendData(F("AT+CIFSR\r\n"),1000,DEBUG); //get ip address
  }

void loop() {
  if (esp8266.available()) { // check if esp8266 is sending message
    if (esp8266.find("+IPD,")) {
      delay(1000); //waiting for response: 0,234:GET /?pinD2=1
      int connectionId=esp8266.read()-48;  //turn ASCII to number
      bool on=false;
      if (esp8266.find("GET /?pin")) { //retrieve page name (router)
        char type=(char)esp8266.read(); //read char after ?pin
        int pin=esp8266.parseInt(); //get first int number from serial
        int val=esp8266.parseInt(); //get first int number from serial
        if (val==1) {on=true;}
        if (type=='D') { //update output status
          Serial.print(F("Digital pin "));
          Serial.print(pin);
          Serial.print(F(" is changed to "));
          Serial.println(val);        
          pinMode(pin, OUTPUT); //set pin as ouput
          digitalWrite(pin, val);
          }
        }
      String webpage=F("<html><body>");
      webpage += F("<h3>Click update button to turn D13 pin ON or OFF</h3>");
      webpage += F("<form action='/' method='GET'>");
      webpage += F("<input type='radio' name='pinD13' value='1'");
      if (digitalRead(13)) {webpage += F(" checked>");}
      else {webpage += F(">");}
      webpage += F("ON");
      webpage += F("<input type='radio' name='pinD13' value='0'");
      if (digitalRead(13)) {webpage += F(">");}
      else {webpage += F(" checked>");}
      webpage += F("OFF");  
      webpage += F(" State : ");
      if (digitalRead(13) == HIGH) {webpage += F(" ON");}
      else if (digitalRead(13) == LOW) {webpage += F(" OFF");}
      webpage += F(" <input type='submit' value='Update'>");
      webpage += F("</form>");  
      webpage += F("</body></html>");
      String cipSend=F("AT+CIPSEND=");
      cipSend += connectionId;
      cipSend += ",";
      cipSend += webpage.length();
      cipSend += F("\r\n");
      sendData(cipSend,1000,DEBUG);
      sendData(webpage,1000,DEBUG);
      delay(1);
      sendData("AT+CIPCLOSE=" + (String)connectionId + "\r\n",1000,DEBUG);    
      }
    }
  }

boolean connectWifi(String ssid, String pwd) {
  String res=sendData("AT+CWJAP=\"" + ssid + F("\",\"") + pwd + F("\"\r\n"),8000,DEBUG);
  res.replace("\r\n",""); //remove all line terminator
  if (res.indexOf("OK") != -1) {return true;}
  else {return false;}
  }

String sendData(String command, const int timeout, boolean debug) {
  String res=F("");
  esp8266.print(command);
  long int time=millis();
  while ((time + timeout) > millis()) {
    while(esp8266.available()) {res.concat((char)esp8266.read());}
    }
  if (debug) {Serial.print(res);}
  return res;
  }

修改的部分只有黃色高亮度部分, 實際測試結果如下 :


上面兩個小 LED 是 RX, TX, 第三個是 PWR 電源燈, 第四個小 LED 便是 NANO 連接 D13 腳的內建 LED, 利用區網連線 ESP8266 的伺服器, 就可以透過 Arduino 輸出的網頁來控制 LED 的明滅. 也可以用手機連線同一無線基地台來進行遠端控制, 當然這個遠端只是無線基地台信號涵蓋內的範圍, 還不是 Global.

參考 :

# Monitor your home remotely using the Arduino WiFi Shield 
# LED’s Control Through ESP8266 + Arduino Web Page
# Control a Lamp Remotely Using the ESP8266 WiFi Chip
How to Control Your ESP8266 From Anywhere in the World
# ESP8266 Thing Development Board Hookup Guide
An easy way to control your Arduino from Internet


沒有留言 :