「Bluetooth気温計のデータをラズパイで取得しrrdtoolで描画できるようにした。」のusbrhのコードを再度書き直したについて
10年前にUSB温度・湿度計モジュール(以下usbrh)を連続的にとれるコードを書いていたが、サーバのHDDが壊れるとともに消えてしまった模様。
しょうがいないのでNetBSDのvmstatのコードを参考にしつつ連続的に取得するコードを追加。後日、GitHubにでも置いてみるかなぁ。使ったことないからよくわからん。
コマンドの使い方はこんな感じ
./usbrh -h usage: usbrh [-v] [-f device] [-c count] [-w wait] [-t timeformat] timeformat: unix=unix time, at=at time, default:RFC3339 ./usbrh -w 60 -t unix 1628922942 28.72 63.7
rrdtoolに入れる際はこんな感じ
./usbrh -w 60 -t unix | awk '{ print "update /XXXX/usbrh.rrd " $1 ":" $2 ":" $3; fflush()}' | rrdtool - &
ちなみにRRDファイルの作成は以下のコマンドで実施
rrdtool create usbrh.rrd --start "00:00 07/01/2021" \ --step 60 \ --no-overwrite \ DS:Temperature:GAUGE:600:U:U \ DS:Humidity:GAUGE:600:0:100 \ RRA:MAX:0.5:1:5256000GitHubにおいてないので、いったんにここに書くが、まずは USBRH on *BSDからtar玉をダウンロードしてmain.cを下記と入れ替えてコンパイルする。もとのaoyamaさんのコードがBSDライセンスなので、自分で書いた部分のライセンスをBSDライセンスの文言でさらに追加すればいいのかしら。。。
(動作確認 NetBSD/amd64 9.2)
/* * $Id: main.c,v 1.4 2007/01/10 13:11:30 aoyama Exp $ * * Copyright (c) 2006 Kenji AOYAMA <aoyama@nk-home.net> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <sys/ioctl.h> #include <sys/param.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <time.h> #include <dev/usb/usb.h> #include <dev/usb/usbhid.h> /* prototypes */ void usage(void); int main(int, char *[]); int check_device(char *); #define USBRH_VENDOR 0x1774 #define USBRH_PRODUCT 0x1001 #define DEFAULT_DEVICE "/dev/uhid0" extern char *__progname; extern char *optarg; extern int optind; extern float calc_temp(unsigned int); extern float calc_humid(unsigned int, float); int vflag = 0; int main(int argc, char *argv[]) { struct usb_ctl_report ucr; struct timespec interval; int ch, fd, ret; int reps; float t, h; u_char buf[8]; char date[64]; char devname[MAXPATHLEN]; time_t ti; int uflag, aflag, rflag; reps = 0; uflag=aflag=rflag=0; interval.tv_sec = 0; interval.tv_nsec = 0; strlcpy(devname, DEFAULT_DEVICE, sizeof(devname)); while ((ch = getopt(argc, argv, "c:f:ht:vw:")) != -1) { switch(ch) { case 'c': reps = atoi(optarg); break; case 'f': strlcpy(devname, optarg, sizeof(devname)); break; case 'h': usage(); break; case 't': if(strcmp(optarg,"unix")==0){ uflag = 1; }else if(strcmp(optarg,"at")==0){ aflag = 1; }else{ rflag = 1; } break; case 'v': vflag = 1; break; case 'w': interval.tv_sec = atol(optarg); break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (check_device(devname) != 1) { fprintf(stderr, "%s: can not find USBRH device on %s\n", __progname, devname); exit(1); } if ((fd = open(devname, O_RDWR)) < 0) { perror(devname); exit(1); } /* * XXX: If we issue SET_REPORT only once, read(2) sometimes * blocks. So we issue SET_REPORT twice, with 1 second interval, * that seems OK. */ ucr.ucr_report = UHID_OUTPUT_REPORT; if (ioctl(fd, USB_SET_REPORT, &ucr) < 0) { perror("USB_SET_REPORT"); exit(1); } sleep(1); for(;;){ if (interval.tv_sec) { if (!reps) reps = -1; } else if (reps){ interval.tv_sec = 1; } ucr.ucr_report = UHID_OUTPUT_REPORT; if (ioctl(fd, USB_SET_REPORT, &ucr) < 0) { perror("USB_SET_REPORT"); exit(1); } if ((ret = read(fd, buf, 7)) == -1) { fprintf(stderr, "read error\n"); exit(1); } // close(fd); /* * Now we got 7 bytes data from the device. * * buf[0] Humidity raw data (high byte) * buf[1] Humidity raw data (low byte) * buf[2] Temperature raw data (high byte) * buf[3] Temperature raw data (low byte) * buf[4] ??? * buf[5] ??? * buf[6] ??? */ /* Calculate the real values */ t = calc_temp(buf[2] * 256 + buf[3]); h = calc_humid(buf[0] * 256 + buf[1], t); ti = time(NULL); if(uflag){ sprintf(date,"%ld", ti); }else if(aflag){ strftime(date, sizeof(date), "%H:%M %m/%d/%Y", localtime(&ti)); }else if(rflag){ strftime(date, sizeof(date), "%Y-%m-%dT%H:%M:%S%z", localtime(&ti)); } if (vflag) { printf("Date\tTemperature\tHumidity\n"); } printf("%s %.2f %.1f\n", date, t, h); fflush(stdout); if (reps >= 0 && --reps <=0) break; (void)nanosleep(&interval, NULL); } return 0; } void usage(void) { fprintf(stderr, "usage: %s [-v] [-f device] [-c count] [-w wait] [-t timeformat]\n", __progname); fprintf(stderr, "timeformat: unix=unix time, at=at time, default:RFC3339\n"); exit(1); } /* * Check USBRH vendor ID and product ID on specified device. * Return 1 if matches. */ int check_device(char *devname) { int fd; struct usb_device_info udi; #if defined(__NetBSD__) || defined(__OpenBSD__) /* On NetBSD/OpenBSD, /dev/uhid? can accept USB_GET_DEVICEINFO ioctl. */ if ((fd = open(devname, O_RDWR)) < 0) { perror(devname); exit(1); } if (ioctl(fd, USB_GET_DEVICEINFO, &udi) < 0) { perror("USB_GET_DEVICEINFO"); exit(1); } close(fd); /* vendor and product ID check */ if ((udi.udi_vendorNo == USBRH_VENDOR) && (udi.udi_productNo == USBRH_PRODUCT)) { return 1; } return 0; #else /* Otherwise, walk through from /dev/usb? devices. */ int cnt, addr; char buf1[MAXPATHLEN], buf2[MAXPATHLEN]; for (cnt = 0; cnt < 10; cnt++) { /* XXX: is this enough? */ snprintf(buf1, sizeof(buf1), "/dev/usb%d", cnt); fd = open(buf1, O_RDONLY); if (fd < 0) continue; for (addr = 1; addr < USB_MAX_DEVICES; addr++) { udi.udi_addr = addr; if (ioctl(fd, USB_DEVICEINFO, &udi) < 0) continue; strlcpy(buf2, "/dev/", sizeof(buf2)); strlcat(buf2, udi.udi_devnames[0], sizeof(buf2)); #ifdef DEBUG printf("%s Addr %d, Vendor 0x%04x, Product 0x%04x, " "%s, %s, %s, %s, %s\n", buf1, addr, udi.udi_vendorNo, udi.udi_productNo, udi.udi_devnames[0], udi.udi_devnames[1], udi.udi_devnames[2], udi.udi_devnames[3], buf2); #endif if ((strcmp(devname, buf2) == 0) && (udi.udi_vendorNo == USBRH_VENDOR) && (udi.udi_productNo == USBRH_PRODUCT)) { return 1; } } close(fd); } return 0; #endif }
0 件のコメント:
コメントを投稿