time_t wvutilsGetYearStartTime (int archiveInterval) { time_t ntime = time(NULL); struct tm locTime; ntime -= WV_SECONDS_IN_YEAR; ntime -= SECONDS_IN_INTERVAL(archiveInterval); localtime_r (&ntime, &locTime); locTime.tm_hour = 0; locTime.tm_min = archiveInterval; locTime.tm_sec = 0; locTime.tm_isdst = -1; ntime = mktime (&locTime); return ntime; }
static void processNewArchiveRecord (HTML_WORK *work, WVIEW_MSG_ARCHIVE_NOTIFY *armsg) { HISTORY_DATA data; ARCHIVE_PKT arcRecord; int currHour, currDay, currMonth, currYear; float gmtOffsetHours; int startmin, starthour, startday, startmonth, startyear; int i, DSTFlag; int16_t tempShort; time_t ntime, baseTime; struct tm locTime; int deltaArchiveIntervals; // ... generate the mesonet file htmlgenMesonetFile (work->mgrId, armsg); // ... check to see if a DST change has occured DSTFlag = wvutilsDetectDSTChange(); if (DSTFlag != WVUTILS_DST_NO_CHANGE) { radMsgLog (PRI_STATUS, "DST change: updating astronomical times for new local time..."); ntime = time (NULL); localtime_r (&ntime, &locTime); currDay = locTime.tm_mday; currMonth = locTime.tm_mon + 1; currYear = locTime.tm_year + 1900; #ifdef HAVE_TM_GMTOFF gmtOffsetHours = locTime.tm_gmtoff/(60.0*60.0); #else gmtOffsetHours = gmtoffset()/(60.0*60.0); #endif // ... update the sun times: sunTimesGetSunRiseSet (currYear, currMonth, currDay, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10, RS_TYPE_SUN, &work->mgrId->sunrise, &work->mgrId->sunset); sunTimesGetSunRiseSet (currYear, currMonth, currDay, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10, RS_TYPE_CIVIL, &work->mgrId->civilrise, &work->mgrId->civilset); sunTimesGetSunRiseSet (currYear, currMonth, currDay, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10, RS_TYPE_ASTRO, &work->mgrId->astrorise, &work->mgrId->astroset); sunTimesGetSunRiseSet (currYear, currMonth, currDay, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10, RS_TYPE_MIDDAY, &work->mgrId->midday, &tempShort); work->mgrId->dayLength = sunTimesGetDayLength (currYear, currMonth, currDay, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10); GetMoonRiseSetTimes (currYear, currMonth, currDay, (float)gmtOffsetHours, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10, &work->mgrId->moonrise, NULL, &work->mgrId->moonset, NULL); // restart the generation timer as the change may leave it in limbo radProcessTimerStart (work->timer, 5000L); } baseTime = time (NULL); // ... update our data by adding the new sample //// Interval change: // ... determine time to start for last sample startmin = wvutilsGetMin(armsg->dateTime); starthour = wvutilsGetHour(armsg->dateTime); startday = wvutilsGetDay(armsg->dateTime); startmonth = wvutilsGetMonth(armsg->dateTime); startyear = wvutilsGetYear(armsg->dateTime); currHour = starthour; currDay = startday; currMonth = startmonth; currYear = startyear; if (work->LastArchiveDateTime != 0) { // compute the number of archive intervals since the last good record deltaArchiveIntervals = armsg->dateTime - work->LastArchiveDateTime; deltaArchiveIntervals /= 60; if (deltaArchiveIntervals < work->archiveInterval) { // this is odd, report and bail out radMsgLog (PRI_MEDIUM, "processNewArchiveRecord: " "minutes since last archive record (%d) " "less than archive interval (%d) - " "ignoring record...", deltaArchiveIntervals, work->archiveInterval); return; } deltaArchiveIntervals /= work->archiveInterval; } else { deltaArchiveIntervals = 1; } work->LastArchiveDateTime = armsg->dateTime; if (dbsqliteArchiveGetAverages (work->mgrId->isMetricUnits, work->archiveInterval, &data, armsg->dateTime, 1) <= 0) { // populate history data with ARCHIVE_VALUE_NULL for (i = 0; i < DATA_INDEX_MAX(work->isExtendedData); i ++) { data.values[i] = ARCHIVE_VALUE_NULL; data.samples[i] = 0; } radMsgLog (PRI_MEDIUM, "no data found for sample..."); } wvutilsLogEvent (PRI_STATUS, "Adding %d minute sample for %4.4d-%2.2d-%2.2d %2.2d:%2.2d...", work->archiveInterval, startyear, startmonth, startday, starthour, startmin); // ... set the archiveAvailable flag for generation... work->mgrId->newArchiveMask |= NEW_ARCHIVE_SAMPLE; // add the RX check value to the data here data.values[DATA_INDEX_rxCheckPercent] = armsg->rxPercent; htmlmgrAddSampleValue (work->mgrId, &data, deltaArchiveIntervals); // generate an ASCII entry in the day's browser file (if enabled) if (dbsqliteArchiveGetRecord(armsg->dateTime, &arcRecord) == OK) { arcrecGenerate(&arcRecord, work->mgrId->isMetricUnits); } //// Hour change? if (work->histLastHour != currHour) { // determine times to start for last hour: ntime = time (NULL); localtime_r (&ntime, &locTime); locTime.tm_sec = 0; locTime.tm_min = work->archiveInterval; locTime.tm_hour = currHour; locTime.tm_mday = currDay; locTime.tm_mon = currMonth - 1; locTime.tm_year = currYear - 1900; locTime.tm_isdst = -1; ntime = mktime (&locTime); ntime -= WV_SECONDS_IN_HOUR; localtime_r (&ntime, &locTime); starthour = locTime.tm_hour; if (dbsqliteArchiveGetAverages (work->mgrId->isMetricUnits, work->archiveInterval, &data, ntime, WV_SECONDS_IN_HOUR/SECONDS_IN_INTERVAL(work->archiveInterval)) <= 0) { // populate history data with ARCHIVE_VALUE_NULL for (i = 0; i < DATA_INDEX_MAX(work->isExtendedData); i ++) { data.values[i] = ARCHIVE_VALUE_NULL; data.samples[i] = 0; } radMsgLog (PRI_MEDIUM, "no data found for last hour..."); } wvutilsLogEvent (PRI_STATUS, "Adding hour sample..."); // ... set the archiveAvailable flag for generation... work->mgrId->newArchiveMask |= NEW_ARCHIVE_HOUR; htmlmgrAddHourValue (work->mgrId, &data); work->histLastHour = currHour; } //// Day change? if (work->histLastDay != currDay) { // determine times to start for last day: // normalize packed time: ntime = time (NULL); localtime_r (&ntime, &locTime); locTime.tm_sec = 0; locTime.tm_min = work->archiveInterval; locTime.tm_hour = 0; locTime.tm_mday = currDay; locTime.tm_mon = currMonth - 1; locTime.tm_year = currYear - 1900; locTime.tm_isdst = -1; #ifdef HAVE_TM_GMTOFF gmtOffsetHours = locTime.tm_gmtoff/(60.0*60.0); #else gmtOffsetHours = gmtoffset()/(60.0*60.0); #endif ntime = mktime (&locTime); ntime -= WV_SECONDS_IN_DAY; localtime_r (&ntime, &locTime); if (dbsqliteArchiveGetAverages (work->mgrId->isMetricUnits, work->archiveInterval, &data, ntime, WV_SECONDS_IN_DAY/SECONDS_IN_INTERVAL(work->archiveInterval)) <= 0) { // populate history data with ARCHIVE_VALUE_NULL for (i = 0; i < DATA_INDEX_MAX(work->isExtendedData); i ++) { data.values[i] = ARCHIVE_VALUE_NULL; data.samples[i] = 0; } radMsgLog (PRI_MEDIUM, "no data found for last day..."); } else { // Add a day history record: wvutilsLogEvent(PRI_STATUS, "Storing day history for %s", ctime(&ntime)); dbsqliteHistoryInsertDay(&data); } // ... set the archiveAvailable flag for generation... work->mgrId->newArchiveMask |= NEW_ARCHIVE_DAY; wvutilsLogEvent(PRI_STATUS, "Adding day sample..."); htmlmgrAddDayValue (work->mgrId, &data); work->histLastDay = currDay; // Start the timeout to do NOAA updates: radProcessTimerStart(work->noaaTimer, HTML_NOAA_UPDATE_DELAY); // ... update the sun times sunTimesGetSunRiseSet (currYear, currMonth, currDay, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10, RS_TYPE_SUN, &work->mgrId->sunrise, &work->mgrId->sunset); sunTimesGetSunRiseSet (currYear, currMonth, currDay, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10, RS_TYPE_CIVIL, &work->mgrId->civilrise, &work->mgrId->civilset); sunTimesGetSunRiseSet (currYear, currMonth, currDay, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10, RS_TYPE_ASTRO, &work->mgrId->astrorise, &work->mgrId->astroset); sunTimesGetSunRiseSet (currYear, currMonth, currDay, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10, RS_TYPE_MIDDAY, &work->mgrId->midday, &tempShort); work->mgrId->dayLength = sunTimesGetDayLength (currYear, currMonth, currDay, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10); GetMoonRiseSetTimes (currYear, currMonth, currDay, (float)gmtOffsetHours, (float)work->mgrId->stationLatitude/10, (float)work->mgrId->stationLongitude/10, &work->mgrId->moonrise, NULL, &work->mgrId->moonset, NULL); } return; }
// read archive database to initialize our historical arrays: int htmlmgrHistoryInit (HTML_MGR_ID id) { HISTORY_DATA data; int startmin, starthour, startday, startmonth, startyear; time_t ntime, baseTime, tempTime, arcTime; struct tm locTime; int i, j, k, retVal, saveHour; // Compute when last archive record should have been: arcTime = time(NULL); localtime_r(&arcTime, &locTime); locTime.tm_min = ((locTime.tm_min/id->archiveInterval)*id->archiveInterval); locTime.tm_sec = 0; arcTime = mktime(&locTime); // first, figure out our start label indexes and populate the history arrays // for each of day, week, month and year: // do the samples in the last day: id->dayStart = wvutilsGetDayStartTime(id->archiveInterval); // update the sample label array: htmlmgrSetSampleLabels(id); baseTime = arcTime; saveHour = -1; for (i = 0; i < DAILY_NUM_VALUES(id); i ++) { ntime = baseTime; ntime -= (WV_SECONDS_IN_DAY - (i*SECONDS_IN_INTERVAL(id->archiveInterval))); retVal = dbsqliteArchiveGetAverages (id->isMetricUnits, id->archiveInterval, &data, ntime, 1); if (retVal <= 0) { for (j = 0; j < DATA_INDEX_MAX(id->isExtendedData); j ++) { id->dayValues[j][i] = ARCHIVE_VALUE_NULL; } } else { for (j = 0; j < DATA_INDEX_MAX(id->isExtendedData); j ++) { if (data.values[j] <= ARCHIVE_VALUE_NULL || data.samples[j] == 0) { id->dayValues[j][i] = ARCHIVE_VALUE_NULL; } else if (j == DATA_INDEX_rain || j == DATA_INDEX_windDir || j == DATA_INDEX_ET) { id->dayValues[j][i] = data.values[j]; } else { id->dayValues[j][i] = data.values[j]/data.samples[j]; } } } if (((i % 50) == 0) || ((i + 1) == DAILY_NUM_VALUES(id))) { radMsgLog(PRI_STATUS, "htmlHistoryInit: DAY: samples=%d", i); } } // do the hours in the last week: id->weekStartTime_T = wvutilsGetWeekStartTime (id->archiveInterval); ntime = id->weekStartTime_T; for (i = 0; i < WEEKLY_NUM_VALUES; i ++) { retVal = dbsqliteArchiveGetAverages (id->isMetricUnits, id->archiveInterval, &data, ntime, WV_SECONDS_IN_HOUR/SECONDS_IN_INTERVAL(id->archiveInterval)); if (retVal <= 0) { for (j = 0; j < DATA_INDEX_MAX(id->isExtendedData); j ++) { id->weekValues[j][i] = ARCHIVE_VALUE_NULL; } } else { for (j = 0; j < DATA_INDEX_MAX(id->isExtendedData); j ++) { if (data.values[j] <= ARCHIVE_VALUE_NULL || data.samples[j] == 0) { id->weekValues[j][i] = ARCHIVE_VALUE_NULL; } else if (j == DATA_INDEX_rain || j == DATA_INDEX_windDir || j == DATA_INDEX_ET) { id->weekValues[j][i] = data.values[j]; } else { id->weekValues[j][i] = data.values[j]/data.samples[j]; } } } if (((i % 50) == 0) || ((i + 1) == WEEKLY_NUM_VALUES)) { radMsgLog(PRI_STATUS, "htmlHistoryInit: WEEK: samples=%d", i); } ntime += WV_SECONDS_IN_HOUR; } // do the hours in the last month: id->monthStartTime_T = wvutilsGetMonthStartTime (id->archiveInterval); ntime = id->monthStartTime_T; for (i = 0; i < MONTHLY_NUM_VALUES; i ++) { retVal = dbsqliteArchiveGetAverages (id->isMetricUnits, id->archiveInterval, &data, ntime, WV_SECONDS_IN_HOUR/SECONDS_IN_INTERVAL(id->archiveInterval)); if (retVal <= 0) { for (j = 0; j < DATA_INDEX_MAX(id->isExtendedData); j ++) { id->monthValues[j][i] = ARCHIVE_VALUE_NULL; } } else { for (j = 0; j < DATA_INDEX_MAX(id->isExtendedData); j ++) { if (data.values[j] <= ARCHIVE_VALUE_NULL || data.samples[j] == 0) { id->monthValues[j][i] = ARCHIVE_VALUE_NULL; } else if (j == DATA_INDEX_rain || j == DATA_INDEX_windDir || j == DATA_INDEX_ET) { id->monthValues[j][i] = data.values[j]; } else { id->monthValues[j][i] = data.values[j]/data.samples[j]; } } } if (((i % 50) == 0) || ((i + 1) == MONTHLY_NUM_VALUES)) { radMsgLog(PRI_STATUS, "htmlHistoryInit: MONTH: samples=%d", i); } ntime += WV_SECONDS_IN_HOUR; } // do the days in the last year (not including today): dbsqliteHistoryInit(); dbsqliteHistoryPragmaSet("synchronous", "off"); ntime = arcTime; ntime -= WV_SECONDS_IN_YEAR; localtime_r (&ntime, &locTime); locTime.tm_hour = 0; locTime.tm_min = id->archiveInterval; locTime.tm_sec = 0; locTime.tm_isdst = -1; ntime = mktime(&locTime); id->yearStartTime_T = ntime; for (i = 0; i < YEARLY_NUM_VALUES; i ++) { if (dbsqliteHistoryGetDay(ntime, &data) == ERROR) { retVal = dbsqliteArchiveGetAverages(id->isMetricUnits, id->archiveInterval, &data, ntime, WV_SECONDS_IN_DAY/SECONDS_IN_INTERVAL(id->archiveInterval)); if (retVal <= 0) { data.startTime = ntime; for (j = 0; j < DATA_INDEX_MAX(id->isExtendedData); j ++) { data.values[j] = ARCHIVE_VALUE_NULL; } } else { // Add to the database: data.startTime = ntime; radMsgLog(PRI_STATUS, "htmlHistoryInit: storing day history for %s", ctime(&ntime)); dbsqliteHistoryInsertDay(&data); } } for (j = 0; j < DATA_INDEX_MAX(id->isExtendedData); j ++) { if (data.values[j] <= ARCHIVE_VALUE_NULL || data.samples[j] == 0) { id->yearValues[j][i] = ARCHIVE_VALUE_NULL; } else if (j == DATA_INDEX_rain || j == DATA_INDEX_windDir || j == DATA_INDEX_ET) { id->yearValues[j][i] = data.values[j]; } else { id->yearValues[j][i] = data.values[j]/data.samples[j]; } } if (((i % 50) == 0) || ((i + 1) == YEARLY_NUM_VALUES)) { radMsgLog(PRI_STATUS, "htmlHistoryInit: YEAR: samples=%d", i); } ntime += WV_SECONDS_IN_DAY; } dbsqliteHistoryPragmaSet("synchronous", "normal"); return OK; }