2016年11月12日 星期六

ESP8266 設備狀態監視 + 紀錄 + 網路斷線後重開指定設備(ADSL)


 ESP8266 偵測 網路斷線  後重開設備 + Thingspeak狀態監視 及 紀錄

算是這一篇的軟體升級版本XD

























**  紅色字體部分請依現場環境修改 **




/*

 for  arduinoIDE 1.6.12 支援 ADC_MODE(ADC_VCC 但檔案目錄不支援中文,否則會檢查編譯錯誤
2016-11-12 by yulie~

使用第2腳控制繼電器時,於上傳程式當下必須將第2腳斷開,否則無法上傳程式

   2016-10-03 簡化程式碼,增加被測裝置數量
   2016-09-27 功能測試完成


  定義update區域欄位
  1:  0=loss, 1=Device Active,  2= local boot
  2:  0=loss, 1=Device Active,  2= local boot
  3:  0=loss, 1=Device Active,  2= local boot
  4:  0=loss, 1=Device Active,  2= local boot

  6: reboot count
  7: Wi-Fi Fail count
  8: ESP8266 Core Volt
  thingspeak Server 只傳單一區域值第一筆之後的資料沒辦法再進資料庫
  reedited for ESP8266 2016-09-17 by yulie~
  H/W ESP8266
  Network  service  check ipaddress & port
  2015-07-26 by yulie~
*/
word chkTime  =  60;           // Sec 檢測連狀態間隔時間
byte actTime  =  60;           //  次  檢測連狀態正常達該次數後發 Active 紀錄 dev0 or dev1
byte wait     =   5;           //  次  檢測連線狀態失敗達該次數後關電重啟 only dev0
word wifiFail = 300;           // Sec Wi-Fi connect fail  Reboot wait time
byte off_time =   8;           // Sec   設備斷電秒數
byte Relay_1  =  14;           // 使用第14腳控制繼電器
byte LED      =  16;           // 使用第16腳控LED
#include <ESP8266WiFi.h>


#define SSID "****"          // 無線網路連線名稱
#define PASS "******" // 無線網路連線密碼
char ip_1[] = "www.google.com"; word port_1 = 80;  // 被檢查ip位址 & port
char ip_2[] = "192.168.1.31";   word port_2 = 80;  // 被檢查ip位址 & port
char ip_3[] = "192.168.1.32";   word port_3 = 80;  // 被檢查ip位址 & port
char ip_4[] = "192.168.1.52";   word port_4 = 80;  // 被檢查ip位址 & port

char serverIP[] = "api.thingspeak.com"; word serverPort = 80;
const String GET = "GET /update?key=******************"; //ID for 網路設備重開記錄
unsigned long t, u, v, w = 0;
byte actCoun, devFail, status_1, status_1a, status_2, status_2a, status_3, status_3a, status_4, status_4a;;
word WiFi_fail, reboot_count;
ADC_MODE(ADC_VCC);                  //for core voltage

void setup() {
  t, u, v, w = millis();
  Serial.begin(115200); Serial.print("Connect to Wi-Fi : ");
  Serial.println("."); Serial.println("start setup ...");
  pinMode(Relay_1, OUTPUT); pinMode(LED, OUTPUT);
  for (byte i = 0; i < 6; i++) {
    digitalWrite(LED, HIGH); delay(500); digitalWrite(LED, LOW); delay(500);
  }

  WiFi.mode(WIFI_STA);                          // Connecting to a WiFi network
  Serial.print("Connect to Wi-Fi :  ");
  Serial.println( SSID );
  WiFi.begin( SSID, PASS );                     //Connect to Wi-Fi
  updata(2, 2, 2, 2, 2, 0, 0);                  //開機信息為 2,2,0,0
  float voltaje = ESP.getVcc();
  Serial.print(voltaje / 1024);
  Serial.println(" V");
}

