/* Copyright (C) 2019-2021 Logaev Maxim (turbocat2001), GPLv2 */ /* Info: App uses api from openweathermap.org. The standard configuration uses my token and the city of Moscow. You can always change it in the weather.json file. weather.json configuration example: { "Celsius": false, // Enabled fahrenheit (Optional) "Location": "Berlin", // City Berlin "Token": "19ffa14b3dc0e238175829461d1788b8", // OpenWeatherMap token "Lang": "ru", // Language (Optional) "AutoUpdate": 5 // In minutes. 0 - disabled (Optional) } */ #include #include #include #include #include "json/json.h" #include #include #include #include #define VERSION "Weather 1.5" enum BUTTONS{ BTN_QUIT = 1, BTN_UPDATE = 2 }; #define START_YPOS 34 #define UTF8_W 8 #define CP866_W 6 #define JSON_OBJ(X) value->u.object.values[X] #define OK 200 unsigned WINDOW_W = 230; #define API "api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=%s&lang=%s" #define IMAGE_URL "openweathermap.org/img/w/%s.png" Image *blend=NULL; const char *config_name = "/sys/Settings/weather.json"; unsigned char char_size=1; uint64_t AutoUpdateTime = 0; char *wind_speed_str, *pressure_str, *visibility_str, *humidity_str, *update_str, *wind_deg_str; char lang[3]="en"; char format_temp_str[6]; char full_url[512]; char full_url_image[256]; char temp_char='K'; struct kolibri_system_colors sys_color_table; pos_t win_pos; #pragma pack(push,1) struct open_weather_data{ char City[100]; int wind_speed; int wind_deg; int pressure; int humidity; char weath_desc[100]; int visibility; int timezone; char image_code[4]; int temp; }myw; #pragma pack(pop) void notify_show(char *text) { start_app("/sys/@notify", text); } void* safe_malloc(size_t size) { void *p=malloc(size); if(p==NULL){ notify_show("'Memory allocation error!' -E"); exit(0); }else{ return p; } } void draw_format_text_sys(int x, int y, color_t color, const char *format_str, ... ) // Форматированный вывод в окно { char tmp_buff[100]; va_list ap; va_start (ap, format_str); vsnprintf(tmp_buff, sizeof tmp_buff ,format_str, ap); va_end(ap); draw_text_sys(tmp_buff, x, y , 0, color); } void find_and_set(json_value *value, struct open_weather_data* weather) // Ищем значения в json и заполняем структуру "myw" { for(int i=0; iu.object.length; i++){ if(!strcmp(JSON_OBJ(i).name, "main")){ if(JSON_OBJ(i).value->u.object.values[0].value->type==json_double) { weather->temp = (int)JSON_OBJ(i).value->u.object.values[0].value->u.dbl; }else{ weather->temp = JSON_OBJ(i).value->u.object.values[0].value->u.integer; } weather->pressure = JSON_OBJ(i).value->u.object.values[4].value->u.integer; weather->humidity = JSON_OBJ(i).value->u.object.values[5].value->u.integer; } if(!strcmp(JSON_OBJ(i).name, "name")){ if(!strcmp(&JSON_OBJ(i).value->u.string.ptr[JSON_OBJ(i).value->u.string.length-3], "’")){ strncpy(weather->City, JSON_OBJ(i).value->u.string.ptr, JSON_OBJ(i).value->u.string.length-3); }else{ strcpy(weather->City, JSON_OBJ(i).value->u.string.ptr); } } if(!strcmp(JSON_OBJ(i).name, "weather")){ strcpy(weather->weath_desc, JSON_OBJ(i).value->u.array.values[0]->u.object.values[2].value->u.string.ptr); strcpy(weather->image_code, JSON_OBJ(i).value->u.array.values[0]->u.object.values[3].value->u.string.ptr); } if(!strcmp(JSON_OBJ(i).name, "wind")){ weather->wind_deg = JSON_OBJ(i).value->u.object.values[1].value->u.integer; if(JSON_OBJ(i).value->u.object.values[0].value->type==json_double) { weather->wind_speed = (int)JSON_OBJ(i).value->u.object.values[0].value->u.dbl; }else{ weather->wind_speed = JSON_OBJ(i).value->u.object.values[0].value->u.integer; } } if(!strcmp(JSON_OBJ(i).name, "visibility")){ weather->visibility = JSON_OBJ(i).value->u.integer; } if(!strcmp(JSON_OBJ(i).name, "timezone")){ weather->timezone = JSON_OBJ(i).value->u.integer/60/60; } if(!strcmp(JSON_OBJ(i).name, "message")){ char *errmsg = safe_malloc(weather->timezone = JSON_OBJ(i).value->u.string.length+6); sprintf(errmsg,"'%s!' -E", JSON_OBJ(i).value->u.string.ptr); notify_show(errmsg); free(errmsg); } } } http_msg* get_json(char *City, char *Token, char* Units) { sprintf(full_url, API, City, Token, Units, lang); http_msg *h = http_get(full_url, 0, HTTP_FLAG_BLOCK, ""); http_long_receive(h); if (h->status == OK || h->status == 404) { return h; } else { http_free(h); return NULL; } } void get_image() // Функция загрузки изображения { sprintf(full_url_image, IMAGE_URL, myw.image_code); http_msg *h= http_get(full_url_image, 0, HTTP_FLAG_BLOCK, ""); http_long_receive(h); if (h->status == OK) { Image *image = img_decode(h->content_ptr, h->content_length, 0); // Декодирование RAW данных в данные изображения if (image->Type != IMAGE_BPP32) { image = img_convert(image, NULL, IMAGE_BPP32, 0, 0); // Конвертируем картику в BPP32 if (!image) { notify_show("'Convetring image error!' -E"); exit(0); } } blend = img_create(64, 64, IMAGE_BPP32); // Создаём фон для картинки img_fill_color(blend, 64, 64, sys_color_table.work_area); // Заливаем фон цветом окна Image* image2 = img_scale(image, 0, 0, 50, 50, NULL, LIBIMG_SCALE_STRETCH , LIBIMG_INTER_BILINEAR, 64, 64); // Растягиваем изображение img_blend(blend, image2, 0, 0, 0, 0, 64, 64); // Смешиваем растянутую картинку и фон для получения прозрачности img_destroy(image); // Уничтожаем исходную картинку img_destroy(image2); // Уничтажаем растянутую картинку }else{ notify_show("'Image not loaded!!' -W"); } if(h!=NULL){ http_free(h); } } void RedrawGUI() // Перересовываем интерфейс { begin_draw(); // Начинам прорисовку int new_win_w = (strlen(myw.City)/char_size+10)*(UTF8_W+char_size-1); // Если название города не влезает в окно if(new_win_wu.object.length; i++){ if(!strcmp(JSON_OBJ(i).name, "Location") && JSON_OBJ(i).value->type==json_string){ *City = JSON_OBJ(i).value->u.string.ptr; // Получаем название города } else if(!strcmp(JSON_OBJ(i).name, "Token") && JSON_OBJ(i).value->type==json_string){ *Token = JSON_OBJ(i).value->u.string.ptr; // Получаем токен } else if(!strcmp(JSON_OBJ(i).name, "Celsius") && JSON_OBJ(i).value->type==json_boolean){ if(JSON_OBJ(i).value->u.boolean){ *Units = "metric"; temp_char = 'C'; }else{ *Units = "imperial"; temp_char = 'F'; } } else if(!strcmp(JSON_OBJ(i).name, "Lang") && JSON_OBJ(i).value->type==json_string){ strncpy(lang, JSON_OBJ(i).value->u.string.ptr,2); // Получаем язык } else if(!strcmp(JSON_OBJ(i).name, "AutoUpdate") && JSON_OBJ(i).value->type==json_integer){ AutoUpdateTime = JSON_OBJ(i).value->u.integer; // Получаем время автообновлений данных } } if(*City==NULL || *Token ==NULL){ notify_show("'Invalid config!' -E"); exit(0); } free(config_buff); fclose(config_j); } void Update(char* city, char* token, char* units) // Обновление данных { if(blend!=NULL){ img_destroy(blend); // Уничтожение картинику с прозрачностью blend = NULL; } memset(&myw, 0, sizeof myw); // Обнуляем структуру strcpy(myw.City,"None"); strcpy(myw.weath_desc,"unknown"); http_msg *json_file = get_json(city, token, units); // Получаем данные о погоде в формате json if(json_file != NULL){ json_value* value=json_parse(json_file->content_ptr, json_file->content_length); // Парсим json файл find_and_set(value, &myw); // Ищем значения в json sprintf(format_temp_str, "%s°%c","%d",temp_char); // Формируем строку для вывода температуры get_image(); // Получаем картинку json_value_free(value); // Уничтожаем полученные json значения http_free(json_file); }else{ notify_show("'Connection error!' -E"); } } void set_lang() { if(!strcmp(lang, "ru")){ wind_speed_str = "Скорость ветра: %d м/с"; pressure_str = "Давление: %d гПa"; visibility_str = "Видимость: %d м"; humidity_str = "Влажность: %d %s"; update_str = "Обновить"; wind_deg_str = "Направление ветра: %d°"; WINDOW_W = 250; char_size = 2; }else if(!strcmp(lang, "de")){ wind_speed_str = "Windgeschwindigkeit: %d m/s"; pressure_str = "Druck: %d hPa"; visibility_str = "Sichtbarkeit: %d m"; humidity_str = "Luftfeuchtigkeit: %d %s"; wind_deg_str = "Windrichtung %d°"; WINDOW_W = 270; update_str = "Aktualisieren"; }else{ pressure_str = "Pressure: %d hPa"; humidity_str = "Humidity: %d %s"; visibility_str = "Visibility: %d m"; wind_speed_str = "Wind speed: %d m/s"; wind_deg_str = "Wind direction: %d°"; update_str = "Refresh"; } } int main() { win_pos = get_mouse_pos(0); // Получаем позицию курсора if(!kolibri_libimg_init()){ // Загружаем libimg.obj notify_show("Libimg.obj not loaded!' -E"); exit(0); } get_system_colors(&sys_color_table); // Получаем таблица цветов char *City=NULL, *Token=NULL, *Units=NULL; // Указатели на токен, название города, систему мер get_config(&City, &Token, &Units); // Загружаем конфиг set_lang(); // Установить язык приложения Update(City, Token, Units); uint32_t (*event)(); if(AutoUpdateTime<=0){ event = get_os_event; }else{ event = wait_for_event; } while(1){ switch(event(6000*AutoUpdateTime)){ // Получаем системное событие case KOLIBRI_EVENT_NONE: // Нет события Update(City, Token, Units); debug_printf("Weather: Update\n"); break; case KOLIBRI_EVENT_REDRAW: // Событие перерисовки RedrawGUI(); break; case KOLIBRI_EVENT_BUTTON: // Событие кнопок switch (get_os_button()){ case BTN_UPDATE: Update(City, Token, Units); RedrawGUI(); break; case BTN_QUIT: // Кнопка выхода exit(0); break; } break; } } return 0; }