]> git.itanic.dy.fi Git - BME280_driver/blobdiff - tempd.c
Add simple tempd daemon
[BME280_driver] / tempd.c
diff --git a/tempd.c b/tempd.c
new file mode 100644 (file)
index 0000000..51b9ded
--- /dev/null
+++ b/tempd.c
@@ -0,0 +1,259 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+
+#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;
+
+       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);
+
+       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;
+}