From af26b84b20b6d9d0e0ce690e8011a037e87dc5c8 Mon Sep 17 00:00:00 2001 From: Mika Laitio Date: Tue, 25 Jan 2011 23:26:38 +0200 Subject: [PATCH] Added support for cacheing monthly data. Fixed various small errors in initial calculations. Signed-off-by: Mika Laitio --- src/Data.cc | 8 + src/Data.hh | 6 +- src/Date.cc | 49 ++++-- src/Date.hh | 4 +- src/DeviceData.cc | 45 +++++- src/DeviceData.hh | 7 + src/StoreCache.cc | 403 +++++++++++++++++++++++++++++++++++++++++----- src/StoreDay.cc | 29 ++-- src/W1Util.cc | 6 +- 9 files changed, 490 insertions(+), 67 deletions(-) diff --git a/src/Data.cc b/src/Data.cc index 923def1..49dd507 100644 --- a/src/Data.cc +++ b/src/Data.cc @@ -195,6 +195,14 @@ string Data::to_string() { return to_string(3); } +int Data::get_value_count() { + return value_arr.size(); +} + +double Data::get(int indx) { + return value_arr[indx]; +} + DataRange::DataRange() { val_matrix = NULL; column_count = 0; diff --git a/src/Data.hh b/src/Data.hh index fe819b5..07bea1a 100644 --- a/src/Data.hh +++ b/src/Data.hh @@ -31,11 +31,13 @@ namespace plp { static Data *parse_string(const std::string& data_str); plp::Date get_date(); void set_date(plp::Date *date_param); + int get_value_count(); + double get(int indx); std::string get_unit(); std::valarray value_arr; private: - plp::Date date_time; - std::string unit; + plp::Date date_time; + std::string unit; }; class DataRange { diff --git a/src/Date.cc b/src/Date.cc index 86b2cdc..e45b544 100644 --- a/src/Date.cc +++ b/src/Date.cc @@ -136,7 +136,7 @@ bool Date::before_or_equal_month(Date *date2) { string s2; ret_val = false; - if (this->year < date2->month) { + if (this->year < date2->year) { ret_val = true; } else { @@ -212,7 +212,20 @@ bool Date::before_or_equal(Date *date2) { return ret_val; } -void Date::tomorrow() { +void Date::next_hour() { + sec = 0; + min = 0; + hour++; + if (hour < 0) { + hour = 0; + } + if (hour >= 24) { + hour = 0; + next_day(); + } +} + +void Date::next_day() { if ((month > 0) && (month <= 12)) { day++; @@ -234,17 +247,27 @@ void Date::tomorrow() { } } -void Date::next_hour() { - if ((hour >= 0) && - (hour <= 24)) { - hour++; - if (hour > 24) { - hour = 0; - tomorrow(); - } +void Date::next_month() { + sec = 0; + min = 0; + hour = 0; + day = 1; + month++; + if (month > 12) { + month = 1; + year++; } } +void Date::next_year() { + sec = 0; + min = 0; + hour = 0; + day = 1; + month = 1; + year++; +} + void Date::inc_minutes(int minutes) { int day_c; int hour_c; @@ -255,13 +278,13 @@ void Date::inc_minutes(int minutes) { hour_c = minutes / 60; minutes = minutes - hour_c * 60; for (ii = 0; ii < day_c; ii++) { - tomorrow(); + next_day(); } for (ii = 0; ii < hour_c; ii++) { hour++; if (hour > 24) { hour = 0; - tomorrow(); + next_day(); } } min = min + minutes; @@ -270,7 +293,7 @@ void Date::inc_minutes(int minutes) { hour++; if (hour > 24) { hour = 0; - tomorrow(); + next_day(); } } } diff --git a/src/Date.hh b/src/Date.hh index 2a1015c..1a578a4 100644 --- a/src/Date.hh +++ b/src/Date.hh @@ -23,8 +23,10 @@ namespace plp { virtual ~Date(); void printout(); bool is_leap_year(); - void tomorrow(); void next_hour(); + void next_day(); + void next_month(); + void next_year(); void inc_minutes(int minutes); void inc_seconds(int seconds); Date *clone(); diff --git a/src/DeviceData.cc b/src/DeviceData.cc index d47eb00..d13287c 100644 --- a/src/DeviceData.cc +++ b/src/DeviceData.cc @@ -212,6 +212,43 @@ DataRange *DeviceData::get_summary(Date *date_param, return ret_val; } +DataRange *DeviceData::get_monthly_summary(Date *date, + EnumSummaryCalculationType calc_type_param) { + return get_summary(date, calc_type_param, PERIOD_MONTHLY); +} + +DataRange *DeviceData::get_monthly_summary(Date *date) { + DataRange *ret_val; + + ret_val = get_monthly_summary(date, summary_calc_type); + return ret_val; +} + +DataRange *DeviceData::get_monthly_summary(Date *start_date, + Date *end_date) { + DataRange *ret_val; + DataRange *data; + Date *date; + + ret_val = NULL; + date = start_date->clone(); + while(date->before_or_equal_month(end_date)) { + data = get_monthly_summary(date); + if (data != NULL) { + if (ret_val == NULL) { + ret_val = new DataRange(data); + } + else { + ret_val->add(data); + } + delete(data); + } + date->next_month(); + } + delete(date); + return ret_val; +} + DataRange *DeviceData::get_daily_summary(Date *date, EnumSummaryCalculationType calc_type_param) { return get_summary(date, calc_type_param, PERIOD_DAILY); @@ -243,7 +280,7 @@ DataRange *DeviceData::get_daily_summary(Date *start_date, } delete(data); } - date->tomorrow(); + date->next_day(); } delete(date); return ret_val; @@ -287,7 +324,7 @@ DataRange *DeviceData::get_hourly_summary(Date *start_date, delete(data); } } - date->tomorrow(); + date->next_day(); } delete(date); return ret_val; @@ -305,11 +342,11 @@ DataRange *DeviceData::get_data(Date *start_date, switch(period) { case PERIOD_YEARLY: log_debug("get yearly summary: %s - %s\n", start_date->to_string().c_str(), end_date->to_string().c_str()); - ret_val = get_daily_summary(start_date, end_date); + ret_val = get_monthly_summary(start_date, end_date); break; case PERIOD_MONTHLY: log_debug("get monthly summary\n"); - ret_val = get_daily_summary(start_date, end_date); + ret_val = get_monthly_summary(start_date, end_date); break; case PERIOD_DAILY: log_debug("get daily summary\n"); diff --git a/src/DeviceData.hh b/src/DeviceData.hh index 2c16410..367e00f 100644 --- a/src/DeviceData.hh +++ b/src/DeviceData.hh @@ -23,6 +23,13 @@ namespace w1 { DeviceData(std::string device_id); virtual ~DeviceData(); plp::DataRange *get_data_range(); + plp::DataRange *get_monthly_summary(plp::Date *date, EnumSummaryCalculationType calc_type); + /** + * Get summary data calculated from the daily data items that is meaning full. + * Depending from the device type, it may be daily mean value, daily delta, highest value, etc... + */ + plp::DataRange *get_monthly_summary(plp::Date *date); + plp::DataRange *get_monthly_summary(plp::Date *start_date, plp::Date *end_date); plp::DataRange *get_daily_summary(plp::Date *date, EnumSummaryCalculationType calc_type); /** * Get summary data calculated from the daily data items that is meaning full. diff --git a/src/StoreCache.cc b/src/StoreCache.cc index 68a9f58..3fc9c4b 100644 --- a/src/StoreCache.cc +++ b/src/StoreCache.cc @@ -18,12 +18,6 @@ using namespace w1; StoreCache::StoreCache(string device_id_param, Date *date_time_param): Store(device_id_param, date_time_param) { -/* - store_fname = get_file_name(device_id_param, - date_time_param, - period_type_param, - calc_type_param); -*/ } StoreCache::~StoreCache() { @@ -37,13 +31,22 @@ string StoreCache::get_dir_name(string device_id_param, char buffer[30]; string bd_name; - snprintf(buffer, 30, "%d/%02d", date_time_param->year, date_time_param->month); bd_name = DeviceConfig::get_base_dir_name(); bd_name = W1Util::concat_paths(bd_name, CACHE_DIR_NAME); bd_name = W1Util::concat_paths(bd_name, device_id_param); bd_name = W1Util::concat_paths(bd_name, SUMMARY_PERIOD_NAMES_ARRAY[period_type_param]); bd_name = W1Util::concat_paths(bd_name, CALCULATION_TYPE_NAMES_ARRAY[calc_type_param]); - ret_val = bd_name + "/" + buffer; + if (period_type_param == PERIOD_YEARLY) { + ret_val = bd_name; + } + else if (period_type_param == PERIOD_MONTHLY) { + snprintf(buffer, 30, "%d", date_time_param->year); + ret_val = bd_name + "/" + buffer; + } + else { + snprintf(buffer, 30, "%d/%02d", date_time_param->year, date_time_param->month); + ret_val = bd_name + "/" + buffer; + } return ret_val; } @@ -55,10 +58,20 @@ string StoreCache::get_file_name(string device_id_param, string fname; char buffer[30]; - snprintf(buffer, 30, "%d-%02d-%02d", - date_time_param->year, - date_time_param->month, - date_time_param->day); + if (period_type_param == PERIOD_YEARLY) { + snprintf(buffer, 30, "%d", date_time_param->year); + } + else if (period_type_param == PERIOD_MONTHLY) { + snprintf(buffer, 30, "%d-%02d", + date_time_param->year, + date_time_param->month); + } + else { + snprintf(buffer, 30, "%d-%02d-%02d", + date_time_param->year, + date_time_param->month, + date_time_param->day); + } fname = buffer; fname = fname + DATAFILE_SUFFIX; ret_val = get_dir_name(device_id_param, date_time_param, period_type_param, calc_type_param); @@ -93,10 +106,71 @@ DataRange *StoreCache::get_mean(EnumSummaryPeriod period_type_param) { } } if (ret_val == NULL) { - store = new StoreDay(device_id, date); - ret_val = store->get_mean(period_type_param); - save(fname, ret_val, 4); - delete(store); + switch(period_type_param) { + case PERIOD_YEARLY: + break; + case PERIOD_MONTHLY: { + Data *cur_data; + Data *res_data; + Date *cur_date; + Date *max_date; + int ii; + int cnt; + int val_cnt; + DataRange *dr; + + cur_date = date->clone(); + max_date = date->clone(); + max_date->next_month(); + cur_data = NULL; + res_data = NULL; + cnt = 0; + while(cur_date->before(max_date)) { + store = new StoreDay(device_id, cur_date); + dr = store->get_mean(PERIOD_DAILY); + if (dr != NULL) { + cur_data = dr->get_first(); + if (cur_data != NULL) { + cnt++; + if (res_data == NULL) { + res_data = cur_data; + } + else { + val_cnt = res_data->get_value_count(); + for (ii = 0; ii < val_cnt; ii++) { + res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii]; + } + delete(cur_data); + } + } + delete(dr); + } + delete(store); + cur_date->next_day(); + } + if ((res_data != NULL) && + (cnt > 0)) { + for (ii = 0; ii < val_cnt; ii++) { + res_data->value_arr[ii] = res_data->value_arr[ii] / cnt; + } + ret_val = new DataRange(res_data); + save(fname, ret_val, 4); + delete(res_data); + } + delete(cur_date); + delete(max_date); + } + break; + case PERIOD_DAILY: + case PERIOD_HOURLY: + case PERIOD_MINUTELY: + case PERIOD_SECONDLY: + store = new StoreDay(device_id, date); + ret_val = store->get_mean(period_type_param); + save(fname, ret_val, 4); + delete(store); + break; + } } return ret_val; } @@ -112,7 +186,7 @@ DataRange *StoreCache::get_sum(EnumSummaryPeriod period_type_param) { fname = get_file_name(device_id, date, period_type_param, - MEAN); + SUM); if (store_data == NULL) { if (access(fname.c_str(), R_OK) == 0) { load(fname); @@ -128,10 +202,68 @@ DataRange *StoreCache::get_sum(EnumSummaryPeriod period_type_param) { } } if (ret_val == NULL) { - store = new StoreDay(device_id, date); - ret_val = store->get_sum(period_type_param); - save(fname, ret_val, 4); - delete(store); + switch(period_type_param) { + case PERIOD_YEARLY: + break; + case PERIOD_MONTHLY: { + Data *cur_data; + Data *res_data; + Date *cur_date; + Date *max_date; + int ii; + int cnt; + int val_cnt; + DataRange *dr; + + cur_date = date->clone(); + max_date = date->clone(); + max_date->next_month(); + cur_data = NULL; + res_data = NULL; + cnt = 0; + while(cur_date->before(max_date)) { + store = new StoreDay(device_id, cur_date); + dr = store->get_sum(PERIOD_DAILY); + if (dr != NULL) { + cur_data = dr->get_first(); + if (cur_data != NULL) { + cnt++; + if (res_data == NULL) { + res_data = cur_data; + } + else { + val_cnt = res_data->get_value_count(); + for (ii = 0; ii < val_cnt; ii++) { + res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii]; + } + delete(cur_data); + } + } + delete(dr); + } + delete(store); + cur_date->next_day(); + } + if ((res_data != NULL) && + (cnt > 0)) { + ret_val = new DataRange(res_data); + save(fname, ret_val, 4); + delete(res_data); + } + delete(cur_date); + delete(max_date); + } + break; + case PERIOD_DAILY: + case PERIOD_HOURLY: + case PERIOD_MINUTELY: + case PERIOD_SECONDLY: + store = new StoreDay(device_id, date); + ret_val = store->get_sum(period_type_param); + save(fname, ret_val, 4); + delete(store); + break; + } } return ret_val; } @@ -147,7 +279,7 @@ DataRange *StoreCache::get_delta(EnumSummaryPeriod period_type_param) { fname = get_file_name(device_id, date, period_type_param, - MEAN); + DELTA); if (store_data == NULL) { if (access(fname.c_str(), R_OK) == 0) { // read from cache file @@ -164,10 +296,73 @@ DataRange *StoreCache::get_delta(EnumSummaryPeriod period_type_param) { } } if (ret_val == NULL) { - store = new StoreDay(device_id, date); - ret_val = store->get_delta(period_type_param); - save(fname, ret_val, 4); - delete(store); + switch(period_type_param) { + case PERIOD_YEARLY: + break; + case PERIOD_MONTHLY: { + Data *first_data; + Data *last_data; + Data *cur_data; + Date *cur_date; + Date *limit_date; + int ii; + int cnt; + + cur_date = date->clone(); + limit_date = date->clone(); + limit_date->next_month(); + first_data = NULL; + last_data = NULL; + while(cur_date->before(limit_date)) { + store = new StoreDay(device_id, cur_date); + if (first_data == NULL) { + cur_data = store->get_oldest_data(); + if (cur_data != NULL) { + first_data = cur_data->clone(); + last_data = cur_data->clone(); + delete(cur_data); + } + } + cur_data = store->get_newest_data(); + if (cur_data != NULL) { + if (last_data != NULL) { + delete(last_data); + } + last_data = cur_data; + } + delete(store); + cur_date->next_day(); + } + delete(cur_date); + delete(limit_date); + if (first_data != NULL) { + if (last_data == NULL) { + last_data = first_data->clone(); + } + cnt = last_data->get_value_count(); + for (ii = 0; ii < cnt; ii++) { + last_data->value_arr[ii] = last_data->value_arr[ii] - first_data->value_arr[ii]; + } + cur_date = first_data->get_date().clone(); + last_data->set_date(cur_date); + delete(cur_date); + ret_val = new DataRange(last_data); + delete(first_data); + delete(last_data); + save(fname, ret_val, 4); + } + } + break; + case PERIOD_DAILY: + case PERIOD_HOURLY: + case PERIOD_MINUTELY: + case PERIOD_SECONDLY: + store = new StoreDay(device_id, date); + ret_val = store->get_delta(period_type_param); + save(fname, ret_val, 4); + delete(store); + break; + } } return ret_val; } @@ -183,7 +378,7 @@ DataRange *StoreCache::get_max(EnumSummaryPeriod period_type_param) { fname = get_file_name(device_id, date, period_type_param, - MEAN); + MAX); if (store_data == NULL) { if (access(fname.c_str(), R_OK) == 0) { load(fname); @@ -199,10 +394,78 @@ DataRange *StoreCache::get_max(EnumSummaryPeriod period_type_param) { } } if (ret_val == NULL) { - store = new StoreDay(device_id, date); - ret_val = store->get_max(period_type_param); - save(fname, ret_val, 4); - delete(store); + switch(period_type_param) { + case PERIOD_YEARLY: + break; + case PERIOD_MONTHLY: { + Data *cur_data; + Data *res_data; + Date *cur_date; + Date *max_date; + int ii; + int cnt; + int val_cnt; + DataRange *dr; + + cur_date = date->clone(); + max_date = date->clone(); + max_date->next_month(); + cur_data = NULL; + res_data = NULL; + cnt = 0; + while(cur_date->before(max_date)) { + store = new StoreDay(device_id, cur_date); + dr = store->get_max(PERIOD_DAILY); + if (dr != NULL) { + cur_data = dr->get_first(); + if (cur_data != NULL) { + cnt++; + if (res_data == NULL) { + res_data = cur_data; + } + else { + val_cnt = res_data->get_value_count(); + int changed = 0; + for (ii = 0; ii < val_cnt; ii++) { + if (cur_data->value_arr[ii] > res_data->value_arr[ii]) { + res_data->value_arr[ii] = cur_data->value_arr[ii]; + changed = 1; + } + } + if (changed == 1) { + Date new_date; + + new_date = cur_data->get_date(); + res_data->set_date(&new_date); + } + delete(cur_data); + } + } + delete(dr); + } + delete(store); + cur_date->next_day(); + } + if ((res_data != NULL) && + (cnt > 0)) { + ret_val = new DataRange(res_data); + save(fname, ret_val, 4); + delete(res_data); + } + delete(cur_date); + delete(max_date); + } + break; + case PERIOD_DAILY: + case PERIOD_HOURLY: + case PERIOD_MINUTELY: + case PERIOD_SECONDLY: + store = new StoreDay(device_id, date); + ret_val = store->get_max(period_type_param); + save(fname, ret_val, 4); + delete(store); + break; + } } return ret_val; } @@ -218,7 +481,7 @@ DataRange *StoreCache::get_min(EnumSummaryPeriod period_type_param) { fname = get_file_name(device_id, date, period_type_param, - MEAN); + MIN); if (store_data == NULL) { if (access(fname.c_str(), R_OK) == 0) { load(fname); @@ -234,10 +497,78 @@ DataRange *StoreCache::get_min(EnumSummaryPeriod period_type_param) { } } if (ret_val == NULL) { - store = new StoreDay(device_id, date); - ret_val = store->get_min(period_type_param); - save(fname, ret_val, 4); - delete(store); + switch(period_type_param) { + case PERIOD_YEARLY: + break; + case PERIOD_MONTHLY: { + Data *cur_data; + Data *res_data; + Date *cur_date; + Date *max_date; + int ii; + int cnt; + int val_cnt; + DataRange *dr; + + cur_date = date->clone(); + max_date = date->clone(); + max_date->next_month(); + cur_data = NULL; + res_data = NULL; + cnt = 0; + while(cur_date->before(max_date)) { + store = new StoreDay(device_id, cur_date); + dr = store->get_min(PERIOD_DAILY); + if (dr != NULL) { + cur_data = dr->get_first(); + if (cur_data != NULL) { + cnt++; + if (res_data == NULL) { + res_data = cur_data; + } + else { + val_cnt = res_data->get_value_count(); + int changed = 0; + for (ii = 0; ii < val_cnt; ii++) { + if (cur_data->value_arr[ii] < res_data->value_arr[ii]) { + res_data->value_arr[ii] = cur_data->value_arr[ii]; + changed = 1; + } + } + if (changed == 1) { + Date new_date; + + new_date = cur_data->get_date(); + res_data->set_date(&new_date); + } + delete(cur_data); + } + } + delete(dr); + } + delete(store); + cur_date->next_day(); + } + if ((res_data != NULL) && + (cnt > 0)) { + ret_val = new DataRange(res_data); + save(fname, ret_val, 4); + delete(res_data); + } + delete(cur_date); + delete(max_date); + } + break; + case PERIOD_DAILY: + case PERIOD_HOURLY: + case PERIOD_MINUTELY: + case PERIOD_SECONDLY: + store = new StoreDay(device_id, date); + ret_val = store->get_min(period_type_param); + save(fname, ret_val, 4); + delete(store); + break; + } } return ret_val; } diff --git a/src/StoreDay.cc b/src/StoreDay.cc index 8d35952..fb5c175 100644 --- a/src/StoreDay.cc +++ b/src/StoreDay.cc @@ -436,10 +436,12 @@ plp::DataRange *StoreDay::get_max_or_min(EnumSummaryPeriod period_type_param, bo date = data->get_date(); if ((ii <= (row_count -1)) && ((frq_sec == -1) || (date.before(limit_d)))) { + int changed = 0; if (max == true) { for (jj = 0; jj < col_count; jj++) { if (calc->value_arr[jj] < data->value_arr[jj]) { calc->value_arr[jj] = data->value_arr[jj]; + changed = 1; } } } @@ -447,9 +449,16 @@ plp::DataRange *StoreDay::get_max_or_min(EnumSummaryPeriod period_type_param, bo for (jj = 0; jj < col_count; jj++) { if (data->value_arr[jj] < calc->value_arr[jj]) { calc->value_arr[jj] = data->value_arr[jj]; + changed = 1; } } } + if (changed == 1) { + Date new_date; + + new_date = data->get_date(); + calc->set_date(&new_date); + } } if ((ii >= (row_count -1)) || ((frq_sec != -1) && (date.before(limit_d) == false))) { @@ -525,17 +534,19 @@ DataRange *StoreDay::get_oldest_and_newest_data(string fname_param) { } else { in.open(fname_param.c_str()); - while (in.eof() == false) { - getline(in, line); - if (line.empty() == false) { - if (o_data == NULL) { - o_data = Data::parse_string(line); + if (in.is_open() == true) { + while (in.eof() == false) { + getline(in, line); + if (line.empty() == false) { + if (o_data == NULL) { + o_data = Data::parse_string(line); + } + prev_line = line; } - prev_line = line; } - } - if (prev_line.empty() == false) { - n_data = Data::parse_string(prev_line); + if (prev_line.empty() == false) { + n_data = Data::parse_string(prev_line); + } } } } diff --git a/src/W1Util.cc b/src/W1Util.cc index 452d729..b375a35 100644 --- a/src/W1Util.cc +++ b/src/W1Util.cc @@ -78,9 +78,10 @@ bool W1Util::mkdirs(const char *path) { *p = '\0'; // if dir does not exist, create it if (access(path, F_OK) != 0) { - log_debug("trying to create directory: %s\n", path); + //log_debug("trying to create directory: %s\n", path); err_flg = mkdir(path, S_IRWXU); if (err_flg != 0) { + log_error("Could not create directory: %s\n", path); ret_val = false; break; } @@ -91,9 +92,10 @@ bool W1Util::mkdirs(const char *path) { if (ret_val == true) { // if dir does not exist, create it if (access(path, F_OK) != 0) { - log_debug("trying to create directory: %s\n", path); + //log_debug("trying to create directory: %s\n", path); err_flg = mkdir(path, S_IRWXU); if (err_flg != 0) { + log_error("Could not create directory: %s\n", path); ret_val = false; } } -- 2.41.1