void loop() {
  while ( WiFi.status() != WL_CONNECTED )           // 持續等待並連接到指定的 WiFi SSID
  { // 如果連線AP 失敗時執行這一段程式
    Serial.print( "Wi-Fi failed count : " );
    delay(1000);
    WiFi_fail++;
    WiFi_fail = constrain ( WiFi_fail, 0, 65534);   //  限制該值在0~100 之間
    Serial.println(WiFi_fail);
    if (WiFi_fail >= wifiFail) {                    //connect Wifi fail over 3min Run
      rebootPower_1();
      WiFi_fail = 0;
    }
  }

  t = millis(); if (t - u > (chkTime * 1000)) {     //30000 mS on chk
    u = millis();
    actCoun++;
    Serial.println(" ");
    status_1 =  chkdev(ip_1, port_1);
    status_2 =  chkdev(ip_2, port_2);
    status_3 =  chkdev(ip_3, port_3);
    status_4 =  chkdev(ip_4, port_4);
    if (status_1 == 1)digitalWrite(LED, HIGH);
    if (status_1 == 0)digitalWrite(LED, LOW);

    //狀態改變時上傳
    if (status_1 !=  status_1a
        || status_2 !=  status_2a
        || status_3 !=  status_3a
        || status_4 !=  status_4a) {
      status_1a = status_1;                           //狀態更新,做為下一次狀態比較用
      status_2a = status_2;                           //狀態更新,做為下一次狀態比較用
      status_3a = status_3;                           //狀態更新,做為下一次狀態比較用
      status_4a = status_4;                           //狀態更新,做為下一次狀態比較用
      if ( status_1 == 1 )updata(status_1, status_2, status_3, status_4, 0, reboot_count, WiFi_fail);
    }

    if (status_1 == 1) devFail = 0;           //斷線計數歸零
    else {
      devFail++;                              //裝置斷線計數,給重開設備判斷用
      actCoun = 0;
    }

    // device 0 or device 1  每60次傳送一次存活信息
    if (actCoun >= actTime )updata(status_1, status_2, status_3, status_4, 0, reboot_count, WiFi_fail);

    //裝置矢聯達指定次數則啓動繼電器關機重開
    if (devFail >= wait) {
      rebootPower_1();
      devFail = 0;
    }
    //showCount();  //for debug
    //reboot_count != 0 or WiFi_fail != 0 and connect OK send infomation...
    if ((reboot_count != 0 || WiFi_fail != 0) && status_1 == 1) updata(status_1, status_2, status_3, status_4, 0, reboot_count, WiFi_fail);
  }
}

//-------------------------------------------------------------------------------void updata()
word updata(word field1, word field2, word field3, word field4, word field5, word field6, word field7) {
  float voltaje = ESP.getVcc(); voltaje = voltaje / 1024;
  WiFiClient client;
  if (client.connect(serverIP, serverPort)) {
    String getStr = GET +
                    "&field1=" + String((float)field1, 0) +     // active 01
                    "&field2=" + String((float)field2, 0) +     // active 02
                    "&field3=" + String((float)field3, 0) +     // active 03
                    "&field4=" + String((float)field4, 0) +     // active 04
                    "&field5=" + String((float)field5, 0) +     // active 05
                    "&field6=" + String((float)field6, 0) +     // reboot_count
                    "&field7=" + String((float)field7, 0) +     // WiFi_X_count
                    "&field8=" + String((float)voltaje, 2) +    // Chip Vcc
                    " HTTP/1.1\r\n";;
    client.print( getStr );
    client.print( "Host: api.thingspeak.com\n" );
    client.print( "Connection: close\r\n\r\n" );
    delay(10);
    // 處理遠端伺服器回傳的訊息,程式碼可以寫在這裡!
    Serial.println(getStr);
    client.stop();
    actCoun = 0;      //如果狀態傳送就將先前的存活計數歸零
    WiFi_fail  = 0;
    reboot_count = 0;
  }
  else {                               //連線失敗執行此段程式
    Serial.print(ip_1); Serial.print(" : "); Serial.print(port_1); Serial.println(" ThingSpeak Server disconnection  ---- X  ");
  }
  client.stop();
}

//------------------------------------------------------------------------------- check device
byte chkdev(char* IP, word PORT) {
  WiFiClient client;
  if (client.connect(IP, PORT)) {    //連線成功執行此段程式
    Serial.print(IP); Serial.print(" : "); Serial.print(PORT); Serial.println(" check device  connected ");
    return 1;
  }
  else {                               //連線失敗執行此段程式
    Serial.print(IP); Serial.print(" : "); Serial.print(PORT); Serial.println(" check device  disconnection  ---- X  ");
    return 0;
  }
}

//-------------------------------------------------------------------------------status_1, status_2
void showCount() {   //for debug
  Serial.print("status_1 : "); Serial.println(status_1);   Serial.print("status_2 : "); Serial.println(status_2);
  Serial.print("WiFi_fail : ");  Serial.println(WiFi_fail);  Serial.print("reboot_count : "); Serial.println(reboot_count);
  uint32_t getVcc = ESP.getVcc();  float voltaje = ESP.getVcc();  Serial.println("core Volt : "); Serial.print(voltaje / 1024);
  Serial.println(" V");
}

//-------------------------------------------------------------------------------void rebootPower_1()
void rebootPower_1() {
  digitalWrite(Relay_1, HIGH); // Relay N.C connect (device power down)
  Serial.print("power down~  Wait  "); Serial.print(off_time); Serial.println(" Sec ..");
  delay(off_time * 1000);          //device power down 5 sec
  digitalWrite(Relay_1, LOW);
  Serial.println("power up");
  reboot_count++;
}