mirror of
https://github.com/eddyem/small_tel.git
synced 2026-05-07 13:27:06 +03:00
some fixes; add forced shutdown
This commit is contained in:
@@ -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)"},
|
||||
|
||||
@@ -91,19 +93,20 @@ 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"},
|
||||
{"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_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"},
|
||||
{"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
|
||||
};
|
||||
|
||||
@@ -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(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){
|
||||
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);
|
||||
// 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(){
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
* @brief showdata - send to client sensor's data
|
||||
* @param client - client data
|
||||
* @param N - index of station
|
||||
* @param N - -1 for common data or station index for specific meteo
|
||||
*/
|
||||
static void showdataN(sl_sock_t *client, int N){
|
||||
static void showdata(sl_sock_t *client, int N){
|
||||
char buf[FULL_LEN];
|
||||
val_t v;
|
||||
sensordata_t *s = get_plugin_w_message(client, N);
|
||||
int Ncoll = 0;
|
||||
sensordata_t *s = NULL;
|
||||
if(N < 0){
|
||||
Ncoll = collected_amount();
|
||||
}else{
|
||||
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;
|
||||
Ncoll = s->Nvalues;
|
||||
}
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
time_t oldest = time(NULL) - WeatherConf.ahtung_delay, mstm = 0;
|
||||
|
||||
/**
|
||||
* @brief showdata - send to client common gathered data
|
||||
* @param client - client data
|
||||
*/
|
||||
static void showdata(sl_sock_t *client){
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user