#include #include #include #include #include #include #include #include #include #include #include #include #include #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) static int read_1wire_temp(const char *path, double *temp) { char buf[16]; int fd; int ret; int retries = 0; retry: fd = open(path, O_RDONLY); if (fd < 0) { printf("%s: Failed to open file %s: %m\n", __func__, path); return -1; } ret = read(fd, buf, sizeof(buf) - 1); if (ret < 0) { printf("%s: Failed read temperature from file %s: %m\n", __func__, path); goto out_close; } buf[ret] = '\0'; *temp = atof(buf); ret = 0; out_close: close(fd); if (*temp == 85) { ret = -1; if (retries < 3) { retries++; printf("Retrying 1wire read, try %d\n", retries); goto retry; } } return ret; } struct data_entry { time_t time; double temperature; double humidity; double pressure; double dew_point; }; static char *addrstr(struct sockaddr_in *addr) { static char str[32]; snprintf(str, sizeof(str), "%s:%d", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port)); str[sizeof(str) - 1] = '\0'; return str; } static int fetch_bmed_data(struct sockaddr_in *addr, struct data_entry *data) { char buf[64]; int fd; int ret; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { printf("%s: Failed to create socket: %m\n", __func__); return -1; } ret = connect(fd, (struct sockaddr *)addr, sizeof(*addr)); if (ret < 0) { printf("%s: Failed to connect at %s: %m\n", __func__, addrstr(addr)); goto out_close; } /* * Send timestamp of the first entry we want. Data is * generated every 60 seconds, so this should give us the last * entry only */ ret = dprintf(fd, "%ld\n", time(NULL) - 60); if (ret < 0) { printf("%s: Failed to send timestamp to bmed at %s: %m\n", __func__, addrstr(addr)); goto out_close; } ret = read(fd, buf, sizeof(buf) - 1); if (ret < 0) { printf("%s: Failed read data from bmed at %s: %m\n", __func__, addrstr(addr)); goto out_close; } buf[ret] = 0; ret = sscanf(buf, "%ld:%lf:%lf:%lf:%lf", &data->time, &data->temperature, &data->pressure, &data->humidity, &data->dew_point); if (ret != 5) { printf("%s: Read only %d datapoints out of 5 from string: %s\n", __func__, ret, buf); ret = -1; } else { ret = 0; } out_close: close(fd); return ret; } static int parse_ip_port(const char *str, struct sockaddr_in *addr) { char ip[16]; char *s; long int len; int ret; s = strstr(str, ":"); len = s - str; if (len >= (long)sizeof(ip) || len < 0 || !s) { printf("%s: Unable to parse ip:port from string %s, %ld\n", __func__, str, len); return -1; } strncpy(ip, str, len); ip[len] = '\0'; ret = inet_aton(ip, &addr->sin_addr); if (!ret) { printf("Invalid address: %s\n", ip); return -1; } s++; addr->sin_port = htons(atoi(s)); printf("%s:Parsed %s from %s: \n", __func__, addrstr(addr), str); addr->sin_family = AF_INET; return 0; } static int daemon_loop(const char *temp_path, struct sockaddr_in *bme_addr) { struct sockaddr_in addr_in; struct data_entry data; int listen_fd, fd, ret; double temp = 0; bzero(&addr_in, sizeof(addr_in)); listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd < 0) { } addr_in.sin_family = AF_INET; addr_in.sin_port = htons(6000); addr_in.sin_addr.s_addr = INADDR_ANY; ret = bind(listen_fd, (struct sockaddr *)&addr_in, sizeof(addr_in)); if (ret < 0) { printf("%s: Failed to bind to addr %s: %m\n", __func__, addrstr(&addr_in)); goto close_socket; } ret = listen(listen_fd, 5); if (ret < 0) { printf("Failed to listen(): %m\n"); goto close_socket; } while (1) { char buf[128]; socklen_t peerlen = 0; int onewire_ok, bme_ok; int i, ret, len; fd = accept(listen_fd, (struct sockaddr *)&addr_in, &peerlen); if (fd < 0) { printf("%s: Error while accept(): %m\n", __func__); continue; } ret = read_1wire_temp(temp_path, &temp); onewire_ok = !ret; if (onewire_ok) printf("1wire data: %.2lf\n", temp); ret = fetch_bmed_data(bme_addr, &data); bme_ok = !ret; if (bme_ok) printf("bmed data: %ld %.4lf %.4lf %.4lf %.4lf\n", data.time, data.temperature, data.humidity, data.pressure, data.dew_point); if (!onewire_ok) temp = data.temperature; len = snprintf(buf, sizeof(buf), "%.1lf %.1lf %.1lf %.1lf\n\r", min(temp, data.temperature), data.humidity, data.pressure, data.dew_point); for (i = 0; i < (int)sizeof(buf) && buf[i]; i++) if (buf[i] == '.') buf[i] = ','; ret = write(fd, buf, len); if (ret < 0) printf("%s: Failed to write to %s: %m\n", __func__, addrstr(&addr_in)); close(fd); } close_socket: close(listen_fd); return ret; } int main(int argc, char *argv[]) { char *path; struct sockaddr_in addr; int ret; if (argc < 3) { printf("Usage: %s [1wire path] [bmed ip:addr]\n", argv[0]); return 1; } bzero(&addr, sizeof(addr)); ret = parse_ip_port(argv[2], &addr); if (ret < 0) return 1; path = argv[1]; daemon_loop(path, &addr); return 0; }