[ARM入门] 【每周分享】【瑞萨RA8D1 LVGL/LWIP评测】7、接入心知天气并显示天气信息

[复制链接]
40|0
EPTmachine 发表于 2026-2-3 19:03 | 显示全部楼层 |阅读模式
@21小跑堂、#申请原创

1 HTTP简单介绍

HTTP协议是互联网上应用最为广泛的一种网络协议,它的全称是Hypertext Transfer Protocol(超文本传输协议),默认的端口号为80。HTTP协议是一种用于由客户端向服务器传输超文本(例如HTML)的协议,它基于TCP/IP通信协议进行数据传输。

HTTP协议的工作流程大致如下:

  1. 客户端(通常是浏览器)与服务器建立连接。这个连接是通过TCP/IP协议建立的,通常需要指定服务器的IP地址和端口号。
  2. 客户端向服务器发送一个HTTP请求。HTTP请求通常包括一个请求行、一些请求头和请求体。请求行包括请求方法(如GET、POST等)、请求的资源路径和HTTP协议的版本。请求头包含一些额外的信息,如请求的资源类 型、请求的认证信息等。请求体则包含客户端发送给服务器的实际数据。
  3. 服务器接收到HTTP请求后,根据请求方法和路径查找并返回相应的文件作为应答。这个文件可以是HTML页面、图片、视频等资源。
  4. 客户端与服务器关闭连接。在完成数据传输后,客户端和服务器会关闭连接,释放网络资源。

以上就是HTTP协议的基本工作流程。通过这个协议,客户端可以向服务器请求和接收各种类型的资源,从而实现互联网上的信息共享和交互

2 利用心知天气API获取天气

心知天气提供免费的API,为方便演示,注册账号从控制面板可以获得服务的私钥,正式产品中不建议使用这种方式。

seniverse_control_panel.png

利用LWIP实现HTTP GET,通过HTTP通讯从服务器获取带有天气信息的数据。

  • 首先通过LWIP获取主机(也就是域名)的IP地址。
  • 然后TCP通过80端口连接这个IP地址。
  • 向主机发送数据。
  • 接受主机返回的数据。

2.1 添加代码

【每周分享】【瑞萨RA8D1 LVGL/LWIP评测】6、基于lwip实现sntp功能和RTC时间设置
https://bbs.21ic.com/icview-3505453-1-1.html
(出处: 21ic电子技术开发论坛)

导入之前帖子中的 RA8D1_06_LWIP_SNTP_RTC工程,FSP中修改lwip模块内部的sys timeout内存块数量并生成代码。

internal_memory_pools_add.png

HTTP GET获取的返回数据格式为JSON数据,拉取cJSON代码仓库,将其中的 cJSON.c\hcJSON_Utils.c\h文件添加到工程的src文件夹中,调用其中的接口函数用于数据解析。

定义用于连接心知天气服务器、存储和解析返回的报文的宏和变量。

xSemaphoreHandle    wait_dns_sem;
ip_addr_t  sntp_server_ip;
ip_addr_t  weather_server_ip;

#define WEATHER_HOST_NAME   "api.seniverse.com"
#define WEATHER_URL         "GET /v3/weather/now.json?key=<private_key>&location=wuxi&language=zh-Hans&unit=c\r\n\r\n"

uint8_t net_buf[2048];
char weather_str[100];
uint32_t data_len = 0;
uint8_t *ret_data = NULL;

定义以下函数用于心知天气网站的DNS解析,获取对应的IP地址。

static void dns_found2(const char *name, const ip_addr_t *addr, void *arg)
{
  LWIP_UNUSED_ARG(arg);
  printf("%s: %s\n", name, addr ? ipaddr_ntoa(addr) : "<not found>");
  weather_server_ip.addr=addr->addr;
  xSemaphoreGive(wait_dns_sem);
}

static void dns_dorequest2(ip_addr_t *dnsresp)
{
  const char* dnsname = "api.seniverse.com";

  if (dns_gethostbyname(dnsname, dnsresp, dns_found2, NULL) == ERR_OK) {
  }

  xSemaphoreTake(wait_dns_sem,portMAX_DELAY);
}


void lwip_app_thread_entry(void *pvParameters)
{
    FSP_PARAMETER_NOT_USED (pvParameters);
    ....
    ret_data=net_buf;

    wait_dns_sem=xSemaphoreCreateBinary();
    ...

    dns_dorequest2(&weather_server_ip);

}

获取到IP地址,使用以下函数连接到服务器,发送请求数据的HTTP GET数据,并接收返回的数据

/**
 * @brief http get request
 *
 * @param host_name host name
 * @param url url,resource path
 * @param ret_str the http get return
 * @param ret_str_len the content returned by HTTP GET
 * @param ret_str_max_len the content length returned by HTTP GET
 * @return int return execution result
 */
