2120浏览
查看: 2120|回复: 0

[ESP8266/ESP32] TTGO TFT屏幕模块解析DarkSky气象数据和时钟显示

[复制链接]
本帖最后由 topdog 于 2021-11-26 00:05 编辑

TTGO TFT屏幕是一款ESP32和1.44寸LCD屏幕组合的产品,屏幕由ST7789驱动。ESP32自带520 kB SRAM和QSPI外接4MB flash。最近用Arduino的方法解析世界著名的气象服务网站Dark Sky,做一个彩色的时钟和气象的桌面显示,中间还有一条动感的火焰。效果如下图:

TTGO TFT屏幕模块解析DarkSky气象数据和时钟显示图3

知识点阐述:
1,LCD驱动ST7789的库,使用TFT_eSPI库:
我结合这款产品把库改了一下,放在文章结尾网盘链接里面给小伙伴们分享。
1.44寸换算成像素就是135x240,实体性化屏幕:TFT_eSPI tft = TFT_eSPI(135, 240);
初始化屏幕: tft.init();
屏幕旋转角度:tft.setRotation(0);
使用官方黑色清屏:tft.fillScreen(TFT_BLACK);标定位置和文字大小:tft.setCursor(0, 0);  tft.setTextFont(2); 也可以简略写:tft.setCursor(0, 0,2);
设置文字色彩: tft.setTextColor(TFT_YELLOW); 屏幕上输出数据:tft.println(TimeZoneCity);

2,享受Dark Sky的服务需要注册一下,在https://darksky.net/dev/account查看一下Your Secret Key,然后我们用https://api.darksky.net/forecast/[key]/[latitude],[longitude] 来看看上海的天气情况吧。细心的小伙伴发现这里使用的https协议。HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
3,数据的解析,使用ArduinoJson库:
我们把上述的网站链接粘贴到浏览器地址栏,得到气象数据反馈。全选复制到ArduinoJosn官方网站提供的助手。第一步按下图选择。

TTGO TFT屏幕模块解析DarkSky气象数据和时钟显示图1


4,ESP32官方在Flash上建立了一个叫做nvs的分区,而Preferences功能就是建立在该分区上的。ESP32中默认分区( Partition Scheme: “Default 4MB with spiffs (1.2MB APP /1.5MB SPIFFS)” )情况下nvs分区的大小为 20480 字节,实际可存放的数据大小要小于这个值( 单个数据来说最大为496K或者97%的nvs分区大小 )。Preferences中数据以键值对(key - value)的方式存储。在键值对之上还有一层命名空间 ,不同命名空间中可以有相同的键名存在。在Preferences中命名空间和键名均为字符串,并且长度不大于15个字节。
首先创建一个实体: Preferences DarkSky;
其次给出DarkSkySpace命名空间:DarkSky.begin("DarkSkySpace");  
本示例中往实体空间里面存放数据只涉及String和Float两种数据类型:DarkSky.putString("precipType",currently_precipType); DarkSky.putFloat("temperature", currently_temperature);
相对应提取数据,查询没有结果返回值是自由设定的,此处String类型返回null,Float返回0:String precipType = DarkSky.getString("precipType","null");  float temperature = DarkSky.getFloat("temperature", 0);
5,非阻塞多任务ESP32使用Ticker库可以简单的完成,ESP32联网以后先Changer.once(1, GetData);   去解析一次气象数据,数据存入nvs分区,然后SetDisplayStore.attach(SetDisplayPeriod, SetDisplay);每秒读取时间日期和nvs分区里已经存储的气象数据。GetDataStore.attach(GetDataPeriod, GetData);注册一小时解析的任务,避免频繁访问。
6,烧录程序时开发板的选择:

TTGO TFT屏幕模块解析DarkSky气象数据和时钟显示图2


程序如下:

#include <Arduino.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <TFT_eSPI.h>
#include <Ticker.h>
#include <Preferences.h>
#include "flame.h"

#define TFT_GREY 0x5AEB
#define lightblue 0x01E9
#define darkred 0xA041
#define blue 0x5D9B

TFT_eSPI tft = TFT_eSPI(135, 240);
WiFiMulti WiFiMulti;
Preferences DarkSky;

Ticker  SetDisplayStore;
Ticker  GetDataStore;
Ticker  Changer;

const float SetDisplayPeriod = 1;
const float GetDataPeriod = 3600;

const int pwmFreq = 312500;
const int pwmLedChannelTFT = 0;
const int backlight = 199;

String api_key = "你的API密钥";
String latitude =  "31.1456941";
String longitude = "121.5219842";

