夏休み自由研究用、BLE温度計
24Hの温度変化を記録
子供の自由研究で、温度を測りたいということは良くあります。10分に1回、あるいは1時間に1回、温度を測るとか。しかしながら、子供はどうも飽き性で長続きしません。そこで、自動的に24時間、等しい時間間隔で温度を測定して、記録する装置を作ります。
ワイアレスで作りたかったので、Koshian を使いました。使った部品は以下の通りです。母艦はWindows 7 32ビットです。
回路図は上の通りです。2個のサーミスタをAD0, AD1に接続しています。このサーミスタは10kΩとのことですので、AD0, AD1 には半分の1.5Vくらいがかかる予定です。AD2は電圧のリファレンスとしてVCCに接続しています。
Windows 7でBluetoothを受信する仕組みは、以前記載しました[Windows 7 のnoble でBluetooth LE を使う](http://qiita.com/YumeYakata/items/ddf871ba3aeeafc47f88]を利用しました。
使用モジュール
- npm install noble
node でBluetooth LEを使う。 - npm install fs
温度と測定した時間をファイルに書き込む。 - npm install date-utils
現在時刻を取得する。
プログラム
- AD変換の値から、抵抗値を求め温度を求める計算
だだし、抵抗値は1%程度の誤差があるので、ぴったりの温度にはならない。
ondosokutai.js
//抵抗の実測地
const R0=10243; //AD0につながっている10k ohmeの実測値
const R1=11206; //AD1につながっている10k ohmeの実測値
// 抵抗値の補正
// rr --- 10k ohme の測定値
// rd --- AD0, AD1とAD2との比
//
function ondo0(rd){ return ondo(rregist(R0,rd)); }
function ondo1(rd){ return ondo(rregist(R1,rd)); }
function rregist(rr,rd)
{
var dd=rd/(1-rd)*rr;
return dd;
}
// 抵抗値から温度を求める
// bt --- 温度
const BCOEF=3380; //B coefficient
const RB=10000; //25度の時の抵抗値
const T0=25
const AT=273 //absolute temperature
function ondo(rr)
{
var alpha=Math.log(rr/RB);
var beta=(T0+AT)*alpha/BCOEF;
var bt = (T0-AT*beta)/(beta+1);
return bt;
}
writefile.js
var fs = require('fs'); //ファイル書き込み
require('date-utils'); //日付時間の獲得
exports.writedata = writedata //書き込み関数のexports
var dt = new Date();
var formatted = dt.toFormat("YYYY/MM/DD/ HH24:MI:SS");
// data2, data1, data0 はそれぞれADCの結果の生値
function writedata(data2,data1,data0)
{
dt = new Date();
formatted = dt.toFormat("YYYY/MM/DD,HH24:MI:SS"); //時間も記録する。
var dt0 = Math.floor(ondo0(data0/data2)*100)/100.
var dt1 = Math.floor(ondo1(data1/data2)*100)/100.
fs.appendFile('writetest.txt',formatted + "," + dt0+" , "+ dt1 +"\n");
console.log(dt0 + ":" + dt1 +"\n");
}
ble_ondokei.js
// 2017.8/14
// BLE 温度計
// This example to use Koshian with Bluetooth LE
// Koshian is a compatible module of Konashi
// http://konashi.ux-xu.com/documents/
// Special Thanks for http://www.1ft-seabass.jp/memo/2015/12/17/nodejs-noble-konashi-connect/
//
var noble = require('noble');
var BO = require('./writefile.js');
var require('./ondosokutai.js');
// ----------------------------------------------------------------------------
// To connect Bluetooth LE
//
// Koshian自体のサービスID
var KOSHIAN_SERVICE_UUID = '229bff0003fb40da98a7b0def65c2d4b';
// 操作したいpinのID
var KOSHIAN_PIO_SETTING_PINID = '229b300003fb40da98a7b0def65c2d4b';
var KOSHIAN_PIO_PULLUP_PINID = '229b300103fb40da98a7b0def65c2d4b'
var KOSHIAN_PIO_OUTPUT_PINID = '229b300203fb40da98a7b0def65c2d4b';
var KOSHIAN_PIO_INPUT_NORTIFICATION_PINID = '229b300303fb40da98a7b0def65c2d4b';
var KOSHIAN_PWM_CONFIG_PINID = '229b300403fb40da98a7b0def65c2d4b';
var KOSHIAN_PWM_PARAMETER_PINID = '229b300503fb40da98a7b0def65c2d4b';
var KOSHIAN_PWM_DUTY_PINID = '229b300603fb40da98a7b0def65c2d4b';
var KOSHIAN_ANALOG_DRIVE_PINID = '229b300703fb40da98a7b0def65c2d4b';
var KOSHIAN_ANALOG_READ0_PINID = '229b300803fb40da98a7b0def65c2d4b';
var KOSHIAN_ANALOG_READ1_PINID = '229b300903fb40da98a7b0def65c2d4b';
var KOSHIAN_ANALOG_READ2_PINID = '229b300a03fb40da98a7b0def65c2d4b';
var KOSHIAN_HARDWARE_RESETID = '229B301403FB40DA98A7B0DEF65C2D4B';
// 各CHARACTERISTICSをUUIDから判断してcharacteristic格納する変数
var KOSHIAN_CHARACTERISTICS_ANALOG_READ0;
var KOSHIAN_CHARACTERISTICS_ANALOG_READ1;
var KOSHIAN_CHARACTERISTICS_ANALOG_READ2;
var KOSHIAN_CHARACTERISTICS_PIO_SETTINGS;
var KOSHIAN_CHARACTERISTICS_PIO_OUTPUT;
var KOSHIAN_CHARACTERISTICS_PIO_INPUT;
var KOSHIAN_CHARACTERISTICS_PIO_PULLUP;
var KOSHIAN_CHARACTERISTICS_HARDWARE_RESET;
// スイッチ、アナログバリューのバッファー
var mPIO_0=0;
var mPIO_1=0;
var mAG0=0; //AD0 Data
var mAG1=0; //AD1 Data
var mAG2=0; //AD2 Data
var mAT0=0; //AD0 Data
var mAT1=0; //AD1 Data
var mAT2=0; //AD2 Data
var mCnt0=0; //平均のためのCounter
var mCnt1=0; //平均のためのCounter
var mCnt2=0; //平均のためのCounter
var mTgl=0; //AD切り替え
// 状態がパワーONだったらスキャンに移行
noble.on('stateChange', function(state) {
console.log('on -> stateChange: ' + state);
if (state === 'poweredOn') {
noble.startScanning();
} else {
noble.stopScanning();
}
});
noble.on('scanStart', function() {
console.log('on -> scanStart');
});
noble.on('scanStop', function() {
console.log('on -> scanStop');
});
// discover 機器が発見されたら
noble.on('discover', function(peripheral) {
console.log('on -> discover: ' + peripheral);
// まずスキャンをとめる
noble.stopScanning();
// KOSHIAN接続時のイベント
peripheral.on('connect', function() {
console.log('on -> connect');
this.discoverServices();
});
// KOSHIAN切断時のイベント
peripheral.on('disconnect', function() {
console.log('on -> disconnect');
});
// 見つけたサービス(機器)へのアクセス
peripheral.on('servicesDiscover', function(services) {
console.log('on -> services length ' + services.length);
for(var i = 0; i < services.length; i++) {
// サービスがKOSHIAN_SERVICE_UUIDと一致した時だけ処理
if(services[i]['uuid'] == KOSHIAN_SERVICE_UUID){
console.log('on -> find KOSHIAN ' + i);
// サービスのcharacteristic捜索
services[i].on('includedServicesDiscover', function(includedServiceUuids) {
console.log('on -> service included services discovered [' + includedServiceUuids + ']');
this.discoverCharacteristics();
});
// characteristic取得イベント
services[i].on('characteristicsDiscover', function(characteristics) {
console.log('on -> Duscover characteristics ' + characteristics.length);
// characteristics配列から必要なCHARACTERISTICSをUUIDから判断してcharacteristic格納
for(var j = 0; j < characteristics.length; j++) {
// アナログ入力 characteristic
if( KOSHIAN_ANALOG_READ0_PINID == characteristics[j].uuid ){
console.log("KOSHIAN_CHARACTERISTICS_ANALOG_READ exist!!");
KOSHIAN_CHARACTERISTICS_ANALOG_READ0 = characteristics[j];
}
if( KOSHIAN_ANALOG_READ1_PINID == characteristics[j].uuid ){
console.log("KOSHIAN_CHARACTERISTICS_ANALOG_READ exist!!");
KOSHIAN_CHARACTERISTICS_ANALOG_READ1 = characteristics[j];
}
if( KOSHIAN_ANALOG_READ2_PINID == characteristics[j].uuid ){
console.log("KOSHIAN_CHARACTERISTICS_ANALOG_READ exist!!");
KOSHIAN_CHARACTERISTICS_ANALOG_READ2 = characteristics[j];
}
}
// スイッチ、ボリュームの読み込み
setInterval(function(){
switch(mTgl){
case 0:
KOSHIAN_CHARACTERISTICS_ANALOG_READ0.read(function(error, data) {
if (data) {
var temp = (data[1] + data[0]*256);
mAG0 += temp;
mCnt0++;
}
});
break;
case 1:
KOSHIAN_CHARACTERISTICS_ANALOG_READ1.read(function(error, data) {
if (data) {
var temp = (data[1] + data[0]*256);
mAG1 += temp;
mCnt1++;
}
});
break;
case 2:
KOSHIAN_CHARACTERISTICS_ANALOG_READ2.read(function(error, data) {
if (data) {
var temp = (data[1] + data[0]*256);
mAG2 += temp ;
mCnt2++;
}
});
break;
}
mTgl++;
if(mTgl==3) mTgl=0;
if(mCnt0==10){
mAT0=mAG0/10;
mAG0=0; mCnt0=0;
}
if(mCnt1==10){
mAT1=mAG1/10;
mAG1=1; mCnt1=0;
}
if(mCnt2==10){
mAT2=mAG2/10;
mAG2=0; mCnt2=0;
BO.writedata(mAT2,mAT1,mAT0);
}
}, 100);
});
services[i].discoverIncludedServices();
}
}
});
// 機器との接続開始
peripheral.connect();
});