prettyprint

2023年1月30日 星期一

[Raspberry Pi Pico W (c-sdk)] lwIP: Ep 2. HTTP Client Application & Weather Station

 本文章介紹Raspberry Pi Pico W c-sdk,使用lwIP的HTTP Client Application 存取openweathermap網站的氣象資料,顯示在TFT LCD上。



使用httpc_get_file_dns function取得 網站資料。分別設定三個callback function:
1: httpc_result_fn:
2. httpc_headers_done_fn:

3.altcp_recv_fn:
err_t recv_fn(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err)

詳細程式碼請參閱文末說明。
成果影片:



程式碼:
 #include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "lwip/apps/http_client.h"
#include "modules/ili9341_tft/fonts/wind_deg.h"
#include "modules/ili9341_tft/fonts/wind.h"
#include "modules/ili9341_tft/fonts/temp.h"
#include "modules/ili9341_tft/fonts/feels.h"
#include "modules/ili9341_tft/fonts/humidity.h"
#include "modules/ili9341_tft/fonts/Rain.h"
#include "modules/ili9341_tft/fonts/Clouds.h"
#include "modules/ili9341_tft/fonts/Clear.h"

#include "modules/ili9341_tft/fonts/Font36.h"
#include "modules/ili9341_tft/fonts/font_fixedsys_mono_24.h"

#include "hardware/rtc.h"

#include "modules/ili9341_tft/ili9341.h"
#include "time.h"

#include "ntp_time.h"
#include "cJSON.h"
#include "math.h"

char ssid[] = "your_SSIO";
char pass[] = "your_PASSWORD";
uint32_t country = CYW43_COUNTRY_TAIWAN;
uint32_t auth = CYW43_AUTH_WPA2_AES_PSK;

char myBuff[1000];
typedef struct weather_data_t {
    cJSON *data_json;
    bool completed;
    int temp;
    int feels_like;
    uint8_t humidity;
    uint16_t pressure;
    uint8_t name[20];
    uint8_t weather[10];
    float wind_speed;
    uint16_t wind_deg;
}WEATHER_DATA;

WEATHER_DATA weather_data;

void rotate_image(const uint8_t *src, uint8_t *dest, uint16_t width, uint16_t height, uint16_t deg) {
    
    double sinx = sin((-1*deg)/180.0 * M_PI);  // -degrees
    double cosx = cos((-1*deg)/180.0 * M_PI);
    
    uint16_t inputImage[width][height];
    uint16_t rotatedImage[width][height];

    for (int y=0; y < height; y++) {
        for (int x=0; x < width; x++) {
            inputImage[x][y] = src[y*width*2+2*x]<<8 | src[y*width*2+2*x+1];
        }
    }

    int xCenter = height/2;        // Rotate image by its center.
    int yCenter = width/2;
    int xt,yt,xRotate,yRotate;

    for(int x=0; x<height; x++) {
        xt = x - xCenter;
        double xt_cosx = xt*cosx;
        double xt_sinx = xt*sinx;
        for(int y=0; y<width; y++) {
            yt = y - yCenter;
            xRotate = (int)(lround(xt_cosx - (yt*sinx)) + xCenter);
            yRotate = lround((yt*cosx) + xt_sinx) + yCenter;  
            if( (xRotate >= 0) && (xRotate < height) && (yRotate >= 0) && (yRotate < width) ) {
                rotatedImage[x][y] = inputImage[xRotate][yRotate];
            } else {
                rotatedImage[x][y] = 0xffff;
            }
        }
    }
    
    for (int y=0; y < height; y++) {
        for (int x=0; x < width; x++) {
            dest[y*width*2+2*x] = rotatedImage[x][y] >> 8;
            dest[y*width*2+2*x+1] = rotatedImage[x][y] &0xff;
        }
    }
}

void result(void *arg, httpc_result_t httpc_result,
        u32_t rx_content_len, u32_t srv_res, err_t err)

{
    if (httpc_result == HTTPC_RESULT_OK) {
        printf("transfer complete\n");
        printf("result=%d\n", httpc_result);
    } else {
        printf("httpc error, result=:%d\n", httpc_result);
    }
}

err_t headers(httpc_state_t *connection, void *arg, 
    struct pbuf *hdr, u16_t hdr_len, u32_t content_len)
{
    return ERR_OK;
}

err_t body(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err)
{
    pbuf_copy_partial(p, myBuff, p->tot_len, 0);
    printf("%s", myBuff);
    weather_data.data_json = cJSON_Parse(myBuff);
    weather_data.completed=true;
    return ERR_OK;
}


