This article records a case with the following functions: connecting to Wi-Fi, network timing, starting the timer (1s), outputting the time once a minute (whole minute) through the serial port, and outputting real-time weather information every 5 minutes.
1. Request weather
To request weather, users need to register and obtain the api_key through the "Xinzhi Weather" site. I won't go into details about the registration and usage process here. If you are not sure, you can check the official website ( https://www.seniverse.com/ ).
This example only tests the acquisition of real-time weather data. The weather-related data only includes "status (sunny, etc.)" and "temperature". The request interface address is as follows:
https://api.seniverse.com/v3/weather/now.json?key=your_api_key&location=beijing&language=zh-Hans&unit=c
The HTTPClient instance of ESP32-Arduino is used to request the weather. The weather data obtained is in JSON format. Therefore, the ArduinoJson library is loaded in this case. The earlier version installed is 6.18.5. The latest version is 6.19.4 according to the update prompt.
Figure 7-1 Library installation
Figure 7-2 JSON format returned by Xinzhi Weather
2. Weather case code
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
//-----SSID & password
const char *ssid = "yourssid"; //WIFI名称
const char *password = "yourpsw"; //密码
//-----NTP server & timezone offset
const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 14400; //3600*4 for UTC+8
const int daylightOffset_sec = 14400;
struct tm t; //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 & 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&location=tianjin&language=en&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(&t)){
Serial.println("Failed to obtain time");
return;
} else {
Serial.println(&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)++ >= 59) timestate = ONEMIN;
}
//-----print localtime per minute & 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(&t)) {
Serial.println("Failed to obtain time");
return;
}
Serial.println(&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, &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 > 0) {
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
if(httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println(payload);
//parse response string to DynamicJsonDocument instance
deserializeJson(doc, payload);
//get top level Json-Object
JsonObject obj = doc.as<JsonObject>();
//get "results" property then parse the value to Json-Array
JsonVariant resultsvar = obj["results"];
JsonArray resultsarr = resultsvar.as<JsonArray>();
//get array index 0 which is now weather info
JsonVariant resultselementvar = resultsarr[0];
JsonObject resultselementobj = resultselementvar.as<JsonObject>();
//get city, temp, last_update time
JsonVariant namevar = resultselementobj["location"]["name"];
String namestr = namevar.as<String>();
Serial.println(namestr);
JsonVariant temperaturevar = resultselementobj["now"]["temperature"];
String temperaturestr = temperaturevar.as<String>();
Serial.println(temperaturestr);
JsonVariant last_updatevar = resultselementobj["last_update"];
String last_updatestr = last_updatevar.as<String>();
Serial.println(last_updatestr);
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n",
http.errorToString(httpCode).c_str());
}
http.end(); //end http connectiong
}
}