锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

Wio Terminal 天气小助手(Funpack 项目)

时间:2022-08-03 17:19:00 sitemap wio传感器

Demo 概述

这个 Demo 展示了如何使用 Wio Terminal 天气小助手,Wio Terminal 通过 I2C 接口连接温湿度传感器 AHT10 通过对室内环境温湿度的实时监测,同时通过 WiFi 网络可以在未来三天获取当地天气信息和天气预报,并使用按钮切换显示界面。

实现功能

重点难点

  • 实现温湿度传感器的实时读取和显示
  • 从 Web API 获取天气信息并进行分析 JSON 数据

硬件材料

  • 1 x Wio Terminal
  • 1x AHT10 传感器模块

安装依赖库

本示例 Demo 依赖 LCD 库、ArduinoJson 库、AHTX0 库和 Bounce2 库:

  • LCD 库在安装 Seeed SAMD Boards 库时已经包含了,可以参考 Wio Terminal 开发环境。
  • ArduinoJson 库可以在 GitHub 仓库下载,在 Arduino IDE 点击 项目 > 加载库 > 添加 .ZIP 库… 可添加库。
  • AHTX0 库可以在 GitHub 仓库下载,在 Arduino IDE 点击 项目 > 加载库 > 添加 .ZIP 库… 可添加库。
  • Bounce2 库可以在 GitHub 仓库下载,在 Arduino IDE 点击 项目 > 加载库 > 添加 .ZIP 库… 可添加库。

提示:这些库也可以在 Arduino IDE 搜索并安装库管理器。

另外,我们也用过 Free_Fonts.h 库中提供的一些免费字体一些免费字体,并将其放在这里 Arduino 工程中。

读取传感器

读取 AHT10 传感器温湿度数据的示例代码如下:

#include   Adafruit_AHTX0 aht;  void setup() { 
             Serial.begin(115200);      if (! aht.begin()) { 
                 while (1) delay(10);     } }  void loop() { 
             sensors_event_t humidity, temp;          // populate temp and humidity objects with fresh data     aht.getEvent(&humidity, &temp);          Serial.print("Temperature: "); Serial.print(temp.temperature);      Serial.print("Humidity: "); Serial.print(humidity.relative_humidity);

    delay(500);
}

天气 API

有很多提供天气信息的 Web API,可以参考《一些好用的天气 API》,本文使用高德地图 API 获取实时天气及天气预测。GET 请求的 URL 如下:

实时天气(当天)

https://restapi.amap.com/v3/weather/weatherInfo?city=441802&key=yourkey

天气预测(未来三天)

https://restapi.amap.com/v3/weather/weatherInfo?city=441802&key=yourkey&extensions=all

参数说明:

  • city 是城市编码,比如 441802 代表广州;
  • key 是应用对应的代码,需要在平台申请(提示:将 yourkey 替换为你申请的 Key 代码);
  • extensions 表示获取类型,缺省值是 base,表示获取实况天气,all 表示获取预报天气;
  • output 表示返回格式,可选 JSON 或 XML,默认返回 JSON 格式数据。

以实时天气 API 为例,返回的 JSON 数据如下:

{ 
        
    "status":"1",
    "count":"1",
    "info":"OK",
    "infocode":"10000",
    "lives":[
        { 
        "province":"广东",
         "city":"广州市",
         "adcode":"440100",
         "weather":"晴",
         "temperature":"17",
         "winddirection":"北",
         "windpower":"≤3",
         "humidity":"64",
         "reporttime":"2021-12-12 19:00:44"
        }
    ]
}

完整代码

提示:将下面代码中的 ssidpassword 替换成你的 WiFi 网络;将 URL_BASEURL_ALL 中的 cityCode 替换成需要查询的城市,将 yourKey 替换成你的 Key。

另外,本 Demo 并未实现中文显示,如需显示中文字体,可参考 Wio Terminal LCD 中文显示。

#include 
#include 
#include 
#include 

/* Display */
#include "Free_Fonts.h"
#include "TFT_eSPI.h"

/* Sensor */
#include 

/* Button */
#include 

