616 lines
19 KiB
C
616 lines
19 KiB
C
/*----------------------------------------------------------------------------
|
||
* Copyright (c) Fenda Technologies Co., Ltd. 2021. All rights reserved.
|
||
*
|
||
* Description: sql_weather.c
|
||
*
|
||
* Author: saimen
|
||
*
|
||
* Create: 2024-06-08
|
||
*--------------------------------------------------------------------------*/
|
||
|
||
#include "string.h"
|
||
#include <stdlib.h>
|
||
#include "sys_typedef.h"
|
||
#include "sys_config.h"
|
||
#include "linux/crc32.h"
|
||
#include "sql_weather.h"
|
||
|
||
/**********************************************************************************************************************
|
||
* DEFINE
|
||
*/
|
||
#define ENABLE_STATIC_PRINT false
|
||
#define static_print_error(...) sys_sql_log_e(__VA_ARGS__) //错误信息打印一般常开
|
||
#define static_print_warn(...) sys_sql_log_w(__VA_ARGS__) //警告信息打印一般常开
|
||
#if ENABLE_STATIC_PRINT
|
||
#define static_print_debug(...) sys_sql_log_d(__VA_ARGS__)
|
||
#else
|
||
#define static_print_debug(...)
|
||
#endif
|
||
|
||
|
||
#define FILE_VERSION_WEATHER (1)//>0
|
||
#define FILE_PATH_WEATHER "/system/sql_weather.bin"
|
||
|
||
#define WEATHER_TIMEOUT_SECOND_DIFF (12*60*60) //12小时秒数
|
||
#define WEATHERUPDATE_MIN_COUNT 120 //2小时分钟数
|
||
#define WEATHERUPDATE_SECOND_DIFF_COUNT 2 //设备与APP秒数误差
|
||
#define WEATHER_FORECAST_DAYS 7 //预报天数
|
||
#define LOCATION_TEXT_MAX_LEN 32 //地址描述最大字节数
|
||
#define WEATHER_TEXT_MAX_LEN 20 //天气描述最大字节数
|
||
#define AIR_TEXT_MAX_LEN 16 //空气描述最大字节数
|
||
|
||
|
||
typedef struct {
|
||
uint32_t date_timestamp; //预报日期,日的秒级
|
||
int8_t temperature_min; //最低温度(℃) ,放大十倍后的数据
|
||
int8_t temperature_max; //最高温度(℃) ,
|
||
uint16_t protocol_value; //天气状况协议值
|
||
uint16_t aqi; //空气质量指数
|
||
char aqi_text[AIR_TEXT_MAX_LEN]; //空气质量文字描述(最多5个中文字,比如 重度污染) -- utf-8
|
||
char weather_text[WEATHER_TEXT_MAX_LEN]; //天气状况文字描述(最多6个中文字) -- utf-8
|
||
} weather_forecast_t;
|
||
|
||
#pragma pack(4) //alignment 4 bytes
|
||
typedef struct {
|
||
uint32_t init_flag:8; //标记模块是否初始化。=0 无效数据;=1 正常数据;=2 恢复数据。
|
||
uint32_t version:8; //结构体版本
|
||
|
||
uint32_t app_switch:8; //APP天气开关
|
||
uint32_t timeout:8; //天气过期,0x55-未过期,其它-已过期(过期时间以12小时为限)
|
||
uint32_t update_timestamp; //更新时间 UTC 秒
|
||
weather_forecast_t forecast[WEATHER_FORECAST_DAYS]; //N天天气(当天算起的N天)
|
||
uint8_t forecast_count; //实际预报天数
|
||
int8_t now_temperature; //当前温度(℃)
|
||
int8_t now_humidity; //当前湿度(%)
|
||
int8_t now_wind_speed; //当前风速(级)
|
||
uint8_t net_state; //APP天气连网状态,0=无网络,1=有网络
|
||
uint8_t temper_unit; //温度单位,0=℃,1= F -- 取TemperatureType枚举量
|
||
uint16_t sunrise_time; //日出时间 单位:分钟
|
||
uint16_t sunset_time; //日落时间 单位:分钟
|
||
uint8_t update_hour; //更新时间-小时
|
||
uint8_t update_minute; //更新时间-分钟,在SetWeatherInfo的时候转换为RTC时间,用于UI显示更新时间
|
||
char location_txt[LOCATION_TEXT_MAX_LEN]; //市区域名称
|
||
|
||
//uint8_t revs[4]; //保证8字节对齐
|
||
uint32_t crc32; //
|
||
} weather_def_t;
|
||
#pragma pack()
|
||
|
||
static weather_def_t g_weather_info = {0};
|
||
static bool g_weather_need_save = false;
|
||
|
||
/**********************************************************************************************************************
|
||
* 固定接口
|
||
*/
|
||
int sql_weather_init(void)
|
||
{
|
||
int ret = RET_SUCCESS;
|
||
uint32_t ui32_crc;
|
||
|
||
static_print_warn("[%s],sizeof(weather_def_t) = %d\r\n", FILE_PATH_WEATHER, sizeof(weather_def_t));
|
||
ui32_crc = Crc32Part(0,(const char *)&g_weather_info, sizeof(weather_def_t) - 4);
|
||
if(ui32_crc != g_weather_info.crc32 || g_weather_info.version != FILE_VERSION_WEATHER)
|
||
{
|
||
sql_weather_test();
|
||
/*----------------test------------------*/
|
||
memcpy(g_weather_info.location_txt, "深圳市", sizeof("深圳市"));
|
||
g_weather_info.now_temperature = 29;
|
||
g_weather_info.update_hour = 11;
|
||
g_weather_info.update_minute = 15;
|
||
g_weather_info.forecast[0].protocol_value = 0x02;
|
||
g_weather_info.forecast[0].temperature_max = 35;
|
||
g_weather_info.forecast[0].temperature_min = 20;
|
||
/*----------------end------------------*/
|
||
g_weather_need_save = true;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
void* sql_weather_get_info(uint32_t *len, char **path)
|
||
{
|
||
g_weather_info.crc32 = Crc32Part(0,(const char *)&g_weather_info, sizeof(weather_def_t) - 4);
|
||
*len = sizeof(weather_def_t);
|
||
*path = (char*)FILE_PATH_WEATHER;
|
||
return &g_weather_info;
|
||
}
|
||
|
||
void sql_weather_set_save_flag(uint8_t value)
|
||
{
|
||
g_weather_need_save = value;
|
||
}
|
||
|
||
uint8_t sql_weather_get_save_flag(void)
|
||
{
|
||
return g_weather_need_save;
|
||
}
|
||
|
||
/**********************************************************************************************************************
|
||
* 通用接口
|
||
*/
|
||
void sql_weather_set_switch(uint8_t en)
|
||
{
|
||
if(g_weather_info.app_switch != en)
|
||
{
|
||
g_weather_info.app_switch = en;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
uint8_t sql_weather_get_switch(void)
|
||
{
|
||
return g_weather_info.app_switch;
|
||
}
|
||
|
||
void sql_weather_set_temper_unit(uint8_t unit)
|
||
{
|
||
if(g_weather_info.temper_unit != unit)
|
||
{
|
||
g_weather_info.temper_unit = unit;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
uint8_t sql_weather_get_temper_unit(void)
|
||
{
|
||
return g_weather_info.temper_unit;
|
||
}
|
||
|
||
void sql_weather_set_net_state(uint8_t state)
|
||
{
|
||
if(g_weather_info.net_state != state)
|
||
{
|
||
g_weather_info.net_state = state;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
uint8_t sql_weather_get_net_state(void)
|
||
{
|
||
return g_weather_info.net_state;
|
||
}
|
||
|
||
void sql_weather_set_timeout(uint8_t en)
|
||
{
|
||
if(g_weather_info.timeout != en)
|
||
{
|
||
g_weather_info.timeout = en;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
uint8_t sql_weather_get_timeout(void)
|
||
{
|
||
return g_weather_info.timeout;
|
||
}
|
||
|
||
void sql_weather_set_update_timestamp(uint32_t time)
|
||
{
|
||
if(g_weather_info.update_timestamp != time)
|
||
{
|
||
g_weather_info.version = FILE_VERSION_WEATHER; //让数据保留
|
||
g_weather_info.update_timestamp = time;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
uint32_t sql_weather_get_update_timestamp(void)
|
||
{
|
||
return g_weather_info.update_timestamp;
|
||
}
|
||
|
||
void sql_weather_set_location_txt( char *text,uint32_t len)
|
||
{
|
||
uint32_t str_len;
|
||
str_len = len;
|
||
if(str_len>=LOCATION_TEXT_MAX_LEN)
|
||
{
|
||
str_len = LOCATION_TEXT_MAX_LEN - 1;
|
||
}
|
||
memcpy(g_weather_info.location_txt, text, str_len);
|
||
g_weather_info.location_txt[str_len] = 0;
|
||
g_weather_need_save = true;
|
||
}
|
||
|
||
char* sql_weather_get_location_txt(void)
|
||
{
|
||
return &g_weather_info.location_txt[0];
|
||
}
|
||
|
||
void sql_weather_set_now_temperature(int8_t temper)
|
||
{
|
||
if(g_weather_info.now_temperature != temper)
|
||
{
|
||
g_weather_info.now_temperature = temper;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
int8_t sql_weather_get_now_temperature(void)
|
||
{
|
||
return g_weather_info.now_temperature;
|
||
}
|
||
|
||
void sql_weather_set_update_hour(uint8_t hour)
|
||
{
|
||
if(g_weather_info.update_hour != hour)
|
||
{
|
||
g_weather_info.update_hour = hour;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
uint8_t sql_weather_get_update_hour(void)
|
||
{
|
||
return g_weather_info.update_hour;
|
||
}
|
||
|
||
void sql_weather_set_update_minute(uint8_t minute)
|
||
{
|
||
if(g_weather_info.update_minute != minute)
|
||
{
|
||
g_weather_info.update_minute = minute;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
uint8_t sql_weather_get_update_minute(void)
|
||
{
|
||
return g_weather_info.update_minute;
|
||
}
|
||
|
||
void sql_weather_set_sunrise_time(uint16_t sunrise_time)
|
||
{
|
||
if(g_weather_info.sunrise_time != sunrise_time)
|
||
{
|
||
g_weather_info.sunrise_time = sunrise_time;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
uint16_t sql_weather_get_sunrise_time(void)
|
||
{
|
||
return g_weather_info.sunrise_time;
|
||
}
|
||
|
||
void sql_weather_set_sunset_time(uint16_t sunset_time)
|
||
{
|
||
if(g_weather_info.sunset_time != sunset_time)
|
||
{
|
||
g_weather_info.sunset_time = sunset_time;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
uint16_t sql_weather_get_sunset_time(void)
|
||
{
|
||
return g_weather_info.sunset_time;
|
||
}
|
||
/**********************************************************************************************************************
|
||
* weather forecast
|
||
*/
|
||
uint8_t sql_weather_get_forecast_max(void)
|
||
{
|
||
return WEATHER_FORECAST_DAYS;
|
||
}
|
||
|
||
void sql_weather_set_forecast_count(uint8_t value)
|
||
{
|
||
if(value<=WEATHER_FORECAST_DAYS)
|
||
{
|
||
if(g_weather_info.forecast_count != value)
|
||
{
|
||
g_weather_info.forecast_count = value;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
uint8_t sql_weather_get_forecast_count(void)
|
||
{
|
||
return g_weather_info.forecast_count;
|
||
}
|
||
|
||
void sql_weather_set_forecast_protocol_value(uint8_t index,uint16_t value)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
if(g_weather_info.forecast[index].protocol_value != value)
|
||
{
|
||
g_weather_info.forecast[index].protocol_value = value;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
uint16_t sql_weather_get_forecast_protocol_value(uint8_t index)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
return g_weather_info.forecast[index].protocol_value;
|
||
}
|
||
else
|
||
{
|
||
return RET_ERROR;
|
||
}
|
||
}
|
||
|
||
void sql_weather_set_forecast_date_timestamp(uint8_t index,uint32_t time)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
if(g_weather_info.forecast[index].date_timestamp != time)
|
||
{
|
||
g_weather_info.forecast[index].date_timestamp = time;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
uint32_t sql_weather_get_forecast_date_timestamp(uint8_t index)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
return g_weather_info.forecast[index].date_timestamp;
|
||
}
|
||
else
|
||
{
|
||
return RET_ERROR;
|
||
}
|
||
}
|
||
|
||
void sql_weather_set_forecast_temperature_max(uint8_t index,int8_t value)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
if(g_weather_info.forecast[index].temperature_max != value)
|
||
{
|
||
g_weather_info.forecast[index].temperature_max = value;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
int8_t sql_weather_get_forecast_temperature_max(uint8_t index)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
return g_weather_info.forecast[index].temperature_max;
|
||
}
|
||
else
|
||
{
|
||
return RET_ERROR;
|
||
}
|
||
}
|
||
|
||
void sql_weather_set_forecast_temperature_min(uint8_t index,int8_t value)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
if(g_weather_info.forecast[index].temperature_min != value)
|
||
{
|
||
g_weather_info.forecast[index].temperature_min = value;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
int8_t sql_weather_get_forecast_temperature_min(uint8_t index)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
return g_weather_info.forecast[index].temperature_min;
|
||
}
|
||
else
|
||
{
|
||
return RET_ERROR;
|
||
}
|
||
}
|
||
|
||
void sql_weather_set_humidity(uint8_t value)
|
||
{
|
||
if(g_weather_info.now_humidity != value)
|
||
{
|
||
g_weather_info.now_humidity = value;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
int8_t sql_weather_get_humidity(void)
|
||
{
|
||
return g_weather_info.now_humidity;
|
||
}
|
||
|
||
void sql_weather_set_wind_speed(uint8_t value)
|
||
{
|
||
if(g_weather_info.now_wind_speed != value)
|
||
{
|
||
g_weather_info.now_wind_speed = value;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
uint8_t sql_weather_get_wind_speed(void)
|
||
{
|
||
return g_weather_info.now_wind_speed;
|
||
}
|
||
|
||
void sql_weather_set_forecast_aqi(uint8_t index,uint16_t value)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
if(g_weather_info.forecast[index].aqi != value)
|
||
{
|
||
g_weather_info.forecast[index].aqi = value;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
uint16_t sql_weather_get_forecast_aqi(uint8_t index)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
return g_weather_info.forecast[index].aqi;
|
||
}
|
||
else
|
||
{
|
||
return RET_ERROR;
|
||
}
|
||
}
|
||
|
||
void sql_weather_set_forecast_aqi_text(uint8_t index,char *text,uint32_t len)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
uint32_t str_len;
|
||
str_len = len;
|
||
if(str_len>=AIR_TEXT_MAX_LEN)
|
||
{
|
||
str_len = AIR_TEXT_MAX_LEN - 1;
|
||
}
|
||
memcpy(g_weather_info.forecast[index].aqi_text, text, str_len);
|
||
g_weather_info.forecast[index].aqi_text[str_len] = 0;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
char * sql_weather_get_forecast_aqi_text(uint8_t index)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
return &g_weather_info.forecast[index].aqi_text[0];
|
||
}
|
||
else
|
||
{
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
void sql_weather_set_forecast_weather_text(uint8_t index,char *text,uint32_t len)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
uint32_t str_len;
|
||
str_len = len;
|
||
if(str_len>=WEATHER_TEXT_MAX_LEN)
|
||
{
|
||
str_len = WEATHER_TEXT_MAX_LEN - 1;
|
||
}
|
||
memcpy(g_weather_info.forecast[index].weather_text, text, str_len);
|
||
g_weather_info.forecast[index].weather_text[str_len] = 0;
|
||
g_weather_need_save = true;
|
||
}
|
||
}
|
||
|
||
char * sql_weather_get_forecast_weather_text(uint8_t index)
|
||
{
|
||
if(index<WEATHER_FORECAST_DAYS)
|
||
{
|
||
return &g_weather_info.forecast[index].weather_text[0];
|
||
}
|
||
else
|
||
{
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
//--------------------------------------------------------------------------------------------------------
|
||
// ----------------- 模拟测试代码 ------------------
|
||
//--------------------------------------------------------------------------------------------------------
|
||
//#include "rtc_api.h"
|
||
void sql_weather_test(void)
|
||
{
|
||
static uint32_t cnt = 0;
|
||
uint32_t mode = 0;
|
||
weather_def_t* weatherInfo = &g_weather_info;
|
||
|
||
static_print_warn("sql_weather_test()\r\n");
|
||
//打桩设置实时天气数据
|
||
//weatherInfo.appSwitch = 1;
|
||
#if 1
|
||
//weatherInfo->update_timestamp = rtc_api_get_utc_timestamp();
|
||
//设置随机数种子
|
||
srand(weatherInfo->update_timestamp);
|
||
switch(rand() % 5) { //范围:0~4
|
||
case 0:
|
||
strcpy(weatherInfo->location_txt, "高新区");
|
||
break;
|
||
case 1:
|
||
strcpy(weatherInfo->location_txt, "宝安区");
|
||
break;
|
||
case 2:
|
||
strcpy(weatherInfo->location_txt, "迎泽区");
|
||
break;
|
||
case 3:
|
||
strcpy(weatherInfo->location_txt, "Huangpu Area");
|
||
break;
|
||
case 4:
|
||
strcpy(weatherInfo->location_txt, "Haidian Area");
|
||
break;
|
||
default:
|
||
strcpy(weatherInfo->location_txt, "雁塔区");
|
||
break;
|
||
}
|
||
//struct tm *dateTime = rtc_api_get_datetime_by_timestamp(weatherInfo->update_timestamp + (8*3600));
|
||
//weatherInfo->update_hour = dateTime->tm_hour;
|
||
//weatherInfo->update_minute = dateTime->tm_min;
|
||
if((rand() % 2) == 1) {
|
||
weatherInfo->timeout = 0x55;
|
||
} else {
|
||
weatherInfo->timeout = 0;
|
||
}
|
||
|
||
mode = cnt % 6;
|
||
if(mode == 5) {
|
||
weatherInfo->temper_unit = TEMP_FAHRENHEIT;
|
||
} else {
|
||
weatherInfo->temper_unit = (temperature_enum)(rand() % 2); //温度类型范围:0~1
|
||
}
|
||
weatherInfo->now_temperature = (rand() % 100) - 50; //默认为摄氏度,天气温范围:-50~49,单位:摄氏度
|
||
|
||
mode = cnt % 6;
|
||
//打桩设置预报天气数据
|
||
weatherInfo->forecast_count = ARRY_NUM(g_weather_info.forecast);
|
||
for(int i = 0; i < ARRY_NUM(g_weather_info.forecast); i++) {
|
||
if(weatherInfo->forecast[i].protocol_value == 0) { //实时天气为晴
|
||
weatherInfo->forecast[i].protocol_value = 999;
|
||
strcpy(weatherInfo->forecast[i].weather_text, "阴天多云");
|
||
weatherInfo->forecast[i].aqi = 19; //天气指数低
|
||
strcpy(weatherInfo->forecast[i].aqi_text, "良");
|
||
} else {
|
||
weatherInfo->forecast[i].protocol_value = 104;
|
||
strcpy(weatherInfo->forecast[i].weather_text, "晴转多云");
|
||
weatherInfo->forecast[i].aqi = rand() % 500; //天气指数随机
|
||
strcpy(weatherInfo->forecast[i].aqi_text, "优");
|
||
}
|
||
//默认按照摄氏度计算
|
||
if(mode == 5) {
|
||
//最高温度
|
||
weatherInfo->forecast[i].temperature_max = 49.0;
|
||
//最低温度
|
||
weatherInfo->forecast[i].temperature_min = -50.0;
|
||
} else {
|
||
if(weatherInfo->now_temperature >= 0) {
|
||
//最高温度
|
||
weatherInfo->forecast[i].temperature_max = (rand() % (50 - (int)weatherInfo->now_temperature)) + weatherInfo->now_temperature;
|
||
weatherInfo->forecast[i].temperature_max = ((weatherInfo->forecast[i].temperature_max) > 49 ? 49 : (weatherInfo->forecast[i].temperature_max));
|
||
//最低温度
|
||
weatherInfo->forecast[i].temperature_min = (rand() % (50 + (int)weatherInfo->now_temperature)) - 50;
|
||
weatherInfo->forecast[i].temperature_min = (weatherInfo->forecast[i].temperature_min) < (-50) ? (-50) : (weatherInfo->forecast[i].temperature_min);
|
||
} else {
|
||
//最高温度
|
||
weatherInfo->forecast[i].temperature_max = (rand() % (49 - (int)weatherInfo->now_temperature)) + weatherInfo->now_temperature + 1;
|
||
weatherInfo->forecast[i].temperature_max = ((weatherInfo->forecast[i].temperature_max) > 49 ? 49 : (weatherInfo->forecast[i].temperature_max));
|
||
//最低温度
|
||
weatherInfo->forecast[i].temperature_min = (rand() % (51 + (int)weatherInfo->now_temperature)) - 50;
|
||
weatherInfo->forecast[i].temperature_min = (weatherInfo->forecast[i].temperature_min) < (-50) ? (-50) : (weatherInfo->forecast[i].temperature_min);
|
||
}
|
||
}
|
||
weatherInfo->forecast[i].date_timestamp = weatherInfo->update_timestamp + (i + 1) * 86400;
|
||
}
|
||
|
||
#endif
|
||
cnt++;
|
||
}
|
||
|