void get_weather_data(WEATHER_DATA *wdata, uint8_t* city) {
    
    cJSON_Delete(weather_data.data_json);
    weather_data.completed=false;
 
    httpc_connection_t settings;
    settings.result_fn = result;
    settings.headers_done_fn = headers;
    settings.use_proxy = false;
    uint8_t qstr[200];
    sprintf(qstr, "/data/2.5/weather?q=%s,tw&APPID={your_APPID}", city);
    err_t err = httpc_get_file_dns(
            "api.openweathermap.org",
            LWIP_IANA_PORT_HTTP,
            qstr,
            &settings,
            body,
            NULL,
            NULL
    ); 

    while(!wdata->completed) {
        //printf("not receive data yet!\n");
        sleep_ms(100);
    }
    cJSON *main = cJSON_GetObjectItem(wdata->data_json, "main");
    cJSON *wind = cJSON_GetObjectItem(wdata->data_json, "wind");
    cJSON *weather = cJSON_GetArrayItem(cJSON_GetObjectItem(wdata->data_json, "weather"), 0);
    wdata->temp=(int)(round((cJSON_GetNumberValue(cJSON_GetObjectItem(main, "temp"))-273.15)));
    wdata->feels_like=(int)(round((cJSON_GetNumberValue(cJSON_GetObjectItem(main, "feels_like"))-273.15)));
    wdata->humidity=(int)(cJSON_GetNumberValue(cJSON_GetObjectItem(main, "humidity")));
    wdata->pressure=(uint16_t)(cJSON_GetNumberValue(cJSON_GetObjectItem(main, "pressure")));
    wdata->wind_speed=(cJSON_GetNumberValue(cJSON_GetObjectItem(wind, "speed")));
    wdata->wind_deg=(uint16_t)(cJSON_GetNumberValue(cJSON_GetObjectItem(wind, "deg")));
    strcpy(wdata->weather,cJSON_GetStringValue(cJSON_GetObjectItem(weather, "main")));
    strcpy(wdata->name,cJSON_GetStringValue(cJSON_GetObjectItem(wdata->data_json, "name")));
    //uint32_t dt =(uint32_t) cJSON_GetNumberValue(cJSON_GetObjectItem(wdata->data_json, "dt"));
    //uint32_t timezone =(uint32_t) cJSON_GetNumberValue(cJSON_GetObjectItem(wdata->data_json, "timezone"));
    //time_t t = dt+timezone;
    //struct tm *now = gmtime(&t);
    datetime_t now;
    rtc_get_datetime(&now);

    //cJSON_free(main);
    //cJSON_free(wind);
    //cJSON_free(weather);
    uint8_t buf[20];

    ili9341_draw_string_withbg(65, 5, "                            ", 0xffff, 0xffff, &Font36);
    ili9341_draw_string_withbg(65, 5, wdata->name, 0xff00, 0xffff, &Font36);
    sprintf(buf, "%d  ", wdata->temp);
    ili9341_draw_string_withbg(75, 65, buf, 0x001f, 0xffff, &Font36);
    sprintf(buf, "%d  ", wdata->feels_like);
    ili9341_draw_string_withbg(225, 65, buf, 0x001f, 0xffff, &Font36);
    sprintf(buf, "%d%s  ", wdata->humidity, "%");
    ili9341_draw_string_withbg(65, 125, buf, 0x001f, 0xffff, &Font36);
    sprintf(buf, "%dhPa ", wdata->pressure);
    ili9341_draw_string_withbg(185, 125, buf, 0x001f, 0xffff, &Font36);
    sprintf(buf, "%.1fm/s  ", wdata->wind_speed);
    ili9341_draw_string_withbg(75, 185, buf, 0x001f, 0xffff, &Font36);
    rotate_image(image_data_wind_deg, rotate_image_data_wind_deg, wind_deg.width, wind_deg.height, wdata->wind_deg);
    ili9341_draw_bitmap(160, 185, &rotate_wind_deg);
    sprintf(buf, "%02d/%02d", now.month, now.day);
    ili9341_draw_string_withbg(220, 185, buf, 0xf800, 0xffff, &font_fixedsys_mono_24);
    sprintf(buf, "%02d:%02d", now.hour, now.min);
    ili9341_draw_string_withbg(220, 210, buf, 0xf800, 0xffff, &font_fixedsys_mono_24);
    if (strcmp(wdata->weather, "Clouds")==0) {
        ili9341_draw_bitmap(250, 5, &Clouds);
    }
    if (strcmp(wdata->weather, "Rain")==0) {
        ili9341_draw_bitmap(250, 5, &Rain);
    }
    if (strcmp(wdata->weather, "Clear")==0) {
        ili9341_draw_bitmap(250, 5, &Clear);
    }

}   

bool  wifi_connect() {
    cyw43_arch_enable_sta_mode();
    if (cyw43_arch_wifi_connect_timeout_ms(ssid, pass, auth, 10000)) {
        printf("wifi connect error\n");
        return false;
    }
    int wait_secs = 0;
    int link_state;
    while (wait_secs <= 10) {
        link_state = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
        if (link_state != CYW43_LINK_UP) {
            wait_secs++;
            if (wait_secs == 10) {
                printf("Can not get ip address\n");
                return false;
            }
            sleep_ms(1000);
        } else {
            break;
        }
    }
    return true;
}

void weather_background() {
    ili9341_draw_string(5,5, "City:", 0x0000, &Font36);
    ili9341_draw_bitmap(5, 65, &temp);
    ili9341_draw_bitmap(165, 65, &feels);
    ili9341_draw_bitmap(5, 125, &humidity);
    ili9341_draw_bitmap(5, 185, &wind);
}
int main()
{
    stdio_init_all();
    cyw43_arch_init();
    ili9341_init();
    weather_data.data_json=cJSON_CreateObject();
    
    weather_background();
    if (!wifi_connect()) {
        printf("connect wifi error\n");
    }
    ntp_time_init();
    get_ntp_time();
    while(1) { 
        get_weather_data(&weather_data, "Taipei");
        sleep_ms(5000);

        get_weather_data(&weather_data, "Taitung");
        sleep_ms(5000);

        get_weather_data(&weather_data, "Kaohsiung");
        sleep_ms(5000);
        }

}

沒有留言:

張貼留言