《項目》 之 ESP8266 助力疫情

//日期:2020/2/10
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <U8g2lib.h>
#include <Wire.h>

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

#define LED D4
#define DEBUG //是否開啓debug功能

#ifdef DEBUG
#define DebugPrintln(message)    Serial.println(message)
#else
#define DebugPrintln(message)
#endif

#ifdef DEBUG
#define DebugPrint(message)    Serial.print(message)
#else
#define DebugPrint(message)
#endif

//聲明方法
bool autoConfig();
void smartConfig();
bool sendRequest();
bool skipResponseHeaders();
void readReponseContent(char* content, size_t maxSize);
void stopConnect();
void clrEsp8266ResponseBuffer(void);
bool parseUserData(char* content);
void displayData();
  
const unsigned long BAUD_RATE = 115200;// serial connection speed
const unsigned long HTTP_TIMEOUT = 5000;               // max respone time from server
const size_t MAX_CONTENT_SIZE = 3000;                   // max size of the HTTP response
const char* host = "lab.isaaclin.cn";
const char* provice = "陝西省";
//https://lab.isaaclin.cn/nCoV/api/area?latest=1&province=陝西省

int flag = HIGH;//默認當前滅燈
WiFiClient client;
char response[MAX_CONTENT_SIZE];
char endOfHeaders[] = "\r\n\r\n";

long lastTime = 0;
// 請求服務間隔
long Delay = 20000;
// 疫情數據變量
int confirmedCount;
int suspectedCount;
int curedCount;
int deadCount;

// 西安疫情數據變量
int xian_confirmedCount;
int xian_suspectedCount;
int xian_curedCount;
int xian_deadCount;

// 渭南疫情數據變量
int weinan_confirmedCount;
int weinan__suspectedCount;
int weinan__curedCount;
int weinan__deadCount;

/**
* @Desc 初始化操作
*/
void setup() {
  Serial.begin(BAUD_RATE);
  pinMode(LED,OUTPUT);
  digitalWrite(LED, HIGH);

  // 初始化OLED顯示屏
  u8g2.begin();
  u8g2.enableUTF8Print();
  u8g2.setFont(u8g2_font_wqy12_t_gb2312a);
  u8g2.setFontPosTop();
  u8g2.clearDisplay();
  u8g2.firstPage();
  //開機界面
  do
  {
  u8g2.setCursor(32, 16);
  u8g2.print("武漢加油!");
  u8g2.setCursor(32, 32);
  u8g2.print("中國加油!");
  }
  while (u8g2.nextPage());
  

  if(!autoConfig()){
    smartConfig();
    DebugPrint("Connecting to WiFi");//寫幾句提示,哈哈
    while (WiFi.status() != WL_CONNECTED) {
    //這個函數是wifi連接狀態,返回wifi鏈接狀態
       delay(500);
       DebugPrint(".");
    }
  }
  
  delay(1000);
  digitalWrite(LED, LOW);
  DebugPrintln("IP address: ");
  DebugPrintln(WiFi.localIP());//WiFi.localIP()返回8266獲得的ip地址
  lastTime = millis();
  
  //使能軟件看門狗的觸發間隔
  ESP.wdtEnable(5000);
}
  
/**
* @Desc  主函數
*/
void loop() {
  while (!client.connected()){
     if (!client.connect(host, 80)){
         flag = !flag;
         digitalWrite(LED, flag);
         delay(500);
         //餵狗
         ESP.wdtFeed();
     }
  }

  digitalWrite(LED, HIGH);

  if(millis()-lastTime>=Delay){
   //每間隔20s左右調用一次
     lastTime = millis();
     if (sendRequest() && skipResponseHeaders()) {
       clrEsp8266ResponseBuffer();
       readReponseContent(response, sizeof(response));
       if (parseUserData(response)) {
          
       }
     }
  }
  
   //餵狗
   ESP.wdtFeed();
}

/**
* 自動連接20s 超過之後自動進入SmartConfig模式
*/
bool autoConfig(){
  WiFi.mode(WIFI_AP_STA);     //設置esp8266 工作模式
  WiFi.begin();
  delay(2000);//剛啓動模塊的話 延時穩定一下
  DebugPrintln("AutoConfiging ......");
  for(int index=0;index<10;index++){
    int wstatus = WiFi.status();
    if (wstatus == WL_CONNECTED){
      DebugPrintln("AutoConfig Success");
      DebugPrint("SSID:");
      DebugPrintln(WiFi.SSID().c_str());
      DebugPrint("PSW:");
      DebugPrintln(WiFi.psk().c_str());
      return true;
    }else{
      DebugPrint(".");
      delay(500);
      flag = !flag;
      digitalWrite(LED, flag);
    } 
  }
  DebugPrintln("AutoConfig Faild!");
  return false;
}

/**
* 開啓SmartConfig功能
*/
void smartConfig()
{
  WiFi.mode(WIFI_STA);
  delay(1000);
  DebugPrintln("Wait for Smartconfig");
  // 等待配網
  WiFi.beginSmartConfig();
  while (1){
    DebugPrint(".");
    delay(200);
    flag = !flag;
    digitalWrite(LED, flag);
    
    if (WiFi.smartConfigDone()){
      //smartconfig配置完畢
      DebugPrintln("SmartConfig Success");
      WiFi.mode(WIFI_AP_STA);     //設置esp8266 工作模式
      WiFi.setAutoConnect(true);  // 設置自動連接
      break;
    }
  }
}

