mirror of
https://github.com/eddyem/small_tel.git
synced 2026-05-01 18:37:07 +03:00
simplest local weather proxy over SHM
This commit is contained in:
@@ -2,11 +2,17 @@ Different daemons & tools
|
||||
=========================
|
||||
|
||||
- *10micron_stellarium* - simple daemon for 10-micron mount management from stellarium interface
|
||||
- *domedaemon* - open/close Baaden dome by network query
|
||||
- *astrosib* - some scripts used during observations
|
||||
- *deprecated* - deprecated code
|
||||
- *domedaemon-astrosib* - deprecated astrosib daemon
|
||||
- *domedaemon_baader* - open/close Baaden dome by network query
|
||||
- *domedaemon-astrosib* - open/close Astrosib dome by network query
|
||||
- *netdaemon* - template for net-daemons
|
||||
- *netsocket* - scripts for management of network 220V-socket
|
||||
- *send_coordinates* - get/send coordinates to 10-micron mount through stellarium daemon
|
||||
- *teldaemon* - open/close Astrosib-500 scope covers by network query
|
||||
- *weatherdaemon* - weather daemon for old meteostation
|
||||
- *weatherdaemon_newmeteo* - daemon for new (chinese) meteostation
|
||||
- *send_coordinates* - get/send coordinates to 10-micron mount through stellarium daemon (almost deprecated)
|
||||
- *teldaemon_astrosib* - open/close Astrosib-500 scope covers by network query
|
||||
- *weatherdaemon* - weather daemon for old meteostation (almost deprecated)
|
||||
- *weatherdaemon_multimeteo* - (pre-developed) version of weather daemon for ALL sensors on "Astro-M" complex
|
||||
- *weatherdaemon_newmeteo* - daemon for new (chinese) meteostation (almost deprecated)
|
||||
- *weather_database* - make database by data of almost deprecated weather daemons
|
||||
- *weather_proxy* - (pre-developed) daemon gathering meteo data and sharing it on localhost over SHM
|
||||
|
||||
33
Daemons/weather_proxy/Makefile
Normal file
33
Daemons/weather_proxy/Makefile
Normal file
@@ -0,0 +1,33 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -fPIC
|
||||
LDFLAGS = -lrt -pthread
|
||||
|
||||
all: weather_daemon libweather.so weather_clt_example
|
||||
|
||||
weather_daemon: weather_daemon.o
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
weather_clt_example: weather_clt_example.o
|
||||
$(CC) -o $@ $^ $(LDFLAGS) -l weather -L.
|
||||
|
||||
weather_daemon.o: weather_daemon.c weather_data.h
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
libweather.so: weather_client.o
|
||||
$(CC) -shared -o $@ $^ $(LDFLAGS)
|
||||
|
||||
#libweather.a: weather_client.o
|
||||
# ar rcs $@ $^
|
||||
|
||||
weather_client.o: weather_client.c weather_data.h
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
weather_clt_example.o: weather_clt_example.c libweather.so
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
clean:
|
||||
rm -f *.o weather_daemon libweather.so libweather.a weather_clt_example
|
||||
|
||||
install:
|
||||
cp libweather.so /usr/local/lib/
|
||||
cp weather_data.h /usr/local/include/
|
||||
57
Daemons/weather_proxy/weather_client.c
Normal file
57
Daemons/weather_proxy/weather_client.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "weather_data.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <semaphore.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SHM_NAME "/weather_shm"
|
||||
#define SEM_NAME "/weather_sem"
|
||||
|
||||
int get_weather_data(weather_data_t *data) {
|
||||
int shm_fd;
|
||||
sem_t *sem;
|
||||
weather_data_t *shared_data;
|
||||
int ret = 0;
|
||||
|
||||
shm_fd = shm_open(SHM_NAME, O_RDONLY, 0600);
|
||||
if (shm_fd == -1) {
|
||||
perror("shm_open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
shared_data = mmap(NULL, sizeof(weather_data_t), PROT_READ, MAP_SHARED, shm_fd, 0);
|
||||
if (shared_data == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
close(shm_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sem = sem_open(SEM_NAME, 0);
|
||||
if (sem == SEM_FAILED) {
|
||||
perror("sem_open");
|
||||
munmap(shared_data, sizeof(weather_data_t));
|
||||
close(shm_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sem_wait(sem) == -1) {
|
||||
perror("sem_wait");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memcpy(data, shared_data, sizeof(weather_data_t));
|
||||
|
||||
sem_post(sem);
|
||||
|
||||
cleanup:
|
||||
sem_close(sem);
|
||||
munmap(shared_data, sizeof(weather_data_t));
|
||||
close(shm_fd);
|
||||
return ret;
|
||||
}
|
||||
13
Daemons/weather_proxy/weather_clt_example.c
Normal file
13
Daemons/weather_proxy/weather_clt_example.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "weather_data.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
weather_data_t wd;
|
||||
if (get_weather_data(&wd) == 0) {
|
||||
printf("Weather: %d, Max wind: %.1f, Wind: %.1f, Temp: %.1f; updated @%.1f\n",
|
||||
wd.weather, wd.windmax, wd.wind, wd.exttemp, wd.last_update);
|
||||
} else {
|
||||
fprintf(stderr, "Failed to get weather data\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
335
Daemons/weather_proxy/weather_daemon.c
Normal file
335
Daemons/weather_proxy/weather_daemon.c
Normal file
@@ -0,0 +1,335 @@
|
||||
#include "weather_data.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <semaphore.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define DEAD_TMOUT 15
|
||||
#define RECONN_TMOUT 5
|
||||
#define STAT_TMOUT 60
|
||||
#define WEAT_TMOUT 5
|
||||
|
||||
#define SHM_NAME "/weather_shm"
|
||||
#define SEM_NAME "/weather_sem"
|
||||
|
||||
static int shm_fd = -1;
|
||||
static sem_t *sem = NULL;
|
||||
static weather_data_t *shared_data = NULL;
|
||||
static volatile int running = 1;
|
||||
|
||||
#if 0
|
||||
static void log_message(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsyslog(LOG_DAEMON | LOG_INFO, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void log_error(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsyslog(LOG_DAEMON | LOG_ERR, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define log_message(...) do{printf("message: "); printf(__VA_ARGS__); printf("\n");}while(0)
|
||||
#define log_error(...) do{printf("error: "); printf(__VA_ARGS__); printf("\n");}while(0)
|
||||
|
||||
static void signal_handler(int sig) {
|
||||
if (sig == SIGTERM || sig == SIGINT) {
|
||||
running = 0;
|
||||
log_message("Received signal %d, shutting down", sig);
|
||||
}
|
||||
}
|
||||
|
||||
static int init_ipc(void) {
|
||||
shm_fd = shm_open(SHM_NAME, O_RDWR, 0600); // try to open existant SHM
|
||||
if (shm_fd == -1) {
|
||||
printf("Create new shared memory\n");
|
||||
// no - create new
|
||||
shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0600);
|
||||
if (shm_fd == -1) {
|
||||
log_error("shm_open (create) failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (ftruncate(shm_fd, sizeof(weather_data_t)) == -1) {
|
||||
log_error("ftruncate failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
shared_data = mmap(NULL, sizeof(weather_data_t), PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, shm_fd, 0);
|
||||
if (shared_data == MAP_FAILED) {
|
||||
log_error("mmap failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
// default values to data
|
||||
} else {
|
||||
printf("Use existant SHM\n");
|
||||
// use existant SHM
|
||||
shared_data = mmap(NULL, sizeof(weather_data_t), PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, shm_fd, 0);
|
||||
if (shared_data == MAP_FAILED) {
|
||||
log_error("mmap failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(shared_data, 0, sizeof(weather_data_t));
|
||||
|
||||
// create samaphore if no
|
||||
sem = sem_open(SEM_NAME, O_CREAT, 0600, 1);
|
||||
if (sem == SEM_FAILED) {
|
||||
log_error("sem_open failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// free IPC
|
||||
static void cleanup_ipc(void) {
|
||||
if (sem != NULL) {
|
||||
sem_close(sem);
|
||||
if(-1 == sem_unlink(SEM_NAME)) perror("Can't delete semaphore");
|
||||
}
|
||||
if (shared_data != NULL) {
|
||||
munmap(shared_data, sizeof(weather_data_t));
|
||||
}
|
||||
if (shm_fd != -1) {
|
||||
close(shm_fd);
|
||||
if (shm_unlink(SHM_NAME) == -1) {
|
||||
perror("can't unlink SHM");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_line(const char *line, weather_data_t *data) {
|
||||
char key[64];
|
||||
char value[256];
|
||||
if (sscanf(line, "%63[^=]=%255s", key, value) == 2) {
|
||||
if (strcmp(key, "weather") == 0) {
|
||||
if (strcmp(value, "good") == 0)
|
||||
data->weather = WEATHER_GOOD;
|
||||
else if (strcmp(value, "bad") == 0)
|
||||
data->weather = WEATHER_BAD;
|
||||
else if (strcmp(value, "terrible") == 0)
|
||||
data->weather = WEATHER_TERRIBLE;
|
||||
printf("got weather: %d\n", data->weather);
|
||||
} else if (strcmp(key, "Windmax") == 0) {
|
||||
data->windmax = atof(value);
|
||||
printf("got windmax: %g\n", data->windmax);
|
||||
} else if (strcmp(key, "Rain") == 0) {
|
||||
data->rain = atoi(value);
|
||||
printf("got rain: %d\n", data->rain);
|
||||
} else if (strcmp(key, "Clouds") == 0) {
|
||||
data->clouds = atof(value);
|
||||
printf("got clouds: %g\n", data->clouds);
|
||||
} else if (strcmp(key, "Wind") == 0) {
|
||||
data->wind = atof(value);
|
||||
printf("got wind: %g\n", data->wind);
|
||||
} else if (strcmp(key, "Temperature") == 0) {
|
||||
data->exttemp = atof(value);
|
||||
printf("got temp: %g\n", data->exttemp);
|
||||
} else if (strcmp(key, "Pressure") == 0) {
|
||||
data->pressure = atof(value);
|
||||
printf("got pressure: %g\n", data->pressure);
|
||||
} else if (strcmp(key, "Humidity") == 0) {
|
||||
data->humidity = atof(value);
|
||||
printf("got humidity: %g\n", data->humidity);
|
||||
} else if (strcmp(key, "prohibited") == 0) {
|
||||
data->prohibited = atoi(value);
|
||||
} else if (strcmp(key, "Time") == 0) {
|
||||
data->last_update = atof(value);
|
||||
// update all
|
||||
if (sem_wait(sem) == -1) {
|
||||
log_error("sem_wait failed: %s", strerror(errno));
|
||||
} else {
|
||||
memcpy(shared_data, data, sizeof(weather_data_t));
|
||||
sem_post(sem);
|
||||
log_message("Weather data updated");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int sock = -1;
|
||||
static FILE *sock_file = NULL;
|
||||
|
||||
static int opensock(const char *server_ip, int port){
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
log_error("socket creation failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_in server_addr;
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(port);
|
||||
if (inet_pton(AF_INET, server_ip, &server_addr.sin_addr) <= 0) {
|
||||
log_error("invalid address: %s", server_ip);
|
||||
close(sock);
|
||||
sock = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
|
||||
log_error("connect failed: %s", strerror(errno));
|
||||
close(sock);
|
||||
sock = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int flags = fcntl(sock, F_GETFL, 0);
|
||||
if (flags == -1){
|
||||
perror("fcntl F_GETFL");
|
||||
}else{
|
||||
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) perror("fcntl F_SETFL");
|
||||
}
|
||||
|
||||
sock_file = fdopen(sock, "r");
|
||||
if (!sock_file) {
|
||||
log_error("fdopen failed: %s", strerror(errno));
|
||||
close(sock);
|
||||
sock = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int request_weather_data() {
|
||||
static time_t tstat = 0, tcur = 0;
|
||||
|
||||
char *request = "\n";
|
||||
time_t tnow = time(NULL);
|
||||
if(tnow - tcur >= WEAT_TMOUT){
|
||||
tcur = tnow;
|
||||
}else if(tnow - tstat >= STAT_TMOUT){
|
||||
tstat = tnow;
|
||||
request = "stat60\n";
|
||||
}else return 1; // not now
|
||||
|
||||
printf("try to send request: '%s", request);
|
||||
if (send(sock, request, strlen(request), 0) < 0) {
|
||||
log_error("send failed: %s", strerror(errno));
|
||||
close(sock);
|
||||
sock = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void run_daemon(const char *server_ip, int port) {
|
||||
char line[256];
|
||||
weather_data_t new_data;
|
||||
opensock(server_ip, port); // just try: in case of error reopen next time
|
||||
memcpy(&new_data, shared_data, sizeof(weather_data_t));
|
||||
time_t lastert = time(NULL);
|
||||
while (running) {
|
||||
time_t tnow = time(NULL);
|
||||
if (-1 == sock || request_weather_data() == -1) {
|
||||
if(tnow - lastert > RECONN_TMOUT){ // try to reconnect
|
||||
log_error("Failed to request weather data, retry");
|
||||
if(-1 == opensock(server_ip, port)) lastert += 5;
|
||||
else lastert = tnow;
|
||||
}
|
||||
}else lastert = tnow;
|
||||
|
||||
while (fgets(line, sizeof(line), sock_file)) {
|
||||
line[strcspn(line, "\r\n")] = '\0';
|
||||
printf("parse '%s'\n", line);
|
||||
parse_line(line, &new_data);
|
||||
}
|
||||
}
|
||||
close(sock);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void daemonize(void) {
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("fork");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (pid > 0) exit(EXIT_SUCCESS);
|
||||
|
||||
if (setsid() < 0) {
|
||||
perror("setsid");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("second fork");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (pid > 0) exit(EXIT_SUCCESS);
|
||||
|
||||
if (chdir("/") < 0) {
|
||||
perror("chdir");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
umask(0);
|
||||
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
open("/dev/null", O_RDWR);
|
||||
dup(0);
|
||||
dup(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <server_ip> <port>\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char *server_ip = argv[1];
|
||||
int port = atoi(argv[2]);
|
||||
if (port <= 0 || port > 65535) {
|
||||
fprintf(stderr, "Invalid port\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//daemonize();
|
||||
|
||||
log_message("Starting weather daemon, server %s:%d", server_ip, port);
|
||||
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = signal_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (init_ipc() != 0) {
|
||||
log_error("IPC initialization failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
run_daemon(server_ip, port);
|
||||
|
||||
cleanup_ipc();
|
||||
log_message("Weather daemon stopped");
|
||||
return 0;
|
||||
}
|
||||
26
Daemons/weather_proxy/weather_data.h
Normal file
26
Daemons/weather_proxy/weather_data.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
typedef enum {
|
||||
WEATHER_GOOD = 0,
|
||||
WEATHER_BAD = 1,
|
||||
WEATHER_TERRIBLE = 2
|
||||
} weather_condition_t;
|
||||
|
||||
typedef struct {
|
||||
weather_condition_t weather;
|
||||
float windmax;
|
||||
int rain;
|
||||
float clouds;
|
||||
float wind;
|
||||
float exttemp;
|
||||
float pressure;
|
||||
float humidity;
|
||||
int prohibited;
|
||||
double last_update;
|
||||
} weather_data_t;
|
||||
|
||||
int get_weather_data(weather_data_t *data);
|
||||
|
||||
1
Daemons/weather_proxy/weather_proxy.cflags
Normal file
1
Daemons/weather_proxy/weather_proxy.cflags
Normal file
@@ -0,0 +1 @@
|
||||
-std=c17
|
||||
2
Daemons/weather_proxy/weather_proxy.config
Normal file
2
Daemons/weather_proxy/weather_proxy.config
Normal file
@@ -0,0 +1,2 @@
|
||||
// Add predefined macros for your project here. For example:
|
||||
// #define THE_ANSWER 42
|
||||
1
Daemons/weather_proxy/weather_proxy.creator
Normal file
1
Daemons/weather_proxy/weather_proxy.creator
Normal file
@@ -0,0 +1 @@
|
||||
[General]
|
||||
1
Daemons/weather_proxy/weather_proxy.cxxflags
Normal file
1
Daemons/weather_proxy/weather_proxy.cxxflags
Normal file
@@ -0,0 +1 @@
|
||||
-std=c++17
|
||||
4
Daemons/weather_proxy/weather_proxy.files
Normal file
4
Daemons/weather_proxy/weather_proxy.files
Normal file
@@ -0,0 +1,4 @@
|
||||
weather_client.c
|
||||
weather_clt_example.c
|
||||
weather_daemon.c
|
||||
weather_data.h
|
||||
0
Daemons/weather_proxy/weather_proxy.includes
Normal file
0
Daemons/weather_proxy/weather_proxy.includes
Normal file
Reference in New Issue
Block a user