【Funpack第12期】基于Wio Terminal的天气预报仪
制作一个自动联网的天气预报仪,在设计界面显示温湿度、天气情况、空气质量以及未来三天内的天气变化
标签
嵌入式系统
显示
dzsl_user
更新2021-12-28
1867

工程说明

本工程基于PIO(PlatformIO)搭建,采用Arduino框架,采取的外部软件包及其依赖如下所示:

 Dependency Graph
 |-- <Seeed Arduino rpcUnified> 2.1.3
 |   |-- <Seeed Arduino FreeRTOS> 1.1.0
 |   |-- <Seeed_Arduino_mbedtls> 3.0.1
 |-- <Seeed Arduino rpcWiFi> 1.0.5
 |   |-- <Seeed Arduino rpcUnified> 2.1.3
 |   |   |-- <Seeed Arduino FreeRTOS> 1.1.0
 |   |   |-- <Seeed_Arduino_mbedtls> 3.0.1
 |   |-- <Seeed_Arduino_mbedtls> 3.0.1
 |   |-- <Seeed Arduino FS> 2.1.1
 |   |   |-- <SPI> 1.0
 |   |   |   |-- <Adafruit Zero DMA Library> 1.0.4
 |-- <Seeed Arduino FS> 2.1.1
 |   |-- <SPI> 1.0
 |   |   |-- <Adafruit Zero DMA Library> 1.0.4
 |-- <Seeed Arduino SFUD> 2.0.2
 |   |-- <Seeed Arduino FS> 2.1.1
 |   |   |-- <SPI> 1.0
 |   |   |   |-- <Adafruit Zero DMA Library> 1.0.4
 |   |-- <SPI> 1.0
 |   |   |-- <Adafruit Zero DMA Library> 1.0.4
 |-- <Seeed_Arduino_mbedtls> 3.0.1
 |-- <millisDelay> 1.3
 |-- <ArduinoJson> 6.18.0
 |-- <lvgl> 8.0.1
 |   |-- <Seeed Arduino rpcUnified> 2.1.3
 |   |   |-- <Seeed Arduino FreeRTOS> 1.1.0
 |   |   |-- <Seeed_Arduino_mbedtls> 3.0.1
 |   |-- <Seeed Arduino FreeRTOS> 1.1.0
 |-- <Seeed Arduino RTC> 2.0.0
 |-- <Seeed_Arduino_LCD> 1.6.0
 |   |-- <SPI> 1.0
 |   |   |-- <Adafruit Zero DMA Library> 1.0.4
 |   |-- <Seeed Arduino FS> 2.1.1
 |   |   |-- <SPI> 1.0
 |   |   |   |-- <Adafruit Zero DMA Library> 1.0.4
 |-- <SPI> 1.0
 |   |-- <Adafruit Zero DMA Library> 1.0.4
 |-- <Wire> 1.0
  • 其中millisDelaySeeed_Arduino_mbedtls这两个库在PIO官方库中均不存在,已经额外添加到本工程的lib下,其余库均为PIO提供或bsp中提供

本工程的基本结构如下:

  • include、test:PIO工程默认生成文件夹,本工程中暂时未使用

  • lib:PIO中没有的库

  • src:整个工程的源码

    • assets:各种图标与字体

整体资源占用如下:

资源占用

编译下载

在PlatformIO中打开,点击编译并烧录即可编译工程并下载到板子中

实现功能

主要实现如下工程:

  1. 通过wifi链接网络,并从和风天气上在线获取当地的天气情况

  2. 采用LVGL设计界面,分别展示当前时间与天气

    1. 采用NTP同步时间,并且用数字表盘相似

    2. 所有字体图标等资源直接内嵌到代码中,无需外部flash或sd卡

    3. 展示当前地区的温湿度、天气情况、空气质量以及未来三天内的天气变化

  3. 状况

各功能主要代码 main

void setup()
{
    pinMode(WIO_KEY_A, INPUT_PULLUP);
    ...
    pinMode(WIO_BUZZER, OUTPUT);

    lvgl_init();
    device_init();
}

void loop()
{
    long last_time = millis();
    delay(5);
    lv_timer_handler(); /* let the GUI do its work */
    lv_tick_inc(int(millis() - last_time));
    ntp_handler();
}
  • Arduino的主体框架,包括lvgl的初始化与gpio的初始化

  • device_init中会初始化wifi、ntp以及相关界面,同时会通过lvgl在屏幕上输出开机进度条

ntp

