예제 #1
0
// check interval HILOWs against the station-generated archive record
// (the VP is a goofy animal in terms of protocol)
int computedDataCheckHiLows (WVIEWD_WORK *work, ARCHIVE_PKT *newRecord)
{
    WV_SENSOR       *sample = work->sensors.sensor[STF_INTERVAL];
    float           chill, dew, heat;

    if (sensorGetHigh(&sample[SENSOR_OUTTEMP]) < ((float)newRecord->value[DATA_INDEX_outTemp]))
    {
        // update the high value only
        sensorUpdateHighValue (&sample[SENSOR_OUTTEMP], (float)newRecord->value[DATA_INDEX_outTemp]);
    }

    if (sensorGetLow(&sample[SENSOR_OUTTEMP]) > ((float)newRecord->value[DATA_INDEX_outTemp]))
    {
        // update the low value only
        sensorUpdateLowValue (&sample[SENSOR_OUTTEMP], (float)newRecord->value[DATA_INDEX_outTemp]);
    }

    if (sensorGetHigh(&sample[SENSOR_WGUST]) < (float)newRecord->value[DATA_INDEX_windGust])
    {
        // update the high and when high values only
        sensorUpdateWhenHighValue (&sample[SENSOR_WGUST],
                                   (float)newRecord->value[DATA_INDEX_windGust],
                                   (float)newRecord->value[DATA_INDEX_windGustDir]);
    }

    if (sensorGetHigh(&sample[SENSOR_RAINRATE]) < ((float)newRecord->value[DATA_INDEX_rainRate]))
    {
        // update the high value only
        sensorUpdateHighValue (&sample[SENSOR_RAINRATE], (float)newRecord->value[DATA_INDEX_rainRate]);
    }

    if ((newRecord->value[DATA_INDEX_rain] == 0) ||
            (sensorGetCumulative(&sample[SENSOR_RAIN]) < ((float)newRecord->value[DATA_INDEX_rain])))
    {
        // update the cumulative value only
        sensorUpdateCumulative (&sample[SENSOR_RAIN], (float)newRecord->value[DATA_INDEX_rain]);
    }

    if ((newRecord->value[DATA_INDEX_ET] == 0) ||
            (sensorGetCumulative(&sample[SENSOR_ET]) < ((float)newRecord->value[DATA_INDEX_ET])))
    {
        // update the cumulative value only
        sensorUpdateCumulative (&sample[SENSOR_ET], (float)newRecord->value[DATA_INDEX_ET]);
    }

    return OK;
}
예제 #2
0
파일: station.c 프로젝트: breu/wview
int stationSendArchiveNotifications (WVIEWD_WORK *work, float sampleRain)
{
    WVIEW_MSG_ARCHIVE_NOTIFY    notify;
    float                       tempfloat;

    notify.dateTime         = work->archiveDateTime;
    notify.intemp           = (int)floorf(work->loopPkt.inTemp * 10);
    notify.inhumidity       = work->loopPkt.inHumidity;
    notify.temp             = (int)floorf(work->loopPkt.outTemp * 10);
    notify.humidity         = work->loopPkt.outHumidity;
    notify.barom            = (int)floorf(work->loopPkt.barometer * 1000);
    notify.stationPressure  = (int)floorf(work->loopPkt.stationPressure * 1000);
    notify.altimeter        = (int)floorf(work->loopPkt.altimeter * 1000);
    notify.winddir          = work->loopPkt.windDir;
    notify.wspeed           = work->loopPkt.windSpeed;
    notify.dewpoint         = (int)floorf(work->loopPkt.dewpoint * 10);
    notify.hiwspeed         = work->loopPkt.windGust;
    notify.rxPercent        = work->loopPkt.rxCheckPercent;
    notify.sampleRain       = sampleRain;

    tempfloat = sensorGetCumulative (&work->sensors.sensor[STF_HOUR][SENSOR_RAIN]);
    tempfloat *= 100;
    tempfloat += 0.5;
    notify.rainHour    = (int)tempfloat;

    tempfloat = sensorGetCumulative (&work->sensors.sensor[STF_DAY][SENSOR_RAIN]);
    tempfloat *= 100;
    tempfloat += 0.5;
    notify.rainDay     = (int)tempfloat;

    if (radMsgRouterMessageSend (WVIEW_MSG_TYPE_ARCHIVE_NOTIFY, &notify, sizeof(notify))
        == ERROR)
    {
        // can't send!
        radMsgLog (PRI_HIGH, "radMsgRouterMessageSend failed: notify");
        return ERROR;
    }

    return OK;
}
예제 #3
0
파일: daemon.c 프로젝트: breu/wview
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;
}
예제 #4
0
파일: daemon.c 프로젝트: breu/wview
static void daemonStoreArchiveRecord (ARCHIVE_PKT *newRecord)
{
    float           carryOverRain, carryOverET, sampleRain, tempf;
    int             deltaTime, tempInt;
    USHORT          tempRainBits;

    if (newRecord == NULL)
    {
        radMsgLog (PRI_MEDIUM, "daemonStoreArchiveRecord: record is NULL!");
        return;
    }

    deltaTime = newRecord->dateTime - wviewdWork.archiveDateTime;
    if (deltaTime == 0)
    {
        // discard it, same as previous record
        radMsgLog (PRI_MEDIUM,
                   "daemonStoreArchiveRecord: record has same timestamp as previous!");
        return;
    }
    else if (deltaTime < 0)
    {
        // chunk it, it is just wrong
        radMsgLog (PRI_MEDIUM,
                   "StoreArchiveRecord: record has earlier timestamp than previous (DST change?)");
        return;
    }

    wviewdWork.archiveDateTime = newRecord->dateTime;

    wvutilsLogEvent (PRI_STATUS, "storing record for %4.4d-%2.2d-%2.2d %2.2d:%2.2d",
                     wvutilsGetYear(newRecord->dateTime),
                     wvutilsGetMonth(newRecord->dateTime),
                     wvutilsGetDay(newRecord->dateTime),
                     wvutilsGetHour(newRecord->dateTime),
                     wvutilsGetMin(newRecord->dateTime));

    if (dbsqliteArchiveStoreRecord(newRecord) == ERROR)
    {
        radMsgLog (PRI_MEDIUM, "daemonStoreArchiveRecord: dbsqliteArchiveStoreRecord failed!!!");
        emailAlertSend(ALERT_TYPE_FILE_IO);
        return;
    }

    // if we are running normally (out of init), do normal activities:
    if (wviewdWork.runningFlag)
    {
        // Check to see if a DST change has occured:
        // Note: wvutilsDetectDSTChange can only be called once per process per
        //       DST event.
        if (wvutilsDetectDSTChange() != WVUTILS_DST_NO_CHANGE)
        {
            radMsgLog (PRI_STATUS, 
                       "DST change: scheduling station time update (if supported)");

            // Update the time zone info:
            tzset();

            // Adjust station time:
            stationSyncTime(&wviewdWork);
        }

        // save trace accumulator amounts:
        if (newRecord->value[DATA_INDEX_rain] > ARCHIVE_VALUE_NULL)
        {
            sampleRain = (float)newRecord->value[DATA_INDEX_rain];
            carryOverRain = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_INTERVAL][SENSOR_RAIN]);
            carryOverRain -= sampleRain;
            if (carryOverRain < 0)
            {
                carryOverRain = 0;
            }
        }

        if (newRecord->value[DATA_INDEX_ET] > ARCHIVE_VALUE_NULL)
        {
            carryOverET = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_INTERVAL][SENSOR_ET]);
            carryOverET -= (float)newRecord->value[DATA_INDEX_ET];
            if (carryOverET < 0)
            {
                carryOverET = 0;
            }
        }

        // compute HILOW data:
        computedDataUpdate (&wviewdWork, newRecord);

        // clear for the next archive period (saving trace amounts):
        computedDataClearInterval (&wviewdWork, carryOverRain, carryOverET);

        // compute storm rain:
        if (newRecord->value[DATA_INDEX_rain] > ARCHIVE_VALUE_NULL &&
            newRecord->value[DATA_INDEX_rainRate] > ARCHIVE_VALUE_NULL)
        {
            stormRainUpdate ((float)newRecord->value[DATA_INDEX_rainRate],
                             (float)newRecord->value[DATA_INDEX_rain]);
        }

        // sync to sensors:
        wviewdWork.loopPkt.stormRain  = stormRainGet();
        wviewdWork.loopPkt.stormStart = stormRainGetStartTimeT();
        wviewdWork.loopPkt.dayRain    = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_DAY][SENSOR_RAIN]);
        wviewdWork.loopPkt.monthRain  = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_MONTH][SENSOR_RAIN]);
        wviewdWork.loopPkt.yearRain   = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_YEAR][SENSOR_RAIN]);
        wviewdWork.loopPkt.dayET      = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_DAY][SENSOR_ET]);
        wviewdWork.loopPkt.monthET    = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_MONTH][SENSOR_ET]);
        wviewdWork.loopPkt.yearET     = sensorGetCumulative(&wviewdWork.sensors.sensor[STF_YEAR][SENSOR_ET]);

        // send archive notification:
        stationSendArchiveNotifications (&wviewdWork, sampleRain);
    }

    statusIncrementStat(WVIEW_STATS_ARCHIVE_PKTS_RX);
    return;
}
예제 #5
0
파일: sensor.c 프로젝트: HEnquist/wview
// get a daily cumulative value based on the RTF_INTERVAL and RTF_DAY time frames - 
float sensorGetDailyCumulative (WV_SENSOR set[STF_MAX][SENSOR_MAX], SENSOR_TYPES type)
{
    return (sensorGetCumulative(&set[STF_INTERVAL][type]) + sensorGetCumulative(&set[STF_DAY][type]));
}
예제 #6
0
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;
}