// INSTANTIATE 3 Button OBJECT
Bounce2::Button btnA = Bounce2::Button();
Bounce2::Button btnL = Bounce2::Button();
Bounce2::Button btnR = Bounce2::Button();

Adafruit_AHTX0 aht;
TFT_eSPI       tft;

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPassword";

const char* URL_BASE = "https://restapi.amap.com/v3/weather/weatherInfo?city=cityCode&key=yourKey";
const char* URL_ALL  = "https://restapi.amap.com/v3/weather/weatherInfo?city=cityCode&key=yourKey&extensions=all";

WiFiClientSecure client;

#define STR_SIZE_MAX 16

typedef struct lives { 
        
    char province[16];
    char city[16];
    char adcode[16];
    char weather[16];
    char temperature[16];
    char humidity[16];
    char winddirection[16];
    char windpower[16];
    char reporttime[16];
} lives_t;

lives_t lives_data;

typedef struct forecasts { 
        
    char date[16];
    char week[16];
    char dayweather[16];
    char nightweather[16];
    char daytemp[16];
    char nighttemp[16];
    char daywind[16];
    char nightwind[16];
    char daypower[16];
    char nightpower[16];
} forecasts_t;

#define FORECASTS_SIZE 4
forecasts_t forecasts_data[FORECASTS_SIZE];

enum { 
        
    PAGE_1 = 1,
    PAGE_2 = 2,
    PAGE_3 = 3,
    PAGE_4 = 4,
    PAGE_5 = 5,
    PAGE_MAX = PAGE_5
};

int currentPage = PAGE_1;
boolean pageChanged = false;
boolean update_flag = true;

void setup()
{ 
        
    btnA.attach( WIO_KEY_C ,  INPUT_PULLUP );
    btnL.attach( WIO_5S_LEFT ,  INPUT_PULLUP );
    btnR.attach( WIO_5S_RIGHT ,  INPUT_PULLUP );

    btnA.interval(5);
    btnL.interval(5);
    btnR.interval(5);

    btnA.setPressedState(LOW); 
    btnL.setPressedState(LOW); 
    btnR.setPressedState(LOW); 

    Serial.begin(115200);

    if (! aht.begin()) { 
        
        Serial.println("Could not find AHT? Check wiring");
        while (1) delay(10);
    }
    Serial.println("AHT10 or AHT20 found");

    tft.init();
    tft.setRotation(3);
    tft.fillScreen(tft.color565(24,15,60));
    tft.fillScreen(TFT_NAVY);
    tft.setFreeFont(FMB12);
    tft.setCursor((320 - tft.textWidth("Funpack Weather Box"))/2, 100);
    tft.print("Funpack Weather Box");

    tft.setFreeFont(FM9);
    tft.setTextColor(TFT_LIGHTGREY);
    tft.setCursor((320 - tft.textWidth("Connecting WiFi..."))/2, 180);
    tft.print("Connecting WiFi...");
    
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) { 
         //Check for the connection
        delay(500);
        Serial.println("Connecting WiFi...");
    }
    Serial.print("Connected to the WiFi network with IP: ");
    Serial.println(WiFi.localIP());
    //client.setCACert(test_root_ca);

    if(&client) { 
           
        getWeatherLives();
        getWeatherForecasts();
    }
    drawWeatherLivePage(lives_data);
}