void ntp_init()
{
    // declare a time object
    DateTime now;
    // localtime
    unsigned long devicetime = getNTPtime();

    ...

    // get and print the current rtc time
    now = rtc.now();
    Serial.print("RTC time is: ");
    Serial.println(now.timestamp(DateTime::TIMESTAMP_FULL));

    // adjust time using ntp time
    rtc.adjust(DateTime(devicetime));

    // print boot update details
    Serial.println("RTC (boot) time updated.");
    // get and print the adjusted rtc time
    now = rtc.now();
    Serial.print("Adjusted RTC (boot) time is: ");
    Serial.println(now.timestamp(DateTime::TIMESTAMP_FULL));

    // start millisdelays timers as required, adjust to suit requirements
    updateDelay.start(12 * 60 * 60 * 1000); // update time via ntp every 12 hrs
}

void ntp_handler()
{
    DateTime now;
    unsigned long devicetime;

    if (updateDelay.justFinished())
    { // 12 hour loop
        // repeat timer
        updateDelay.repeat(); // repeat

        // update rtc time
        devicetime = getNTPtime();
        if (devicetime == 0)
        {
            Serial.println("Failed to get time from network time server.");
        }
        else
        {
            rtc.adjust(DateTime(devicetime));
            Serial.println("");
            Serial.println("rtc time updated.");
            // get and print the adjusted rtc time
            now = rtc.now();
            Serial.print("Adjusted RTC time is: ");
            Serial.println(now.timestamp(DateTime::TIMESTAMP_FULL));
        }
    }
}
  • ntp_init中通过网络获取时间,同时更新本地时间,接着会通过millisDelay库设置没12小时更新一次时间

  • ntp_handler会每隔一段时间调用一次,查看是否需要更新本地时间

HeFeng

void HeFeng::doUpdateCurr(CurrentData &data)
{
    HTTPClient https;
    if (https.begin(client, url))
    { // HTTPS
        int httpCode = https.GET();
        if (httpCode > 0)
        {
            if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY)
            {
                String payload = https.getString();
                Serial.println(payload);

                DynamicJsonDocument jsonBuffer(2048);
                deserializeJson(jsonBuffer, payload);
                JsonObject root = jsonBuffer.as<JsonObject>();

                // data.code = root["code"].toInt();
                data.code = root["code"];
                ...
                data.dew = root["now"]["dew"].as<String>();
            }
        }
        else
            ...
        https.end();
    }
    else
        ...
}

const lv_img_dsc_t* HeFeng::getMeteoconIcon(int cond_code)
{
    switch (cond_code)
    {
    case 100:
    case 150:
        return &icon_qingtian;
    ...
    case 504:
        return &icon_fuchen;
    }
    return NULL;
}
  • 通过wifi解析和风天气的API,获得对应的数据

  • 通过解析的数据编号,获得相应的图标地址

app_clock

void app_weather_init(lv_obj_t * scr)
{
    CurrentData nowdata;
    hefeng.doUpdateCurr(nowdata);

    AirQualityData airdata;
    hefeng.doUpdateAirQuality(airdata);

    int days = 3;
    DailyData dailyData[days];
    hefeng.doUpdateDaily(dailyData, days);

    //当天
    const lv_img_dsc_t* img = hefeng.getMeteoconIcon(nowdata.icon);
    lv_obj_t * img1 = lv_img_create(scr);
    ...

    //后三天
    img = hefeng.getMeteoconIcon(dailyData[0].iconDay);
    img1 = lv_img_create(scr);
    ...
}
  • 调用HeFeng模块获得天气数据并通过lvgl显示

app_weather

static void set_sec_value(void * indic, int32_t v)
{
    lasttime = rtc.now();
    lv_meter_set_indicator_value(meter, (lv_meter_indicator_t *)indic_sec, lasttime.second()%60);
    lv_meter_set_indicator_value(meter, (lv_meter_indicator_t *)indic_min, lasttime.minute()%60);
    lv_meter_set_indicator_value(meter, (lv_meter_indicator_t *)indic_hour, (lasttime.hour()%12)*5);
}

void app_clock_init(lv_obj_t * scr)
{
    meter = lv_meter_create(scr);
    lv_obj_set_size(meter, 220, 220);
    lv_obj_center(meter);
    ...
}
  • 调用rtc模块获得本地时间数据并通过lvgl显示

功能展示及说明

开机进度条:

开机进度条

时钟:

FnIHLZrN5hgKzZtg7M7Kv8uyaKz6

天气:

FgUKCf5lZ0wPWnqZTduNokKmSojG

心得体会

感谢硬禾举办的这次活动,让我有机会接触到wio terminal这款非常不错的板卡,丰富的资料与外设让我能够学到很多相关知识。

最后还是要吐槽下电子森林这个编辑器,对代码和图片编辑不太友好,建议支持markdown格式

再多吐槽一句,编辑项目时每一栏都需要分开保存,有点小小的无语。。。

附件下载
WeatherStation.zip
PlatformIO 工程源码
团队介绍
团队成员
dzsl_user
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号