好凉一个秋,一周天气先知。-Arduino中文社区 - Powered by Discuz! Archiver

topdog 发表于 2022-10-6 00:03

好凉一个秋,一周天气先知。

本帖最后由 topdog 于 2022-10-6 19:35 编辑

国庆节和重阳节转眼就过去了。进入深秋,天气也在陡然变化。我们就需要更加呵护家人,提前感知一周的天气变化,细心的你一定能够发现家里的长辈也是特别关心气象预报的电视节目,有的时候错过了节目就会很遗憾,那么用深圳晶彩智能3.5寸彩色屏采用分辨率480x320彩色液晶屏,做一个一周气象预报桌面展示器吧。



本示例特点使用了大量图标来表示一周内每天的气象,还加入了月相变化。数据采至 https://darksky.net/dev ,享受Dark Sky的服务需要注册一下,在https://darksky.net/dev/account查看一下Your Secret Key,然后我们用https://api.darksky.net/forecast//, 来看看上海浦东的天气情况吧。细心的小伙伴发现这里使用的https协议。HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
歪果仁对月相的命名。

我国对月相自古以来有独特的名称,本例中我用了一个数组,结合24张月相图来标签。这样也可以使孩子们更加了解我国悠久的天文文化。

程序如下:
/*
   https://darksky.net/dev
   https://github.com/Bodmer/TFT_eSPI
   https://github.com/GyverLibs/UnixTime
   https://github.com/bblanchon/ArduinoJson
   https://github.com/fbiego/ESP32Time
*/


#define FS_NO_GLOBALS
#include <FS.h>

#ifdef ESP32
#include "SPIFFS.h"// For ESP32 only
#endif

#include <UnixTime.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ESP32Time.h>
#include "sntp.h"
#include <TFT_eSPI.h>

#define CHINESE "fonts/hanyi30"

const char* ssid   = "你的WiFi名称";   // your network SSID (name of wifi network)
const char* password = "你的WiFi密码"; // your network password

const char *ntpServer1 = "ntp1.aliyun.com"; //阿里云NTP时间源服务器
const char *ntpServer2 = "s1a.time.edu.cn"; //北京邮电大学
const long gmtOffset_sec = 8 * 3600;      //参数就是用来修正时区的,比如对于我们东八区(UTC/GMT+08:00)来说该参数就需要填写 8 * 3600
const int daylightOffset_sec = 0;

const int WeekY = 230;
const int DailyDataY = 250;
const int temperatureHighY = 310;
const int temperatureLowY = 330;

bool booted = true;
long lastDownloadUpdate = millis();
const int UPDATE_INTERVAL_SECS = 3600000; // 1小时

const String ShowWeek = {"???", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
const String moonPhase = {"新月", "新月", "新月", "上蛾眉", "上蛾眉", "上蛾眉", "上弦月", "上弦月", "上弦月", "上凸月", "上凸月","满月", "满月", "下凸月", "下凸月", "下凸月", "下弦月", "下弦月", "下弦月", "下蛾眉", "下蛾眉", "下蛾眉", "下蛾眉","新月"};
String api_key = "你的darksky.net API key";
String latitude ="纬度";
String longitude = "经度";
String payload = " ";


const char* rootCACertificate = \
                              "-----BEGIN CERTIFICATE-----\n" \
                              "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n" \
                              "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" \
                              "b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n" \
                              "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n" \
                              "b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n" \
                              "ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n" \
                              "9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n" \
                              "IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n" \
                              "VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n" \
                              "93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n" \
                              "jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" \
                              "AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n" \
                              "A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n" \
                              "U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n" \
                              "N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n" \
                              "o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n" \
                              "5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n" \
                              "rqXRfboQnoZsG4q5WTP468SQvvG5\n" \
                              "-----END CERTIFICATE-----\n";

struct tm timeinfo;
ESP32Time rtc;
UnixTime stamp(8);
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite top = TFT_eSprite(&tft);

void setup() {
//Initialize serial and wait for port to open:
Serial.begin(115200);
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);

pinMode(16, OUTPUT);
digitalWrite(16, HIGH);

pinMode(17, OUTPUT);
digitalWrite(17, HIGH);

pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
yield();

Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
WiFi.begin(ssid, password);

// attempt to connect to Wifi network:
while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    // wait 1 second for re-trying
    yield();
}

