diff --git a/Daemons/weatherdaemon_multimeteo/cmdlnopts.c b/Daemons/weatherdaemon_multimeteo/cmdlnopts.c index e0fc71a..e24d036 100644 --- a/Daemons/weatherdaemon_multimeteo/cmdlnopts.c +++ b/Daemons/weatherdaemon_multimeteo/cmdlnopts.c @@ -52,19 +52,21 @@ weather_conf_t WeatherConf = { .wind.good = 5., // < 5m/s - good weather .wind.bad = 10., // > 10m/s - bad weather .wind.terrible = 15., // > 15m/s - terrible weather - .wind.negflag = 0, .humidity.good = 65., - .humidity.bad = 80., - .humidity.terrible = 90., - .humidity.negflag = 0, + .humidity.bad = 87., + .humidity.terrible = 94., .clouds.good = 2500., .clouds.bad = 2000., .clouds.terrible = 500., - .clouds.negflag = 1, + .clouds.negflag = 1, // the higher values is the better .sky.good = -40., .sky.bad = -10., .sky.terrible = 0., - .sky.negflag = 0 + .ligtdist.good = 60., // no lightnings near + .ligtdist.bad = 10., // 10km + .ligtdist.terrible = 5., // <=5km - ahtung! + .ligtdist.negflag = 1, // the nearest is the worse + .ligtdist.shtdnflag = 1, // force shutdown if too close }; static glob_pars G; @@ -77,7 +79,7 @@ static glob_pars G; {"port", NEED_ARG, NULL, 0, arg_string, APTR(&G.port), "network port to connect (default: " DEFAULT_PORT "); hint: use \"localhost:port\" to make local net socket"}, \ {"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), "save logs to file (default: none)"}, \ {"pidfile", NEED_ARG, NULL, 'P', arg_string, APTR(&G.pidfile), "pidfile name (default: " DEFAULT_PID ")"}, \ - {"sockpath",NEED_ARG, NULL, 0, arg_string, APTR(&G.sockname), "UNIX socket path (starting from '\\0' for anonimous) of command socket"}, \ + {"sockpath",NEED_ARG, NULL, 0, arg_string, APTR(&G.sockname), "UNIX socket path (starting from '@' for anonimous) of command socket"}, \ {"plugin", MULT_PAR, NULL, 'p', arg_string, APTR(&G.plugins), "add this weather plugin (may be a lot of); FORMAT: \"dlpath:l:dev\", where `dlpath` - path of plugin library; `l` - 'D' for device, 'U' for UNIX-socket or 'N' for INET socket; dev - path to device and speed (like /dev/ttyS0:9600), UNIX socket name or host:port for INET"}, \ {"pollt", NEED_ARG, NULL, 'T', arg_int, APTR(&G.pollt), "set maximal polling interval (seconds, integer)"}, @@ -90,20 +92,21 @@ sl_option_t cmdlnopts[] = { }; sl_option_t confopts[] = { - {"verbose", NEED_ARG, NULL, 'a', arg_int, APTR(&G.verb), "logfile verbocity level"}, - {"ahtung_delay",NEED_ARG,NULL, 'b', arg_int, APTR(&WeatherConf.ahtung_delay),"delay in seconds after bad weather to change to good"}, - {"good_wind",NEED_ARG, NULL, 'c', arg_double, APTR(&WeatherConf.wind.good), "good wind while less this"}, - {"bad_wind", NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.wind.bad), "bad wind if more than this"}, - {"terrible_wind",NEED_ARG, NULL,0, arg_double, APTR(&WeatherConf.wind.terrible), "terrible wind if more than this"}, - {"good_humidity",NEED_ARG, NULL,0, arg_double, APTR(&WeatherConf.humidity.good), "humidity is good until this"}, - {"bad_humidity",NEED_ARG, NULL,0, arg_double, APTR(&WeatherConf.humidity.bad), "humidity is bad if greater"}, - {"terrible_humidity",NEED_ARG,NULL, 0, arg_double, APTR(&WeatherConf.humidity.terrible), "humidity is terrible if greater"}, - {"good_clouds",NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.clouds.good), "good weather when \"clouds value\" greater than this"}, - {"bad_clouds",NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.clouds.bad), "if less than this, clouds are bad"}, - {"terrible_clouds",NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.clouds.terrible), "if less, clouds are terrible"}, - {"good_sky",NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.sky.good), "sky-ambient less than this is good"}, - {"bad_sky",NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.sky.bad), "sky-ambient greater than this is bad"}, - {"terrible_sky",NEED_ARG,NULL, 0, arg_double, APTR(&WeatherConf.sky.terrible), "sky-ambient greater than this is terrible"}, + {"verbose", NEED_ARG, NULL, 'a', arg_int, APTR(&G.verb), "logfile verbocity level"}, + {"ahtung_delay",NEED_ARG, NULL, 'b', arg_int, APTR(&WeatherConf.ahtung_delay), "delay in seconds after bad weather to change to good"}, + {"good_wind", NEED_ARG, NULL, 'c', arg_double, APTR(&WeatherConf.wind.good), "good wind while less this"}, + {"bad_wind", NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.wind.bad), "bad wind if more than this"}, + {"terrible_wind",NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.wind.terrible), "terrible wind if more than this"}, + {"good_humidity",NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.humidity.good), "humidity is good until this"}, + {"bad_humidity",NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.humidity.bad), "humidity is bad if greater"}, + {"terrible_humidity",NEED_ARG,NULL, 0, arg_double, APTR(&WeatherConf.humidity.terrible), "humidity is terrible if greater"}, + {"good_clouds", NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.clouds.good), "good weather when \"clouds value\" less than this"}, + {"bad_clouds", NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.clouds.bad), "if greater than this, clouds are bad"}, + {"terrible_clouds",NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.clouds.terrible), "if greater, clouds are terrible"}, + {"clouds_negflag",NEED_ARG, NULL, 0, arg_int, APTR(&WeatherConf.clouds.negflag), "==1 to invert sign (lesser value is worst)"}, + {"good_sky", NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.sky.good), "sky-ambient less than this is good"}, + {"bad_sky", NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.sky.bad), "sky-ambient greater than this is bad"}, + {"terrible_sky",NEED_ARG, NULL, 0, arg_double, APTR(&WeatherConf.sky.terrible), "sky-ambient greater than this is terrible"}, COMMON_OPTS end_option }; diff --git a/Daemons/weatherdaemon_multimeteo/mainweather.c b/Daemons/weatherdaemon_multimeteo/mainweather.c index 8b45ee4..40894f4 100644 --- a/Daemons/weatherdaemon_multimeteo/mainweather.c +++ b/Daemons/weatherdaemon_multimeteo/mainweather.c @@ -52,6 +52,11 @@ enum{ NSKYTEMP, NCOMMWEATH, NLASTAHTUNG, + NAHTUNGRSN, + NLIGHTDIST, + NBADWEATH, + NTERRWEATH, + NFORCEDSHTDN, NAMOUNT_OF_DATA }; @@ -73,8 +78,14 @@ static val_t collected_data[NAMOUNT_OF_DATA] = { [NCLOUDS] = {.sense = VAL_BROKEN, .type = VALT_FLOAT, .meaning = IS_CLOUDS}, [NSKYTEMP] = {.sense = VAL_BROKEN, .type = VALT_FLOAT, .meaning = IS_SKYTEMP}, // these are calculated values - [NCOMMWEATH] = {.value.i = 0, .sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_OTHER, .name = "WEATHER", .comment = "Weather level (0 - good, 3 - obs. prohibited)"}, - [NLASTAHTUNG] = {.value.i = 0, .sense = VAL_RECOMMENDED, .type = VALT_UINT, .meaning = IS_OTHER, .name = "EVTTIME", .comment = "UNIX-time of last weather level increasing"}, + [NCOMMWEATH] = {.sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_OTHER, .name = "WEATHER", .comment = "Weather (0..3: good/bad/terrible/prohibited)"}, + [NLASTAHTUNG] = {.sense = VAL_RECOMMENDED, .type = VALT_UINT, .meaning = IS_OTHER, .name = "EVTTIME", .comment = "UNIX-time of last weather level changing"}, + [NAHTUNGRSN] = {.sense = VAL_RECOMMENDED, .type = VALT_STRING, .meaning = IS_OTHER, .name = "EVTRSN", .comment = "Last weather level increasing reason"}, + [NLIGHTDIST] = {.sense = VAL_FORCEDSHTDN, .type = VALT_FLOAT, .meaning = IS_LIGTDIST}, + // virtual values for weather level / flags changing + [NBADWEATH] = {.sense = VAL_BROKEN, .type = VALT_UINT, .meaning = IS_BADWEATH, .name = "BADWEATH", .comment = "Flag changing weather level to 'BAD'"}, + [NTERRWEATH] = {.sense = VAL_BROKEN, .type = VALT_UINT, .meaning = IS_TERRIBLEWEATH, .name = "TERWEATH", .comment = "Flag changing weather level to 'TERRIBLE'"}, + [NFORCEDSHTDN] = {.sense = VAL_FORCEDSHTDN, .type = VALT_UINT, .meaning = IS_FORCEDSHTDN, .name = "FORCEOFF", .comment = "Station should be powered off NOW"}, // {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_OTHER}, }; @@ -178,7 +189,7 @@ int get_collected(val_t *val, int N){ return FALSE; } pthread_mutex_lock(&datamutex); - DBG("Copied data of %d", N); + //DBG("Copied data of %d", N); *val = collected_data[N]; pthread_mutex_unlock(&datamutex); return TRUE; @@ -189,17 +200,18 @@ static void fix_new_data(val_t *collected, val_t *fresh){ if(!collected || !fresh) return; if(collected->time > fresh->time) return; // lower `collected` level if data is too old - if(fresh->time - collected->time > 60) collected->sense = VAL_UNNECESSARY; + if(fresh->time - collected->time > WeatherConf.ahtung_delay) collected->sense = VAL_UNNECESSARY; if(collected->sense < fresh->sense) return; - if(collected->sense != fresh->sense) collected->sense = fresh->sense; // take new lower level + if(collected->sense != fresh->sense) collected->sense = fresh->sense; // take new level //DBG("Refresh collected value"); collected->time = fresh->time; if(collected->type == fresh->type){ // good case + memcpy(&collected->value, &fresh->value, sizeof(num_t)); //DBG("Types are the same"); - collected->value = fresh->value; return; } // bad case: have different types + // DON'T convert between string and number types! switch(collected->type){ case VALT_UINT: switch(fresh->type){ @@ -237,43 +249,68 @@ static void fix_new_data(val_t *collected, val_t *fresh){ default: break; } break; + default: break; } } -static void chkweatherlevel(int *curlevel, double curvalue, weather_cond_t *curcond, int *ahtungtime){ - double good = curcond->good, bad = curcond->bad, terrible = curcond->terrible; +// increase weather level if need, also check force shutdown flags +// @return 0 if level wasn't changed, or +1 if was increased +static int chkweatherlevel(int *curlevel, double curvalue, weather_cond_t const *curcond){ + double good = curcond->good, bad = curcond->bad, terrible = curcond->terrible, prohibited = curcond->prohibited; + int haveproh = (prohibited > terrible) ? 1 : 0; // value have `prohibited` field if(curcond->negflag){ // negate curvalue = -curvalue; good = -good; bad = -bad; terrible = -terrible; + prohibited = -prohibited; } int newlevel = -1; - if(curvalue > terrible) newlevel = WEATHER_TERRIBLE; - else if(curvalue > bad) newlevel = WEATHER_BAD; + if(haveproh && curvalue > prohibited){ + newlevel = WEATHER_PROHIBITED; + DBG("---> new level is PROHIBITED, val=%g", curvalue); + }else if(curvalue > terrible){ + newlevel = WEATHER_TERRIBLE; + DBG("---> new level is TERRIBLE, val=%g", curvalue); + }else if(curvalue > bad) newlevel = WEATHER_BAD; else if(curvalue < good) newlevel = WEATHER_GOOD; - if(newlevel == -1) return; + if(newlevel == -1) return 0; time_t curt = time(NULL); - if(newlevel > *curlevel){ - DBG("newlevel: %d, current: %d INCREASED", newlevel, *curlevel); - *curlevel = newlevel; - if(*ahtungtime < curt) *ahtungtime = (int) curt; // refresh event time - }else if(newlevel < *curlevel){ // check timeout to make level lower - if(curt - *ahtungtime > WeatherConf.ahtung_delay){ - DBG("newlevel: %d, current: %d DECREASED", newlevel, *curlevel); - *curlevel = newlevel; - } + if(curcond->shtdnflag && newlevel >= WEATHER_TERRIBLE){ + DBG("Forced shutdown flag is set, curvalue: %g", curvalue); + // set to one collected data flag and its time + val_t *f = &collected_data[NFORCEDSHTDN]; + f->value.i = 1; + f->time = (int) curt; + // and set current weather level to prohibited + *curlevel = WEATHER_PROHIBITED; } + if(newlevel > *curlevel){ + // TODO: add logging + DBG("local level increased to %d", newlevel); + *curlevel = newlevel; + return 1; + } + return 0; } +// conditions for "bad weather" flag (if it ==1 set BAD WEATH) +static weather_cond_t const badweathflag = {.good = 0.1, .bad = 0.5, .terrible = 2.}; +// conditions for "terrible weather" flag +static weather_cond_t const terrweathflag = {.good = 0.1, .bad = 0.5, .terrible = 0.7}; +// conditions for "prohibited weather" flag +static weather_cond_t const prohibweathflag = {.good = 0.1, .bad = 0.5, .terrible = 0.6, .prohibited = 0.7}; +// conditions for "force shutdown" flag +static weather_cond_t const shtdnflag = {.good = 0.1, .bad = 0.5, .terrible = 0.7, .shtdnflag = 1, .prohibited = 0.8}; + void refresh_sensval(sensordata_t *s){ //FNAME(); - static time_t poll_time = 0; + //static time_t poll_time = 0; + char reason[KEY_LEN+1] = {0}; // reason of weather level increasing val_t value; if(!s || !s->get_value) return; - if(poll_time == 0) poll_time = get_pollT(); - int curlevel = collected_data[NCOMMWEATH].value.i; - int curahtungtime = collected_data[NLASTAHTUNG].value.i; + //if(poll_time == 0) poll_time = get_pollT(); + int curlevel = 0; // this is worse weather leavel, start from best time_t curtime = time(NULL); double dir = -100., dir2 = -100.; // mean wind directions //DBG("%d meteo values", s->Nvalues); @@ -283,11 +320,16 @@ void refresh_sensval(sensordata_t *s){ //DBG("got value"); int idx = -1; double curvalue; - weather_cond_t *curcond = NULL; + switch(value.type){ + case VALT_UINT: curvalue = (double) value.value.u; break; + case VALT_INT: curvalue = (double) value.value.i; break; + case VALT_FLOAT: curvalue = (double) value.value.f; break; + default: curvalue = 0.; + } + const weather_cond_t *curcond = NULL; switch(value.meaning){ case IS_WIND: idx = NWIND; - curvalue = (double) value.value.f; curcond = &WeatherConf.wind; add_windspeed(&windspeeds, curvalue, curtime); break; @@ -297,7 +339,6 @@ void refresh_sensval(sensordata_t *s){ break; case IS_HUMIDITY: idx = NHUMIDITY; - curvalue = (double) value.value.f; curcond = &WeatherConf.humidity; break; case IS_AMB_TEMP: @@ -308,39 +349,52 @@ void refresh_sensval(sensordata_t *s){ break; case IS_PRECIP: idx = NPRECIP; - if(value.value.i && curlevel < WEATHER_TERRIBLE){ - curlevel = WEATHER_TERRIBLE; - curahtungtime = curtime; - } + curcond = &prohibweathflag; + if(curvalue > 0.) DBG("IS_PRECIP == 1 !!!"); break; case IS_PRECIP_LEVEL: idx = NPRECIP_LEVEL; + curcond = &terrweathflag; break; case IS_MIST: idx = NMIST; - if(value.value.i && curlevel < WEATHER_TERRIBLE){ - curahtungtime = curtime; - curlevel = WEATHER_TERRIBLE; - } + curcond = &terrweathflag; break; case IS_CLOUDS: idx = NCLOUDS; - curvalue = (double) value.value.f; curcond = &WeatherConf.clouds; break; case IS_SKYTEMP: idx = NSKYTEMP; - curvalue = (double) value.value.f; curcond = &WeatherConf.sky; break; + case IS_LIGTDIST: + idx = NLIGHTDIST; + curcond = &WeatherConf.ligtdist; + break; + case IS_BADWEATH: + idx = NBADWEATH; + curcond = &badweathflag; + break; + case IS_TERRIBLEWEATH: + idx = NTERRWEATH; + curcond = &terrweathflag; + break; + case IS_FORCEDSHTDN: + idx = NFORCEDSHTDN; + curcond = &shtdnflag; + break; default : break; } if(idx < 0 || idx >= NAMOUNT_OF_DATA) continue; //DBG("IDX=%d", idx); pthread_mutex_lock(&datamutex); fix_new_data(&collected_data[idx], &value); + if(curcond){ + if(1 == chkweatherlevel(&curlevel, curvalue, curcond)) + get_fieldname(&value, reason); // copy to `reason` reason of last level increasing + } pthread_mutex_unlock(&datamutex); - if(!Forbidden && curcond) chkweatherlevel(&curlevel, curvalue, curcond, &curahtungtime); } pthread_mutex_lock(&datamutex); // refresh max @@ -358,19 +412,52 @@ void refresh_sensval(sensordata_t *s){ collected_data[NWINDMAX1].time = curtime; //DBG("check ahtung"); if(Forbidden) collected_data[NCOMMWEATH].value.i = WEATHER_PROHIBITED; - else collected_data[NCOMMWEATH].value.i = curlevel; - if(collected_data[NLASTAHTUNG].value.i < curahtungtime) collected_data[NLASTAHTUNG].value.i = curahtungtime; + else{ + if(collected_data[NCOMMWEATH].value.i > curlevel){ // check timeout to make level lower + // DBG("curtime: %zd, curahtt: %d, diff: %zd, delay: %d", curtime, collected_data[NLASTAHTUNG].value.i, curtime - collected_data[NLASTAHTUNG].value.i, WeatherConf.ahtung_delay); + if(curtime - collected_data[NLASTAHTUNG].value.i > WeatherConf.ahtung_delay){ + DBG("newlevel: %d, current: %d DECREASED", curlevel, collected_data[NCOMMWEATH].value.i); + collected_data[NCOMMWEATH].value.i = curlevel; + collected_data[NLASTAHTUNG].value.i = curtime; + if(1 < snprintf(collected_data[NAHTUNGRSN].value.str, KEY_LEN+1, "%s", reason)) + collected_data[NAHTUNGRSN].time = curtime; + } + }else{ + if(collected_data[NCOMMWEATH].value.i < curlevel){ // set to worse + DBG("newlevel: %d, current: %d INCREASED", curlevel, collected_data[NCOMMWEATH].value.i); + collected_data[NCOMMWEATH].value.i = curlevel; + if(1 < snprintf(collected_data[NAHTUNGRSN].value.str, KEY_LEN+1, "%s", reason)) + collected_data[NAHTUNGRSN].time = curtime; + } + if(curlevel){ + collected_data[NLASTAHTUNG].value.i = curtime; // refresh last ahtung time only for level > good + collected_data[NAHTUNGRSN].time = curtime; + } + } + } collected_data[NCOMMWEATH].time = curtime; collected_data[NLASTAHTUNG].time = curtime; pthread_mutex_unlock(&datamutex); //DBG("Refreshed"); } +// set/clear `forbid` flag void forbid_observations(int f){ if(f) Forbidden = 1; else Forbidden = 0; + int curt = (int) time(NULL); + pthread_mutex_lock(&datamutex); + collected_data[NLASTAHTUNG].value.i = curt; + collected_data[NLASTAHTUNG].time = curt; + sprintf(collected_data[NAHTUNGRSN].value.str, "FORBID"); + collected_data[NAHTUNGRSN].time = curt; + pthread_mutex_unlock(&datamutex); + DBG("Change FORBID status to %d", f); } +// `forbid` flag getter +int is_forbidden(){ return Forbidden; } + #if 0 // main cycle void run_mainweather(){ diff --git a/Daemons/weatherdaemon_multimeteo/mainweather.h b/Daemons/weatherdaemon_multimeteo/mainweather.h index 0743e96..ac01c10 100644 --- a/Daemons/weatherdaemon_multimeteo/mainweather.h +++ b/Daemons/weatherdaemon_multimeteo/mainweather.h @@ -25,14 +25,16 @@ enum{ WEATHER_GOOD, // good to start observations WEATHER_BAD, // bad for start, but can run WEATHER_TERRIBLE, // need close the dome - WEATHER_PROHIBITED, // need close all, park and power off <-- by SIGUSR1/SIGUSR2 + WEATHER_PROHIBITED, // need close all, park and power off equipment <-- by SIGUSR1/SIGUSR2 + by FORCEOFF }; typedef struct{ double good; // if value less than this, weather is good double bad; // if value greater than this, weather is bad double terrible; // if value greater than this, weather is terrible + double prohibited; // ... int negflag; // reversal flag (good if > val, etc) + int shtdnflag; // ==1 to shut down if `terrible` } weather_cond_t; typedef struct{ @@ -45,6 +47,8 @@ typedef struct{ weather_cond_t clouds; // sky temperature minus ambient temperature, degC weather_cond_t sky; + // distance to lightning + weather_cond_t ligtdist; } weather_conf_t; // defined in cmdlnopts.c @@ -54,5 +58,6 @@ int collected_amount(); int get_collected(val_t *val, int N); void forbid_observations(int f); +int is_forbidden(); void refresh_sensval(sensordata_t *s); //void run_mainweather(); diff --git a/Daemons/weatherdaemon_multimeteo/plugins/dummy.c b/Daemons/weatherdaemon_multimeteo/plugins/dummy.c index eece63c..c9c1d35 100644 --- a/Daemons/weatherdaemon_multimeteo/plugins/dummy.c +++ b/Daemons/weatherdaemon_multimeteo/plugins/dummy.c @@ -22,7 +22,7 @@ #define SENSOR_NAME "Dummy weatherstation" -#define NS (6) +#define NS (7) static const val_t values[NS] = { // fields `name` and `comment` have no sense until value meaning is `IS_OTHER` {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_WIND}, @@ -31,6 +31,7 @@ static const val_t values[NS] = { // fields `name` and `comment` have no sense u {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_PRESSURE}, {.sense = VAL_RECOMMENDED, .type = VALT_FLOAT, .meaning = IS_HUMIDITY}, {.sense = VAL_OBLIGATORY, .type = VALT_UINT, .meaning = IS_PRECIP}, + {.sense = VAL_FORCEDSHTDN, .type = VALT_FLOAT, .meaning = IS_LIGTDIST}, }; static void *mainthread(void *s){ @@ -38,7 +39,7 @@ static void *mainthread(void *s){ double t0 = sl_dtime(); sensordata_t *sensor = (sensordata_t *)s; while(1){ - DBG("locked"); + //DBG("locked"); pthread_mutex_lock(&sensor->valmutex); float f = sensor->values[0].value.f + (drand48() - 0.5) / 2.; if(f >= 0.) sensor->values[0].value.f = f; @@ -48,13 +49,19 @@ static void *mainthread(void *s){ if(f > 13. && f < 21.) sensor->values[2].value.f = f; f = sensor->values[3].value.f + (drand48() - 0.5) / 100.; if(f > 585. && f < 615.) sensor->values[3].value.f = f; - f = sensor->values[4].value.f + (drand48() - 0.5)*10.; + f = sensor->values[4].value.f + (drand48() - 0.5) * 10.; if(f > 60. && f <= 100.) sensor->values[4].value.f = f; sensor->values[5].value.u = (f > 98.) ? 1 : 0; + //if(!sensor->values[5].value.u && drand48() > 0.7) sensor->values[5].value.u = 1; time_t cur = time(NULL); - for(int i = 0; i < NS; ++i) sensor->values[i].time = cur; + for(int i = 0; i < NS-1; ++i) sensor->values[i].time = cur; + f = sensor->values[6].value.f - (drand48() - 0.2) * 100.; + if(f > 0. && f < 60000){ + sensor->values[6].value.f = f; + sensor->values[6].time = cur; + } pthread_mutex_unlock(&sensor->valmutex); - DBG("unlocked"); + //DBG("unlocked"); if(sensor->freshdatahandler) sensor->freshdatahandler(sensor); while(sl_dtime() - t0 < sensor->tpoll) usleep(500); t0 = sl_dtime(); @@ -75,8 +82,9 @@ sensordata_t *sensor_new(int N, time_t pollt, int _U_ fd){ s->values[1].value.f = 180.; s->values[2].value.f = 17.; s->values[3].value.f = 600.; - s->values[4].value.f = 80.; + s->values[4].value.f = 89.; s->values[5].value.u = 0; + s->values[6].value.f = 54000.; s->PluginNo = N; if(pthread_create(&s->thread, NULL, mainthread, (void*)s)){ s->kill(s); diff --git a/Daemons/weatherdaemon_multimeteo/sensors.c b/Daemons/weatherdaemon_multimeteo/sensors.c index 724fd27..afc99fc 100644 --- a/Daemons/weatherdaemon_multimeteo/sensors.c +++ b/Daemons/weatherdaemon_multimeteo/sensors.c @@ -178,7 +178,8 @@ static const char* const NM[IS_OTHER] = { // names of standard fields [IS_PRECIP_LEVEL]="PRECIPLV", [IS_MIST] = "MIST", [IS_CLOUDS] = "CLOUDS", - [IS_SKYTEMP] = "SKYTEMP" + [IS_SKYTEMP] = "SKYTEMP", + [IS_LIGTDIST] = "LIGTDIST", }; // format "sense" of sensor, like "[WIND][1]=2" @@ -192,6 +193,19 @@ int format_senssense(const val_t *v, char *buf, int buflen, int Np){ return (got < buflen) ? got : buflen; // full or truncated } +void get_fieldname(const val_t *v, char buf[KEY_LEN+1]){ + if(!v || !buf) return; + int idx = v->meaning; + const char *name = NULL; + if(idx < IS_OTHER){ + name = NM[idx]; + }else{ + name = v->name; + } + if(name) snprintf(buf, KEY_LEN+1, "%s", name); + else buf[0] = 0; // empty +} + /** * @brief format_sensval - snprintf sensor's value into buffer * @param v - value to get @@ -202,16 +216,18 @@ int format_senssense(const val_t *v, char *buf, int buflen, int Np){ */ int format_sensval(const val_t *v, char *buf, int buflen, int Np){ if(!v || !buf || buflen < 1) return -1; - char strval[VAL_LEN+1]; + char strval[VAL_LEN]; + int fieldlen = 20; // minimal distance between '=' and '/' is 22 bytes switch(v->type){ case VALT_UINT: snprintf(strval, VAL_LEN, "%u", v->value.u); break; case VALT_INT: snprintf(strval, VAL_LEN, "%d", v->value.i); break; case VALT_FLOAT: snprintf(strval, VAL_LEN, "%.2f", v->value.f); break; + case VALT_STRING: sprintf(strval, "'%s'", v->value.str); fieldlen = -20; break; default: sprintf(strval, "'ERROR'"); } const char* const CMT[IS_OTHER] = { // comments for standard fields [IS_WIND] = "Wind, m/s", - [IS_WINDDIR] = "Instant wind direction, degr (CW from north to FROM)", + [IS_WINDDIR] = "Wind direction, degr (CW from north to FROM)", [IS_HUMIDITY] = "Humidity, percent", [IS_AMB_TEMP] = "Ambient temperature, degC", [IS_INNER_TEMP] = "In-dome temperature, degC", @@ -221,7 +237,8 @@ int format_sensval(const val_t *v, char *buf, int buflen, int Np){ [IS_PRECIP_LEVEL]="Cumulative precipitation level (mm)", [IS_MIST] = "Mist (1 - yes, 0 - no)", [IS_CLOUDS] = "Integral sky quality value (bigger - better)", - [IS_SKYTEMP] = "Mean sky temperatyre" + [IS_SKYTEMP] = "Mean sky temperatyre", + [IS_LIGTDIST] = "Distance to last lightning, km", }; const char *name = NULL, *comment = NULL; int idx = v->meaning; @@ -232,19 +249,23 @@ int format_sensval(const val_t *v, char *buf, int buflen, int Np){ name = v->name; comment = v->comment; } + if(!name) return 0; // no name pointed - don't show this value + if(!comment) comment = "-"; int got; - if(Np > -1) got = snprintf(buf, buflen, "%s[%d]=%s / %s", name, Np, strval, comment); - else got = snprintf(buf, buflen, "%s=%s / %s", name, strval, comment); + if(Np > -1) got = snprintf(buf, buflen, "%s[%d] = %s / %s", name, Np, strval, comment); + else got = snprintf(buf, buflen, "%-*s= %*s / %s", KEY_LEN, name, fieldlen, strval, comment); return (got < buflen) ? got : buflen; // full or truncated } // the same for measurement time formatting -int format_msrmttm(time_t t, char *buf, int buflen){ +int format_msrmttm(time_t t, char *buf, int buflen, int Np){ if(!buf || buflen < 1) return -1; char cmt[COMMENT_LEN+1]; struct tm *T = localtime(&t); strftime(cmt, COMMENT_LEN, "%F %T", T); - int got = snprintf(buf, buflen, "TMEAS=%zd / Last measurement time: %s", t, cmt); + int got; + if(Np > -1) got = snprintf(buf, buflen, "TWEATH[%d] = %zd / Last weather time: %s", Np, t, cmt); + else got = snprintf(buf, buflen, "TWEATH = %20zd / Last weather time: %s", t, cmt); return (got < buflen) ? got : buflen; } diff --git a/Daemons/weatherdaemon_multimeteo/sensors.h b/Daemons/weatherdaemon_multimeteo/sensors.h index 802faa3..71c5e4e 100644 --- a/Daemons/weatherdaemon_multimeteo/sensors.h +++ b/Daemons/weatherdaemon_multimeteo/sensors.h @@ -30,7 +30,8 @@ int get_nplugins(); int find_val_by_name(sensordata_t *s, const char *name); int format_senssense(const val_t *v, char *buf, int buflen, int Np); int format_sensval(const val_t *v, char *buf, int buflen, int Np); -int format_msrmttm(time_t t, char *buf, int buflen); +int format_msrmttm(time_t t, char *buf, int buflen, int Np); int change_val_sense(sensordata_t *s, int idx, valsense_t sense); int set_pollT(time_t t); +void get_fieldname(const val_t *v, char buf[KEY_LEN+1]); time_t get_pollT(); diff --git a/Daemons/weatherdaemon_multimeteo/server.c b/Daemons/weatherdaemon_multimeteo/server.c index 6bd6e59..1b1c606 100644 --- a/Daemons/weatherdaemon_multimeteo/server.c +++ b/Daemons/weatherdaemon_multimeteo/server.c @@ -26,9 +26,6 @@ #include "sensors.h" #include "server.h" -// if measurement time oldest than now minus `oldest_interval`, we think measurement are too old -static time_t oldest_interval = 60; - // server's sockets: net and local (UNIX) static sl_sock_t *netsocket = NULL, *localsocket; //static pthread_t netthread, locthread; @@ -70,60 +67,42 @@ sensordata_t *get_plugin_w_message(sl_sock_t *client, int N){ } /** - * @brief showdataN - send to user meteodata of Nth station - * @param client - client data - * @param N - index of station - */ -static void showdataN(sl_sock_t *client, int N){ - char buf[FULL_LEN]; - val_t v; - sensordata_t *s = get_plugin_w_message(client, N); - if(!s) return; - time_t oldest = time(NULL) - oldest_interval; - uint64_t Tsum = 0; int nsum = 0; - for(int i = 0; i < s->Nvalues; ++i){ - if(!s->get_value(s, &v, i)) continue; - if(v.time < oldest) continue; - if(1 > format_sensval(&v, buf, FULL_LEN, N)) continue; - DBG("formatted: '%s'", buf); - sl_sock_sendstrmessage(client, buf); - sl_sock_sendbyte(client, '\n'); - ++nsum; Tsum += v.time; - } - if(nsum > 0){ - oldest = (time_t)(Tsum / nsum); - if(0 < format_msrmttm(oldest, buf, FULL_LEN)){ // send mean measuring time - DBG("Formatted time: '%s'", buf); - sl_sock_sendstrmessage(client, buf); - sl_sock_sendbyte(client, '\n'); - } - } -} - -/** - * @brief showdata - send to client common gathered data + * @brief showdata - send to client sensor's data * @param client - client data + * @param N - -1 for common data or station index for specific meteo */ -static void showdata(sl_sock_t *client){ +static void showdata(sl_sock_t *client, int N){ char buf[FULL_LEN]; val_t v; - int Ncoll = collected_amount(); - time_t oldest = time(NULL) - oldest_interval; - uint64_t Tsum = 0; int nsum = 0; + int Ncoll = 0; + sensordata_t *s = NULL; + if(N < 0){ + Ncoll = collected_amount(); + }else{ + s = get_plugin_w_message(client, N); + if(!s) return; + Ncoll = s->Nvalues; + } + time_t oldest = time(NULL) - WeatherConf.ahtung_delay, mstm = 0; + for(int i = 0; i < Ncoll; ++i){ - if(!get_collected(&v, i)){ DBG("Can't get %dth value", i); continue; } - if(v.time < oldest){ DBG("%dth value is too old", i); continue; } - if(1 > format_sensval(&v, buf, FULL_LEN, -1)){ DBG("Can't format"); continue; } - DBG("formatted: '%s'", buf); + int ans = 0; + if(N < 0) ans = get_collected(&v, i); + else ans = s->get_value(s, &v, i); + if(!ans){ DBG("Can't get %dth value", i); continue; } + // hide old and broken sensors data + if(v.time < oldest || v.sense > VAL_UNNECESSARY){ /*DBG("%dth value is too old", i);*/ continue; } + if(1 > format_sensval(&v, buf, FULL_LEN, N)){ DBG("Can't format %d", i); continue; } + //DBG("formatted: '%s'", buf); sl_sock_sendstrmessage(client, buf); sl_sock_sendbyte(client, '\n'); - ++nsum; Tsum += v.time; + if(v.time > mstm) mstm = v.time; } - DBG("nsum=%d", nsum); - if(nsum > 0){ - oldest = (time_t)(Tsum / nsum); - if(0 < format_msrmttm(oldest, buf, FULL_LEN)){ // send mean measuring time - DBG("Formatted time: '%s'", buf); + // also send FORCE flag if have + if(N < 0 && is_forbidden()) sl_sock_sendstrmessage(client, "FORBID = 1 / Observations are forbidden by operator\n"); + if(mstm){ + if(0 < format_msrmttm(mstm, buf, FULL_LEN, N)){ // send mean measuring time + //DBG("Formatted time: '%s'", buf); sl_sock_sendstrmessage(client, buf); sl_sock_sendbyte(client, '\n'); } @@ -136,11 +115,11 @@ static sl_sock_hresult_e gethandler(sl_sock_t *client, _U_ sl_sock_hitem_t *item if(!client) return RESULT_FAIL; int N = get_nplugins(); if(N < 1) return RESULT_FAIL; - if(!req) showdata(client); + if(!req) showdata(client, -1); else{ int n; if(!sl_str2i(&n, req) || n < 0 || n >= N) return RESULT_BADVAL; - showdataN(client, n); + showdata(client, n); } return RESULT_SILENCE; } diff --git a/Daemons/weatherdaemon_multimeteo/weathlib.h b/Daemons/weatherdaemon_multimeteo/weathlib.h index ddf2c4d..c0fc369 100644 --- a/Daemons/weatherdaemon_multimeteo/weathlib.h +++ b/Daemons/weatherdaemon_multimeteo/weathlib.h @@ -36,6 +36,7 @@ // importance of values typedef enum{ + VAL_FORCEDSHTDN, // if this value is `terrible`, `forced sthudtown` flag will be set VAL_OBLIGATORY, // can't be omitted VAL_RECOMMENDED, // recommended to show VAL_UNNECESSARY, // may be shown by user request @@ -57,13 +58,19 @@ typedef enum{ IS_MIST, // mist (1 - yes, 0 - no) IS_CLOUDS, // integral clouds value (bigger - better) IS_SKYTEMP, // mean sky temperatyre - IS_OTHER // something other - read "name" and "comment" + IS_LIGTDIST, // distance to lightning + IS_OTHER, // something other - read "name" and "comment" + // values after `IS_OTHER` have no pre-defined names and comments!!! + IS_BADWEATH, // if meet this flag, set weather level to "BAD" + IS_TERRIBLEWEATH, // -//- "TERRIBLE" + IS_FORCEDSHTDN, // like "on battery" flag from UPS } valmeaning_t; typedef union{ uint32_t u; int32_t i; float f; + char str[KEY_LEN+1];// up to 8 symbols (with terminating zero) } num_t; // type of value @@ -71,7 +78,7 @@ typedef enum{ VALT_UINT, VALT_INT, VALT_FLOAT, - //VALT_STRING, + VALT_STRING, } valtype_t; // value