sonicfirr 发表于 2022-8-28 14:03

【Beetle ESP32-C3】七、网络授时和请求天气(Arduino)

<div class='showpostmsg'><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本篇记录一个案例,功能为:连接Wi-Fi,网络授时,开启定时器(1s),每分钟(整分钟)串口输出一次时间,每5分钟输出一次实时天气信息。</p>

<h2><b>1、请求天气</b></h2>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 请求天气是通过&ldquo;心知天气&rdquo;站点,需要使用者自行注册并获取api_key。相关注册和使用过程,这里就不啰嗦了,不清楚的朋友可以自己到官网上查看(<a href="https://www.seniverse.com/">https://www.seniverse.com/</a>)。</p>

<p>本例仅测试实时天气数据获取,天气相关数据只有&ldquo;状态(晴朗之类)&rdquo;和&ldquo;气温&rdquo;,请求接口地址如下:</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://api.seniverse.com/v3/weather/now.json?key=your_api_key&amp;location=beijing&amp;language=zh-Hans&amp;unit=c"><u>https://api.seniverse.com/v3/weather/now.json?key=your_api_key&amp;location=beijing&amp;language=zh-Hans&amp;unit=c</u></a>&nbsp;</p>

<p>&nbsp;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 请求天气使用ESP32-Arduino的HTTPClient实例,获取的天气数据为JSON格式,因此案例加载了ArduinoJson库,装得比较早版本是6.18.5,看更新提示最新版是6.19.4了。</p>

<p>&nbsp;</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p align="center">图7-1&nbsp;库安装</p>

<p align="center">&nbsp;</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p align="center">图7-2&nbsp;心知天气返回的JSON格式</p>

<p align="center">&nbsp;</p>

<h2><b>2、天气案例代码</b></h2>

<pre>
<code>#include &lt;Arduino.h&gt;
#include &lt;WiFi.h&gt;
#include &lt;WiFiMulti.h&gt;
#include &lt;HTTPClient.h&gt;
#include &lt;ArduinoJson.h&gt;

//-----SSID &amp; password
const char *ssid = "yourssid";      //WIFI名称
const char *password = "yourpsw";   //密码

//-----NTP server &amp; timezone offset
const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 14400;   //3600*4 for UTC+8
const intdaylightOffset_sec = 14400;
struct tmt;                         //time struct
void printLocalTime(void);

//-----timer HW per second
#define INMIN   0x60                //in 60s flag
#define ONEMIN    0x61                //one minute flag
hw_timer_t *timer = NULL;             //timer variable
volatile SemaphoreHandle_t timersem;//timer fire sem
void IRAM_ATTR onTimer(void);         //callback func
void initTimer(void);
static uint8_t timestate = INMIN;   //flag variable

//-----weather server URL &amp; instance for json parsing
DynamicJsonDocument doc(1024);      //json doc instance
const char *url = "https://api.thinkpage.cn/v3/weather/now.json?key=your_api_key&amp;location=tianjin&amp;language=en&amp;unit=c";
void getWeather(void);                //request now weather func               

void setup() {
Serial.begin(115200);
//-----connect AP
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
}
//-----print IP address
Serial.println(" CONNECTED");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
//-----initialize and get the time then initialize timer(per sec)
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
if(!getLocalTime(&amp;t)){
    Serial.println("Failed to obtain time");
    return;
} else {
    Serial.println(&amp;t, "%A, %B %d %Y %H:%M:%S");
    initTimer(); //timer init
}
}

void loop() {
//-----update time state per second
if(xSemaphoreTake(timersem, 0) == pdTRUE) {
    if((t.tm_sec)++ &gt;= 59)timestate = ONEMIN;
}
//-----print localtime per minute &amp; weather info per 5 minutes
if(timestate == ONEMIN) {
    timestate = INMIN;
    if(WiFi.status() == WL_CONNECTED) {
      printLocalTime();
      if(t.tm_min%5 == 0) getWeather();
    }   
}
}

//-----print local time function
void printLocalTime() {
if(!getLocalTime(&amp;t)) {
    Serial.println("Failed to obtain time");
    return;
}
Serial.println(&amp;t, "%F %T %A");
}
//-----second timer callback function
void IRAM_ATTR onTimer() {
xSemaphoreGiveFromISR(timersem, NULL);
}
//-----intialize timer function
void initTimer() {
timersem = xSemaphoreCreateBinary();
//ESP32 sysclk is 80MHz.
//frequency division factor to 80,
//then timer clock is 1MHz.
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &amp;onTimer, true);
timerAlarmWrite(timer, 1000000, true); //1000000us timer
timerAlarmEnable(timer);
}
//-----request now weather function
void getWeather() {
if((WiFi.status() == WL_CONNECTED)) {
    HTTPClient http;         //create HTTPClient instance
    http.begin(url);         //begin HTTP request
    int httpCode = http.GET(); //get response code - normal:200
    if(httpCode &gt; 0) {
      Serial.printf(" GET... code: %d\n", httpCode);
      if(httpCode == HTTP_CODE_OK) {
          String payload = http.getString();      
          Serial.println(payload);
          //parse response stringto DynamicJsonDocument instance
          deserializeJson(doc, payload);
          //get top level Json-Object
          JsonObject obj = doc.as&lt;JsonObject&gt;();
          //get "results" property then parse the value to Json-Array
          JsonVariant resultsvar = obj["results"];
          JsonArray resultsarr = resultsvar.as&lt;JsonArray&gt;();
          //get array index 0 which is now weather info
          JsonVariant resultselementvar = resultsarr;
          JsonObject resultselementobj = resultselementvar.as&lt;JsonObject&gt;();
          //get city, temp, last_update time
          JsonVariant namevar = resultselementobj["location"]["name"];
          String namestr = namevar.as&lt;String&gt;();
          Serial.println(namestr);
      
          JsonVariant temperaturevar = resultselementobj["now"]["temperature"];
          String temperaturestr = temperaturevar.as&lt;String&gt;();
          Serial.println(temperaturestr);
      
          JsonVariant last_updatevar = resultselementobj["last_update"];
          String last_updatestr = last_updatevar.as&lt;String&gt;();
          Serial.println(last_updatestr);
      }
    } else {
      Serial.printf(" GET... failed, error: %s\n",
      http.errorToString(httpCode).c_str());
    }
    http.end(); //end http connectiong
}
}

</code></pre>

<p>&nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

Jacktang 发表于 2022-8-29 07:15

<p>网络授时和请求天气功能测评的不错,期待后续</p>

wangerxian 发表于 2022-8-29 10:35

<p>如何获取地区?自己输入地区信息吗?</p>

lcofjp 发表于 2022-8-29 19:13

wangerxian 发表于 2022-8-29 10:35
如何获取地区?自己输入地区信息吗?

<p>地址信息在请求的url里面</p>

wangerxian 发表于 2022-8-30 13:09

lcofjp 发表于 2022-8-29 19:13
地址信息在请求的url里面

<p>看到了,我看用的是拼音,如果有重名的是不是会出问题。</p>

sonicfirr 发表于 2022-9-3 11:24

wangerxian 发表于 2022-8-30 13:09
看到了,我看用的是拼音,如果有重名的是不是会出问题。

<p>就是url请求参数,相关参数可以在心知天气网站查找,网站应该自己解决了重名问题吧(个人猜想)</p>
页: [1]
查看完整版本: 【Beetle ESP32-C3】七、网络授时和请求天气(Arduino)