/**
* @發送請求指令
*/
bool sendRequest() {
  // We now create a URI for the request
  //心知天氣
  String GetUrl = "/nCoV/api/area";
  GetUrl += "?latest=1";
  GetUrl += "&province=";
  GetUrl += provice;
  
  // This will send the request to the server
  client.print(String("GET ") + GetUrl + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  delay(1000);
  return true;
}
 
/**
* @Desc 跳過 HTTP 頭,使我們在響應正文的開頭
*/
bool skipResponseHeaders() {
  // HTTP headers end with an empty line
  bool ok = client.find(endOfHeaders);
  if (!ok) {
    DebugPrintln("No response or invalid response!");
  }
  return ok;
}
 
/**
* @Desc 從HTTP服務器響應中讀取正文
*/
void readReponseContent(char* content, size_t maxSize) {
  size_t length = client.readBytes(content, maxSize);
  delay(100);
  content[length] = 0;
  client.flush();//這句代碼需要加上  不然會發現每隔一次client.find會失敗
}
  
// 關閉與HTTP服務器連接
void stopConnect() {
  client.stop();
}
 
void clrEsp8266ResponseBuffer(void){
    memset(response, 0, MAX_CONTENT_SIZE);      //清空
}

bool parseUserData(char* content) {
//    -- 根據我們需要解析的數據來計算JSON緩衝區最佳大小
//   如果你使用StaticJsonBuffer時才需要
//    const size_t BUFFER_SIZE = 1024;
//   在堆棧上分配一個臨時內存池
//    StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
//    -- 如果堆棧的內存池太大,使用 DynamicJsonBuffer jsonBuffer 代替
  DynamicJsonBuffer jsonBuffer;
  
  JsonObject& root = jsonBuffer.parseObject(content);
  
  if (!root.success()) {
    Serial.println("JSON parsing failed!");
    return false;
  }

  // -------- 對應省數據 -----------
  JsonObject& provinces = root["results"][0];
  const char* country = provinces["country"]; // "中國"
  const char* provinceName = provinces["provinceName"]; // "省份"
  confirmedCount = provinces["confirmedCount"];
  suspectedCount = provinces["suspectedCount"];
  curedCount = provinces["curedCount"];
  deadCount = provinces["deadCount"];
  
  // -------- 串口打印實時疫情信息 -----------
  Serial.printf("%s新型肺炎疫情實時數據",provice);
  Serial.println("-----------------------------------------");

  Serial.printf("確診:%d | 疑似:%d | 治癒:%d | 死亡:%d",confirmedCount,suspectedCount,curedCount,deadCount);
  Serial.println();
  // -------- cities -----------
  JsonArray& cities = provinces["cities"];

  for( int index = 0; index < cities.size(); index ++){
    JsonObject& ciry = cities[index];
    const char* cityName = ciry["cityName"]; // "寧波"
    confirmedCount = ciry["confirmedCount"];
    suspectedCount = ciry["suspectedCount"];
    curedCount = ciry["curedCount"];
    deadCount = ciry["deadCount"];
    Serial.printf("%s | 確診:%d | 疑似:%d | 治癒:%d | 死亡:%d",cityName,confirmedCount,suspectedCount,curedCount,deadCount);
    Serial.println();
  }
  Serial.println("-----------------------------------------");
    // -------- 西安數據 -----------
    JsonObject& xian = cities[0];
    const char* hangzhou_cityName = xian["cityName"]; // "西安"
    xian_confirmedCount = xian["confirmedCount"];
    xian_suspectedCount = xian["suspectedCount"];
    xian_curedCount = xian["curedCount"];
    xian_deadCount = xian["deadCount"];

    // -------- 渭南數據 -----------
    JsonObject& weinan = cities[5];
    const char* ningbo_cityName = weinan["cityName"]; // "渭南"
    weinan_confirmedCount = weinan["confirmedCount"];
    weinan__suspectedCount = weinan["suspectedCount"];
    weinan__curedCount = weinan["curedCount"];
    weinan__deadCount = weinan["deadCount"];

  u8g2.firstPage();
  do
  {
    displayData();
  }
  while (u8g2.nextPage());
  return true;
}

// 在OLED上顯示實時疫情數據
void displayData() {
  u8g2.clearDisplay();

  // 繪製表格
  u8g2.drawFrame(0, 16, 128, 48);
  u8g2.drawLine(0, 32, 127, 32);
  u8g2.drawLine(0, 48, 127, 48);
  u8g2.drawLine(32, 16, 32, 63);
  u8g2.drawLine(64, 16, 64, 63);
  u8g2.drawLine(96, 16, 96, 63);

  // 標題
  u8g2.setCursor(18, 2);
  u8g2.print("陝西疫情實時信息");

  // 表格類別
  u8g2.setCursor(36, 20);
  u8g2.print("確診");
  u8g2.setCursor(68, 20);
  u8g2.print("治癒");
  u8g2.setCursor(100, 20);
  u8g2.print("死亡");

  // 西安情況
  u8g2.setCursor(4, 36);
  u8g2.print("西安");
  u8g2.setCursor(38, 36);
  u8g2.print(xian_confirmedCount);
  u8g2.setCursor(72, 36);
  u8g2.print(xian_curedCount);
  u8g2.setCursor(104, 36);
  u8g2.print(xian_deadCount);

  // 渭南情況
  u8g2.setCursor(4, 52);
  u8g2.print("渭南");
  u8g2.setCursor(40, 52);
  u8g2.print(weinan_confirmedCount);
  u8g2.setCursor(72, 52);
  u8g2.print(weinan__curedCount);
  u8g2.setCursor(104, 52);
  u8g2.print(weinan__deadCount);
}
  • 一起來看下效果吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章