Serial.print("Connected to ");
Serial.println(ssid);
yield();

if (WiFi.status() == WL_CONNECTED)
{   
    sntp_servermode_dhcp(1);
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);
    yield();
}

if (getLocalTime(&timeinfo))
{
    rtc.setTimeStruct(timeinfo);
    yield();
}

if (!SPIFFS.begin()) {
    //Serial.println("SPIFFS initialisation failed!");
    while (1) yield(); // Stay here twiddling thumbs waiting
}
//Serial.println("\r\nSPIFFS initialised.");

// Now initialise the TFT
tft.begin();
tft.setRotation(0);// 0 & 2 Portrait. 1 & 3 landscape
tft.fillScreen(TFT_BLACK);
//Serial.println("\nStarting connection to server...");

yield();
}

void loop() {
if ( booted || (millis() - lastDownloadUpdate > 2 * UPDATE_INTERVAL_SECS))//2小时
{
    GetData();
    lastDownloadUpdate = millis();
    booted = false;
}

TopTime();
}


void GetData(void) {
WiFiClientSecure *client = new WiFiClientSecure;
if (client)
{
    client->setCACert(rootCACertificate);
    {
      HTTPClient https;
      if (https.begin(*client, "https://api.darksky.net/forecast/" + api_key + "/" + latitude + "," + longitude + "?exclude=currently&units=si&lang=en")) {

      int httpCode = https.GET();

      if (httpCode > 0) {

          if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
            String payload = https.getString();
            DynamicJsonDocument doc(24576);

            DeserializationError error = deserializeJson(doc, payload);

            const char* timezone = doc["timezone"]; // "Asia/Shanghai"
            String TimeZone = timezone;
            int CityList = TimeZone.lastIndexOf('/');
            String City = TimeZone.substring(CityList + 1);

            JsonObject daily = doc["daily"];
            const char* daily_summary = daily["summary"]; // "Rain next Sunday."
            const char* daily_icon = daily["icon"]; // "rain"

            JsonArray daily_data = daily["data"];

            JsonObject daily_data_0 = daily_data;
            long daily_data_0_time = daily_data_0["time"]; // 1663430400
            const char* daily_data_0_summary = daily_data_0["summary"]; // "Humid and mostly cloudy throughout the ...
            const char* daily_data_0_icon = daily_data_0["icon"]; // "partly-cloudy-day"
            long daily_data_0_sunriseTime = daily_data_0["sunriseTime"]; // 1663450860 日升
            long daily_data_0_sunsetTime = daily_data_0["sunsetTime"]; // 1663495080 日落
            float daily_data_0_moonPhase = daily_data_0["moonPhase"]; // 0.77 月相
            float daily_data_0_temperatureHigh = daily_data_0["temperatureHigh"]; // 28.08
            float daily_data_0_temperatureLow = daily_data_0["temperatureLow"]; // 21.81
            float daily_data_0_humidity = daily_data_0["humidity"]; // 0.9
            float daily_data_0_pressure = daily_data_0["pressure"]; // 1005.7
            float daily_data_0_windSpeed = daily_data_0["windSpeed"]; // 4.95
            int daily_data_0_windBearing = daily_data_0["windBearing"]; // 346
            float daily_data_0_cloudCover = daily_data_0["cloudCover"]; // 0.66

            JsonObject daily_data_2 = daily_data;
            const char* daily_data_2_icon = daily_data_2["icon"]; // "partly-cloudy-day"
            float daily_data_2_temperatureHigh = daily_data_2["temperatureHigh"]; // 25.76
            float daily_data_2_temperatureLow = daily_data_2["temperatureLow"]; // 17.4

            JsonObject daily_data_3 = daily_data;
            const char* daily_data_3_icon = daily_data_3["icon"]; // "partly-cloudy-day"
            float daily_data_3_temperatureHigh = daily_data_3["temperatureHigh"]; // 25.54
            float daily_data_3_temperatureLow = daily_data_3["temperatureLow"]; // 17.12

            JsonObject daily_data_4 = daily_data;
            const char* daily_data_4_icon = daily_data_4["icon"]; // "partly-cloudy-day"
            float daily_data_4_temperatureHigh = daily_data_4["temperatureHigh"]; // 27.15
            float daily_data_4_temperatureLow = daily_data_4["temperatureLow"]; // 18.49


            JsonObject daily_data_5 = daily_data;
            const char* daily_data_5_icon = daily_data_5["icon"]; // "partly-cloudy-day"
            float daily_data_5_temperatureHigh = daily_data_5["temperatureHigh"]; // 27.15
            float daily_data_5_temperatureLow = daily_data_5["temperatureLow"]; // 18.49

            JsonObject daily_data_6 = daily_data;
            const char* daily_data_6_icon = daily_data_6["icon"]; // "partly-cloudy-day"
            float daily_data_6_temperatureHigh = daily_data_6["temperatureHigh"]; // 27.15
            float daily_data_6_temperatureLow = daily_data_6["temperatureLow"]; // 18.49

            JsonObject daily_data_7 = daily_data;
            const char* daily_data_7_icon = daily_data_7["icon"]; // "partly-cloudy-day"
            float daily_data_7_temperatureHigh = daily_data_7["temperatureHigh"]; // 27.15
            float daily_data_7_temperatureLow = daily_data_7["temperatureLow"]; // 18.49

            //Serial.println(City);
            tft.fillScreen(TFT_BLACK);

            drawBmp(("/icon/" + (String)daily_data_0_icon + ".bmp").c_str(), 10, 120);   //概述

            int windAngle = (daily_data_0_windBearing + 22.5) / 45;
            if (windAngle > 7) windAngle = 0;
            String wind[] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW" };
            drawBmp(("/wind/" + wind + ".bmp").c_str(), 120, 140);   //风向

            tft.unloadFont();
            tft.setTextFont(2);
            tft.setTextColor(TFT_ORANGE, TFT_BLACK);

            tft.setCursor(130, 200);
            tft.print(daily_data_0_windSpeed);    //风速
            stamp.getDateTime(daily_data_2["time"]);
            tft.drawString(ShowWeek, 20, WeekY);
            stamp.getDateTime(daily_data_3["time"]) ;
            tft.drawString(ShowWeek, 70, WeekY);
            stamp.getDateTime(daily_data_4["time"]);
            tft.drawString(ShowWeek, 120, WeekY);
            stamp.getDateTime(daily_data_5["time"]);
            tft.drawString(ShowWeek, 170, WeekY);
            stamp.getDateTime(daily_data_6["time"]);
            tft.drawString(ShowWeek, 220, WeekY);
            stamp.getDateTime(daily_data_7["time"]) ;
            tft.drawString(ShowWeek, 270, WeekY);

            drawBmp(("/icon50/" + (String)daily_data_2_icon + ".bmp").c_str(), 10, DailyDataY);
            drawBmp(("/icon50/" + (String)daily_data_3_icon + ".bmp").c_str(), 10 + 50, DailyDataY);
            drawBmp(("/icon50/" + (String)daily_data_4_icon + ".bmp").c_str(), 10 + 100, DailyDataY);
            drawBmp(("/icon50/" + (String)daily_data_5_icon+ ".bmp").c_str(), 10 + 150, DailyDataY);
            drawBmp(("/icon50/" + (String)daily_data_6_icon+ ".bmp").c_str(), 10 + 200, DailyDataY);
            drawBmp(("/icon50/" + (String)daily_data_7_icon+ ".bmp").c_str(), 10 + 250, DailyDataY);

            tft.setTextColor(TFT_RED, TFT_BLACK);
            tft.setCursor(20, temperatureHighY);
            tft.print(daily_data_2_temperatureHigh);
            tft.setCursor(70, temperatureHighY);
            tft.print(daily_data_3_temperatureHigh);
            tft.setCursor(120, temperatureHighY);
            tft.print(daily_data_4_temperatureHigh);
            tft.setCursor(170, temperatureHighY);
            tft.print(daily_data_5_temperatureHigh);
            tft.setCursor(220, temperatureHighY);
            tft.print(daily_data_6_temperatureHigh);
            tft.setCursor(270, temperatureHighY);
            tft.print(daily_data_7_temperatureHigh);

            tft.setTextColor(TFT_BLUE, TFT_BLACK);
            tft.setCursor(20, temperatureLowY);
            tft.print(daily_data_2_temperatureLow);
            tft.setCursor(70, temperatureLowY);
            tft.print(daily_data_3_temperatureLow);
            tft.setCursor(120, temperatureLowY);
            tft.print(daily_data_4_temperatureLow);
            tft.setCursor(170, temperatureLowY);
            tft.print(daily_data_5_temperatureLow);
            tft.setCursor(220, temperatureLowY);
            tft.print(daily_data_6_temperatureLow);
            tft.setCursor(270, temperatureLowY);
            tft.print(daily_data_7_temperatureLow);

            tft.setTextFont(4);
            tft.setTextColor(TFT_WHITE, TFT_BLACK);

            tft.drawString(daily_data_0_summary, 0, 100);
            tft.setCursor(200, 125);
            tft.print(daily_data_0_temperatureHigh);
            tft.setCursor(200, 150);
            tft.print(daily_data_0_temperatureLow);
            tft.drawString("oC", 275, 135);
            tft.setCursor(180, 180);
            tft.print(daily_data_0_pressure);
            tft.drawString("hpa", 275, 180);

            stamp.getDateTime(daily_data_0_sunriseTime);
            int SunriseTimeHour = stamp.hour;
            int SunriseTimeMinute = stamp.minute;
            tft.setTextColor(TFT_ORANGE, TFT_BLACK);
            tft.drawString("Sun", 10, 370);
            tft.setTextColor(TFT_WHITE, TFT_BLACK);
            tft.setCursor(10, 400);
            tft.print(SunriseTimeHour);
            tft.print(":");
            tft.print(SunriseTimeMinute);

            stamp.getDateTime(daily_data_0_sunsetTime);
            int SunSetTimeHour = stamp.hour;
            int SunSetTimeMinute = stamp.minute;
            tft.setCursor(10, 430);
            tft.print(SunSetTimeHour);
            tft.print(":");
            tft.print(SunSetTimeMinute);

            tft.setTextColor(TFT_ORANGE, TFT_BLACK);
            tft.drawString("Cloud", 200, 360);
            tft.setTextColor(TFT_WHITE, TFT_BLACK);
            tft.setCursor(200, 380);
            tft.print(daily_data_0_cloudCover * 100, 0);
            tft.print("%");
            tft.setTextColor(TFT_ORANGE, TFT_BLACK);
            tft.drawString("Humidity", 200, 410);
            tft.setTextColor(TFT_WHITE, TFT_BLACK);
            tft.setCursor(200, 430);
            tft.print(daily_data_0_humidity * 100, 0);
            tft.print("%");

            int moonAgeImage = (int)(24 * daily_data_0_moonPhase);
            tft.loadFont(CHINESE);
            tft.setTextWrap(true);
            tft.setTextColor(TFT_YELLOW, TFT_BLACK);
            tft.setCursor(100, 430);
            tft.print(moonPhase);
            if (moonAgeImage >= 24) moonAgeImage = 0;
            drawBmp(("/moon/moonphase_L" + String(moonAgeImage) + ".bmp").c_str(), 110, 360); //月相
            yield();
          }
          https.end();
          String payload = " ";
      }
      }
      delete client;
    }
}
}

void TopTime(void) {
top.setColorDepth(8);
top.createSprite(320, 90);
top.fillSprite(TFT_BLACK);

top.loadFont(CHINESE);
top.setTextWrap(true);
top.setTextColor(TFT_YELLOW, TFT_BLACK);
top.setCursor(5, 0);
top.print("日期:");
top.setCursor(5, 30);
top.print("时间:");
top.setCursor(5, 60);
top.print("城市:上海浦东");
top.unloadFont();
top.setTextColor(TFT_CYAN, TFT_BLACK);
top.setTextFont(4);
top.setCursor(80, 0);
top.print(rtc.getDate());
top.setCursor(80, 30);
top.print(rtc.getTime());

top.pushSprite(0, 0);
top.deleteSprite();
}

Arduino IDE烧写附件:



页: [1]
查看完整版本: 好凉一个秋,一周天气先知。