ARCHIVE_PKT *computedDataGenerateArchive (WVIEWD_WORK *work) { WV_SENSOR *sample = work->sensors.sensor[STF_INTERVAL]; time_t nowtime = time (NULL); int tempInt; float tempfloat, tempfloat1; struct tm bknTime; Data_Indices index; // create the time_t time for the record: localtime_r (&nowtime, &bknTime); bknTime.tm_sec = 0; ArcRecStore.dateTime = (int32_t)mktime(&bknTime); ArcRecStore.usUnits = 1; ArcRecStore.interval = work->archiveInterval; // Set all values to NULL by default: for (index = DATA_INDEX_barometer; index < DATA_INDEX_MAX; index ++) { ArcRecStore.value[index] = ARCHIVE_VALUE_NULL; } // have we received any LOOP updates this interval? if (sensorGetSamples(&sample[SENSOR_OUTTEMP]) == 0) { // we have not - squawk about it and exit radMsgLog (PRI_MEDIUM, "computedDataGenerateArchive: no samples for this interval!"); return NULL; } // Set the values we can: ArcRecStore.value[DATA_INDEX_outTemp] = (float)sensorGetAvg (&sample[SENSOR_OUTTEMP]); ArcRecStore.value[DATA_INDEX_rain] = (float)sensorGetCumulative (&sample[SENSOR_RAIN]); ArcRecStore.value[DATA_INDEX_rainRate] = (float)sensorGetHigh (&sample[SENSOR_RAINRATE]); ArcRecStore.value[DATA_INDEX_barometer] = (float)sensorGetAvg (&sample[SENSOR_BP]); ArcRecStore.value[DATA_INDEX_pressure] = wvutilsConvertSLPToSP((float)ArcRecStore.value[DATA_INDEX_barometer], (float)ArcRecStore.value[DATA_INDEX_outTemp], (float)work->elevation); ArcRecStore.value[DATA_INDEX_altimeter] = wvutilsConvertSPToAltimeter((float)ArcRecStore.value[DATA_INDEX_pressure], (float)work->elevation); ArcRecStore.value[DATA_INDEX_inTemp] = (float)sensorGetAvg (&sample[SENSOR_INTEMP]); ArcRecStore.value[DATA_INDEX_inHumidity] = (float)sensorGetAvg (&sample[SENSOR_INHUMID]); ArcRecStore.value[DATA_INDEX_outHumidity] = (float)sensorGetAvg (&sample[SENSOR_OUTHUMID]); ArcRecStore.value[DATA_INDEX_windSpeed] = (float)sensorGetAvg (&sample[SENSOR_WSPEED]); if (sensorGetHigh (&sample[SENSOR_WGUST]) >= 0) { ArcRecStore.value[DATA_INDEX_windGust] = (float)sensorGetHigh (&sample[SENSOR_WGUST]); } else { ArcRecStore.value[DATA_INDEX_windGust] = 0; } // save the high wind speed in the loop packet work->loopPkt.windGust = (uint16_t)ArcRecStore.value[DATA_INDEX_windGust]; ArcRecStore.value[DATA_INDEX_dewpoint] = wvutilsCalculateDewpoint ((float)ArcRecStore.value[DATA_INDEX_outTemp], (float)ArcRecStore.value[DATA_INDEX_outHumidity]); ArcRecStore.value[DATA_INDEX_windchill] = wvutilsCalculateWindChill ((float)ArcRecStore.value[DATA_INDEX_outTemp], (float)ArcRecStore.value[DATA_INDEX_windSpeed]); ArcRecStore.value[DATA_INDEX_heatindex] = wvutilsCalculateHeatIndex ((float)ArcRecStore.value[DATA_INDEX_outTemp], (float)ArcRecStore.value[DATA_INDEX_outHumidity]); if (ArcRecStore.value[DATA_INDEX_windSpeed] > 0 || ArcRecStore.value[DATA_INDEX_windGust] > 0) { ArcRecStore.value[DATA_INDEX_windDir] = (float)windAverageCompute(&work->sensors.wind[STF_INTERVAL]); ArcRecStore.value[DATA_INDEX_windGustDir] = (float)sensorGetWhenHigh(&sample[SENSOR_WGUST]); } // These are conditional based on loop data being populated: if (work->loopPkt.radiation != 0xFFFF) ArcRecStore.value[DATA_INDEX_radiation] = (float)sensorGetAvg (&sample[SENSOR_SOLRAD]); if (work->loopPkt.UV != 0xFFFF) ArcRecStore.value[DATA_INDEX_UV] = (float)sensorGetAvg (&sample[SENSOR_UV]); if (work->loopPkt.sampleET != ARCHIVE_VALUE_NULL) ArcRecStore.value[DATA_INDEX_ET] = (float)sensorGetCumulative (&sample[SENSOR_ET]); if (work->loopPkt.wxt510Hail != ARCHIVE_VALUE_NULL) ArcRecStore.value[DATA_INDEX_hail] = (float)sensorGetCumulative (&sample[SENSOR_HAIL]); if (work->loopPkt.wxt510Hailrate != ARCHIVE_VALUE_NULL) ArcRecStore.value[DATA_INDEX_hailrate] = (float)sensorGetHigh (&sample[SENSOR_HAILRATE]); // Get a few directly from the last LOOP_PKT: if (work->loopPkt.rxCheckPercent != 0xFFFF) ArcRecStore.value[DATA_INDEX_rxCheckPercent] = (float)work->loopPkt.rxCheckPercent; if (work->loopPkt.wxt510HeatingTemp != ARCHIVE_VALUE_NULL) ArcRecStore.value[DATA_INDEX_heatingTemp] = (float)work->loopPkt.wxt510HeatingTemp; if (work->loopPkt.wxt510HeatingVoltage != ARCHIVE_VALUE_NULL) ArcRecStore.value[DATA_INDEX_heatingVoltage] = (float)work->loopPkt.wxt510HeatingVoltage; if (work->loopPkt.wxt510SupplyVoltage != ARCHIVE_VALUE_NULL) ArcRecStore.value[DATA_INDEX_supplyVoltage] = (float)work->loopPkt.wxt510SupplyVoltage; if (work->loopPkt.wxt510ReferenceVoltage != ARCHIVE_VALUE_NULL) ArcRecStore.value[DATA_INDEX_referenceVoltage] = (float)work->loopPkt.wxt510ReferenceVoltage; if (work->loopPkt.wmr918WindBatteryStatus != 0xFF) ArcRecStore.value[DATA_INDEX_windBatteryStatus] = (float)work->loopPkt.wmr918WindBatteryStatus; if (work->loopPkt.wmr918RainBatteryStatus != 0xFF) ArcRecStore.value[DATA_INDEX_rainBatteryStatus] = (float)work->loopPkt.wmr918RainBatteryStatus; if (work->loopPkt.wmr918OutTempBatteryStatus != 0xFF) ArcRecStore.value[DATA_INDEX_outTempBatteryStatus] = (float)work->loopPkt.wmr918OutTempBatteryStatus; if (work->loopPkt.wmr918InTempBatteryStatus != 0xFF) ArcRecStore.value[DATA_INDEX_inTempBatteryStatus] = (float)work->loopPkt.wmr918InTempBatteryStatus; return &ArcRecStore; }
static int daemonStationLoopComplete (void) { float tempf, sampleRain, sampleET; if (!wviewdWork.runningFlag) { return OK; } // Adjust for calibrations: // DO NOT calibrate pressure here: wviewdWork.loopPkt.inTemp *= wviewdWork.calMInTemp; wviewdWork.loopPkt.inTemp += wviewdWork.calCInTemp; wviewdWork.loopPkt.outTemp *= wviewdWork.calMOutTemp; wviewdWork.loopPkt.outTemp += wviewdWork.calCOutTemp; wviewdWork.loopPkt.inHumidity *= wviewdWork.calMInHumidity; wviewdWork.loopPkt.inHumidity += wviewdWork.calCInHumidity; wviewdWork.loopPkt.outHumidity *= wviewdWork.calMOutHumidity; wviewdWork.loopPkt.outHumidity += wviewdWork.calCOutHumidity; wviewdWork.loopPkt.windSpeed *= wviewdWork.calMWindSpeed; wviewdWork.loopPkt.windSpeed += wviewdWork.calCWindSpeed; wviewdWork.loopPkt.windDir *= wviewdWork.calMWindDir; wviewdWork.loopPkt.windDir += wviewdWork.calCWindDir; wviewdWork.loopPkt.windDir %= 360; wviewdWork.loopPkt.sampleRain *= wviewdWork.calMRain; wviewdWork.loopPkt.sampleRain += wviewdWork.calCRain; wviewdWork.loopPkt.rainRate *= wviewdWork.calMRainRate; wviewdWork.loopPkt.rainRate += wviewdWork.calCRainRate; // now calculate a few after all calibrations: wviewdWork.loopPkt.dewpoint = wvutilsCalculateDewpoint(wviewdWork.loopPkt.outTemp, (float)wviewdWork.loopPkt.outHumidity); wviewdWork.loopPkt.windchill = wvutilsCalculateWindChill(wviewdWork.loopPkt.outTemp, (float)wviewdWork.loopPkt.windSpeed); wviewdWork.loopPkt.heatindex = wvutilsCalculateHeatIndex(wviewdWork.loopPkt.outTemp, (float)wviewdWork.loopPkt.outHumidity); // store the results: computedDataStoreSample (&wviewdWork); // lose any trace amounts to avoid rounding up by sprintf: sampleRain = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_INTERVAL][SENSOR_RAIN]); sampleRain *= 100; sampleRain = floorf (sampleRain); sampleRain /= 100; sampleET = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_INTERVAL][SENSOR_ET]); sampleET *= 1000; sampleET = floorf (sampleET); sampleET /= 1000; // do some post-processing on the LOOP data: tempf = stormRainGet(); if (tempf > 0) tempf += sampleRain; wviewdWork.loopPkt.stormRain = tempf; wviewdWork.loopPkt.stormStart = stormRainGetStartTimeT(); tempf = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_DAY][SENSOR_RAIN]); tempf += sampleRain; wviewdWork.loopPkt.dayRain = tempf; tempf = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_MONTH][SENSOR_RAIN]); tempf += sampleRain; wviewdWork.loopPkt.monthRain = tempf; tempf = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_YEAR][SENSOR_RAIN]); tempf += sampleRain; wviewdWork.loopPkt.yearRain = tempf; if (sampleET > ARCHIVE_VALUE_NULL) { tempf = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_DAY][SENSOR_ET]); tempf += sampleET; wviewdWork.loopPkt.dayET = tempf; tempf = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_MONTH][SENSOR_ET]); tempf += sampleET; wviewdWork.loopPkt.monthET = tempf; tempf = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_YEAR][SENSOR_ET]); tempf += sampleET; wviewdWork.loopPkt.yearET = tempf; } wviewdWork.loopPkt.yearRainMonth = wviewdWork.stationRainSeasonStart; statusIncrementStat(WVIEW_STATS_LOOP_PKTS_RX); return OK; }
// compute HILOW value deltas static int computeDataChanges (WVIEWD_WORK *work) { time_t retVal; time_t timenow, timeweekago, timedayago, timehourago; LOOP_PKT *current = &work->loopPkt; float temp; SENSOR_STORE *store = &work->sensors; ARCHIVE_PKT arcRecord; int sqlInterval = work->archiveInterval * 60; // get our three times of interest: timenow = time(NULL); timeweekago = timenow - (WV_SECONDS_IN_DAY * 7); timedayago = timenow - WV_SECONDS_IN_DAY; timehourago = timenow - WV_SECONDS_IN_HOUR; // initialize the store store->hourchangetemp = 0; store->hourchangewind = 0; store->hourchangewinddir = 0; store->hourchangehumid = 0; store->hourchangedewpt = 0; store->hourchangebarom = 0; store->daychangetemp = 0; store->daychangewind = 0; store->daychangewinddir = 0; store->daychangehumid = 0; store->daychangedewpt = 0; store->daychangebarom = 0; store->weekchangetemp = 0; store->weekchangewind = 0; store->weekchangewinddir = 0; store->weekchangehumid = 0; store->weekchangedewpt = 0; store->weekchangebarom = 0; // now on to the record examination... retVal = dbsqliteArchiveGetFirstRecord(timeweekago-sqlInterval, timeweekago+sqlInterval, &arcRecord); if (retVal != ERROR) { // Week Ago: if (current->outTemp > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_outTemp] > ARCHIVE_VALUE_NULL) store->weekchangetemp = current->outTemp - (float)arcRecord.value[DATA_INDEX_outTemp]; else store->weekchangetemp = 0; if (arcRecord.value[DATA_INDEX_windSpeed] > ARCHIVE_VALUE_NULL) store->weekchangewind = current->windSpeed - (float)arcRecord.value[DATA_INDEX_windSpeed]; else store->weekchangewind = 0; if (arcRecord.value[DATA_INDEX_windDir] >= 0) store->weekchangewinddir = (int16_t)((float)current->windDir - (float)arcRecord.value[DATA_INDEX_windDir]); else store->weekchangewinddir = 0; if (arcRecord.value[DATA_INDEX_outHumidity] > ARCHIVE_VALUE_NULL) store->weekchangehumid = current->outHumidity - (uint16_t)arcRecord.value[DATA_INDEX_outHumidity]; else store->weekchangehumid = 0; if (current->dewpoint > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_outTemp] > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_outHumidity] > ARCHIVE_VALUE_NULL) { temp = wvutilsCalculateDewpoint ((float)arcRecord.value[DATA_INDEX_outTemp], (float)arcRecord.value[DATA_INDEX_outHumidity]); store->weekchangedewpt = current->dewpoint - temp; } else { store->weekchangedewpt = 0; } if (current->barometer > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_barometer] > ARCHIVE_VALUE_NULL) store->weekchangebarom = current->barometer - (float)arcRecord.value[DATA_INDEX_barometer]; else store->weekchangebarom = 0; } retVal = dbsqliteArchiveGetFirstRecord(timedayago-sqlInterval, timedayago+sqlInterval, &arcRecord); if (retVal != ERROR) { // Day Ago: if (current->outTemp > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_outTemp] > ARCHIVE_VALUE_NULL) store->daychangetemp = current->outTemp - (float)arcRecord.value[DATA_INDEX_outTemp]; else store->daychangetemp = 0; if (arcRecord.value[DATA_INDEX_windSpeed] > ARCHIVE_VALUE_NULL) store->daychangewind = current->windSpeed - (float)arcRecord.value[DATA_INDEX_windSpeed]; else store->daychangewind = 0; if (arcRecord.value[DATA_INDEX_windDir] >= 0) store->daychangewinddir = (int16_t)((float)current->windDir - (float)arcRecord.value[DATA_INDEX_windDir]); else store->daychangewinddir = 0; if (arcRecord.value[DATA_INDEX_outHumidity] > ARCHIVE_VALUE_NULL) store->daychangehumid = current->outHumidity - (uint16_t)arcRecord.value[DATA_INDEX_outHumidity]; else store->daychangehumid = 0; if (current->dewpoint > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_outTemp] > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_outHumidity] > ARCHIVE_VALUE_NULL) { temp = wvutilsCalculateDewpoint ((float)arcRecord.value[DATA_INDEX_outTemp], (float)arcRecord.value[DATA_INDEX_outHumidity]); store->daychangedewpt = current->dewpoint - temp; } else { store->daychangedewpt = 0; } if (current->barometer > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_barometer] > ARCHIVE_VALUE_NULL) store->daychangebarom = current->barometer - (float)arcRecord.value[DATA_INDEX_barometer]; else store->daychangebarom = 0; } retVal = dbsqliteArchiveGetFirstRecord(timehourago-sqlInterval, timehourago+sqlInterval, &arcRecord); if (retVal != ERROR) { // Hour Ago: if (current->outTemp > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_outTemp] > ARCHIVE_VALUE_NULL) store->hourchangetemp = current->outTemp - (float)arcRecord.value[DATA_INDEX_outTemp]; else store->hourchangetemp = 0; if (arcRecord.value[DATA_INDEX_windSpeed] > ARCHIVE_VALUE_NULL) store->hourchangewind = current->windSpeed - (float)arcRecord.value[DATA_INDEX_windSpeed]; else store->hourchangewind = 0; if (arcRecord.value[DATA_INDEX_windDir] >= 0) store->hourchangewinddir = (int16_t)((float)current->windDir - (float)arcRecord.value[DATA_INDEX_windDir]); else store->hourchangewinddir = 0; if (arcRecord.value[DATA_INDEX_outHumidity] > ARCHIVE_VALUE_NULL) store->hourchangehumid = current->outHumidity - (uint16_t)arcRecord.value[DATA_INDEX_outHumidity]; else store->hourchangehumid = 0; if (current->dewpoint > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_outTemp] > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_outHumidity] > ARCHIVE_VALUE_NULL) { temp = wvutilsCalculateDewpoint ((float)arcRecord.value[DATA_INDEX_outTemp], (float)arcRecord.value[DATA_INDEX_outHumidity]); store->hourchangedewpt = current->dewpoint - temp; } else { store->hourchangedewpt = 0; } if (current->barometer > ARCHIVE_VALUE_NULL && arcRecord.value[DATA_INDEX_barometer] > ARCHIVE_VALUE_NULL) store->hourchangebarom = current->barometer - (float)arcRecord.value[DATA_INDEX_barometer]; else store->hourchangebarom = 0; } return OK; }