const char* ntpServer = "time2.cloud.tencent.com";
const long  gmtOffset_sec = 28800;
const int   daylightOffset_sec = 0;

int frame = 0;
String payload = " ";

const char* ssid       = "你的WiFi名称";
const char* password   = "你的WiFi密码";

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";





void SetDisplay() {
  struct tm timeinfo;
  getLocalTime(&timeinfo);

  String TimeZoneCity = DarkSky.getString("TimeZoneCity", "null");
  String summary = DarkSky.getString("summary", "null");
  float temperature = DarkSky.getFloat("temperature", 0);
  float humidity = DarkSky.getFloat("humidity", 0);
  float pressure = DarkSky.getFloat("pressure", 0);
  float windSpeed = DarkSky.getFloat("windSpeed", 0);
  float centigrade = (temperature - 32) / 1.8;

  tft.fillScreen(TFT_BLACK);
  tft.setCursor(0, 0);
  tft.setTextFont(2);
  tft.setTextColor(TFT_YELLOW);
  tft.println(&timeinfo, "%A, %B %d %Y");

  tft.setCursor(0, 30, 2);
  tft.setTextColor(TFT_PINK);
  tft.println(&timeinfo, "%H:%M:%S");

  tft.fillRect(0, 120, 135, 20, TFT_GREENYELLOW);
  tft.setCursor(3, 123, 2);
  tft.setTextColor(TFT_WHITE, lightblue);
  tft.print("TEMP: ");
  tft.print(centigrade);
  tft.drawCircle(90, 124, 2, TFT_BLACK);
  tft.drawString("C", 95, 123, 2);


  tft.fillRect(1, 150, 64, 20, blue);
  tft.setCursor(1, 150, 2);
  tft.println(TimeZoneCity);

  tft.fillRect(70, 150, 64, 20, TFT_RED);
  tft.setCursor(70, 150, 2);
  tft.print("HUMI:");
  tft.println(humidity);


  tft.fillRect(1, 180, 64, 20, TFT_GOLD);
  tft.setCursor(1, 180, 2);
  tft.println(pressure);

  tft.fillRect(70, 180, 64, 20, TFT_SKYBLUE);
  tft.setCursor(70, 180, 2);
  tft.print("WIND:");
  tft.println(windSpeed);

  tft.fillRect(1, 210, 135, 20, TFT_DARKGREEN);
  tft.setCursor(3, 213, 2);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.println(summary);

  tft.pushImage(0, 55, 135, 65, ani[frame]);
  frame++;
  if (frame >= 10)
    frame = 0;
  //delay(200);
}

void setup() {
  Serial.begin(115200);

  sigmaDeltaSetup(pwmLedChannelTFT, pwmFreq);
  sigmaDeltaAttachPin(TFT_BL, pwmLedChannelTFT);
  sigmaDeltaWrite(pwmLedChannelTFT, backlight);

  WiFi.mode(WIFI_STA);
  WiFiMulti.addAP(ssid , password);

  tft.init();
  tft.setRotation(0);
  tft.fillScreen(TFT_BLACK);
  tft.setSwapBytes(true);
  tft.setCursor(0, 0);
  tft.setTextFont(1);
  tft.setTextColor(TFT_WHITE, lightblue);
  tft.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    tft.print(".");
  }
  tft.println("");
  tft.println("WiFi connected.");
  tft.println("IP address: ");
  tft.println(WiFi.localIP());

  DarkSky.begin("DarkSkySpace");

  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  Changer.once(1, GetData);
  SetDisplayStore.attach(SetDisplayPeriod, SetDisplay);
  GetDataStore.attach(GetDataPeriod, GetData);
}

void loop() {}

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

        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 currently = doc["currently"];
            const char* currently_summary = currently["summary"]; // "rain"
            float currently_temperature = currently["temperature"]; // 76.24
            float currently_humidity = currently["humidity"]; // 0.92
            float currently_pressure = currently["pressure"]; // 1015.7
            float currently_windSpeed = currently["windSpeed"]; // 7.57

            DarkSky.putString("TimeZoneCity", City);
            DarkSky.putString("summary", currently_summary);
            DarkSky.putFloat("temperature", currently_temperature);
            DarkSky.putFloat("humidity", currently_humidity);
            DarkSky.putFloat("pressure", currently_pressure);
            DarkSky.putFloat("windSpeed", currently_windSpeed);
          }
          https.end();
          //DarkSky.end();
        }
      }
      delete client;
    }
  }
}


百度网盘分享:链接:https://pan.baidu.com/s/1i79IGoPfJOnHvgDzUqpRpA
提取码:meek





您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail