M5GO(M5Stack)でDHT12とBMP280の気温値を比較


概要

M5GOに付属する環境センサにはDHT12とBMP280が入っており、それぞれ気温と湿度、気温と気圧を測定することができます。サンプルプログラムでは気温はBMP280の方の値を取得(モジュール units 内)するようになっていますが、DHT12でも気温を取得して値を比較してみました。

  • MicroPythonで記述
  • DHT12で気温と湿度を取得
  • BMP280で気温と気圧を取得
  • Ambientへ送信してグラフ化

モジュール(dht12とbmp280)を確認すると取得値の精度は
- DHT12の気温値は小数点以下1桁まで
- BMP280の気温値は小数点以下2桁まで

準備

  • 以下からAmbientのPythonモジュール(ambient.py)を取得

  • 取得したをambient.pyをM5GOに転送

転送にはAdafruit MicroPython Tool (ampy)を使いました。

$ export AMPY_PORT=/dev/tty.SLAB_USBtoUART 
$ ampy put ambient.py /flash/ambient.py
  • Ambient側でチャネルを作成しチャネルIdとライトキーを取得
  • M5GO Cloudから下に貼ったMicroPythonプログラムを実行

結果

今回試した結果では、DHT12で取得した気温値が平均して0.4度程度高い値となりました。正確な温度計を持っていないので、どちらがより正しい値なのかは、わかりませんが。

  • M5GOの画面表示

  • Ambientの画面表示

プログラム

(修正:Ambientへ毎秒送ると制限に引っかかってしまうので、1分間隔で送るように修正しました)

from m5stack import lcd
import machine
import time
import units
import gc
import ambient

# 日本時間に同期
rtc = machine.RTC()
rtc.ntp_sync('ntp.nict.jp', tz='JST-9')
# M5GOのfirmwareがv0.11ではntp_syncでtzを指定するとエラーになるので以下で対応
# rtc.ntp_sync('ntp.nict.jp')
# sys.tz('JST-9')

# 同期が完了するまで100ms程度かかる
for i in range(100):
    if rtc.synced():
        print('synced.')
        break
    print(i, end=' ')
    time.sleep_ms(10)

lcd.font(lcd.FONT_DejaVu18)
lcd.clear()

lcd.print('DHT12',        10,  50)
lcd.print('humidity:',    30,  80)
lcd.print('temperature:', 30, 110)
lcd.print('BMP280',       10, 140)
lcd.print('temperature:', 30, 170)
lcd.print('pressure:',    30, 200)

env = units.ENV(units.PORTA)

# Ambientで取得したチャネルのチャネルId, ライトキーを指定
am = ambient.Ambient(チャネルId, ライトキー)

while True:
    #次の秒までの差分(ミリ秒)を求めてスリープ
    time.sleep_ms(1000 - int(time.time() % 1 * 1000))

    localtime = time.localtime()
    localtime_str = time.strftime('%Y-%m-%d %H:%M:%S', localtime)
    try:
        # DHT12 から気温と湿度を取得
        env.dht12.measure()
        d_h = env.dht12.humidity()
        d_t = env.dht12.temperature()

        # BMP280 から気温と気圧を取得
        b_t, b_p = env.bmp280.values

        lcd.print(localtime_str, 10, 10)
        # 表示桁数が減った時に(気圧が1000から999になった時)
        # 後ろを消すのに空白2個入れる
        lcd.print('{:.2f}%  '.format(d_h),   180,  80) # DHT12の湿度
        lcd.print('{:.2f}C  '.format(d_t),   180, 110) # DHT12の気温
        lcd.print('{:.2f}C  '.format(b_t),   180, 170) # BMP280の気温
        lcd.print('{:.2f}hPa  '.format(b_p), 180, 200) # BMP280の気圧

        # Ambientへの送信は1分間隔で行う。
        # localtime[5](秒) == 0 の時に送信
        if localtime[5] == 0:
            try:
                ar = am.send({'d1': d_t, 'd2': d_h, 'd3': b_t, 'd4': b_p})
            except Exception as e:
                print(localtime_str, ' ambient send error: ', e)

    except Exception as e:
        # 時々I2C bus error が起きる。
        # データを取得できなかった時は時刻を赤字で表示
        lcd.print(localtime_str, 10, 10, lcd.RED)
        print(localtime_str, ' Script Name: ', __name__)
        print('Exception: ', e)

    gc.collect()

おまけ(MPU6500)

M5GO には9軸センサーの MPU9250 が搭載されており、それに含まれる6軸センサーの MPU6500 にも温度センサーがあるので、そちらも試して見ました。M5GO の MicroPython に含まれる MPU6500 用のモジュールには温度取得用のメソッドが無いので、レジスターから直接取得し以下の計算式にて算出しました。

MPU-6500 Register Map and Descriptions
TEMP_degC = ((TEMP_OUT – RoomTemp_Offset)/Temp_Sensitivity) + 21degC
MPU-6500 Product Specification
Sensitivity: 333.87
Room Temp Offset: 0

m5go_temperature_test.py
import machine
import i2c_bus
from dht12   import DHT12
from bmp280  import BMP280
from mpu6500 import MPU6500

i2c = i2c_bus.get(i2c_bus.M_BUS)
dht12 = DHT12(i2c)
bmp280 = BMP280(i2c)
mpu6500 = MPU6500(i2c)

dht12.measure()
d_t = dht12.temperature()
b_t, _ = bmp280.values
m_t = mpu6500._register_short(0x41) / 333.87 + 21

print('Temperature')
print('DHT12:   {:.2f}'.format(d_t))
print('BMP280:  {:.2f}'.format(b_t))
print('MPU6500: {:.2f}'.format(m_t))

実行結果

$ ampy run m5go_temperature_test.py 
Temperature
DHT12:   29.50
BMP280:  28.66
MPU6500: 37.96

MPU9250 は M5GO に組み込まれているため、M5GO 自身の発熱の影響で高い値になるとは思うけど、継続的に測定してグラフ化するとDHT12/BMP280の変化と合っているので、取得値から算出するときの係数を見直せばそれなりにちゃんとした値になる?(DHT12/BMP280でところどころピクッと上がっているのはI2Cのエラーが発生してつなぎ直した時の影響)