void loop()
{ 
        
    btnA.update();
    btnL.update();
    btnR.update();

    if ( btnA.pressed() ) { 
        
        pageChanged = true;
        getWeatherLives();
        getWeatherForecasts();
        currentPage = PAGE_1;
        Serial.print("updated!");
    }

    if ( btnL.pressed() ) { 
        
        pageChanged = true;
        currentPage--;
        if (currentPage < PAGE_1) { 
        
            currentPage = PAGE_MAX;
        }
        Serial.print("prev page: ");Serial.println(currentPage);
    }

    if ( btnR.pressed() ) { 
        
        pageChanged = true;
        currentPage++;
        if (currentPage > PAGE_MAX) { 
        
            currentPage = PAGE_1;
        }
        Serial.print("next page: ");Serial.println(currentPage);
    }
    
    switch (currentPage) { 
        
      case PAGE_1:
      { 
        
        static int cnt = 0;
        if (pageChanged) { 
        
          drawWeatherLivePage(lives_data);
          updateSensorData();
        }
        if (cnt++ % 100000 == 0) { 
        
          updateSensorData();
        }
        
        pageChanged = false;
      } break;
      case PAGE_2:
      { 
        
        if (pageChanged) { 
        
          drawWeatherForecastPage(&forecasts_data[0]);
        }
        pageChanged = false;
      } break;
      case PAGE_3:
      { 
        
        if (pageChanged) { 
        
          drawWeatherForecastPage(&forecasts_data[1]);
        }
        pageChanged = false;
      } break;
      case PAGE_4:
      { 
        
        if (pageChanged) { 
        
          drawWeatherForecastPage(&forecasts_data[2]);
        }
        pageChanged = false;
      } break;
      case PAGE_5:
      { 
        
        if (pageChanged) { 
        
          drawWeatherForecastPage(&forecasts_data[3]);
        }
        pageChanged = false;
      } break;
      default: break;
    }
}

void updateSensorData()
{ 
        
    sensors_event_t humi, temp;
    aht.getEvent(&humi, &temp);// populate temp and humidity objects with fresh data

    drawTempValue(temp.temperature);
    drawHumiValue(humi.relative_humidity);
}

void drawTempValue(const float temp) { 
        
   tft.setFreeFont(FMB24);
   tft.setTextColor(TFT_RED, tft.color565(40,40,86));
   tft.drawString(String(temp, 1), 30, 140);
}

void drawHumiValue(const float humi) { 
        
   tft.setFreeFont(FMB24);
   tft.setTextColor(TFT_GREEN, tft.color565(40,40,86));
   tft.drawString(String(humi, 1), 180, 140);
}

void drawWeatherLivePage(lives_t &lives_data)
{ 
        
    // -----------------LCD---------------------

    tft.fillScreen(tft.color565(24,15,60));
    tft.setFreeFont(FF17);
    tft.setTextColor(tft.color565(224,225,232));
    tft.drawString("Funpack Weather Box", 10, 10);

    tft.setFreeFont(FMB9);
    if (0 == strcmp(lives_data.weather, "晴")) { 
        
      tft.setTextColor(TFT_ORANGE);
      tft.drawString("sunny", 240, 10);
    } else if (0 == strcmp(lives_data.weather, "多云")) { 
        
      tft.setTextColor(TFT_WHITE);
      tft.drawString("cloudy", 240, 10);
    } else if (0 == strcmp(lives_data.weather, "阴")) { 
        
      tft.setTextColor(TFT_LIGHTGREY);
      tft.drawString("cloudy", 240, 10);
    } else if (0 == strcmp(lives_data.weather, "雨")) { 
        
      tft.setTextColor(TFT_DARKCYAN);
      tft.drawString("rainy", 240, 10);
    }
 
    tft.fillRoundRect(10,  45, 145, 180, 5, tft.color565(40,40,86));
    tft.fillRoundRect(165, 45, 145, 180, 5, tft.color565(40,40,86));

    tft.setFreeFont(FM9);
    tft.setTextColor(TFT_WHITE);
    tft.drawString("Temperature", 25, 60);
    tft.drawString("Humidity",   195, 60);
    
    tft.setTextColor(TFT_DARKGREY);
    tft.drawString("degrees C",   35, 200);
    tft.drawString("% rH",       220, 200);

    tft.setFreeFont(FMB24);
    tft.setTextColor(TFT_RED, tft.color565(40,40,86));
    tft.drawString(lives_data.temperature, 30, 100);
    Serial.println(lives_data.temperature);

    tft.setFreeFont(FMB24);
    tft.setTextColor(TFT_GREEN, tft.color565(40,40,86));
    tft.drawString(lives_data.humidity, 180, 100);
    Serial.println(lives_data.humidity);
}

void drawWeatherForecastPage(forecasts_t *forecasts_data)
{ 
        
    // -----------------LCD---------------------

    tft.fillScreen(tft.color565(24,15,60));
    tft.setFreeFont(FF17);
    tft.setTextColor(tft.

相关文章