mirror of
https://github.com/eddyem/small_tel.git
synced 2026-05-01 18:37:07 +03:00
tests works, need real meteo modules
This commit is contained in:
@@ -21,7 +21,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <usefull_macros.h>
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
#include "cmdlnopts.h"
|
#include "cmdlnopts.h"
|
||||||
|
#include "mainweather.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* here are global parameters initialisation
|
* here are global parameters initialisation
|
||||||
@@ -38,12 +40,32 @@ static glob_pars defpars = {
|
|||||||
.port = DEFAULT_PORT,
|
.port = DEFAULT_PORT,
|
||||||
.logfile = NULL,
|
.logfile = NULL,
|
||||||
.verb = 0,
|
.verb = 0,
|
||||||
.pidfile = DEFAULT_PID
|
.pidfile = DEFAULT_PID,
|
||||||
};
|
};
|
||||||
// default config: all values should be wrong or empty to understand than user change them
|
// default config: all values should be wrong or empty to understand than user change them
|
||||||
static glob_pars defconf = {
|
static glob_pars defconf = {
|
||||||
.verb = -1,
|
.verb = -1,
|
||||||
};
|
};
|
||||||
|
// only for config
|
||||||
|
weather_conf_t WeatherConf = {
|
||||||
|
.ahtung_delay = 30*60, // 30 minutes
|
||||||
|
.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,
|
||||||
|
.clouds.good = 2500.,
|
||||||
|
.clouds.bad = 2000.,
|
||||||
|
.clouds.terrible = 500.,
|
||||||
|
.clouds.negflag = 1,
|
||||||
|
.sky.good = -40.,
|
||||||
|
.sky.bad = -10.,
|
||||||
|
.sky.terrible = 0.,
|
||||||
|
.sky.negflag = 0
|
||||||
|
};
|
||||||
|
|
||||||
static glob_pars G;
|
static glob_pars G;
|
||||||
|
|
||||||
@@ -62,13 +84,26 @@ static glob_pars G;
|
|||||||
sl_option_t cmdlnopts[] = {
|
sl_option_t cmdlnopts[] = {
|
||||||
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), "show this help"},
|
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), "show this help"},
|
||||||
{"conffile",NEED_ARG, NULL, 'c', arg_string, APTR(&G.conffile), "configuration file name (consists all or a part of long-named parameters and their values (e.g. plugin=liboldweather.so:D:/dev/ttyS0:115200)"},
|
{"conffile",NEED_ARG, NULL, 'c', arg_string, APTR(&G.conffile), "configuration file name (consists all or a part of long-named parameters and their values (e.g. plugin=liboldweather.so:D:/dev/ttyS0:115200)"},
|
||||||
{"verb", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verb), "logfile verbocity level (each -v increased)"}, \
|
{"verb", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verb), "logfile verbocity level (each -v increased)"},
|
||||||
COMMON_OPTS
|
COMMON_OPTS
|
||||||
end_option
|
end_option
|
||||||
};
|
};
|
||||||
|
|
||||||
sl_option_t confopts[] = {
|
sl_option_t confopts[] = {
|
||||||
{"verbose", NEED_ARG, NULL, 'v', arg_int, APTR(&G.verb), "logfile verbocity level"}, \
|
{"verbose", NEED_ARG, NULL, 'v', arg_int, APTR(&G.verb), "logfile verbocity level"},
|
||||||
|
{"ahtung_delay",NEED_ARG,NULL, 0, arg_int, APTR(&WeatherConf.ahtung_delay),"delay in seconds after bad weather to change to good"},
|
||||||
|
{"good_wind",NEED_ARG, NULL, 0, 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"},
|
||||||
COMMON_OPTS
|
COMMON_OPTS
|
||||||
end_option
|
end_option
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -136,8 +136,9 @@ static int opensocket(char *path, sl_socktype_e type){
|
|||||||
* @return opened file descriptor or -1 in case of error
|
* @return opened file descriptor or -1 in case of error
|
||||||
*/
|
*/
|
||||||
int getFD(char *path){
|
int getFD(char *path){
|
||||||
if(!path || !*path) return -1;
|
if(!path || !*path || strlen(path) < 2) return -1;
|
||||||
char type = *path;
|
char type = *path;
|
||||||
|
if(path[1] != ':') return -1; // after protocol letter should be delimeter
|
||||||
path += 2;
|
path += 2;
|
||||||
switch(type){
|
switch(type){
|
||||||
case 'D': // serial device
|
case 'D': // serial device
|
||||||
|
|||||||
@@ -24,40 +24,54 @@
|
|||||||
#include <usefull_macros.h>
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
#include "cmdlnopts.h"
|
#include "cmdlnopts.h"
|
||||||
|
#include "mainweather.h"
|
||||||
#include "sensors.h"
|
#include "sensors.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
static pid_t childpid = 0;
|
static pid_t childpid = 0;
|
||||||
|
static glob_pars *GP = NULL;
|
||||||
|
|
||||||
|
// SIGUSR1 - FORBID observations
|
||||||
|
// SIGUSR2 - allow
|
||||||
void signals(int signo){
|
void signals(int signo){
|
||||||
if(childpid){
|
if(signo){
|
||||||
|
if(signals != signal(signo, SIG_IGN)) exit(signo); // function called "as is", before sig registration
|
||||||
|
if(childpid == 0){ // child -> test USR1/USR2
|
||||||
|
LOGDBG("Child gotta signal %d", signo);
|
||||||
|
if(signo == SIGUSR1){
|
||||||
|
forbid_observations(1);
|
||||||
|
LOGMSG("Got signal `observations forbidden`");
|
||||||
|
signal(signo, signals);
|
||||||
|
return;
|
||||||
|
}else if(signo == SIGUSR2){
|
||||||
|
forbid_observations(0);
|
||||||
|
LOGMSG("Got signal `observations permitted`");
|
||||||
|
signal(signo, signals);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(childpid){ // master
|
||||||
|
LOGERR("Main process exits with status %d", signo);
|
||||||
|
if(GP && GP->pidfile) unlink(GP->pidfile);
|
||||||
|
}else{ // child
|
||||||
LOGERR("Killed with status %d", signo);
|
LOGERR("Killed with status %d", signo);
|
||||||
closeplugins();
|
closeplugins();
|
||||||
kill_servers();
|
kill_servers();
|
||||||
usleep(1000); // let child close everything before dead
|
|
||||||
}else{
|
|
||||||
LOGERR("Main process exits with status %d", signo);
|
|
||||||
}
|
}
|
||||||
|
usleep(1000); // let child close everything before dead
|
||||||
exit(signo);
|
exit(signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void getpipe(int _U_ signo){
|
static void getpipe(int _U_ signo){
|
||||||
WARNX("Get sigpipe!");
|
WARNX("Get sigpipe!");
|
||||||
|
LOGWARN("SIGPIPE: something disconnected?");
|
||||||
// TODO: check all sensors for disconnected one
|
// TODO: check all sensors for disconnected one
|
||||||
signal(SIGPIPE, getpipe);
|
signal(SIGPIPE, getpipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern const char *__progname;
|
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv){
|
||||||
glob_pars *GP = NULL;
|
|
||||||
sl_init();
|
sl_init();
|
||||||
signal(SIGTERM, signals); // kill (-15) - quit
|
|
||||||
signal(SIGHUP, SIG_IGN); // hup - ignore
|
|
||||||
signal(SIGINT, signals); // ctrl+C - quit
|
|
||||||
signal(SIGQUIT, signals); // ctrl+\ - quit
|
|
||||||
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
|
|
||||||
signal(SIGPIPE, getpipe); // socket disconnected
|
|
||||||
GP = parse_args(argc, argv);
|
GP = parse_args(argc, argv);
|
||||||
if(!GP) ERRX("Error parsing args");
|
if(!GP) ERRX("Error parsing args");
|
||||||
if(!GP->sockname) ERRX("Point command socket name");
|
if(!GP->sockname) ERRX("Point command socket name");
|
||||||
@@ -71,14 +85,23 @@ int main(int argc, char **argv){
|
|||||||
if(GP->pollt > 0){
|
if(GP->pollt > 0){
|
||||||
if(!set_pollT((time_t)GP->pollt)) ERRX("Can't set polling time to %d seconds", GP->pollt);
|
if(!set_pollT((time_t)GP->pollt)) ERRX("Can't set polling time to %d seconds", GP->pollt);
|
||||||
}
|
}
|
||||||
|
signal(SIGTERM, signals); // kill (-15) - quit
|
||||||
|
signal(SIGHUP, SIG_IGN); // hup - ignore
|
||||||
|
signal(SIGINT, signals); // ctrl+C - quit
|
||||||
|
signal(SIGQUIT, signals); // ctrl+\ - quit
|
||||||
|
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
|
||||||
|
signal(SIGPIPE, getpipe); // socket disconnected
|
||||||
|
signal(SIGUSR1, SIG_IGN);
|
||||||
|
signal(SIGUSR2, SIG_IGN);
|
||||||
int nopened = openplugins(GP->plugins, GP->nplugins);
|
int nopened = openplugins(GP->plugins, GP->nplugins);
|
||||||
if(nopened < 1){
|
if(nopened < 1){
|
||||||
LOGERR("No plugins found; exit!");
|
LOGERR("No plugins found; exit!");
|
||||||
ERRX("Can't find any sensor plugin");
|
ERRX("Can't find any sensor plugin");
|
||||||
}
|
}
|
||||||
if(GP->nplugins && GP->nplugins != nopened) LOGWARN("Work without some plugins");
|
if(GP->nplugins && GP->nplugins != nopened) LOGWARN("Work without some plugins");
|
||||||
#ifndef EBUG
|
|
||||||
sl_check4running((char*)__progname, GP->pidfile);
|
sl_check4running((char*)__progname, GP->pidfile);
|
||||||
|
#ifndef EBUG
|
||||||
|
sl_daemonize();
|
||||||
while(1){ // guard for dead processes
|
while(1){ // guard for dead processes
|
||||||
childpid = fork();
|
childpid = fork();
|
||||||
if(childpid){
|
if(childpid){
|
||||||
@@ -94,6 +117,9 @@ int main(int argc, char **argv){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// react for USRx only in child
|
||||||
|
signal(SIGUSR1, signals);
|
||||||
|
signal(SIGUSR2, signals);
|
||||||
if(!start_servers(GP->port, GP->sockname)) ERRX("Can't run server's threads");
|
if(!start_servers(GP->port, GP->sockname)) ERRX("Can't run server's threads");
|
||||||
while(1);
|
while(1);
|
||||||
//WARNX("TEST ends");
|
//WARNX("TEST ends");
|
||||||
|
|||||||
263
Daemons/weatherdaemon_multimeteo/mainweather.c
Normal file
263
Daemons/weatherdaemon_multimeteo/mainweather.c
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the weatherdaemon project.
|
||||||
|
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// collect here weather from all weatherstations sorted by importance
|
||||||
|
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "mainweather.h"
|
||||||
|
#include "sensors.h"
|
||||||
|
#include "weathlib.h"
|
||||||
|
|
||||||
|
static pthread_mutex_t datamutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static int Forbidden = 0;
|
||||||
|
|
||||||
|
// index of meteodata in array
|
||||||
|
enum{
|
||||||
|
NWIND,
|
||||||
|
NWINDDIR,
|
||||||
|
NHUMIDITY,
|
||||||
|
NABM_TEMP,
|
||||||
|
NPRESSURE,
|
||||||
|
NPRECIP,
|
||||||
|
NPRECIP_LEVEL,
|
||||||
|
NMIST,
|
||||||
|
NCLOUDS,
|
||||||
|
NSKYTEMP,
|
||||||
|
NCOMMWEATH,
|
||||||
|
NLASTAHTUNG,
|
||||||
|
NAMOUNT_OF_DATA
|
||||||
|
};
|
||||||
|
|
||||||
|
static val_t collected_data[NAMOUNT_OF_DATA] = {
|
||||||
|
[NWIND] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_WIND},
|
||||||
|
[NWINDDIR] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_WINDDIR},
|
||||||
|
[NHUMIDITY] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_HUMIDITY},
|
||||||
|
[NABM_TEMP] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_AMB_TEMP},
|
||||||
|
[NPRESSURE] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_PRESSURE},
|
||||||
|
[NPRECIP] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_PRECIP},
|
||||||
|
[NPRECIP_LEVEL] = {.sense = VAL_OBLIGATORY, .type = VALT_INT, .meaning = IS_PRECIP_LEVEL},
|
||||||
|
[NMIST] = {.sense = VAL_OBLIGATORY, .type = VALT_INT, .meaning = IS_MIST},
|
||||||
|
[NCLOUDS] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_CLOUDS},
|
||||||
|
[NSKYTEMP] = {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_SKYTEMP},
|
||||||
|
[NCOMMWEATH] = {.value.i = 0, .sense = VAL_OBLIGATORY, .type = VALT_INT, .meaning = IS_OTHER, .name = "weather", .comment = "Weather level (0 - good, 3 - obs. prohibited)"},
|
||||||
|
[NLASTAHTUNG] = {.value.i = 0, .sense = VAL_RECOMMENDED, .type = VALT_INT, .meaning = IS_OTHER, .name = "evttime", .comment = "UNIX-time of last weather level increasing"},
|
||||||
|
// {.sense = VAL_OBLIGATORY, .type = VALT_FLOAT, .meaning = IS_OTHER},
|
||||||
|
};
|
||||||
|
|
||||||
|
int collected_amount(){
|
||||||
|
return NAMOUNT_OF_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_collected(val_t *val, int N){
|
||||||
|
if(!val || N < 0 || N >= NAMOUNT_OF_DATA){
|
||||||
|
DBG("Wrong number (%d) requested or no place for data", N);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&datamutex);
|
||||||
|
DBG("Copied data of %d", N);
|
||||||
|
*val = collected_data[N];
|
||||||
|
pthread_mutex_unlock(&datamutex);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fix_new_data(val_t *collected, val_t *fresh){
|
||||||
|
FNAME();
|
||||||
|
if(!collected || !fresh) return;
|
||||||
|
collected->time = fresh->time;
|
||||||
|
if(collected->type == fresh->type){ // good case
|
||||||
|
collected->value = fresh->value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// bad case: have different types
|
||||||
|
switch(collected->type){
|
||||||
|
case VALT_UINT:
|
||||||
|
switch(fresh->type){
|
||||||
|
case VALT_INT:
|
||||||
|
collected->value.u = (uint32_t) collected->value.i;
|
||||||
|
break;
|
||||||
|
case VALT_FLOAT:
|
||||||
|
collected->value.u = (uint32_t) collected->value.f;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VALT_INT:
|
||||||
|
switch(fresh->type){
|
||||||
|
case VALT_UINT:
|
||||||
|
collected->value.i = (int32_t) collected->value.u;
|
||||||
|
break;
|
||||||
|
case VALT_FLOAT:
|
||||||
|
collected->value.i = (int32_t) collected->value.f;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VALT_FLOAT:
|
||||||
|
switch(fresh->type){
|
||||||
|
case VALT_UINT:
|
||||||
|
collected->value.f = (float) collected->value.u;
|
||||||
|
break;
|
||||||
|
case VALT_INT:
|
||||||
|
collected->value.f = (float) collected->value.i;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void chkweatherlevel(int *curlevel, double curvalue, weather_cond_t *curcond, int *ahtungtime){
|
||||||
|
double good = curcond->good, bad = curcond->bad, terrible = curcond->terrible;
|
||||||
|
if(curcond->negflag){ // negate
|
||||||
|
curvalue = -curvalue;
|
||||||
|
good = -good;
|
||||||
|
bad = -bad;
|
||||||
|
terrible = -terrible;
|
||||||
|
}
|
||||||
|
int newlevel = -1;
|
||||||
|
if(curvalue > terrible) newlevel = WEATHER_TERRIBLE;
|
||||||
|
else if(curvalue > bad) newlevel = WEATHER_BAD;
|
||||||
|
else if(curvalue < good) newlevel = WEATHER_GOOD;
|
||||||
|
if(newlevel == -1) return;
|
||||||
|
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{ // check timeout to make level lower
|
||||||
|
if(curt - *ahtungtime > WeatherConf.ahtung_delay){
|
||||||
|
DBG("newlevel: %d, current: %d DECREASED", newlevel, *curlevel);
|
||||||
|
*curlevel = newlevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh_sensval(sensordata_t *s){
|
||||||
|
FNAME();
|
||||||
|
static time_t poll_time = 0;
|
||||||
|
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;
|
||||||
|
time_t curtime = time(NULL);
|
||||||
|
DBG("%d meteo values", s->Nvalues);
|
||||||
|
for(int i = 0; i < s->Nvalues; ++i){
|
||||||
|
DBG("Try to get %dth value", i);
|
||||||
|
if(!s->get_value(s, &value, i)) continue;
|
||||||
|
DBG("got value");
|
||||||
|
int idx = -1;
|
||||||
|
double curvalue;
|
||||||
|
weather_cond_t *curcond = NULL;
|
||||||
|
switch(value.meaning){
|
||||||
|
case IS_WIND:
|
||||||
|
idx = NWIND;
|
||||||
|
curvalue = (double) value.value.f;
|
||||||
|
curcond = &WeatherConf.wind;
|
||||||
|
break;
|
||||||
|
case IS_WINDDIR:
|
||||||
|
idx = NWINDDIR;
|
||||||
|
break;
|
||||||
|
case IS_HUMIDITY:
|
||||||
|
idx = NHUMIDITY;
|
||||||
|
curvalue = (double) value.value.f;
|
||||||
|
curcond = &WeatherConf.humidity;
|
||||||
|
break;
|
||||||
|
case IS_AMB_TEMP:
|
||||||
|
idx = NABM_TEMP;
|
||||||
|
break;
|
||||||
|
case IS_PRESSURE:
|
||||||
|
idx = NPRESSURE;
|
||||||
|
break;
|
||||||
|
case IS_PRECIP:
|
||||||
|
idx = NPRECIP;
|
||||||
|
if(value.value.i && curlevel < WEATHER_TERRIBLE){
|
||||||
|
curlevel = WEATHER_TERRIBLE;
|
||||||
|
curahtungtime = curtime;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IS_PRECIP_LEVEL:
|
||||||
|
idx = NPRECIP_LEVEL;
|
||||||
|
break;
|
||||||
|
case IS_MIST:
|
||||||
|
idx = NMIST;
|
||||||
|
if(value.value.i && curlevel < WEATHER_TERRIBLE){
|
||||||
|
curahtungtime = curtime;
|
||||||
|
curlevel = WEATHER_TERRIBLE;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
default : break;
|
||||||
|
}
|
||||||
|
if(idx < 0 || idx >= NAMOUNT_OF_DATA) continue;
|
||||||
|
DBG("IDX=%d", idx);
|
||||||
|
time_t freshdelay = (s->PluginNo == 0) ? 0 : poll_time; // use data of less imrortant plugins only if our data is too old
|
||||||
|
time_t curmt = collected_data[idx].time + freshdelay;
|
||||||
|
if(value.time < curmt){
|
||||||
|
DBG("Data too old (value: %zd, curr: %zd", value.time, curmt);
|
||||||
|
continue; // old data
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&datamutex);
|
||||||
|
fix_new_data(&collected_data[idx], &value);
|
||||||
|
pthread_mutex_unlock(&datamutex);
|
||||||
|
if(!Forbidden && curcond) chkweatherlevel(&curlevel, curvalue, curcond, &curahtungtime);
|
||||||
|
}
|
||||||
|
DBG("check ahtung");
|
||||||
|
pthread_mutex_lock(&datamutex);
|
||||||
|
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;
|
||||||
|
collected_data[NCOMMWEATH].time = curtime;
|
||||||
|
collected_data[NLASTAHTUNG].time = curtime;
|
||||||
|
pthread_mutex_unlock(&datamutex);
|
||||||
|
DBG("Refreshed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void forbid_observations(int f){
|
||||||
|
if(f) Forbidden = 1;
|
||||||
|
else Forbidden = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// main cycle
|
||||||
|
void run_mainweather(){
|
||||||
|
int N = get_nplugins();
|
||||||
|
if(N < 1) return;
|
||||||
|
poll_time = get_pollT();
|
||||||
|
while(1){
|
||||||
|
int nactive = 0;
|
||||||
|
pthread_mutex_lock(&datamutex);
|
||||||
|
for(int i = N-1; i > -1; --i){ // the most important is the last
|
||||||
|
sensordata_t *s = get_plugin(i);
|
||||||
|
if(!s || !sensor_alive(s)) continue;
|
||||||
|
++nactive;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&datamutex);
|
||||||
|
if(nactive == 0) break; // no active sensors
|
||||||
|
usleep(10000);
|
||||||
|
}
|
||||||
|
LOGERR("Main weather collector died: all sensors lost");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
58
Daemons/weatherdaemon_multimeteo/mainweather.h
Normal file
58
Daemons/weatherdaemon_multimeteo/mainweather.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the weatherdaemon project.
|
||||||
|
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "weathlib.h"
|
||||||
|
|
||||||
|
// weather conditions
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
int negflag; // reversal flag (good if > val, etc)
|
||||||
|
} weather_cond_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int ahtung_delay; // delay to change "bad weather" to good after last "bad event"
|
||||||
|
// wind, m/s
|
||||||
|
weather_cond_t wind;
|
||||||
|
// humidity, %%
|
||||||
|
weather_cond_t humidity;
|
||||||
|
// "clouds", > 2500 - OK -> should be negated when check!!!
|
||||||
|
weather_cond_t clouds;
|
||||||
|
// sky temperature minus ambient temperature, degC
|
||||||
|
weather_cond_t sky;
|
||||||
|
} weather_conf_t;
|
||||||
|
|
||||||
|
// defined in cmdlnopts.c
|
||||||
|
extern weather_conf_t WeatherConf;
|
||||||
|
|
||||||
|
int collected_amount();
|
||||||
|
int get_collected(val_t *val, int N);
|
||||||
|
|
||||||
|
void forbid_observations(int f);
|
||||||
|
void refresh_sensval(sensordata_t *s);
|
||||||
|
//void run_mainweather();
|
||||||
@@ -37,19 +37,23 @@ static void *mainthread(void _U_ *U){
|
|||||||
FNAME();
|
FNAME();
|
||||||
double t0 = sl_dtime();
|
double t0 = sl_dtime();
|
||||||
while(1){
|
while(1){
|
||||||
|
DBG("locked");
|
||||||
|
pthread_mutex_lock(&sensor.valmutex);
|
||||||
float f = sensor.values[0].value.f + (drand48() - 0.5) / 2.;
|
float f = sensor.values[0].value.f + (drand48() - 0.5) / 2.;
|
||||||
if(f >= 0.) sensor.values[0].value.f = f;
|
if(f >= 0.) sensor.values[0].value.f = f;
|
||||||
f = sensor.values[1].value.f + (drand48() - 0.5) * 4.;
|
f = sensor.values[1].value.f + (drand48() - 0.5) * 4.;
|
||||||
if(f > 160. && f < 200.) sensor.values[1].value.f = f;
|
if(f > 160. && f < 200.) sensor.values[1].value.f = f;
|
||||||
f = sensor.values[2].value.f + (drand48() - 0.5) / 20.;
|
f = sensor.values[2].value.f + (drand48() - 0.5) / 2.;
|
||||||
if(f > 13. && f < 21.) sensor.values[2].value.f = f;
|
if(f > 13. && f < 21.) sensor.values[2].value.f = f;
|
||||||
f = sensor.values[3].value.f + (drand48() - 0.5) / 100.;
|
f = sensor.values[3].value.f + (drand48() - 0.5) / 100.;
|
||||||
if(f > 585. && f < 615.) sensor.values[3].value.f = f;
|
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;
|
if(f > 60. && f <= 100.) sensor.values[4].value.f = f;
|
||||||
sensor.values[5].value.u = (f > 98.) ? 1 : 0;
|
sensor.values[5].value.u = (f > 98.) ? 1 : 0;
|
||||||
time_t cur = time(NULL);
|
time_t cur = time(NULL);
|
||||||
for(int i = 0; i < NS; ++i) sensor.values[i].time = cur;
|
for(int i = 0; i < NS; ++i) sensor.values[i].time = cur;
|
||||||
|
pthread_mutex_unlock(&sensor.valmutex);
|
||||||
|
DBG("unlocked");
|
||||||
if(sensor.freshdatahandler) sensor.freshdatahandler(&sensor);
|
if(sensor.freshdatahandler) sensor.freshdatahandler(&sensor);
|
||||||
while(sl_dtime() - t0 < sensor.tpoll) usleep(500);
|
while(sl_dtime() - t0 < sensor.tpoll) usleep(500);
|
||||||
t0 = sl_dtime();
|
t0 = sl_dtime();
|
||||||
@@ -73,23 +77,12 @@ static int init(struct sensordata_t* s, int N, time_t pollt, int _U_ fd){
|
|||||||
return NS;
|
return NS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief getval - value's getter
|
|
||||||
* @param o (o) - value
|
|
||||||
* @param N - it's index
|
|
||||||
* @return FALSE if failed
|
|
||||||
*/
|
|
||||||
static int getval(struct sensordata_t* s, val_t *o, int N){
|
|
||||||
if(N < 0 || N >= NS) return FALSE;
|
|
||||||
if(o) *o = s->values[N];
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
sensordata_t sensor = {
|
sensordata_t sensor = {
|
||||||
.name = "Dummy weatherstation",
|
.name = "Dummy weatherstation",
|
||||||
.Nvalues = NS,
|
.Nvalues = NS,
|
||||||
.init = init,
|
.init = init,
|
||||||
.onrefresh = common_onrefresh,
|
.onrefresh = common_onrefresh,
|
||||||
.get_value = getval,
|
.valmutex = PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
.get_value = common_getval,
|
||||||
.kill = common_kill,
|
.kill = common_kill,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,8 +43,10 @@ static int format_values(char *buf){
|
|||||||
DBG("TOKEN: %s", token);
|
DBG("TOKEN: %s", token);
|
||||||
if(sl_str2d(&v, token)){
|
if(sl_str2d(&v, token)){
|
||||||
DBG("next value: %g", v);
|
DBG("next value: %g", v);
|
||||||
|
pthread_mutex_lock(&sensor.valmutex);
|
||||||
sensor.values[gotvals].value.f = (float) v;
|
sensor.values[gotvals].value.f = (float) v;
|
||||||
sensor.values[gotvals].time = tnow;
|
sensor.values[gotvals].time = tnow;
|
||||||
|
pthread_mutex_unlock(&sensor.valmutex);
|
||||||
++gotvals;
|
++gotvals;
|
||||||
}
|
}
|
||||||
token = strtok(NULL, ",");
|
token = strtok(NULL, ",");
|
||||||
@@ -135,17 +137,12 @@ static int init(struct sensordata_t *s, int N, time_t pollt, int fd){
|
|||||||
return NS;
|
return NS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getval(struct sensordata_t *s, val_t *o, int N){
|
|
||||||
if(!s || N < 0 || N >= NS) return FALSE;
|
|
||||||
if(o) *o = s->values[N];
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
sensordata_t sensor = {
|
sensordata_t sensor = {
|
||||||
.name = "Dummy socket or serial device weatherstation",
|
.name = "Dummy socket or serial device weatherstation",
|
||||||
.Nvalues = NS,
|
.Nvalues = NS,
|
||||||
.init = init,
|
.init = init,
|
||||||
.onrefresh = common_onrefresh,
|
.onrefresh = common_onrefresh,
|
||||||
.get_value = getval,
|
.valmutex = PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
.get_value = common_getval,
|
||||||
.kill = common_kill,
|
.kill = common_kill,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,9 @@
|
|||||||
#include <usefull_macros.h>
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
#include "fd.h"
|
#include "fd.h"
|
||||||
|
#include "mainweather.h"
|
||||||
#include "sensors.h"
|
#include "sensors.h"
|
||||||
|
#include "weathlib.h"
|
||||||
|
|
||||||
#define WARNXL(...) do{ LOGWARN(__VA_ARGS__); WARNX(__VA_ARGS__); } while(0)
|
#define WARNXL(...) do{ LOGWARN(__VA_ARGS__); WARNX(__VA_ARGS__); } while(0)
|
||||||
#define WARNL(...) do{ LOGWARN(__VA_ARGS__); WARN(__VA_ARGS__); } while(0)
|
#define WARNL(...) do{ LOGWARN(__VA_ARGS__); WARN(__VA_ARGS__); } while(0)
|
||||||
@@ -45,6 +47,8 @@ int set_pollT(time_t t){
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t get_pollT(){ return poll_interval;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get_plugin - get link to opened plugin
|
* @brief get_plugin - get link to opened plugin
|
||||||
* @param o (o) - plugin with given index
|
* @param o (o) - plugin with given index
|
||||||
@@ -71,11 +75,17 @@ void *open_plugin(const char *name){
|
|||||||
return dlh;
|
return dlh;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EBUG
|
/**
|
||||||
// in release this function can be used for meteo logging
|
* @brief dumpsensors - this function called each time some `station` got new data
|
||||||
|
*
|
||||||
|
* @param station - pointer to N'th station opened
|
||||||
|
*/
|
||||||
static void dumpsensors(struct sensordata_t* station){
|
static void dumpsensors(struct sensordata_t* station){
|
||||||
FNAME();
|
FNAME();
|
||||||
if(!station || !station->get_value || station->Nvalues < 1) return;
|
if(!station || !station->get_value || station->Nvalues < 1) return;
|
||||||
|
refresh_sensval(station);
|
||||||
|
DBG("New values...");
|
||||||
|
#ifdef EBUG
|
||||||
char buf[FULL_LEN+1];
|
char buf[FULL_LEN+1];
|
||||||
uint64_t Tsum = 0; int nsum = 0;
|
uint64_t Tsum = 0; int nsum = 0;
|
||||||
int N = (nplugins > 1) ? station->PluginNo : -1;
|
int N = (nplugins > 1) ? station->PluginNo : -1;
|
||||||
@@ -91,8 +101,8 @@ static void dumpsensors(struct sensordata_t* station){
|
|||||||
if(0 < format_msrmttm(last, buf, FULL_LEN+1)){
|
if(0 < format_msrmttm(last, buf, FULL_LEN+1)){
|
||||||
printf("%s\n\n", buf);
|
printf("%s\n\n", buf);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief openplugins - open sensors' plugin and init it
|
* @brief openplugins - open sensors' plugin and init it
|
||||||
@@ -130,9 +140,7 @@ int openplugins(char **paths, int N){
|
|||||||
int ns = S->init(S, nplugins, poll_interval, fd); // here nplugins is index in array
|
int ns = S->init(S, nplugins, poll_interval, fd); // here nplugins is index in array
|
||||||
if(ns < 1) WARNXL("Can't init plugin %s", paths[i]);
|
if(ns < 1) WARNXL("Can't init plugin %s", paths[i]);
|
||||||
else{
|
else{
|
||||||
#ifdef EBUG
|
if(!S->onrefresh || !S->onrefresh(S, dumpsensors)) WARNXL("Can't init refresh funtion");
|
||||||
if(!S->onrefresh(S, dumpsensors)) WARNXL("Can't init refresh funtion");
|
|
||||||
#endif
|
|
||||||
LOGMSG("Plugin %s nave %d sensors", paths[i], ns);
|
LOGMSG("Plugin %s nave %d sensors", paths[i], ns);
|
||||||
allplugins[nplugins++] = S;
|
allplugins[nplugins++] = S;
|
||||||
}
|
}
|
||||||
@@ -172,7 +180,7 @@ int format_sensval(const val_t *v, char *buf, int buflen, int Np){
|
|||||||
case VALT_FLOAT: snprintf(strval, VAL_LEN, "%g", v->value.f); break;
|
case VALT_FLOAT: snprintf(strval, VAL_LEN, "%g", v->value.f); break;
|
||||||
default: sprintf(strval, "'ERROR'");
|
default: sprintf(strval, "'ERROR'");
|
||||||
}
|
}
|
||||||
const char* const NM[] = { // names of standard fields
|
const char* const NM[IS_OTHER] = { // names of standard fields
|
||||||
[IS_WIND] = "WIND",
|
[IS_WIND] = "WIND",
|
||||||
[IS_WINDDIR] = "WINDDIR",
|
[IS_WINDDIR] = "WINDDIR",
|
||||||
[IS_HUMIDITY] = "HUMIDITY",
|
[IS_HUMIDITY] = "HUMIDITY",
|
||||||
@@ -186,7 +194,7 @@ int format_sensval(const val_t *v, char *buf, int buflen, int Np){
|
|||||||
[IS_CLOUDS] = "CLOUDS",
|
[IS_CLOUDS] = "CLOUDS",
|
||||||
[IS_SKYTEMP] = "SKYTEMP"
|
[IS_SKYTEMP] = "SKYTEMP"
|
||||||
};
|
};
|
||||||
const char* const CMT[] = { // comments for standard fields
|
const char* const CMT[IS_OTHER] = { // comments for standard fields
|
||||||
[IS_WIND] = "Wind, m/s",
|
[IS_WIND] = "Wind, m/s",
|
||||||
[IS_WINDDIR] = "Wind direction, degr (CW from north to FROM)",
|
[IS_WINDDIR] = "Wind direction, degr (CW from north to FROM)",
|
||||||
[IS_HUMIDITY] = "Humidity, percent",
|
[IS_HUMIDITY] = "Humidity, percent",
|
||||||
|
|||||||
@@ -30,3 +30,4 @@ int get_nplugins();
|
|||||||
int format_sensval(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 set_pollT(time_t t);
|
int set_pollT(time_t t);
|
||||||
|
time_t get_pollT();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <usefull_macros.h>
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "mainweather.h"
|
||||||
#include "sensors.h"
|
#include "sensors.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
@@ -55,12 +56,11 @@ static sl_sock_hresult_e listhandler(sl_sock_t *client, _U_ sl_sock_hitem_t *ite
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief showdata - send to user meteodata
|
* @brief showdataN - send to user meteodata of Nth station
|
||||||
* @param client - client data
|
* @param client - client data
|
||||||
* @param N - index of station
|
* @param N - index of station
|
||||||
* @param showidx - == TRUE to show index in square brackets
|
|
||||||
*/
|
*/
|
||||||
static void showdata(sl_sock_t *client, int N, int showidx){
|
static void showdataN(sl_sock_t *client, int N){
|
||||||
char buf[FULL_LEN+1];
|
char buf[FULL_LEN+1];
|
||||||
val_t v;
|
val_t v;
|
||||||
sensordata_t *s = NULL;
|
sensordata_t *s = NULL;
|
||||||
@@ -69,7 +69,6 @@ static void showdata(sl_sock_t *client, int N, int showidx){
|
|||||||
sl_sock_sendstrmessage(client, buf);
|
sl_sock_sendstrmessage(client, buf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!showidx || get_nplugins() == 1) N = -1; // only one -> don't show indexes
|
|
||||||
time_t oldest = time(NULL) - oldest_interval;
|
time_t oldest = time(NULL) - oldest_interval;
|
||||||
uint64_t Tsum = 0; int nsum = 0;
|
uint64_t Tsum = 0; int nsum = 0;
|
||||||
for(int i = 0; i < s->Nvalues; ++i){
|
for(int i = 0; i < s->Nvalues; ++i){
|
||||||
@@ -81,24 +80,56 @@ static void showdata(sl_sock_t *client, int N, int showidx){
|
|||||||
sl_sock_sendbyte(client, '\n');
|
sl_sock_sendbyte(client, '\n');
|
||||||
++nsum; Tsum += v.time;
|
++nsum; Tsum += v.time;
|
||||||
}
|
}
|
||||||
oldest = (time_t)(Tsum / nsum);
|
if(nsum > 0){
|
||||||
if(0 < format_msrmttm(oldest, buf, FULL_LEN+1)){ // send mean measuring time
|
oldest = (time_t)(Tsum / nsum);
|
||||||
DBG("Formatted time: '%s'", buf);
|
if(0 < format_msrmttm(oldest, buf, FULL_LEN+1)){ // send mean measuring time
|
||||||
sl_sock_sendstrmessage(client, buf);
|
DBG("Formatted time: '%s'", buf);
|
||||||
sl_sock_sendbyte(client, '\n');
|
sl_sock_sendstrmessage(client, buf);
|
||||||
|
sl_sock_sendbyte(client, '\n');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief showdata - send to client common gathered data
|
||||||
|
* @param client - client data
|
||||||
|
*/
|
||||||
|
static void showdata(sl_sock_t *client){
|
||||||
|
char buf[FULL_LEN+1];
|
||||||
|
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)) continue;
|
||||||
|
if(v.time < oldest) continue;
|
||||||
|
if(1 > format_sensval(&v, buf, FULL_LEN+1, -1)) 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+1)){ // send mean measuring time
|
||||||
|
DBG("Formatted time: '%s'", buf);
|
||||||
|
sl_sock_sendstrmessage(client, buf);
|
||||||
|
sl_sock_sendbyte(client, '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// get meteo data
|
// get meteo data
|
||||||
static sl_sock_hresult_e gethandler(sl_sock_t *client, _U_ sl_sock_hitem_t *item, const char *req){
|
static sl_sock_hresult_e gethandler(sl_sock_t *client, _U_ sl_sock_hitem_t *item, const char *req){
|
||||||
if(!client) return RESULT_FAIL;
|
if(!client) return RESULT_FAIL;
|
||||||
int N = get_nplugins();
|
int N = get_nplugins();
|
||||||
if(N < 1) return RESULT_FAIL;
|
if(N < 1) return RESULT_FAIL;
|
||||||
if(!req) for(int i = 0; i < N; ++i) showdata(client, i, TRUE);
|
if(!req) showdata(client);
|
||||||
else{
|
else{
|
||||||
int n;
|
int n;
|
||||||
if(!sl_str2i(&n, req) || n < 0 || n >= N) return RESULT_BADVAL;
|
if(!sl_str2i(&n, req) || n < 0 || n >= N) return RESULT_BADVAL;
|
||||||
showdata(client, n, FALSE);
|
showdataN(client, n);
|
||||||
}
|
}
|
||||||
return RESULT_SILENCE;
|
return RESULT_SILENCE;
|
||||||
}
|
}
|
||||||
@@ -140,17 +171,18 @@ static sl_sock_hresult_e defhandler(struct sl_sock *s, const char *str){
|
|||||||
return RESULT_SILENCE;
|
return RESULT_SILENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define COMMONHANDLERS \
|
||||||
|
{gethandler, "get", "get all meteo or only for given plugin number", NULL}, \
|
||||||
|
{listhandler, "list", "show all opened plugins", NULL}, \
|
||||||
|
{timehandler, "time", "get server's UNIX time", NULL},
|
||||||
|
|
||||||
// handlers for network and local (UNIX) sockets
|
// handlers for network and local (UNIX) sockets
|
||||||
static sl_sock_hitem_t nethandlers[] = { // net - only getters and client-only setters
|
static sl_sock_hitem_t nethandlers[] = { // net - only getters and client-only setters
|
||||||
{gethandler, "get", "get all meteo or only for given plugin number", NULL},
|
COMMONHANDLERS
|
||||||
{listhandler, "list", "show all opened plugins", NULL},
|
|
||||||
{timehandler, "time", "get server's UNIX time", NULL},
|
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
static sl_sock_hitem_t localhandlers[] = { // local - full amount of setters/getters
|
static sl_sock_hitem_t localhandlers[] = { // local - full amount of setters/getters
|
||||||
{gethandler, "get", "get all meteo or only for given plugin number", NULL},
|
COMMONHANDLERS
|
||||||
{listhandler, "list", "show all opened plugins", NULL},
|
|
||||||
{timehandler, "time", "get server's UNIX time", NULL},
|
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -223,7 +255,7 @@ void kill_servers(){
|
|||||||
sl_sock_delete(&netsocket);
|
sl_sock_delete(&netsocket);
|
||||||
LOGMSG("Server sockets destroyed");
|
LOGMSG("Server sockets destroyed");
|
||||||
//usleep(500);
|
//usleep(500);
|
||||||
//pthread_kill(locthread, 9);
|
//pthread_join(locthread, NULL);
|
||||||
//pthread_kill(netthread, 9);
|
//pthread_join(netthread, NULL);
|
||||||
//LOGMSG("Server threads killed");
|
//LOGMSG("Server threads are dead");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ cmdlnopts.h
|
|||||||
fd.c
|
fd.c
|
||||||
fd.h
|
fd.h
|
||||||
main.c
|
main.c
|
||||||
|
mainweather.c
|
||||||
|
mainweather.h
|
||||||
plugins/dummy.c
|
plugins/dummy.c
|
||||||
plugins/fdexample.c
|
plugins/fdexample.c
|
||||||
sensors.c
|
sensors.c
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ int common_onrefresh(sensordata_t *s, void (*handler)(sensordata_t *)){
|
|||||||
void common_kill(sensordata_t *s){
|
void common_kill(sensordata_t *s){
|
||||||
FNAME();
|
FNAME();
|
||||||
if(!s) return;
|
if(!s) return;
|
||||||
if(0 == pthread_kill(s->thread, -9)){
|
if(0 == pthread_cancel(s->thread)){
|
||||||
DBG("%s main thread killed, join", s->name);
|
DBG("%s main thread canceled, join", s->name);
|
||||||
pthread_join(s->thread, NULL);
|
pthread_join(s->thread, NULL);
|
||||||
DBG("Done");
|
DBG("Done");
|
||||||
}
|
}
|
||||||
@@ -64,3 +64,20 @@ void common_kill(sensordata_t *s){
|
|||||||
FREE(s->values);
|
FREE(s->values);
|
||||||
DBG("Sensor %s killed", s->name);
|
DBG("Sensor %s killed", s->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief common_getval - common value getter
|
||||||
|
* @param s (i) - station
|
||||||
|
* @param o (o) - value or NULL (if you just wants test N)
|
||||||
|
* @param N - number of sensor
|
||||||
|
* @return FALSE if failed
|
||||||
|
*/
|
||||||
|
int common_getval(struct sensordata_t *s, val_t *o, int N){
|
||||||
|
if(!s || N < 0 || N >= s->Nvalues) return FALSE;
|
||||||
|
if(o){
|
||||||
|
pthread_mutex_lock(&s->valmutex);
|
||||||
|
*o = s->values[N];
|
||||||
|
pthread_mutex_unlock(&s->valmutex);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ typedef struct sensordata_t{
|
|||||||
// private members:
|
// private members:
|
||||||
val_t *values; // array of values
|
val_t *values; // array of values
|
||||||
pthread_t thread; // main thread
|
pthread_t thread; // main thread
|
||||||
|
pthread_mutex_t valmutex;// value getter/setter mutex
|
||||||
void (*freshdatahandler)(struct sensordata_t*); // handler of fresh data
|
void (*freshdatahandler)(struct sensordata_t*); // handler of fresh data
|
||||||
int fdes; // file descriptor of device/socket
|
int fdes; // file descriptor of device/socket
|
||||||
sl_ringbuffer_t *ringbuffer; // ringbuffer for device reading
|
sl_ringbuffer_t *ringbuffer; // ringbuffer for device reading
|
||||||
@@ -106,3 +107,4 @@ typedef struct sensordata_t{
|
|||||||
int common_onrefresh(sensordata_t*, void (*handler)(sensordata_t*));
|
int common_onrefresh(sensordata_t*, void (*handler)(sensordata_t*));
|
||||||
void common_kill(sensordata_t *s);
|
void common_kill(sensordata_t *s);
|
||||||
int sensor_alive(sensordata_t *s);
|
int sensor_alive(sensordata_t *s);
|
||||||
|
int common_getval(struct sensordata_t *s, val_t *o, int N);
|
||||||
|
|||||||
Reference in New Issue
Block a user