先日調達した富士通ビー・エス・シーのF-PLUG(エフプラグ)。
F-PLUG |
データの取得は一般公開されているF-PLUG メッセージ一覧に従って一般的なRFCOMMの接続手順をベースに実装すれば良いのだが、まずは動作確認を含めてOBDNマガジンのgoto2048/fplug_for_linuxを利用してみた。
電力は期待通り採れたので動作確認はOKとしたのだが、fptestで温度(Temperature)が採れない事がある事に気付いて調べてみたところ、応答メッセージがF-PLUG メッセージ一覧の仕様と違って1バイト短い事がわかった。湿度、照度は大丈夫そうなのだが、ひとまずデータの最後から2バイトに注目するように改修した。
yano@ML110G7:~/software/fplug_for_linux$ sudo fptest
1.Get Temperature
2.Get Humidity
3.Illumination
4.Watt(Realtime)
5.Exit
Input command no ->1
Temp Command:10,81,00,00,0E,F0,00,00,11,00,62,01,E0,00,
ret size=15
Temp Status:10,81,00,00,00,00,0E,F0,00,72,01,E0,02,0E,01,
Temperature=27.0
1.Get Temperature
2.Get Humidity
3.Illumination
4.Watt(Realtime)
5.Exit
Input command no ->4
ret size=16
Realtime Wattmeter:10,81,00,00,00,22,00,0E,F0,00,72,01,E2,02,73,02,
Watt(Realtime)=62.7W
fpstatusもsensors.cronからデータを取得できるよう同様に改修してみたのだが、応答メッセージの受信以前に要求メッセージの送信がうまくいかない事が多い事がわかった。調べてみると"Transport endpoint is not connected"が発生しているので、ENOTCONNの場合はwriteをリトライするように対処。
ついでに一度の接続で電力、温度、湿度、照度を立て続けに取得できるように改造。
#include <stdint.h>更にread待ちにならないようにpselect監視を挟んでみたのだが、期待通りに受信してもpselectでキャッチできないので、素直にwriteできたらreadするよう着地。あとrootでないと/dev/rfcomm0が"Permission denied"になるのでseteuidするようにしてみたのだが、うまくいかないという問題が残っているものの、取り敢えず期待通りに温度、湿度、照度を含めてデータは採れるようになった。
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include "fplug.h"
#define DEOJ_TOKEN "\x0E\xF0\x00\x72"
#define DEOJ_TOKEN_LEN 4
static unsigned char *
memmem(unsigned char *a, size_t a_len, unsigned char *b, size_t b_len)
{
int i;
for (i = 0; i < (a_len - b_len); i++ ){
if ( a[i] != *b )
continue;
if ( !memcmp(&a[i], b, b_len) )
return &a[i];
}
return NULL;
}
static void dump_message( char *mes, unsigned char *buf, int size )
{
/*
int cnt;
printf( "%s", mes );
for ( cnt=0; cnt<size; cnt++ ) {
printf( "%02X,", buf[cnt] );
}
printf( "\n" );
*/
return;
}
int fp_main( int, int );
int main(int argc, char *argv[])
{
int fd;
struct termios oldtio, newtio;
char *cmd;
if ( argc == 1 ) {
printf("Usage: fpstatus <option>\n");
return(0);
}
if ( *argv[1] == '-' ) argv[1]++;
fd = open(SERIAL_PORT, O_RDWR);
if ( fd < 0 ){
perror("open(/dev/rfcomm0)");
return 0;
}
tcgetattr( fd, &oldtio );
newtio = oldtio;
newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
tcsetattr(fd, TCSANOW, &newtio);
for ( cmd = argv[1]; cmd && *cmd; cmd++ )
fp_main(fd, *cmd);
printf( "\n");
tcsetattr(fd, TCSANOW, &oldtio);
close(fd);
return 0;
}
typedef unsigned char uchar;
size_t fplug_request(int fd, uchar *req_buf,size_t req_len,uchar *res_buf, size_t bufsiz)
{
struct timespec tmspec = { 0, 1000 * 1000 };
int ret, i;
dump_message( "Command:", req_buf, req_len);
for (ret = i = 0;i < 10; i++ ) {
tmspec.tv_nsec = i * 100 * 1000 * 1000;
ret = write(fd, req_buf, req_len);
if ( ret == req_len )
break;
// printf("write()=%d,errno=%d\n", ret, errno);
switch ( errno ){
case ENOTCONN :
nanosleep(&tmspec, NULL);
break;
}
}
ret = read(fd, res_buf, bufsiz);
dump_message( "read:", res_buf, ret );
return ret;
}
int fp_main( int fd, int mode )
{
int cmd;
int cnt;
int a=0;
double f;
int ret;
int i=0;
unsigned char buf[BUFSIZ];
time_t timer;
struct tm *t;
switch(mode) {
case 't':
while (1) {
ret = fplug_request(fd, Temp, sizeof(Temp), buf, BUFSIZ);
if (memmem(buf, ret, DEOJ_TOKEN, DEOJ_TOKEN_LEN)) break;
if ( i++ >10 ) return(0);
}
a = *(int16_t *)&buf[ret-2];
printf( "FP_TEMP=%.1f;", (float)a / 10);
break;
case 'h':
while (1) {
ret = fplug_request(fd, Humid, sizeof(Humid), buf, BUFSIZ);
if (memmem(buf, ret, DEOJ_TOKEN, DEOJ_TOKEN_LEN)) break;
if ( i++ >10 ) return(0);
}
a = *(uint16_t *)&buf[ret-2];
printf( "FP_HUMID=%d;", a );
break;
case 'i':
while (1) {
ret = fplug_request(fd, Illum, sizeof(Illum), buf, BUFSIZ);
if (memmem(buf, ret, DEOJ_TOKEN, DEOJ_TOKEN_LEN)) break;
if ( i++ >10 ) return(0);
}
a = *(uint16_t *)&buf[ret-2];
printf( "FP_ILLUM=%d;", a );
break;
case 'w':
while (1) {
ret = fplug_request(fd, RWatt, sizeof(RWatt), buf, BUFSIZ);
if (memmem(buf, ret, DEOJ_TOKEN, DEOJ_TOKEN_LEN)) break;
if ( i++ >10 ) return(0);
}
a = *(uint16_t *)&buf[ret-2];
printf( "FP_WATT=%.1f;", (float)a / 10);
break;
default:
break;
}
}
【参照】
●富士通ビー・エス・シー http://www.bsc.fujitsu.com/
┣F-PLUG(エフプラグ)
┗F-PLUG メッセージ一覧
●OBDNマガジン http://obdnmagazine.blogspot.jp/
┗富士通ビー・エス・シー F-PLUG [AX3][A6] 2013年3月25日
●ロードバイクときどきiPad/Airなblog http://blogs.yahoo.co.jp/beachinside
┗F-PLUG(電力/明るさ/温度/湿度測定プラグ)を買って来た 2013年8月13日
●Amazon.co.jp https://www.amazon.co.jp/
┗富士通BSC F-PLUG115 電力・温度・湿度・照度測定機能つきプラグ ホワイト BSCESFP0103 4,900円