ESP8266开发之旅 应用篇⑦ 简易版本在线获取特定省份新型冠状病毒情况

只愿长相守 提交于 2020-02-09 18:52:49

授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石。。。

共同学习成长QQ群 622368884,不喜勿加,里面有一大群志同道合的探路人

快速导航
单片机菜鸟的博客快速索引(快速找到你要的)

如果觉得有用,麻烦点赞收藏,您的支持是博主创作的动力。

1.前言

    这一篇,博主将教大家怎么去实现一个简易版本的获取省份疫情情况。
   &ensp功能的图片,如下:
在这里插入图片描述
有条件的同学可以建立一个webserver html页面来显示或者用OLED显示

1.1 知识储备

    本篇需要用到以下知识点:

  • 运用到ArduinoJson V5库,github传送门,请读者自行下载该库放到Arduino安装目录(这里直接使用,博主后面计划会详细讲解该库,敬请期待);
  • 运用到TCP Client,请参考 ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
  • 运用到STA模式,请参考 ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
  • 运用到一键配网功能,请参考 ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网

2. 接口说明

在这里插入图片描述

3. 8266代码

/**
* 日期:2019/02/09
* 功能:武汉加油 中国加油
* 作者:单片机菜鸟
**/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>

#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(const char* host, const char* cityid, const char* apiKey);
bool skipResponseHeaders();
void readReponseContent(char* content, size_t maxSize);
void stopConnect();
void clrEsp8266ResponseBuffer(void);
bool parseUserData(char* content, struct UserData* userData);
  
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 = "广东省";

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;

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

  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();
     }
  }

  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("-----------------------------------------");
  return true;
}

4.总结

武汉加油,中国加油,疫情早日结束。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!