Using RTThread and TouchGFX to realize DIY digital instrument -- synchronous weather information

Keywords: Session network JSON Mobile

catalog:

1. Using RTThread and TouchGFX to realize DIY digital instrument (1) -- using stm32ubmx5.6 to transplant touchGFX4.13
2. Using RTThread and TouchGFX to realize DIY digital instrument (2) -- porting TouchGFX to RTThread system
3. Using RTThread and TouchGFX to realize DIY digital instrument (3) - obtaining temperature and humidity sensor data
4. Using RTThread and TouchGFX to realize DIY digital instrument (4) - synchronous network time
5. Using RTThread and TouchGFX to realize DIY digital instrument (5) - synchronous weather information
6. Use RTThread and TouchGFX to realize DIY digital instrument (6) - link to Alibaba cloud Internet of things platform
7. Using RTThread and TouchGFX to realize DIY digital instrument (7) - using MQTT.fx analog mobile device to communicate between M2M devices
8. Using RTThread and TouchGFX to realize DIY digital instrument (8) -- developing wechat applet
9. Using RTThread and TouchGFX to realize DIY digital instrument (9) -- tutorial of TouchGFX control







Experimental platform:

Hardware: Wildfire challenger STM32F767 V1 development and ESP8266 module
Software: TouchGFXDesigner v4.13 and STM32CubeMX v5.6.0, MDK v5.29, RT thread env tool

Preparation before experiment:

1. Prepare a set of wildfire challenger STM32F767 development version or other core boards
2. Install TouchGFXDesigner v4.13
3. Install STM32CubeMX v5.6.0 and X? Cube? Touchgfx software package
4. Install MDK v5.27 and above
5. Download the RTThread source package https://gitee.com/rtthread/rt-thread
6. Registration Knowing the weather




Download:

Code updating: github code download address https://gitee.com/Aladdin-Wang/hellotouchGFX.git

Contact author:

Add wechat comment touchgfx, pull in touchgfx rtthread technology exchange group to learn together

1. Register for Xinzhi weather to obtain private key





2. Add WebClient package

Because we get weather information by visiting Knowing the weather So we need to open the local Web client.

3. Add CJSON software package

Looking at the API return data of Xinzhi weather, we can see that the data format used is JSON, so we need to open CJSON software package to parse the data.



4. Add use code

weather_httpclient.c

#include <rtthread.h>
#include <webclient.h>
#include <url_code.h>
#include <string.h>
#include "cJSON_util.h"
#include <board.h>
#include <arpa/inet.h> 
#include <netdev.h>
#include <ntp.h>
#include <weather_httpclient.h>
#define LOG_TAG     "weather"
#define LOG_LVL     LOG_LVL_INFO
#include <ulog.h>
#define THREAD_PRIORITY         12
#define THREAD_STACK_SIZE       1024
#define THREAD_TIMESLICE        5

static rt_thread_t tid1 = RT_NULL;
static struct rt_mailbox weather_mb;
static char mb_pool[16];


char *gfxvalue;
#define GET_HEADER_BUFSZ        2048
#define GET_RESP_BUFSZ                2048
#define GET_RESP_CONTENTSZ        4096
#define URL_LEN_MAX                        2048

#define GET_LOCAL_URI                "http://api.seniverse.com/v3/weather/daily.json?key=S97hL3kj6EbnjEmyC&location=%s&language=zh-Hans&unit=c&start=0&days=5"
#define LOCAL_CITY                   "beijing"        

static weather_t gfx_weather[3];

