ストロベリー・リナックスから低価格版の温湿度センサとして HDC1050 のモジュールが発売されています.
これを Raspberry Pi 上の Python から使う方法を紹介します.
特徴的なレジスタ読み出し
このセンサ,使い方は以下の順に制御するだけでとっても簡単.
- 温度・湿度の計測開始を指示
- 一定時間待つ
- 計測結果を読み出し
ただし,計測結果のレジスタの読み出し方法がちょっと変わっています.下図のように,値の読み出し時にレジスタドレスの指定を必要としません.もし指定してしまうと,それは計測開始を意味してしまうので,結果として上手く動作しません.
以降では,これの問題を回避して HDC1050 を制御するスクリプトについて順に説明します.
Python 用 I2C ライブラリの作成
前述の仕様のため,Python から I2C デバイスを制御するときによく使われる smbus が使えません.そこで,I2C 用のライブラリ(i2cbus.py
)を自作することにします.
ライブラリといってもとてもシンプルで,こんな感じです.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import io import fcntl class I2CBus: # ioctl 用 (Linux の i2c-dev.h の定義から引用) I2C_SLAVE = 0x0703 def __init__(self, bus): self.wh = io.open('/dev/i2c-' + str(bus), mode='wb', buffering=0) self.rh = io.open('/dev/i2c-' + str(bus), mode='rb', buffering=0) def write(self, dev_addr, reg_addr, param=None): fcntl.ioctl(self.wh, self.I2C_SLAVE, dev_addr) data=bytearray() data.append(reg_addr) if type(param) is list: data.extend(param) elif not param is None: data.append(param) self.wh.write(data) def read(self, dev_addr, count, reg_addr=None): fcntl.ioctl(self.wh, self.I2C_SLAVE, dev_addr) fcntl.ioctl(self.rh, self.I2C_SLAVE, dev_addr) if not reg_addr is None: self.wh.write(bytearray([reg_addr])) return self.rh.read(count) |
read を 1 個の引数で呼び出すと,レジスタアドレスを指定せずに読み出しを行います.これによって HDC1050 の計測結果を読み出せるようになります.
Python 用の HDC1050 ライブラリ
先ほどの i2cbus を使うと,HDC1050 を制御するライブラリ(hdc1050.py
)はこのように書けます.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#!/usr/bin/env python # -*- coding: utf-8 -*- import time import struct class HDC1050: DEV_ADDR = 0x40 # 7bit REG_TEMP = 0x00 REG_HUMI = 0x01 REG_CONF = 0x02 def __init__(self, bus, dev_addr=DEV_ADDR): self.bus = bus self.dev_addr = dev_addr self.i2cbus = I2CBus(bus) def get_value(self): self.i2cbus.write(self.dev_addr, self.REG_TEMP) time.sleep(0.05) value = self.i2cbus.read(self.DEV_ADDR, 4) temp = struct.unpack('>H', bytes(value[0:2]))[0] temp = float(temp)/65536*165 - 40 humi = struct.unpack('>H', bytes(value[2:4]))[0] humi = float(humi)/65536*100 return { 'temp': temp, 'humi': humi } |
レジスタの値を読み出して,データシートの下記の換算式に沿って計算しているだけです.
Python による HDC1050 の制御
以上をまとめるとスクリプト全体は次のようになります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
#!/usr/bin/env python # -*- coding: utf-8 -*- import io import fcntl import time import struct class I2CBus: # ioctl 用 (Linux の i2c-dev.h の定義から引用) I2C_SLAVE = 0x0703 def __init__(self, bus): self.wh = io.open('/dev/i2c-' + str(bus), mode='wb', buffering=0) self.rh = io.open('/dev/i2c-' + str(bus), mode='rb', buffering=0) def write(self, dev_addr, reg_addr, param=None): fcntl.ioctl(self.wh, self.I2C_SLAVE, dev_addr) data=bytearray() data.append(reg_addr) if type(param) is list: data.extend(param) elif not param is None: data.append(param) self.wh.write(data) def read(self, dev_addr, count, reg_addr=None): fcntl.ioctl(self.wh, self.I2C_SLAVE, dev_addr) fcntl.ioctl(self.rh, self.I2C_SLAVE, dev_addr) if not reg_addr is None: self.wh.write(bytearray([reg_addr])) return self.rh.read(count) class HDC1050: DEV_ADDR = 0x40 # 7bit REG_TEMP = 0x00 REG_HUMI = 0x01 REG_CONF = 0x02 def __init__(self, bus, dev_addr=DEV_ADDR): self.bus = bus self.dev_addr = dev_addr self.i2cbus = I2CBus(bus) def get_value(self): self.i2cbus.write(self.dev_addr, self.REG_TEMP) time.sleep(0.05) value = self.i2cbus.read(self.DEV_ADDR, 4) temp = struct.unpack('>H', bytes(value[0:2]))[0] temp = float(temp)/65536*165 - 40 humi = struct.unpack('>H', bytes(value[2:4]))[0] humi = float(humi)/65536*100 return { 'temp': temp, 'humi': humi } I2C_BUS = 0x1 # Raspberry Pi hdc1050 = HDC1050(I2C_BUS) value = hdc1050.get_value() print('TEMP: %.1f, HUMI: %.1f' % (value['temp'], value['humi'])) |
これを hdc1050.py
という名前で保存して実行すると次のように,温度と湿度が出力されます.
1 2 |
$ python hdc1050.py TEMP: 32.0, HUMI: 58.5 |
ライブラリ化
以上のコードをライブラリ化したものを下記に置いてます.
https://github.com/kimata/rasp-python
コメント
[…] そこで,『Raspberry Pi で温湿度センサ HDC1050 を使う』で作成した i2cbus モジュールを使って TSL2561 を制御するライブラリを作成してみました. […]