分析/* ubus变量 */
static struct ubus_context *ubus_ctx = NULL;
static char *ubus_patch;
/* uci变量 */
static struct uci_context *uci_ctx = NULL;
static struct uci_package *uci_weather = NULL;
/* uloop */
struct uloop_timeout timer;
/* ubus数据接口结构 */
enum {
TEMPERATURE_UNIT,
LOCATION_KEY,
CITY_NAME,
WEATHER_SETTINGS_MAX
};
/* ubus参数解析policy */
static const struct blobmsg_policy ubus_policy[] = {
[TEMPERATURE_UNIT] = {.name = "temperature_unit", .type = BLOBMSG_TYPE_INT32},
[LOCATION_KEY] = {.name = "location_key", .type = BLOBMSG_TYPE_INT32},
[CITY_NAME] = {.name = "city", .type = BLOBMSG_TYPE_STRING},
};
static struct ubus_event_handler weather_settings_ubus_notify = {.cb = ubus_collect_now};
/* 更新时间间隔 */
#define DEFAULT_INTERVAL 21600 //6h
#define MID_INTERVAL 300 //5min
#define FAST_INTERVAL 10 //10s
static int renew_interval = DEFAULT_INTERVAL;
#define MAX_URL_LEN 256
#define POST_TRANSFER_TIMEOUT 5
#define POST_CONNECT_TIMEOUT 5
#define MAX_TOKEN_LEN 128
/* 相关文件地址 */
#define FILE_CLOUD_TOKEN_WEATHER "/tmp/cloud/cloud_token_weather"
#define REALTIME_URL_POSTFIX "/v1/weather/realtime"
#define FORECASTS_URL_POSTFIX "/v1/weather/forecasts"
#define CA_CRT_PATH "/etc/certificate/2048_newroot.cer"
/*
* brief 保存post执行结果status code.
*/
typedef struct _st_http_resinfo
{
long status_code;
}st_http_resinfo;
/*
* brief 保存当日天气数据.
*/
struct realtime_weather_info_struct{
int temperature;
int temperatureMax;
int temperatureMin;
char weatherType[10];
};
static struct realtime_weather_info_struct realtime_weather_info;
/*
* brief 保存未来三日天气数据.
*/
struct forecast_weather_info_struct{
int temperatureMax;
int temperatureMin;
char dayWeatherType[10];
char nightWeatherType[10];
};
static struct forecast_weather_info_struct forecast_weather_info[3];
static int weather_errorcode = 0; /* 云端回传错误代码 */
static char weather_message[20]; /* 云端回传错误信息 */
/**************************************************************************************************/
/* LOCAL_FUNCTIONS */
/**************************************************************************************************/
/*
* fn char* Int2String(int num,char *str)
* details int转string
*
* param[in] num:待转换int str:指向转换得到字符串的指针
* param[out]
*
* return str:指向转换得到字符串的指针
*
* note
*/
char* Int2String(int num,char *str)//10进制
{
int i = 0;//指示填充str
if(num<0)//如果num为负数,将num变正
{
num = -num;
str[i++] = '-';
}
//转换
do
{
str[i++] = num%10+48;//取num最低位 字符0~9的ASCII码是48~57;简单来说数字0+48=48,ASCII码对应字符'0'
num /= 10;//去掉最低位
}while(num);//num不为0继续循环
str[i] = '\0';
//确定开始调整的位置
int j = 0;
if(str[0]=='-')//如果有负号,负号不用调整
{
j = 1;//从第二位开始调整
++i;//由于有负号,所以交换的对称轴也要后移1位
}
//对称交换
for(;j<i/2;j++)
{
//对称交换两端的值 其实就是省下中间变量交换a+b的值:a=a+b;b=a-b;a=a-b;
str[j] = str[j] + str[i-1-j];
str[i-1-j] = str[j] - str[i-1-j];
str[j] = str[j] - str[i-1-j];
}
return str;//返回转换后的值
}
/********************************************ubus相关函数*******************************************/
/*
* fn static void weather_ubus_update_event_generate(int flag);
* details 通过ubus send将更新得到的天气数据发送给其他相关模块
*
* param[in]
* param[out]
*
* return
*
* note
*/
static void weather_ubus_update_event_generate(int flag)
{
static struct blob_buf g_ubus_buf;
void *table_len = NULL;
time_t timep;
struct tm date;
blob_buf_init(&g_ubus_buf, 0);
time(&timep); /* 获取当前unix时间 */
if(0 == flag) /* 0 == flag,发送当日实时天气数据 */
{
date = *(localtime(&timep));
table_len = blobmsg_open_table(&g_ubus_buf, "realtime");
blobmsg_add_u32(&g_ubus_buf , "month" , date.tm_mon + 1);
blobmsg_add_u32(&g_ubus_buf , "day" , date.tm_mday);
blobmsg_add_u32(&g_ubus_buf , "temperature" , realtime_weather_info.temperature);
blobmsg_add_u32(&g_ubus_buf , "temperature_min" , realtime_weather_info.temperatureMin);
blobmsg_add_u32(&g_ubus_buf , "temperature_max" , realtime_weather_info.temperatureMax);
blobmsg_add_string(&g_ubus_buf , "weather_type" , realtime_weather_info.weatherType);
blobmsg_close_table(&g_ubus_buf, table_len);
INFO("[weather_server]: Ubus send realtime weather, renew time:%ld", timep);
}
else /* 1 == flag,发送未来三天天气数据 */
{
timep += 86400; /* 调整到后一天同一时刻 */
date = *(localtime(&timep));
table_len = blobmsg_open_table(&g_ubus_buf, "tomorrow");
blobmsg_add_u32(&g_ubus_buf , "month" , date.tm_mon + 1);
blobmsg_add_u32(&g_ubus_buf , "day" , date.tm_mday);
blobmsg_add_u32(&g_ubus_buf , "temperature_min" , forecast_weather_info[0].temperatureMin);
blobmsg_add_u32(&g_ubus_buf , "temperature_max" , forecast_weather_info[0].temperatureMax);
blobmsg_add_string(&g_ubus_buf , "day_weather_type" , forecast_weather_info[0].dayWeatherType);
blobmsg_add_string(&g_ubus_buf , "night_weather_type" , forecast_weather_info[0].nightWeatherType);
blobmsg_close_table(&g_ubus_buf, table_len);
timep += 86400; /* 调整到后一天同一时刻 */
date = *(localtime(&timep));
table_len = blobmsg_open_table(&g_ubus_buf, "2_days_later");
blobmsg_add_u32(&g_ubus_buf , "month" , date.tm_mon + 1);
blobmsg_add_u32(&g_ubus_buf , "day" , date.tm_mday);
blobmsg_add_u32(&g_ubus_buf , "temperature_min" , forecast_weather_info[1].temperatureMin);
blobmsg_add_u32(&g_ubus_buf , "temperature_max" , forecast_weather_info[1].temperatureMax);
blobmsg_add_string(&g_ubus_buf , "day_weather_type" , forecast_weather_info[1].dayWeatherType);
blobmsg_add_string(&g_ubus_buf , "night_weather_type" , forecast_weather_info[1].nightWeatherType);
blobmsg_close_table(&g_ubus_buf, table_len);
timep += 86400; /* 调整到后一天同一时刻 */
date = *(localtime(&timep));
table_len = blobmsg_open_table(&g_ubus_buf, "3_days_later");
blobmsg_add_u32(&g_ubus_buf , "month" , date.tm_mon + 1);
blobmsg_add_u32(&g_ubus_buf , "day" , date.tm_mday);
blobmsg_add_u32(&g_ubus_buf , "temperature_min" , forecast_weather_info[2].temperatureMin);
blobmsg_add_u32(&g_ubus_buf , "temperature_max" , forecast_weather_info[2].temperatureMax);
blobmsg_add_string(&g_ubus_buf , "day_weather_type" , forecast_weather_info[2].dayWeatherType);
blobmsg_add_string(&g_ubus_buf , "night_weather_type" , forecast_weather_info[2].nightWeatherType);
blobmsg_close_table(&g_ubus_buf, table_len);
INFO("[weather_server]: Ubus send forecast weather, renew time:%ld", timep - 86400 * 3);
}
/* ubus send event */
ubus_send_event(ubus_ctx, "weather_info_update", g_ubus_buf.head);
}
/*
* fn static void ubus_collect_now(struct ubus_context *ubus_ctx,
* struct ubus_event_handler *ev,
* const char *type, struct blob_attr *msg);
* details ubus对象方法回调函数,响应ubus send weather_settings_update,更新地理位置参数并立即更新天气信息
*
* param[in]
* param[out]
*
* return
*
* note
*/
static void ubus_collect_now(struct ubus_context *ubus_ctx, struct ubus_event_handler *ev, const char *type, struct blob_attr *msg)
{
int status = 0;
int temperature_unit = -1;
uint32_t location_key = 0;
struct blob_attr *tb[WEATHER_SETTINGS_MAX] = {NULL};
char buf[128] = {0};
status = blobmsg_parse(ubus_policy, WEATHER_SETTINGS_MAX, tb, blob_data(msg), blob_len(msg));
if (status < 0) {
return;
}
if (tb[TEMPERATURE_UNIT] && blob_data(tb[TEMPERATURE_UNIT])) {
temperature_unit = blobmsg_get_u32(tb[TEMPERATURE_UNIT]);
}
else {
ERR("invalid temperature_unit");
}
if (tb[LOCATION_KEY] && blob_data(tb[LOCATION_KEY])) {
location_key = blobmsg_get_u32(tb[LOCATION_KEY]);
}
else {
ERR("invalid location_key");
}
if (tb[CITY_NAME] && blob_data(tb[CITY_NAME])) {
snprintf(buf, sizeof(buf), "%s", blobmsg_get_string(tb[CITY_NAME]));
}
else {
ERR("invalid city_name");
}
INFO("[weather_server] Ubus rec: temperature_unit=%d, location_key=%d, city_name=%s",temperature_unit, location_key, buf);
/* 更新天气信息 */
weather_timer_cb(&timer);
}
/*
* fn static void ubus_reconn_timer(struct uloop_timeout *timeout)
* details ubus重连
*
* param[in]
* param[out]
*
* return
*
* note
*/
static void ubus_reconn_timer(struct uloop_timeout *timeout)
{
static struct uloop_timeout retry =
{
.cb = ubus_reconn_timer,
};
DEBUG("S:ubus_connection_lost");
if (ubus_reconnect(ubus_ctx, ubus_patch) != 0) {
/* 设置每过两秒尝试重连ubusd */
uloop_timeout_set(&retry, 2000);
return;
}
ubus_add_uloop(ubus_ctx);
}
/*
* fn static int weather_ubus_init(char *path)
* details ubus初始化
*
* param[in]
* param[out]
*
* return
*
* note
*/
static int weather_ubus_init(char *path)
{
ubus_patch = path;
/* 连接ubusd */
ubus_ctx = ubus_connect(path);
if (!ubus_ctx)
{
ERR("S:Failed to connect ubusd");
return -1;
}
/* 设置断线重连回调函数为ubus_reconn_timer */
ubus_ctx->connection_lost = (void (*)(struct ubus_context *))ubus_reconn_timer;
DEBUG("S:succeed to connect ubusd");
if (ubus_register_event_handler(ubus_ctx, &weather_settings_ubus_notify, "weather_settings_update") != 0)
{
ERR("S:Failed to add object to ubusd");
return -1;
}
/* 向uloop注册 */
ubus_add_uloop(ubus_ctx);
DEBUG("S:succeed to add object to ubusd");
return 0;
}
/*
* fn static int weather_ubus_deinit(void)
* details 释放ubus变量
*
* param[in]
* param[out]
*
* return
*
* note
*/
static int weather_ubus_deinit(void)
{
ubus_unregister_event_handler(ubus_ctx, &weather_settings_ubus_notify);
if(ubus_ctx)
{
ubus_free(ubus_ctx);
}
return 0;
}
/**********************************************天气信息请求*****************************************/
/*
* fn static size_t OnWriteData_Post(void* buffer, size_t size, size_t nmemb, void* lpVoid)
* details 将从云端收到的数据写入复制到指定字符串中
*
* param[in]
* param[out]
*
* return
*
* note
*/
static size_t OnWriteData_Post(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
unsigned int len = (unsigned int)size * (unsigned int)nmemb;
char *str = malloc(len + 1);
if (NULL == str || NULL == buffer)
{
return -1;
}
char* pData = buffer;
memset(str, 0, len + 1);
memcpy(str, pData, len);
DEBUG("response: %s", str);
char **response = lpVoid;
*response = str;
return len;
}
/*
* fn static size_t cloud_https_post(const char *pUrl, const char *requestHeader,
* const char *request, char **response, st_http_resinfo *pHttpResInfo)
* details 发送post请求,从云端获取天气数据
*
* param[in]
* param[out]
*
* return
*
* note
*/
static size_t cloud_https_post(const char *pUrl,
const char *requestHeader,
const char *request,
char **response,
st_http_resinfo *pHttpResInfo)
{
CURLcode res;
CURL* curl = NULL;
struct curl_slist *headers = NULL;
if (NULL == pUrl || NULL == request || NULL == response || NULL == pHttpResInfo)
{
return CURLE_FAILED_INIT;
}
DEBUG("pUrl:%s requestHeader:%s request:%s", pUrl, requestHeader, request);
res = curl_global_init(CURL_GLOBAL_ALL);
if (CURLE_OK != res)
{
ERR("curl global init fail and ret %d", res);
return res;
}
curl = curl_easy_init();
if (NULL == curl)
{
res = CURLE_FAILED_INIT;
ERR("curl init fail");
goto exit;
}
// headers = curl_slist_append(headers, "Content-Type: application/json;charset=UTF-8");
headers = curl_slist_append(headers, "Content-Type: application/json");
if (NULL == headers)
{
ERR("curl get header list fail");
goto exit;
}
if ((NULL != requestHeader) && (0 < strlen(requestHeader)))
{
DEBUG("requestHeader is %s", requestHeader);
headers = curl_slist_append(headers, requestHeader);
if (NULL == headers)
{
ERR("curl append requestHeader fail");
goto exit;
}
}
//set url
// DEBUG("request_url:%s",pUrl);
res = curl_easy_setopt(curl, CURLOPT_URL, pUrl);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_URL ret %d", res);
goto exit;
}
//set header
//DEBUG("request_header:%s",headers);
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_HTTPHEADER ret %d", res);
goto exit;
}
//set post method
res = curl_easy_setopt(curl, CURLOPT_POST, 1);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_POST ret %d", res);
goto exit;
}
// DEBUG("request_data:%s",request);
res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_POSTFIELDS ret %d", res);
goto exit;
}
//set read/write params
res = curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_READFUNCTION ret %d", res);
goto exit;
}
res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData_Post);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_WRITEFUNCTION ret %d", res);
goto exit;
}
res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)response);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_WRITEDATA ret %d", res);
goto exit;
}
res = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_NOSIGNAL ret %d", res);
goto exit;
}
//set certificate info
res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_SSL_VERIFYPEER ret %d", res);
goto exit;
}
res = curl_easy_setopt(curl, CURLOPT_CAINFO, CA_CRT_PATH);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_CAINFO ret %d", res);
goto exit;
}
//set CURLOPT_CONNECTTIMEOUT
res = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, POST_TRANSFER_TIMEOUT);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_CONNECTTIMEOUT ret %d", res);
goto exit;
}
//set CURLOPT_TIMEOUT
res = curl_easy_setopt(curl, CURLOPT_TIMEOUT, POST_CONNECT_TIMEOUT);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_TIMEOUT ret %d", res);
goto exit;
}
//CURLOPT needs to be set_ FOLLOWLOCATION is 1, otherwise, the data after redirecting will not be returned
res = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
if (CURLE_OK != res)
{
ERR("curl set option CURLOPT_FOLLOWLOCATION ret %d", res);
goto exit;
}
res = curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
if (CURLE_OK != res)
{
ERR("curl set option CURL_SSLVERSION_TLSv1_2 ret %d", res);
goto exit;
}
res = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &(pHttpResInfo->status_code));
DEBUG("cloud_https_post done. ret %d, http status code %d", res, pHttpResInfo->status_code);
exit:
if (headers)
{
curl_slist_free_all(headers);
}
if (curl)
{
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return res;
}
/*
* fn int get_token_url(char *token, char *url)
* details 获取device token和云端天气预报请求url
*
* param[in]
* param[out]
*
* return
*
* note
*/
int get_token_url(char *token, char *url)
{
int ret = -1;
int retry_count = 3;
FILE *fp = NULL;
while (retry_count > 0)
{
if((fp = fopen(FILE_CLOUD_TOKEN_WEATHER, "r")))
{
fscanf(fp, "%s", token);
fscanf(fp, "%s", url);
fclose(fp);
ret = 0;
break;
}
else
{
system("cloud_getDevToken weather");
}
retry_count--;
}
return ret;
}
/*
* fn static void set_weather_cloud_request_data(char *device_token, char *request_data)
* details 读取uci配置中的location_key,与输入参数device_token共同构造post请求参数
*
* param[in] char *device_token 从云端获取的device token
* char *request_data 存储post请求参数字符串
* param[out]
*
* return
*
* note
*/
static void set_weather_cloud_request_data(char *device_token, char *request_data)
{
//int ret = -1;
json_object* request_data_json = NULL;
const char* request_data_out = NULL;
//FILE *fp = NULL;
int locationkey = 0;
if ((request_data_json = json_object_new_object()) == NULL)
{
goto out;
}
locationkey = uci_get_locationkey();
if ( -1 == locationkey)
{
ERR("uci_get_locationkey failed");
goto out;
}
json_object_object_add(request_data_json, "locationKey", json_object_new_int(locationkey));
json_object_object_add(request_data_json, "deviceToken", json_object_new_string(device_token));
request_data_out = json_object_to_json_string(request_data_json);
memcpy(request_data, request_data_out, strlen(request_data_out));
json_object_put(request_data_json);
return;
out:
return;
}
/*
* fn int get_realtime_info_from_cloud(struct realtime_weather_info_struct *realtime_weather_info,
* char *device_token, char *url_prefix)
* details 从云端获取当日天气数据并解析
*
* param[in] struct realtime_weather_info_struct *realtime_weather_info 存储当日天气数据结构体
* char *device_token 从云端获取的device token
* char *url_prefix 云端请求天气数据url前缀
* param[out]
*
* return ret 0表示获取数据成功,-1表示失败
*
* note
*/
int get_realtime_info_from_cloud(struct realtime_weather_info_struct *realtime_weather_info,
char *device_token, char *url_prefix)
{
int ret = -1;
// int ret_post = 0;
char request_url[128] = {0};
char request_header[64] = {0};
char tmpstr[40] = {0};
char request_data[512] = {0};
char *response = "";
st_http_resinfo httpResInfo;
json_object* response_json = NULL;
json_object* errorcode = NULL;
json_object* message = NULL;
json_object* result = NULL;
json_object* temperature = NULL;
json_object* temperatureMax = NULL;
json_object* temperatureMin = NULL;
json_object* weatherType = NULL;
int errorcode_data = -1;
const char* message_data = NULL;
int temperature_data = -1;
int temperatureMax_data = -1;
int temperatureMin_data = -1;
const char* weatherType_data = NULL;
if (realtime_weather_info == NULL || device_token == NULL || url_prefix == NULL)
{
ERR("params error");
ret = -1;
goto exit;
}
memset(&httpResInfo, 0, sizeof(st_http_resinfo));
sprintf(request_url, "%s%s", url_prefix, REALTIME_URL_POSTFIX);
set_weather_cloud_request_data(device_token, request_data);
//get post result
cloud_https_post(request_url, request_header, request_data, &response, &httpResInfo);
DEBUG("httpResInfo.status_code:%ld",httpResInfo.status_code);
DEBUG("response:%s",response);
if (response && httpResInfo.status_code == 200)
{
response_json = json_tokener_parse(response);
errorcode = json_object_object_get(response_json, "code");
errorcode_data = json_object_get_int(errorcode);
if (0 != errorcode_data)
{
weather_errorcode = errorcode_data;
sprintf(tmpstr, "get weather info errorcode:%d", errorcode_data);
uci_set_option("global", "error", tmpstr);
ret = -1;
goto exit;
}
message = json_object_object_get(response_json, "message");
result = json_object_object_get(response_json, "result");
temperature = json_object_object_get(result, "temperature");
temperatureMax = json_object_object_get(result, "temperatureMax");
temperatureMin = json_object_object_get(result, "temperatureMin");
weatherType = json_object_object_get(result, "weatherType");
message_data = json_object_get_string(message);
temperature_data = json_object_get_int(temperature);
temperatureMax_data = json_object_get_int(temperatureMax);
temperatureMin_data = json_object_get_int(temperatureMin);
weatherType_data = json_object_get_string(weatherType);
if (0 == errorcode_data && message_data && weatherType_data)
{
DEBUG("errorcode : %d", errorcode_data);
DEBUG("message : %s", message_data);
DEBUG("temperature : %d", temperature_data);
DEBUG("temperatureMax : %d", temperatureMax_data);
DEBUG("temperatureMin : %d", temperatureMin_data);
DEBUG("weatherType : %s", weatherType_data);
// tmpstr = uci_get_unit();
// DEBUG("unit:%s",tmpstr);
if (0 == strcmp(uci_get_unit(),"centigrade"))
{
realtime_weather_info->temperature = (temperature_data - 32) / 1.8;
realtime_weather_info->temperatureMax = (temperatureMax_data -32) / 1.8;
realtime_weather_info->temperatureMin = (temperatureMin_data - 32) / 1.8;
}
else
{
realtime_weather_info->temperature = temperature_data;
realtime_weather_info->temperatureMax = temperatureMax_data;
realtime_weather_info->temperatureMin = temperatureMin_data;
}
sprintf(realtime_weather_info->weatherType, "%s", weatherType_data);
weather_errorcode = errorcode_data;
memcpy(weather_message, message_data, strlen(message_data));
ret = 0;
}
}
else
{
uci_set_option("global", "error", "cloud_https_post failed");
ret = -1;
}
exit:
json_object_put(response_json);
json_object_put(errorcode);
json_object_put(message);
json_object_put(result);
json_object_put(temperature);
json_object_put(temperatureMax);
json_object_put(temperatureMin);
json_object_put(weatherType);
return ret;
}
/*
* fn int get_forecast_info_from_cloud(struct forecast_weather_info_struct *forecast_weather_info,
* char *device_token, char *url_prefix)
* details 从云端获取未来三天天气数据并解析
*
* param[in] struct forecast_weather_info_struct *forecast_weather_info 存储未来三天天气数据结构体
* char *device_token 从云端获取的device token
* char *url_prefix 云端请求天气数据url前缀
* param[out]
*
* return ret 0表示获取数据成功,-1表示失败
*
* note
*/
int get_forecast_info_from_cloud(struct forecast_weather_info_struct *forecast_weather_info,
char *device_token, char *url_prefix)
{
int ret = -1;
// int ret_post = 0;
int i = 0;
char request_url[128] = {0};
char request_header[64] = {0};
char tmpstr[40] = {0};
char request_data[512] = {0};
char *response = NULL;
st_http_resinfo httpResInfo;
json_object* response_json = NULL;
json_object* errorcode = NULL;
json_object* message = NULL;
json_object* result = NULL;
json_object* forecastList = NULL;
json_object* ListItem = NULL;
json_object* temperatureMax = NULL;
json_object* temperatureMin = NULL;
json_object* dayWeatherType = NULL;
json_object* nightWeatherType = NULL;
int errorcode_data = -1;
const char* message_data = NULL;
int temperatureMax_data = -1;
int temperatureMin_data = -1;
const char* dayWeatherType_data = NULL;
const char* nightWeatherType_data = NULL;
if (forecast_weather_info == NULL || device_token == NULL || url_prefix == NULL)
{
ERR("params error");
ret = -1;
goto exit;
}
memset(&httpResInfo, 0, sizeof(st_http_resinfo));
sprintf(request_url, "%s%s", url_prefix, FORECASTS_URL_POSTFIX);
set_weather_cloud_request_data(device_token, request_data);
//get post result
cloud_https_post(request_url, request_header, request_data, &response, &httpResInfo);
DEBUG("httpResInfo.status_code:%ld",httpResInfo.status_code);
DEBUG("response:%s",response);
if (response && httpResInfo.status_code == 200)
{
response_json = json_tokener_parse(response);
errorcode = json_object_object_get(response_json, "code");
errorcode_data = json_object_get_int(errorcode);
if (0 != errorcode_data)
{
weather_errorcode = errorcode_data;
sprintf(tmpstr, "get weather info errorcode:%d", errorcode_data);
uci_set_option("global", "error", tmpstr);
ret = -1;
goto exit;
}
message = json_object_object_get(response_json, "message");
result = json_object_object_get(response_json, "result");
forecastList = json_object_object_get(result, "forecastList");
message_data = json_object_get_string(message);
if (0 == errorcode_data && message_data)
{
DEBUG("errorcode : %d", errorcode_data);
DEBUG("message : %s", message_data);
for ( i = 0; i < 3; i++)
{
ListItem = json_object_array_get_idx(forecastList,i);
temperatureMax = json_object_object_get(ListItem, "temperatureMax");
temperatureMin = json_object_object_get(ListItem, "temperatureMin");
dayWeatherType = json_object_object_get(ListItem, "dayWeatherType");
nightWeatherType = json_object_object_get(ListItem, "nightWeatherType");
temperatureMax_data = json_object_get_int(temperatureMax);
temperatureMin_data = json_object_get_int(temperatureMin);
dayWeatherType_data = json_object_get_string(dayWeatherType);
nightWeatherType_data = json_object_get_string(nightWeatherType);
DEBUG("temperatureMax : %d", temperatureMax_data);
DEBUG("temperatureMin : %d", temperatureMin_data);
DEBUG("dayWeatherType : %s", dayWeatherType_data);
DEBUG("nightWeatherType : %s", nightWeatherType_data);
if (dayWeatherType_data && nightWeatherType_data)
{
// tmpstr = uci_get_unit();
// DEBUG("unit:%s",tmpstr);
if (0 == strcmp(uci_get_unit(),"centigrade"))
{
forecast_weather_info[i].temperatureMax = (temperatureMax_data - 32) / 1.8;
forecast_weather_info[i].temperatureMin = (temperatureMin_data - 32) / 1.8;
}
else
{
forecast_weather_info[i].temperatureMax = temperatureMax_data;
forecast_weather_info[i].temperatureMin = temperatureMin_data;
}
sprintf(forecast_weather_info[i].dayWeatherType, "%s", dayWeatherType_data);
sprintf(forecast_weather_info[i].nightWeatherType, "%s", nightWeatherType_data);
}
}
weather_errorcode = errorcode_data;
memcpy(weather_message, message_data, strlen(message_data));
ret = 0;
}
}
else
{
uci_set_option("global", "error", "cloud_https_post failed");
ret = -1;
}
exit:
json_object_put(response_json);
json_object_put(errorcode);
json_object_put(message);
json_object_put(result);
json_object_put(forecastList);
json_object_put(ListItem);
json_object_put(temperatureMax);
json_object_put(temperatureMin);
json_object_put(dayWeatherType);
json_object_put(nightWeatherType);
return ret;
}
/*
* fn static int update_weather_url(void)
* details 更新天气数据
*
* param[in]
* param[out]
*
* return 0表示获取数据成功,-1表示失败
*
* note
*/
static int update_weather_url(void)
{
char device_token[MAX_TOKEN_LEN] = {0};
char cloud_weather_url[MAX_URL_LEN] = {0};
int i = 0;
/* init */
realtime_weather_info.temperature = 0;
realtime_weather_info.temperatureMax = 0;
realtime_weather_info.temperatureMin = 0;
memset(realtime_weather_info.weatherType, 0, sizeof(realtime_weather_info.weatherType));
for ( i = 0; i < 3; i++)
{
forecast_weather_info[i].temperatureMax = 0;
forecast_weather_info[i].temperatureMin = 0;
memset(forecast_weather_info[i].dayWeatherType, 0, sizeof(forecast_weather_info[i].dayWeatherType));
memset(forecast_weather_info[i].nightWeatherType, 0, sizeof(forecast_weather_info[i].nightWeatherType));
}
/* online request */
if (0 == (get_token_url(device_token, cloud_weather_url)))
{
/* get_realtime_info_from_cloud */
if (0 == get_realtime_info_from_cloud(&realtime_weather_info, device_token, cloud_weather_url))
{
weather_ubus_update_event_generate(0);
if (1 != uci_renew(0))
{
ERR("set_realtime_info_to_uci fail");
uci_set_option("global", "error", "set_realtime_info_to_uci fail");
return -1;
}
DEBUG("get_realtime_info_from_cloud succeed");
}
else
{
WARNING("get_realtime_info_from_cloud error");
return -1;
}
/* get_forecast_info_from_cloud */
if (0 == get_forecast_info_from_cloud(forecast_weather_info, device_token, cloud_weather_url))
{
weather_ubus_update_event_generate(1);
if (1 != uci_renew(1))
{
ERR("set_forecast_info_to_uci fail");
uci_set_option("global", "error", "set_forecast_info_to_uci fail");
return -1;
}
DEBUG("get_forecast_info_from_cloud succeed");
}
else
{
WARNING("get_forecast_info_from_cloud error");
return -1;
}
}
else
{
uci_set_option("global", "error", "get_token_url error");
ERR("get_token_url error");
return -1;
}
// /* offline test*/
// (void)device_token;
// (void)cloud_weather_url;
// realtime_weather_info.temperature = 70;
// realtime_weather_info.temperatureMax = 90;
// realtime_weather_info.temperatureMin = 50;
// if (0 == strcmp(uci_get_unit(),"centigrade"))
// {
// realtime_weather_info.temperature = (realtime_weather_info.temperature - 32) / 1.8;
// realtime_weather_info.temperatureMax = (realtime_weather_info.temperatureMax -32) / 1.8;
// realtime_weather_info.temperatureMin = (realtime_weather_info.temperatureMin - 32) / 1.8;
// }
// sprintf(realtime_weather_info.weatherType, "%s", "clear");
// weather_errorcode = 0;
// memcpy(weather_message,"none",sizeof("none"));
// weather_ubus_update_event_generate(0);
// if (1 != uci_renew(0))
// {
// ERR("set_realtime_info_to_uci fail");
// return -1;
// }
// for ( i = 0; i < 3; i++)
// {
// forecast_weather_info[i].temperatureMax = 91 + i;
// forecast_weather_info[i].temperatureMin = 51 + i;
// if (0 == strcmp(uci_get_unit(),"centigrade"))
// {
// forecast_weather_info[i].temperatureMax = (forecast_weather_info[i].temperatureMax - 32) / 1.8;
// forecast_weather_info[i].temperatureMin = (forecast_weather_info[i].temperatureMin - 32) / 1.8;
// }
// sprintf(forecast_weather_info[i].dayWeatherType, "%s", "clear");
// sprintf(forecast_weather_info[i].nightWeatherType, "%s", "rain");
// }
// weather_errorcode = 0;
// memcpy(weather_message,"none",sizeof("none"));
// weather_ubus_update_event_generate(1);
// if (1 != uci_renew(1))
// {
// ERR("set_forecast_info_to_uci fail");
// return -1;
// }
uci_set_option("global", "error", "weather info update success");
return 0;
}
/**********************************************uci相关函数******************************************/
/*
* fn static void config_free(void)
* details uci变量释放
*
* param[in]
* param[out]
*
* return
*
* note
*/
static void config_free(void)
{
if (uci_weather)
{
uci_unload(uci_ctx, uci_weather);
uci_weather = NULL;
}
if (uci_ctx)
{
uci_free_context(uci_ctx);
uci_ctx = NULL;
}
}
/*
* fn static struct uci_package *config_init_package(char *config)
* details 获取uci文件package
*
* param[in]
* param[out]
*
* return
*
* note
*/
static struct uci_package *config_init_package(char *config)
{
struct uci_package *p = NULL;
if (!uci_ctx)
{
/* 申请uci上下文结构uci_ctx */
uci_ctx = uci_alloc_context();
// uci_ctx->flags &= ~UCI_FLAG_STRICT;
}
else
{
/* 查找config文件 */
p = uci_lookup_package(uci_ctx, config);
if (p)
{
uci_unload(uci_ctx, p);
}
DEBUG("S:uci_unload");
}
/* 加载配置到内存 */
if ( UCI_OK != uci_load(uci_ctx, config, &p) )
{
p = NULL;
DEBUG("S:uci load error");
}
return p;
}
/*
* fn static int config_alloc(void)
* details 获取uci文件package,地址保存到全局变量uci_weather中
*
* param[in]
* param[out]
*
* return
*
* note
*/
static int config_alloc(void)
{
uci_weather = config_init_package("weather");
if (!uci_weather)
{
ERR("S:Failed to load weather config");
return 0;
}
DEBUG("S:succeed to load weather config");
return 1;
}
/*
* fn static int uci_init(void)
* details uci初始化
*
* param[in]
* param[out]
*
* return
*
* note
*/
static int uci_init(void)
{
struct uci_section *tmp_sec;
/* 获取uci配置文件 */
if( !config_alloc())
{
ERR("S:config_alloc error");
config_free();
return 0;
}
/* 检查uci配置文件中的section */
tmp_sec = uci_lookup_section(uci_ctx, uci_weather, "global");
if ( !tmp_sec)
{
ERR("S:lookup global section failed");
config_free();
return 0;
}
tmp_sec = uci_lookup_section(uci_ctx, uci_weather, "realtime");
if ( !tmp_sec)
{
ERR("S:lookup realtime section failed");
config_free();
return 0;
}
tmp_sec = uci_lookup_section(uci_ctx, uci_weather, "forecast");
if ( !tmp_sec)
{
ERR("S:lookup forecast section failed");
config_free();
return 0;
}
tmp_sec = uci_lookup_section(uci_ctx, uci_weather, "tomorrow");
if ( !tmp_sec)
{
ERR("S:lookup forecast1 section failed");
config_free();
return 0;
}
tmp_sec = uci_lookup_section(uci_ctx, uci_weather, "2_days_later");
if ( !tmp_sec)
{
ERR("S:lookup forecast2 section failed");
config_free();
return 0;
}
tmp_sec = uci_lookup_section(uci_ctx, uci_weather, "3_days_later");
if ( !tmp_sec)
{
ERR("S:lookup forecast3 section failed");
config_free();
return 0;
}
return 1;
}
/*
* fn static int uci_set_option(char *uci_section, char *uci_option, char *uci_value)
* details 配置uci配置文件option
*
* param[in] char *uci_section section名
* char *uci_option option的key,
* char *uci_value option的value
* param[out]
*
* return
*
* note
*/
static int uci_set_option(char *uci_section, char *uci_option, char *uci_value)
{
int ret = 0;
struct uci_ptr ptr ={
.package = "weather",
.section = uci_section,
.option = uci_option,
.value = uci_value
};
/* 配置uci配置文件option,key=uci_option,value=uci_value*/
ret = uci_set(uci_ctx, &ptr);
if( UCI_OK != ret)
{
ERR("S:set %s failed",uci_option);
return 0;
}
// DEBUG("S:set %s ok",uci_option);
/* 保存配置 */
uci_save(uci_ctx, ptr.p);
uci_commit(uci_ctx, &ptr.p, false);
return 1;
}
/*
* fn int uci_get_locationkey(void)
* details 从uci配置文件中读取locationkey
*
* param[in]
* param[out]
*
* return key 从uci配置文件中读取的locationkey
*
* note
*/
int uci_get_locationkey(void)
{
int key = 0;
const char *key_str = NULL;
struct uci_context *tmpCtx = NULL;
struct uci_package *tmppkg = NULL;
struct uci_section *tmpsec = NULL;
tmpCtx = uci_alloc_context();
if ( UCI_OK != uci_load(tmpCtx, "weather", &tmppkg) )
{
uci_set_option("global", "error", "uci_load weather error");
ERR("S:uci load error");
key = -1;
goto exit;
}
tmpsec = uci_lookup_section(tmpCtx, tmppkg, "global");
if ( !tmpsec)
{
uci_set_option("global", "error", "lookup global section failed");
ERR("S:lookup global section failed");
key = -1;
goto exit;
}
key_str = uci_lookup_option_string(tmpCtx, tmpsec, "location_key");
if(!key_str)
{
uci_set_option("global", "error", "lookup location_key option failed");
ERR("S:lookup location_key option failed");
key = -1;
goto exit;
}
key = atoi(key_str);
DEBUG("uci_get_option location_key:%d",key);
exit:
uci_unload(tmpCtx, tmppkg);
uci_free_context(tmpCtx);
return key;
}
/*
* fn const char *uci_get_unit(void)
* details 从uci配置文件中读取temperature_unit
*
* param[in]
* param[out]
*
* return unit_str 从uci配置文件中读取的temperature_unit
*
* note
*/
const char *uci_get_unit(void)
{
const char *unit_str = NULL;
struct uci_context *tmpCtx = NULL;
struct uci_package *tmppkg = NULL;
struct uci_section *tmpsec = NULL;
tmpCtx = uci_alloc_context();
if ( UCI_OK != uci_load(tmpCtx, "weather", &tmppkg) )
{
uci_set_option("global", "error", "uci_load weather error");
ERR("S:uci load error");
goto exit;
}
tmpsec = uci_lookup_section(tmpCtx, tmppkg, "global");
if ( !tmpsec)
{
uci_set_option("global", "error", "lookup global section failed");
ERR("S:lookup global section failed");
goto exit;
}
unit_str = uci_lookup_option_string(tmpCtx, tmpsec, "temperature_unit");
if(!unit_str)
{
uci_set_option("global", "error", "lookup unit option failed");
ERR("S:lookup unit option failed");
goto exit;
}
DEBUG("uci_get_option unit:%s",unit_str);
exit:
uci_unload(tmpCtx, tmppkg);
uci_free_context(tmpCtx);
return unit_str;
}
/*
* fn static void uci_renew(int flag)
* details 将从云端拿到的天气数据写入uci配置文件,
*
* param[in] int flag 为0时表示写入当日天气数据,为1时表示写入未来三天天气数据
* param[out]
*
* return 0表示写入失败,1表示写入成功
*
* note
*/
static int uci_renew(int flag)
{
time_t timep;
struct tm date;
// char time_cu[10] = "";
char section[20] = "";
char tmpstr[20] = "";
int i = 0;
/* 获取当前unix时间 */
time(&timep);
/* 配置uci配置文件对应option */
if (0 == flag)
{
/* 更新实时天气信息 */
date = * (localtime(&timep));
if (1 != uci_set_option("realtime", "errorcode", Int2String(weather_errorcode,tmpstr)))
{
return 0;
}
if (1 != uci_set_option("realtime", "message", weather_message))
{
return 0;
}
if (1 != uci_set_option("realtime", "time_renew", Int2String((int)timep,tmpstr)))
{
return 0;
}
if (1 != uci_set_option("realtime", "month", Int2String(date.tm_mon + 1,tmpstr)))
{
return 0;
}
if (1 != uci_set_option("realtime", "day", Int2String(date.tm_mday,tmpstr)))
{
return 0;
}
if (1 != uci_set_option("realtime", "temperature", Int2String(realtime_weather_info.temperature,tmpstr)))
{
return 0;
}
if (1 != uci_set_option("realtime", "temperatureMax", Int2String(realtime_weather_info.temperatureMax,tmpstr)))
{
return 0;
}
if (1 != uci_set_option("realtime", "temperatureMin", Int2String(realtime_weather_info.temperatureMin,tmpstr)))
{
return 0;
}
if (1 != uci_set_option("realtime", "weatherType", realtime_weather_info.weatherType))
{
return 0;
}
DEBUG("S:realtime weather uci renew time:%ld", timep);
}
else
{
/* 更新预报天气信息 */
if (1 != uci_set_option("forecast", "errorcode", Int2String(weather_errorcode,tmpstr)))
{
return 0;
}
if (1 != uci_set_option("forecast", "message", weather_message))
{
return 0;
}
if (1 != uci_set_option("forecast", "time_renew", Int2String((int)timep,tmpstr)))
{
return 0;
}
for (i = 0; i < 3; i++)
{
timep += 86400; /* 调整到后一天同一时刻 */
date = * (localtime(&timep));
if (0 == i)
{
sprintf(section,"tomorrow");
}
else
{
sprintf(section,"%d_days_later",i + 1);
}
if (1 != uci_set_option(section, "temperatureMax", Int2String(forecast_weather_info[i].temperatureMax,tmpstr)))
{
return 0;
}
if (1 != uci_set_option(section, "temperatureMin", Int2String(forecast_weather_info[i].temperatureMin,tmpstr)))
{
return 0;
}
if (1 != uci_set_option(section, "dayWeatherType", forecast_weather_info[i].dayWeatherType))
{
return 0;
}
if (1 != uci_set_option(section, "nightWeatherType", forecast_weather_info[i].nightWeatherType))
{
return 0;
}
if (1 != uci_set_option(section, "month", Int2String(date.tm_mon + 1,tmpstr)))
{
return 0;
}
if (1 != uci_set_option(section, "day", Int2String(date.tm_mday,tmpstr)))
{
return 0;
}
}
DEBUG("S:forecast weather uci renew time:%ld", timep - 86400 * 3);
}
return 1;
}
/**********************************************定时控制函数*****************************************/
/*
* fn static void weather_timer_cb(struct uloop_timeout *timer)
* details 定时更新天气数据,renew_interval控制下次更新时间间隔
*
* param[in]
* param[out]
*
* return
*
* note
*/
static void weather_timer_cb(struct uloop_timeout *timer)
{
if (0 != update_weather_url())
{
ERR("S:update_weather_url failed");
if (DEFAULT_INTERVAL == renew_interval)
{
if (-20652 == weather_errorcode)
{
system("rm /tmp/cloud/cloud_token_weather"); /* devicetoken失效 */
renew_interval = FAST_INTERVAL; /* 10s后重试 */
}
else
{
renew_interval = MID_INTERVAL; /* 5min后重试 */
}
}
else if(DEFAULT_INTERVAL > renew_interval * 2)
{
renew_interval *= 2; /* 重试时间*2 */
}
else
{
renew_interval = DEFAULT_INTERVAL + 1; /* 最高时间间隔6h+1s,多1s防止误判,否则再次失败renew_interval又会缩短 */
}
}
else
{
renew_interval = DEFAULT_INTERVAL; /* 成功后时间恢复6h */
}
DEBUG("Period CallBack");
uloop_timeout_set(timer, renew_interval * 1000);
}
/**************************************************************************************************/
/* PUBLIC_FUNCTIONS */
/**************************************************************************************************/
/**************************************************************************************************/
/* GLOBAL_FUNCTIONS */
/**************************************************************************************************/
int main()
{
char *ubus_socket = NULL;
char seed; /* 随机种子 */
memset(&timer, 0, sizeof(timer));
/* ubus初始化 */
uloop_init();
if (-1 == weather_ubus_init(ubus_socket))
{
ERR("S:weather_ubus_init failed");
}
/* uci初始化 */
if (0 == uci_init())
{
ERR("S:uci_init failed");
}
/* 启动随机延迟 */
srand((unsigned int)&seed);
sleep(rand() % 300);
DEBUG("random sleep");
/* 配置定时更新函数 */
timer.cb = weather_timer_cb;
uloop_timeout_set(&timer, 0);
/* uloop启动 */
DEBUG("S:uloop_run start");
uloop_run();
DEBUG("S:uloop_run end");
/*uci变量释放*/
config_free();
/* curl释放*/
curl_global_cleanup();
/* ubus释放*/
weather_ubus_deinit();
uloop_done();
DEBUG("S:uloop_done");
return 0;
}