static void weather_data_parse(char* data)
{
   cJSON *root = RT_NULL, *arrayItem = RT_NULL,*object = RT_NULL, *object2 = RT_NULL,*list = RT_NULL, *item = RT_NULL, *weatheritem = RT_NULL;
        int index, list_size = 0;
   root = cJSON_Parse((const char *)data);
   if (!root)
   {
       rt_kprintf("No memory for cJSON root!\n");
       return;
   }
   arrayItem = cJSON_GetObjectItem(root, "results"); 
    if (arrayItem == RT_NULL)
    {
        rt_kprintf("cJSON get results failed.");
        goto __EXIT;
    }   

	 object = cJSON_GetArrayItem(arrayItem, 0); 
	 if (object == RT_NULL)
    {
        rt_kprintf("cJSON get object failed.");
        goto __EXIT;
    } 
	item = cJSON_GetObjectItem(object, "location");  /* Match sub object 1 */
    if (item == RT_NULL)
    {
        rt_kprintf("cJSON get location failed.");
        goto __EXIT;
    } 
	if((list = cJSON_GetObjectItem(item,"name")) != NULL)   
	{
		rt_kprintf("city: %s\r\n",list->valuestring);
	}
	object2 = cJSON_GetObjectItem(object, "daily");  /* Match sub object 2 */
	 if (object2 == RT_NULL)
    {
        rt_kprintf("cJSON get object2 failed.");
        goto __EXIT;
    } 	
	int size = cJSON_GetArraySize(object2);     //Get the number of objects in the array
	rt_kprintf("\n");
	for(int i = 0 ;i<size;i++ )
	{
		item = cJSON_GetArrayItem(object2, i); 
		
		if (item == RT_NULL)
		{
			rt_kprintf("cJSON get daily failed.");
			goto __EXIT;
		} 
		if((list = cJSON_GetObjectItem(item,"date")) != NULL)   
		{
			rt_kprintf("date: %s\r\n",list->valuestring);
			strncpy(gfx_weather[i].date, list->valuestring,strlen(list->valuestring));	
		}
		if((list = cJSON_GetObjectItem(item,"text_day")) != NULL)   
		{
			rt_kprintf("text_day: %s\r\n",list->valuestring);
			strncpy(gfx_weather[i].text_day, list->valuestring,strlen(list->valuestring));	
		}
		if((list = cJSON_GetObjectItem(item,"code_day")) != NULL)   
		{
			rt_kprintf("code_day: %s\r\n",list->valuestring);
			strncpy(gfx_weather[i].code_day, list->valuestring,strlen(list->valuestring));				
		}
		if((list = cJSON_GetObjectItem(item,"text_night")) != NULL)   
		{
			rt_kprintf("text_night: %s\r\n",list->valuestring);
			strncpy(gfx_weather[i].text_night, list->valuestring,strlen(list->valuestring));				
		}	
		if((list = cJSON_GetObjectItem(item,"high")) != NULL)   
		{
			rt_kprintf("high: %s\r\n",list->valuestring);
			strncpy(gfx_weather[i].high, list->valuestring,strlen(list->valuestring));				
		}
		if((list = cJSON_GetObjectItem(item,"low")) != NULL)   
		{
			rt_kprintf("low: %s\r\n",list->valuestring);
			strncpy(gfx_weather[i].low, list->valuestring,strlen(list->valuestring));				
		}	
		if((list = cJSON_GetObjectItem(item,"wind_direction")) != NULL)   
		{
			rt_kprintf("wind_direction: %s\r\n",list->valuestring);
			strncpy(gfx_weather[i].wind_direction, list->valuestring,strlen(list->valuestring));				
		}
		if((list = cJSON_GetObjectItem(item,"wind_speed")) != NULL)   
		{
			rt_kprintf("wind_speed: %s\r\n",list->valuestring);
			strncpy(gfx_weather[i].wind_speed, list->valuestring,strlen(list->valuestring));			
		}
		if((list = cJSON_GetObjectItem(item,"rainfall")) != NULL)   
		{
			rt_kprintf("rainfall: %s\r\n",list->valuestring);
			strncpy(gfx_weather[i].rainfall, list->valuestring,strlen(list->valuestring));			
		}
		if((list = cJSON_GetObjectItem(item,"humidity")) != NULL)   
		{
			rt_kprintf("humidity: %s\r\n",list->valuestring);
			strncpy(gfx_weather[i].humidity, list->valuestring,strlen(list->valuestring));			
		}	
		rt_kprintf("\n");
	}

__EXIT:
   if (root != RT_NULL)
       cJSON_Delete(root);        
}

