TWELITE で温湿度センサ HDC1000 を動かす

## 部屋が結露するので温湿度を記録したい
最近、寒いなかで加湿しようとすると窓の結露がひどい。何らかの対策をとりたいのだが、そのためには部屋環境を運用する条件の変化に対して湿度と温度がどのように変わるのかを調べる必要がある。また、部屋のなかでも結露しやすい窓際と部屋のまんなか、エアコンの近くなど、場所による局所的な変化もわかるとうれしい。

2014年頃に、ロガーとして使おうとして <a href="https://mono-wireless.com/jp/products/">TWE-LITE</a>と温湿度計(HDC1000)を
購入していた。ブレッドボードも一緒に購入していたのだが、ある程度プログラムをいじろうとした時点で時間がなくなり、放置していた。今回、あらためてホームページを見てみると<a href="https://mono-wireless.com/jp/products/TWE-APPS/App_Tag/index.html">無線タグアプリ</a>というものがリリースされており、ボタン電池の低消費電力でi2cセンサを取り付けた TWE-LITEのチップ（以後チップ）をモニタできるらしい。ただし、チップはデータを保存はしてくれないので、ログを取るには無線が届く範囲(1km以内程度)でパソコンを常時稼働させてデータを受信して保存する必要がある。アプリを書きかえればデータを保存するようにもできるだろうけど、それほどのプログラム時間は確保できそうにない。まあ、将来的にはパソコンの代わりにRasberry-Piでも買ってくれば良いだろう。

##TWE-LITE に温湿度センサー HDC1000 をつなぐ
残念ながら 無線タグアプリは HDC1000 に対応していない。なので、無線タグアプリを自分で修正して HDC1000 に対応させるか、他の方法をとる必要がある。今回は TWE-LITEで遊んでみようということで、デフォルトで入っている「<a href="https://mono-wireless.com/jp/products/TWE-APPS/App_Twelite/index.html">超簡単！TWELITE標準アプリ</a>を使って無線越しに i2c 通信をしてみることにした。

もともとプログラムを書き込んだり通信したりする <a href="https://mono-wireless.com/jp/products/TWE-LITE-R/index.html">TWELITE R </a>と TWELITE２つは購入してある。なので、片方を子機として ブレッドボードに刺して単三電池２本(3.1V)をつなぐ。親機は TWELITE-Rに刺したままの状態で ID=121(0x79)を設定。TeraTerm で 115200bps でつなぐと、無事に通信できたようで、受信したデータが表示された。

次に、ブレッドボードに HDC1000 を配線しよう。なお、HDC1000 は昔、秋月に基板に配線された状態で売っていたもの。基本的にはi2cの２つの信号線と Vcc, GND を配線するだけ。なお、HDC1000は3V以上必要なのでボタン電池では動かない。HDC1000 のマニュアルを見ると、
・i2c アドレスは 0x40 固定
・レジスタ 0x02 : 設定用のレジスタ。
・レジスタ 0x00 : 温度、湿度読み込み。書き込み後にしばらく待って４バイト読み込む
とのこと。

