mirror of
https://github.com/eddyem/small_tel.git
synced 2026-01-31 20:35:09 +03:00
add weather database creator
This commit is contained in:
parent
c70ce5216a
commit
90f712f525
59
Daemons/weather_database/Makefile
Normal file
59
Daemons/weather_database/Makefile
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# run `make DEF=...` to add extra defines
|
||||||
|
PROGRAM := weathlogdaemon
|
||||||
|
LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
|
||||||
|
LDFLAGS += -lusefull_macros -lsqlite3
|
||||||
|
SRCS := $(wildcard *.c)
|
||||||
|
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
|
||||||
|
OBJDIR := mk
|
||||||
|
CFLAGS += -O2 -Wall -Wextra -Wno-trampolines
|
||||||
|
OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o))
|
||||||
|
DEPS := $(OBJS:.o=.d)
|
||||||
|
TARGFILE := $(OBJDIR)/TARGET
|
||||||
|
CC = gcc
|
||||||
|
#TARGET := RELEASE
|
||||||
|
|
||||||
|
ifeq ($(shell test -e $(TARGFILE) && echo -n yes),yes)
|
||||||
|
TARGET := $(file < $(TARGFILE))
|
||||||
|
else
|
||||||
|
TARGET := RELEASE
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET), DEBUG)
|
||||||
|
.DEFAULT_GOAL := debug
|
||||||
|
endif
|
||||||
|
|
||||||
|
release: CFLAGS += -flto
|
||||||
|
release: LDFLAGS += -flto
|
||||||
|
release: $(PROGRAM)
|
||||||
|
|
||||||
|
debug: CFLAGS += -DEBUG -Werror
|
||||||
|
debug: TARGET := DEBUG
|
||||||
|
debug: $(PROGRAM)
|
||||||
|
|
||||||
|
$(TARGFILE): $(OBJDIR)
|
||||||
|
@echo -e "\t\tTARGET: $(TARGET)"
|
||||||
|
@echo "$(TARGET)" > $(TARGFILE)
|
||||||
|
|
||||||
|
$(PROGRAM) : $(TARGFILE) $(OBJS)
|
||||||
|
@echo -e "\t\tLD $(PROGRAM)"
|
||||||
|
$(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM)
|
||||||
|
|
||||||
|
$(OBJDIR):
|
||||||
|
@mkdir $(OBJDIR)
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
-include $(DEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o: %.c
|
||||||
|
@echo -e "\t\tCC $<"
|
||||||
|
$(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo -e "\t\tCLEAN"
|
||||||
|
@rm -rf $(OBJDIR) 2>/dev/null || true
|
||||||
|
|
||||||
|
xclean: clean
|
||||||
|
@rm -f $(PROGRAM)
|
||||||
|
|
||||||
|
.PHONY: clean xclean
|
||||||
11
Daemons/weather_database/Readme
Normal file
11
Daemons/weather_database/Readme
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Collect weather data from new meteostation in sqlite3 database.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
-P, --pidfile=arg pidfile (default: /tmp/wdb
|
||||||
|
-a, --address=arg server name or IP
|
||||||
|
-d, --database=arg database file
|
||||||
|
-h, --help show this help
|
||||||
|
-l, --logfile=arg logging file name
|
||||||
|
-p, --port=arg server port
|
||||||
|
-v, --verbose verbose level (each -v increases)
|
||||||
7
Daemons/weather_database/loghere
Normal file
7
Daemons/weather_database/loghere
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[MSG] 2023/06/01-17:54:37 hello, start
|
||||||
|
[DBG] 2023/06/01-17:54:37 SQLite version: 3.42.0
|
||||||
|
[MSG] 2023/06/01-17:54:37 Started
|
||||||
|
[MSG] 2023/06/01-17:54:37 Created child with pid 10010
|
||||||
|
[MSG] 2023/06/01-17:54:37 SEND to fd 3: statsimple60
|
||||||
|
[WARN] 2023/06/01-17:54:49 Child killed with sig=2
|
||||||
|
[ERR] 2023/06/01-17:54:49 Received signal 2, die
|
||||||
117
Daemons/weather_database/main.c
Normal file
117
Daemons/weather_database/main.c
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the sqlite project.
|
||||||
|
* Copyright 2023 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
#include "sql.h"
|
||||||
|
|
||||||
|
#define DEFAULT_PIDFILE "/tmp/wdb"
|
||||||
|
|
||||||
|
static pid_t childpid = 0;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
char *logfile;
|
||||||
|
char *server;
|
||||||
|
char *port;
|
||||||
|
char *dbname;
|
||||||
|
char *pidfile;
|
||||||
|
int v;
|
||||||
|
int help;
|
||||||
|
} opts_t;
|
||||||
|
static opts_t G = {.pidfile = DEFAULT_PIDFILE};
|
||||||
|
|
||||||
|
//void signals(int signo) __attribute__((noreturn));
|
||||||
|
|
||||||
|
void signals(int signo){
|
||||||
|
if(childpid){ // slave process
|
||||||
|
LOGWARN("Child killed with sig=%d", signo);
|
||||||
|
closedb();
|
||||||
|
exit(signo);
|
||||||
|
}
|
||||||
|
if(signo) LOGERR("Received signal %d, die", signo);
|
||||||
|
unlink(G.pidfile);
|
||||||
|
exit(signo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static myoption cmdlnopts[] = {
|
||||||
|
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&G.help), "show this help"},
|
||||||
|
{"address", NEED_ARG, NULL, 'a', arg_string, APTR(&G.server), "server name or IP"},
|
||||||
|
{"port", NEED_ARG, NULL, 'p', arg_string, APTR(&G.port), "server port"},
|
||||||
|
{"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), "logging file name"},
|
||||||
|
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.v), "verbose level (each -v increases)"},
|
||||||
|
{"pidfile", NEED_ARG, NULL, 'P', arg_string, APTR(&G.pidfile), "pidfile (default: " DEFAULT_PIDFILE},
|
||||||
|
{"database",NEED_ARG, NULL, 'd', arg_string, APTR(&G.dbname), "database file"}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv){
|
||||||
|
char *self = strdup(argv[0]);
|
||||||
|
initial_setup();
|
||||||
|
parseargs(&argc, &argv, cmdlnopts);
|
||||||
|
if(G.help) showhelp(-1, cmdlnopts);
|
||||||
|
if(argc > 0) WARNX("Got %d unused keys", argc);
|
||||||
|
if(!G.dbname) ERRX("Point database file name");
|
||||||
|
if(!G.server) ERRX("Point server IP or name");
|
||||||
|
if(!G.port) ERRX("Point server port");
|
||||||
|
sl_loglevel lvl = LOGLEVEL_ERR + G.v;
|
||||||
|
if(lvl > LOGLEVEL_ANY) lvl = LOGLEVEL_ANY;
|
||||||
|
if(G.logfile) OPENLOG(G.logfile, lvl, 1);
|
||||||
|
LOGMSG("hello, start");
|
||||||
|
LOGDBG("SQLite version: %s", sqlite3_libversion());
|
||||||
|
int sock = open_socket(G.server, G.port);
|
||||||
|
if(sock < 0) ERRX("Can't open socket to %s:%s", G.server, G.port);
|
||||||
|
check4running(self, G.pidfile);
|
||||||
|
// signal reactions:
|
||||||
|
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
|
||||||
|
LOGMSG("Started");
|
||||||
|
#ifndef EBUG
|
||||||
|
unsigned int pause = 5;
|
||||||
|
while(1){
|
||||||
|
childpid = fork();
|
||||||
|
if(childpid){ // master
|
||||||
|
double t0 = dtime();
|
||||||
|
LOGMSG("Created child with pid %d", childpid);
|
||||||
|
wait(NULL);
|
||||||
|
LOGWARN("Child %d died", childpid);
|
||||||
|
if(dtime() - t0 < 1.) pause += 5;
|
||||||
|
else pause = 1;
|
||||||
|
if(pause > 900) pause = 900;
|
||||||
|
sleep(pause); // wait a little before respawn
|
||||||
|
}else{ // slave
|
||||||
|
prctl(PR_SET_PDEATHSIG, SIGTERM); // send SIGTERM to child when parent dies
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(!opendb(G.dbname)) return 1;
|
||||||
|
run_socket(sock);
|
||||||
|
LOGERR("Unreachable code reached");
|
||||||
|
signals(1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
174
Daemons/weather_database/socket.c
Normal file
174
Daemons/weather_database/socket.c
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the sqlite project.
|
||||||
|
* Copyright 2023 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
#include "sql.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief open_socket - open client socket
|
||||||
|
* @param server - server IP or name
|
||||||
|
* @param port - current port
|
||||||
|
* @return socket FD or <0 if error
|
||||||
|
*/
|
||||||
|
int open_socket(const char *server, const char *port){
|
||||||
|
if(!server || !port) return -1;
|
||||||
|
DBG("server: %s, port: %s", server, port);
|
||||||
|
int sock = -1;
|
||||||
|
struct addrinfo hints = {0}, *res;
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
if(getaddrinfo(server, port, &hints, &res) != 0){
|
||||||
|
WARN("getaddrinfo");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for(struct addrinfo *p = res; p; p = p->ai_next){
|
||||||
|
if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0){ // or SOCK_STREAM?
|
||||||
|
LOGWARN("socket()");
|
||||||
|
WARN("socket()");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(connect(sock, p->ai_addr, p->ai_addrlen) == -1){
|
||||||
|
LOGWARN("connect()");
|
||||||
|
WARN("connect()");
|
||||||
|
close(sock); sock = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
// simple wrapper over write: add missed newline and log data
|
||||||
|
static void sendmessage(int fd, const char *msg, int l){
|
||||||
|
if(fd < 1 || !msg || l < 1) return;
|
||||||
|
DBG("send to fd %d: %s [%d]", fd, msg, l);
|
||||||
|
char *tmpbuf = MALLOC(char, l+1);
|
||||||
|
memcpy(tmpbuf, msg, l);
|
||||||
|
if(msg[l-1] != '\n') tmpbuf[l++] = '\n';
|
||||||
|
if(l != send(fd, tmpbuf, l, MSG_NOSIGNAL)){
|
||||||
|
LOGWARN("write()");
|
||||||
|
WARN("write()");
|
||||||
|
}else{
|
||||||
|
if(globlog){ // logging turned ON
|
||||||
|
tmpbuf[l-1] = 0; // remove trailing '\n' for logging
|
||||||
|
LOGMSG("SEND to fd %d: %s", fd, tmpbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FREE(tmpbuf);
|
||||||
|
}
|
||||||
|
static void sendstrmessage(int fd, const char *msg){
|
||||||
|
if(fd < 1 || !msg) return;
|
||||||
|
int l = strlen(msg);
|
||||||
|
sendmessage(fd, msg, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check data from fd (polling function for client)
|
||||||
|
* @param fd - file descriptor
|
||||||
|
* @return 0 in case of timeout, 1 in case of fd have data, -1 if error
|
||||||
|
*/
|
||||||
|
static int canberead(int fd){
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 100;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(fd, &fds);
|
||||||
|
do{
|
||||||
|
int rc = select(fd+1, &fds, NULL, NULL, &timeout);
|
||||||
|
if(rc < 0){
|
||||||
|
if(errno != EINTR){
|
||||||
|
LOGWARN("select()");
|
||||||
|
WARN("select()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}while(1);
|
||||||
|
if(FD_ISSET(fd, &fds)){
|
||||||
|
//DBG("FD_ISSET");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect data and write into database
|
||||||
|
// @return FALSE if can't get full data string
|
||||||
|
static int getdata(int fd){
|
||||||
|
double t0 = dtime();
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
int len = 0, leave = BUFSIZ, got = 0;
|
||||||
|
while(dtime() - t0 < ANS_TIMEOUT){
|
||||||
|
int r = canberead(fd);
|
||||||
|
if(r == 0) continue;
|
||||||
|
r = read(fd, buf + len, leave);
|
||||||
|
if(r < 0){
|
||||||
|
LOGERR("Server died");
|
||||||
|
signals(1);
|
||||||
|
}
|
||||||
|
len += r; leave -= r;
|
||||||
|
if(buf[len-1] == '\n'){
|
||||||
|
buf[--len] = 0;
|
||||||
|
got = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!got) return FALSE; // bad data
|
||||||
|
//green("got: %s\n", buf);
|
||||||
|
weatherstat_t w;
|
||||||
|
if(28 != sscanf(buf, "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
|
||||||
|
&w.windspeed.max, &w.windspeed.min, &w.windspeed.mean, &w.windspeed.rms,
|
||||||
|
&w.winddir.max, &w.winddir.min, &w.winddir.mean, &w.winddir.rms,
|
||||||
|
&w.pressure.max, &w.pressure.min, &w.pressure.mean, &w.pressure.rms,
|
||||||
|
&w.temperature.max, &w.temperature.min, &w.temperature.mean, &w.temperature.rms,
|
||||||
|
&w.humidity.max, &w.humidity.min, &w.humidity.mean, &w.humidity.rms,
|
||||||
|
&w.rainfall.max, &w.rainfall.min, &w.rainfall.mean, &w.rainfall.rms,
|
||||||
|
&w.tmeasure.max, &w.tmeasure.min, &w.tmeasure.mean, &w.tmeasure.rms)){
|
||||||
|
LOGWARN("Bad answer from server: %s", buf);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
//printf("max wind: %g\n", w.windspeed.max);
|
||||||
|
addtodb(&w);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief run_socket run main socket process
|
||||||
|
* @param fd - socket file descripto
|
||||||
|
*/
|
||||||
|
void run_socket(int fd){
|
||||||
|
double t0 = 0.;
|
||||||
|
while(1){
|
||||||
|
double tlast = dtime();
|
||||||
|
if(tlast - t0 >= POLLING_INTERVAL){
|
||||||
|
sendstrmessage(fd, SERVER_COMMAND);
|
||||||
|
if(getdata(fd)) t0 = tlast;
|
||||||
|
}
|
||||||
|
usleep(10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
Daemons/weather_database/socket.h
Normal file
46
Daemons/weather_database/socket.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the sqlite project.
|
||||||
|
* Copyright 2023 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
|
||||||
|
|
||||||
|
// timeout of answer waiting - 1s
|
||||||
|
#define ANS_TIMEOUT (1.)
|
||||||
|
// get data each 1 minute
|
||||||
|
#define POLLING_INTERVAL (60.)
|
||||||
|
// command to get stat for last 60s
|
||||||
|
#define SERVER_COMMAND "statsimple60"
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
double min;
|
||||||
|
double max;
|
||||||
|
double mean;
|
||||||
|
double rms;
|
||||||
|
} stat_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
stat_t windspeed;
|
||||||
|
stat_t winddir;
|
||||||
|
stat_t pressure;
|
||||||
|
stat_t temperature;
|
||||||
|
stat_t humidity;
|
||||||
|
stat_t rainfall;
|
||||||
|
stat_t tmeasure;
|
||||||
|
} weatherstat_t;
|
||||||
|
|
||||||
|
int open_socket(const char *server, const char *port);
|
||||||
|
void run_socket(int fd);
|
||||||
72
Daemons/weather_database/sql.c
Normal file
72
Daemons/weather_database/sql.c
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the sqlite project.
|
||||||
|
* Copyright 2023 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "sql.h"
|
||||||
|
|
||||||
|
static sqlite3 *db = NULL;
|
||||||
|
static sqlite3_stmt *res = NULL;
|
||||||
|
static char *errmsg = NULL;
|
||||||
|
static int rc = 0;
|
||||||
|
|
||||||
|
#define SQL(str, callback, arg) do{if(SQLITE_OK != (rc = sqlite3_exec(db, str, callback, arg, &errmsg))){ WARNX("SQL exec error: %s", errmsg); LOGERR("SQL exec error: %s", errmsg);}}while(0)
|
||||||
|
|
||||||
|
void closedb(){
|
||||||
|
if(res) sqlite3_finalize(res);
|
||||||
|
if(db) sqlite3_close(db);
|
||||||
|
res = NULL;
|
||||||
|
db = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief opendb - try to open sqlite3 database
|
||||||
|
* @param name - filename of db
|
||||||
|
* @return TRUE if all OK
|
||||||
|
*/
|
||||||
|
int opendb(const char *name){
|
||||||
|
closedb();
|
||||||
|
rc = sqlite3_open(name, &db);
|
||||||
|
if(rc != SQLITE_OK){
|
||||||
|
WARNX("Can't open database file %s: %s", name, sqlite3_errmsg(db));
|
||||||
|
sqlite3_close(db);
|
||||||
|
db = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
// time with milliseconds from UNIX time with them
|
||||||
|
// select strftime('%Y-%m-%d %H:%M:%f', 1092941466.123, 'unixepoch');
|
||||||
|
//
|
||||||
|
// get data by timestamp
|
||||||
|
// select * from weatherdata where timestamp < unixepoch('now','-10 minutes') and timestamp > 1685617000;
|
||||||
|
char *sql = "create table if not exists weatherdata(timestamp real primary key asc, windmax real, wind real, windrms real, dir real, dirrms real, pressure real, temperature real, humidiy real, rain real);";
|
||||||
|
SQL(sql, NULL, 0);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add data to DB
|
||||||
|
void addtodb(weatherstat_t *w){
|
||||||
|
if(!w) return;
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
int restlen = BUFSIZ-1;
|
||||||
|
snprintf(buf, restlen, "insert into weatherdata values(%.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f);",
|
||||||
|
w->tmeasure.mean, w->windspeed.max, w->windspeed.mean, w->windspeed.rms, w->winddir.mean, w->winddir.rms,
|
||||||
|
w->pressure.mean, w->temperature.mean, w->humidity.mean, w->rainfall.max);
|
||||||
|
SQL(buf, NULL, 0);
|
||||||
|
}
|
||||||
25
Daemons/weather_database/sql.h
Normal file
25
Daemons/weather_database/sql.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the sqlite project.
|
||||||
|
* Copyright 2023 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 "socket.h"
|
||||||
|
|
||||||
|
int opendb(const char *name);
|
||||||
|
void closedb();
|
||||||
|
void addtodb(weatherstat_t *w);
|
||||||
1
Daemons/weather_database/sqlite.cflags
Normal file
1
Daemons/weather_database/sqlite.cflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c17
|
||||||
5
Daemons/weather_database/sqlite.config
Normal file
5
Daemons/weather_database/sqlite.config
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// Add predefined macros for your project here. For example:
|
||||||
|
// #define THE_ANSWER 42
|
||||||
|
#define EBUG
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#define _XOPEN_SOURCE=1111
|
||||||
1
Daemons/weather_database/sqlite.creator
Normal file
1
Daemons/weather_database/sqlite.creator
Normal file
@ -0,0 +1 @@
|
|||||||
|
[General]
|
||||||
1
Daemons/weather_database/sqlite.cxxflags
Normal file
1
Daemons/weather_database/sqlite.cxxflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c++17
|
||||||
5
Daemons/weather_database/sqlite.files
Normal file
5
Daemons/weather_database/sqlite.files
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
main.c
|
||||||
|
socket.c
|
||||||
|
socket.h
|
||||||
|
sql.c
|
||||||
|
sql.h
|
||||||
1
Daemons/weather_database/sqlite.includes
Normal file
1
Daemons/weather_database/sqlite.includes
Normal file
@ -0,0 +1 @@
|
|||||||
|
.
|
||||||
@ -98,7 +98,7 @@ double stat_for(double Tsec, weatherstat_t *wstat){
|
|||||||
size_t north = 0, south = 0;
|
size_t north = 0, south = 0;
|
||||||
while(st != lastidx){
|
while(st != lastidx){
|
||||||
double w = buf[st].winddir;
|
double w = buf[st].winddir;
|
||||||
if(w < 90. || w > 300.) ++north;
|
if(w < 90. || w > 270.) ++north;
|
||||||
else ++south;
|
else ++south;
|
||||||
if(++st == buflen) st = 0;
|
if(++st == buflen) st = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user