int get_weather(int argc, char **argv)
{
    struct webclient_session* session = RT_NULL;
    unsigned char *buffer = RT_NULL;
    char *URI = RT_NULL;
    int index, ret = 0;
    int bytes_read, resp_status;
    int content_length = -1;
	char *city_name = rt_calloc(1,255);
	if(argc == 1)
	{
		strcpy(city_name, LOCAL_CITY);
	}
	else if (argc == 2)
    {
        strcpy(city_name, argv[1]);
        urlencode(city_name);//Code Chinese
    }
    else if(argc > 2)
    {
        rt_kprintf("wt [CityName]  - webclient GET request test.\n");
        return -1;
    }
        URI = rt_calloc(1, URL_LEN_MAX);        
        rt_snprintf(URI, URL_LEN_MAX, GET_LOCAL_URI, city_name);
    buffer = (unsigned char *) web_malloc(GET_RESP_CONTENTSZ);
    if (buffer == RT_NULL)
    {
        rt_kprintf("no memory for receive buffer.\n");
        ret = -RT_ENOMEM;
        goto __exit;
    }

    /* create webclient session and set header response size */
    session = webclient_session_create(GET_HEADER_BUFSZ);
    if (session == RT_NULL)
    {
        ret = -RT_ENOMEM;
        goto __exit;
    }

    /* send GET request by default header */
        rt_kprintf("send GET request to %s\n", URI);
    if ((resp_status = webclient_get(session, URI)) != 200)
    {
        rt_kprintf("webclient GET request failed, response(%d) error.\n", resp_status);
        ret = -RT_ERROR;
        goto __exit;
    }
    content_length = webclient_content_length_get(session);
    if (content_length < 0)
    {
        rt_kprintf("webclient GET request type is chunked.\n");
        do
        {
            bytes_read = webclient_read(session, buffer, GET_RESP_BUFSZ);
            if (bytes_read <= 0)
            {
                break;
            }

            for (index = 0; index < bytes_read; index++)
            {
                rt_kprintf("%c", buffer[index]);
            }
        } while (1);
        rt_kprintf("\n");
    }
    else
    {
                int content_pos = 0;
        do
        {
            bytes_read = webclient_read(session, buffer+content_pos, GET_RESP_BUFSZ);
            if (bytes_read <= 0)
            {
                                break;
            }
            content_pos += bytes_read;
        } while (content_pos < content_length);
        weather_data_parse((char*)buffer);
    }

__exit:
    if (session)
    {
        webclient_close(session);
    }

    if (buffer)
    {
        web_free(buffer);
    }

    if (URI)
    {
        web_free(URI);
    }

    return ret;
}
weather_t  *gfxget_weather_date(void)
{
	if (rt_mb_recv(&weather_mb, (rt_ubase_t *)&gfx_weather, RT_WAITING_NO) == RT_EOK)
	{
		return gfx_weather;
	}
	else
	{
		return RT_NULL;
	}
    
}
/* Entry function */
static void weather_collect_thread_entry(void *parameter)
{
	//Get network card object
	struct netdev* net = netdev_get_by_name("esp0");
	//Block to determine whether the current network is connected normally
	while(netdev_is_internet_up(net) != 1)
	{
	   rt_thread_mdelay(200);
	}
	if(0== get_weather(1,0))
	{
		rt_mb_send(&weather_mb, (rt_uint32_t)gfx_weather);
	}
	while(1)
	{
		rt_thread_mdelay(5000);
		rt_mb_send(&weather_mb, (rt_uint32_t)gfx_weather);		
	}
}
/* Create thread */
int weather_collect(void)
{
	rt_err_t result = RT_EOK;
	/* Initialize mailbox */
    result = rt_mb_init(&weather_mb,
                        "weather_mbt",                /* The name is sht30 × MBT */
                        &mb_pool[0],                /* The memory pool used by mailbox is MB pool */
                        sizeof(mb_pool) / 4,        /* The number of messages in the mailbox because one message takes up 4 bytes */
                        RT_IPC_FLAG_FIFO);          /* Using FIFO to wait for threads */
    if (result != RT_EOK)
    {
        LOG_D("init mailbox failed.\n");
        return -1;
    }

    /* Create thread*/
    tid1 = rt_thread_create("weather",
            weather_collect_thread_entry, RT_NULL,
                            THREAD_STACK_SIZE,
                            THREAD_PRIORITY, THREAD_TIMESLICE);

    /* If you get the thread control block, start the thread */
    if (tid1 != RT_NULL)
        rt_thread_startup(tid1);

    return 0;
}
INIT_APP_EXPORT(weather_collect);
#ifdef FINSH_USING_MSH
#include <finsh.h>
MSH_CMD_EXPORT_ALIAS(get_weather, wt, wt [CityName]  webclient GET request test);
#endif /* FINSH_USING_MSH */