## TWE-LITE 親機から子機の i2c にアクセス
超簡単！TWELITE標準アプリでは<a href="https://mono-wireless.com/jp/products/TWE-APPS/App_Twelite/step3-I2C.html">適当にコマンドを書くと</a>子機の i2c にアクセスできる。TeraTermに
:78880004400202X
 (88:cmd)(04:R/W) (40:i2cアドレス) (02:レジスタ(設定用) (02:2バイト読み込み)
と打ち込んだら
:788900044001021000
 (89:cmd)(04:R/W)(40:i2cアドレス)(01:成功)(02:2バイト)(1000 : 返り値)
がかえってきた！なお、返り値の 0x1000 はデフォルトの状態で、温度、湿度とも14bitなどを意味する。ちなみに、04(R/W) の場合はアドレスを i2c デバイスに書き込み、その後すぐに設定したバイト数を読む。一方、01(W) の場合はアドレス以外のデータを書き込むこともできる。

特に bit 数などの設定を変える必要はないので、次に温度・湿度を読んでみる。
:78880001400000X
 (88:cmd)(01:W) (40:i2cアドレス) (00:レジスタ(読み込み用) (00:書き込みバイト数)
として温度読み込み開始。次に
:78880002400004X
 (88:cmd)(02:R) (40:i2cアドレス) (04:読み込みバイト数)
と打ち込んだら
:788900020104648CAF98
 (89:cmd)(04:R/W)(40:i2cアドレス)(01:成功)(04:読み込みバイト)(648C: 温度)(AF98: 湿度)
が帰ってきた。温度は返り値×165/65536-40.0, 湿度は 返り値×100/65536 が摂氏温度と相対湿度なので、摂氏 24.81℃、湿度 68.59 % となった。部屋の時計に表示された温度は22℃、湿度は50%なのでだいぶずれがある。

#python でログを取る
まあ、それはともかくとしてデータを取れたので、あとはプログラムでログをとれるようにしよう。ここまでの作業は<a href="https://www.kohgakusha.co.jp/books/detail/978-4-7775-1848-7">TWE-Liteではじめる カンタン電子工作</a>という本を読みながら実際のところはやっているのだが、この本に i2c センサーを使うためのpython のプログラムが書いてある。python は使ったことがないので Windows マシンに python と pyserial をインストール。accessI2C という関数を本からコピーして、あとは上にあるようなやりとりを５秒に一回やって温度と湿度を計算、日付と時刻も取得して適当なファイルと画面にデータを記録した。なお、下のコードのうち accessI2C 関数は上記の書籍に掲載されたそのままなので、その部分の著作権は著者にあります。また、COM6 (シリアルの番号としては5)を使っているので、他のポートを使うときは書き換える必要があります。

````Python:TWELITE-HDC1000log.py
import struct, binascii, serial
import time
from datetime import datetime,date

def accessI2C(s, sendto = 0x78, reqno = 0x00, command = 0x01,
	i2caddress = 0x00, i2ccommand = 0x00,
	data = [], readbyte = -1):
	# make data
	if readbyte == -1:
		# write data
		sendbytes = [sendto, 0x88, reqno, command, i2caddress, i2ccommand, len(data)]
		sendbytes.extend(data)
	else:
		#read bytes
		sendbytes = [sendto, 0x88, reqno, command, i2caddress, i2ccommand, readbyte]
	
	#calculate checksum
	chksum = 0
	for val in sendbytes:
		chksum = (chksum + val) & 0xff
	sendbytes.append((0x100-chksum)&0xff)

	# make hex-string
	bytelen = len(sendbytes)
	ss = struct.Struct(str(bytelen)+"B")
	outstring = binascii.hexlify(ss.pack(*sendbytes)).upper()

	# send command
	s.write(":"+outstring+"\r\n")

	# wait for the results (10 times)
	for i in range(10):
		status = s.readline()
		if status[0:9] == ":" + outstring[0:2] + "89" + outstring[4:8]:
			status = status[1:].rstrip()
			ss = struct.Struct(">BBBBBB")
			parsed = ss.unpack(binascii.unhexlify(status[0:12]))
			if status[4]:
				#succeess
				ss = struct.Struct(str(parsed[5]) + "B")
				result = ss.unpack(binascii.unhexlify(status[12:len(status) - 2]))
				return result
			else:
				return False
			break
	return False
#open COM6, 115200 bps
s = serial.Serial(5, 115200)
send = 0x0a

outf = open('tempout.txt', 'a+')
#read status register
result = accessI2C(s, sendto = send, command = 0x04, i2caddress = 0x40, i2ccommand = 0x02, readbyte = 2)
print('status = %02x %02x' %(result[0], result[1]))

while 1:
	# request data
	result = accessI2C(s, sendto = send, command = 0x01, i2caddress = 0x40, i2ccommand = 0x00)
	if result == False :
		continue
	# wait for the measurement finish
	time.sleep(0.300)
	# read data
	result = accessI2C(s, sendto = send, command = 0x02, i2caddress = 0x40, i2ccommand = 0x02, readbyte = 4)
	if result == False :
		continue
	# calculate temperature and humidity
	temp = ((result[0]*256+result[1])*165.0)/65536 - 40.0
	humid = ((result[2]*256+result[3])*100.0)/65536
	# get date/time and print data
	dt = datetime.now()
	d = dt.strftime('%Y/%m/%d %H:%M:%S')
	print('%s : temp = %f humid = %f' %(d,temp,humid))
	print >> outf, '%s : temp = %f humid = %f' %(d,temp,humid)
	time.sleep(5)
````

動くようになったので、とりあえず数日くらいログを取って、どうなるか見てみよう。

##どーでもいいけど
プログラムを書き込んだりブレッドボードに TWE-LITE を抜き差ししていると、わりと頻繁に TWE-LITE のチップが反応しなくなり、新たなプログラムの書き込みもできない状態になった。これは静電気か何かのせいで設定用の eeprom が壊れているか書き込まれたプログラムが壊れたかが原因と思われる。<a href="https://mono-wireless.com/jp/products/TWE-Lite-DIP/TWE-Lite-DIP-step5.html">裏技編</a>にあるようにTWE-LITEのM2,M3,DI4,SDAをグランドにつないで電源を入れると eeprom が消去されてプログラムが書きこめるようになった。チップが古いのが原因か湿度が低すぎて静電気がひどいのが原因かは不明。