fsp_err_t ln_drv_http_get(uint8_t *host_name,uint8_t *url,uint8_t *ret_str,uint32_t *ret_str_len,uint32_t ret_str_max_len)
{
    //通过Socket创建TCP连接
    FSP_PARAMETER_NOT_USED (host_name);
    int     ret  = 0;
    struct  sockaddr_in  client_addr;
    int     sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock < 0){
        printf("Socket init failed\n");
        return FSP_ERR_ASSERTION;
    }
    memset(&client_addr,0,sizeof(client_addr));
    client_addr.sin_family = AF_INET;
    client_addr.sin_port = htons(80);
    client_addr.sin_addr.s_addr = weather_server_ip.addr;
    memset(&(client_addr.sin_zero), 0, sizeof(client_addr.sin_zero));

    for(int i = 0; i < 10; i ++){
        ret = connect(sock,(struct sockaddr *)&client_addr,sizeof(struct sockaddr));
        if(ret != -1)
            break;
        vTaskDelay(50);
    }

    if(ret == -1){
        printf("TCP Connect failed!\n");
        closesocket(sock);
        vTaskDelay(10);
        return FSP_ERR_ASSERTION;
    }else{
        //向主机发送GET数据
        ret = write(sock,url,strlen((char*)url));
        if(ret != strlen((char*)url)){
            printf("TCP write data failed!\n");
            closesocket(sock);
            return FSP_ERR_ASSERTION;
        }
        //接受主机返回的数据
        ret = recv(sock, ret_str,ret_str_max_len,0);
        closesocket(sock);
        if(ret <= 0){
            printf("TCP read data failed!\n");
            closesocket(sock);
            return FSP_ERR_ASSERTION;
        }else{
            *ret_str_len = ret;
        }
    }
    closesocket(sock);
    return FSP_SUCCESS;
}


void lwip_app_thread_entry(void *pvParameters)
{
    FSP_PARAMETER_NOT_USED (pvParameters);
    ....
    ret_data=net_buf;

    wait_dns_sem=xSemaphoreCreateBinary();
    ...

    dns_dorequest2(&weather_server_ip);
    ln_drv_http_get((uint8_t*)&WEATHER_HOST_NAME,(uint8_t*)&WEATHER_URL,(uint8_t*)ret_data,&data_len,2048);

    printf("HTTP GET RET:%s",(uint8_t *)ret_data);
    ...
}

通过调用cJSON的接口函数,对返回的数据进行解析,提取其中的天气信息。

// 将天气预报信息,构建位需要播报的语音字符串
static bool parse_weather_json(char *analysis_buf, char *tts_str)
{
    char tts_str_temp[100];
    if (analysis_buf == NULL)
        return false;
    cJSON *json_root = cJSON_Parse(analysis_buf);
    if (json_root != NULL)
    {
        cJSON *cjson_arr = cJSON_GetObjectItem(json_root, "results");
        cJSON *cjosn_location = cJSON_GetObjectItem(cJSON_GetArrayItem(cjson_arr, 0), "location");
        printf("\r\n城市 -> %s\r\n", cJSON_GetObjectItem(cjosn_location, "name")->valuestring);
        sprintf(tts_str_temp, "%s", cJSON_GetObjectItem(cjosn_location, "name")->valuestring);
        strcat(tts_str, tts_str_temp);
        // cJSON *cjson_days = cJSON_GetObjectItem(cJSON_GetArrayItem(cjson_arr, 0), "daily");
        cJSON *cjson_today = cJSON_GetObjectItem(cJSON_GetArrayItem(cjson_arr, 0), "now");
        printf("今天天气 -> %s\r\n", cJSON_GetObjectItem(cjson_today, "text")->valuestring);
        printf("温度 -> %s\r\n", cJSON_GetObjectItem(cjson_today, "temperature")->valuestring);
        sprintf(tts_str_temp, "今天天气%s;温度%s摄氏度;",
                cJSON_GetObjectItem(cjson_today, "text")->valuestring,
                cJSON_GetObjectItem(cjson_today, "temperature")->valuestring);
        strcat(tts_str, tts_str_temp);
        printf("%s\r\n", tts_str);
        cJSON_Delete(json_root);
    }
    return true;
}

void lwip_app_thread_entry(void *pvParameters)
{
    FSP_PARAMETER_NOT_USED (pvParameters);
    ....
    ret_data=net_buf;

    wait_dns_sem=xSemaphoreCreateBinary();
    ...

    dns_dorequest2(&weather_server_ip);
    ln_drv_http_get((uint8_t*)&WEATHER_HOST_NAME,(uint8_t*)&WEATHER_URL,(uint8_t*)ret_data,&data_len,2048);

    printf("HTTP GET RET:%s",(uint8_t *)ret_data);
    parse_weather_json(ret_data,weather_str);
    ...
}

2.2 运行效果

编译并烧录程序到开发板,可以得到获取天气信息并输出到串口终端。

weather_data_get.png
upload 附件:RA8D1_07_LWIP_SNTP_RTC_HTTP.zip

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

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

本版积分规则

50

主题

1082

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部
0