weather_httpclient.h

#ifndef __WEATHER_H_
#define __WEATHER_H_
#include <rtthread.h>
typedef struct weather {
	char date[8];				
	char text_day[8];		
	char code_day[8];	
	char text_night[8];	
	char high[8];	
	char low[8];		
	char wind_direction[8];		
	char wind_speed[8];		
	char rainfall[8];	
	char humidity[8];	
} weather_t;


#endif

5. Add URL transcoding file

URL transcoding is required for Chinese place names
url_code.c

#include <url_code.h>
//#include <stdio.h>
#include <string.h>
#include <rtthread.h>

#define BURSIZE 1024

static int hex2dec(char c)
{
        if ('0' <= c && c <= '9') {
                return c - '0';
        } else if ('a' <= c && c <= 'f') {
                return c - 'a' + 10;
        } else if ('A' <= c && c <= 'F') {
                return c - 'A' + 10;
        } else {
                return -1;
        }
}

static char dec2hex(short int c)
{
        if (0 <= c && c <= 9) {
                return c + '0';
        } else if (10 <= c && c <= 15) {
                return c + 'A' - 10;
        } else {
                return (char)-1;
        }
}


/*
* Encode a url
*/
void urlencode(char *url)
{
        int i = 0;
        int len = strlen(url);
        int res_len = 0;
        char *res = rt_calloc(1, BURSIZE);
        for (i = 0; i < len; ++i) {
                char c = url[i];
                if (('0' <= c && c <= '9') ||
                                ('a' <= c && c <= 'z') ||
                                ('A' <= c && c <= 'Z') || c == '/' || c == '.') {
                        res[res_len++] = c;
                } else {
                        int j = (short int)c;
                        if (j < 0)
                                j += 256;
                        int i1, i0;
                        i1 = j / 16;
                        i0 = j - i1 * 16;
                        res[res_len++] = '%';
                        res[res_len++] = dec2hex(i1);
                        res[res_len++] = dec2hex(i0);
                }
        }
        res[res_len] = '\0';
        strcpy(url, res);
        rt_free(res);
}

/*
* Decode url
*/
void urldecode(char *url)
{
        int i = 0;
        int len = strlen(url);
        int res_len = 0;
        char *res = rt_calloc(1, BURSIZE);
        for (i = 0; i < len; ++i) {
                char c = url[i];
                if (c != '%') {
                        res[res_len++] = c;
                } else {
                        char c1 = url[++i];
                        char c0 = url[++i];
                        int num = 0;
                        num = hex2dec(c1) * 16 + hex2dec(c0);
                        res[res_len++] = num;
                }
        }
        res[res_len] = '\0';
        strcpy(url, res);
        rt_free(res);
}

url_code.h

#ifndef __URL_CODE_H__
#define __URL_CODE_H__

void urlencode(char *url);
void urldecode(char *url);

#endif

6. Experiment





Posted by neogemima on Sun, 03 May 2020 15:23:52 -0700