Koshianで作るBLE温度計

# 夏休み自由研究用、BLE温度計
## 24Hの温度変化を記録
　子供の自由研究で、温度を測りたいということは良くあります。10分に１回、あるいは１時間に１回、温度を測るとか。しかしながら、子供はどうも飽き性で長続きしません。そこで、自動的に24時間、等しい時間間隔で温度を測定して、記録する装置を作ります。
　ワイアレスで作りたかったので、Koshian を使いました。使った部品は以下の通りです。母艦はWindows 7 32ビットです。

- [Koshian](https://service.macnica.co.jp/library/107829)
- [サーミスタ103AT-2](http://akizukidenshi.com/catalog/g/gP-07258/)

![Ondokei.PNG](https://qiita-image-store.s3.amazonaws.com/0/58417/50aa4ec2-6a05-74be-1ce8-67b98fda2d3a.png)

　回路図は上の通りです。２個のサーミスタを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変換の値から、抵抗値を求め温度を求める計算  
だだし、抵抗値は１％程度の誤差があるので、ぴったりの温度にはならない。

```javascript: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;
}
```

```javascript: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");
}

```

```javascript: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();
});
```