RaspberryPi
mqtt
IoT
Meshblu
BME280

Raspberry Pi 2からBME280環境センサのデータをPythonでMQTT publishする

More than 3 years have passed since last update.

Raspberry Pi 2のPythonを使いスイッチサイエンスが販売しているBME280の環境センサからデータを取れるようになりました。次はPahoMQTTクライアントをインストールしてpublishしてみます。MQTTブローカー側はMeshbluをクラウド上にインストールして使います。Meshbluを使うとMQTTやHTTP REST、WebSocketなど複数のプロトコル間でメッセージをブリッジできるのでいろいろと楽しむことができます。

プロジェクト

Raspberry Pi 2は本格的なプログラミングを書くのは不向きですが、この程度のコードでしたら直接vimで書いてしまいます。Raspberry Pi 2にログインして適当なディレクトリにプロジェクトを作成します。今回作成したリポジトリはこちらです。最終的にディレクトリは以下のようになります。

$ cd ~/python_apps/bme280
$ tree
.
├── bme280_publish.py
├── bme280.py
├── config.py
└── README.md

Pythonライブラリをスイッチサイエンスのリポジトリからダウンロードして使います。

$ cd ~/python_apps/bme280
$ wget https://raw.githubusercontent.com/SWITCHSCIENCE/BME280/master/Python27/bme280_sample.py

MQTT

MeshbluのMQTTブローカー

私の場合MeshbluのMQTTブローカーを使っています。MeshbluはIoT向けのメッセージングプラットフォームです。MQTTの他にHTTP REST、WebSocket、CoAPなど複数のプロトコルに対応し、相互にブリッジが可能です。MeshbluはNode.jsで書かれているので、MQTTブローカーの実装もNode.jsのMoscaを使っています。今回はMeshbluを使いますが、オープンソースのMQTTブローカーの実装にはMoscaMosquittoPonteなどいろいろあります。

またMeshbluのJavaScriptクライアントを使うと、データソースとして対応しているfreeboardでは直接ブラウザから、MQTTでpublishされたメッセージをWebScocket経由でsubscribeすることもできます。

PahoのMQTTクライアント

MQTTクライアントはPahopaho-mqttを使います。

$ pip install paho-mqtt

MQTTブローカーの設定は簡単にPythonのディクショナリに書いてimportしました。

~/python_apps/bme280-meshblu-py/config.py
conf = {
     "MESHBLU_URL": "xxx.xxx.xxx.xxx",
     "MESHBLU_USER": "5abcfad1-9129-4f4f-b946-cabb6ecd9f6a",
     "MESHBLU_PASSWORD": "d8b721ed",
     "SEND_TO": "28cbe216-1c1c-477a-bbd5-5ee81d30ba02"
}

サンプルコード

bme280_sample.pyはBME280から取得した環境データを標準出力するサンプルです。MQTTクライアントのプログラムからimportして使うように少しプログラムを修正します。

bme280.py

bme280_sample.pyをコピーしてbme280.pyを作成して編集します。修正箇所は以下です。関数内で標準出力をしているところをreturnして、エントリポイントでJSONにして返すだけです。

@@ -66,9 +66,12 @@
    temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
    hum_raw  = (data[6] << 8)  |  data[7]

-   compensate_T(temp_raw)
-   compensate_P(pres_raw)
-   compensate_H(hum_raw)
+   temperature = compensate_T(temp_raw)
+   pressure = compensate_P(pres_raw)
+   humidity = compensate_H(hum_raw)
+        return dict(temperature=temperature,
+                    pressure=pressure,
+                    humidity=humidity)

 def compensate_P(adc_P):
    global  t_fine
@@ -92,7 +95,8 @@
    v2 = ((pressure / 4.0) * digP[7]) / 8192.0
    pressure = pressure + ((v1 + v2 + digP[6]) / 16.0)  

-   print "pressure : %7.2f hPa" % (pressure/100)
+   #print "pressure : %7.2f hPa" % (pressure/100)
+        return "{:.2f}".format(pressure/100)

 def compensate_T(adc_T):
    global t_fine
@@ -100,7 +104,8 @@
    v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2]
    t_fine = v1 + v2
    temperature = t_fine / 5120.0
-   print "temp : %-6.2f ℃" % (temperature) 
+   #print "temp : %-6.2f ℃" % (temperature) 
+        return "{:.2f}".format(temperature)

 def compensate_H(adc_H):
    global t_fine
@@ -114,8 +119,8 @@
        var_h = 100.0
    elif var_h < 0.0:
        var_h = 0.0
-   print "hum : %6.2f %" % (var_h)
-
+   #print "hum : %6.2f %" % (var_h)
+        return "{:.2f}".format(var_h)

 def setup():
    osrs_t = 1          #Temperature oversampling x 1

bme280_publish.py

MQTTクライアントを使うメインプログラムを実装します。スイッチサイエンスさんのbme280_sample.pyをライブラリ用に修正したbme280と、paho-mqttをimportして使います。5秒間隔で環境データを計測してJSONにフォーマット後、MQTTブローカーにpublishするだけです。

~/python_apps/bme280-meshblu-py/bme280_publish.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import paho.mqtt.client as mqtt
from time import sleep
import json
import sys
import bme280
from config import conf

def sensing():
    return bme280.readData()

def on_connect(client, userdata, rc):
    print("Connected with result code {}".format(rc))

def on_publish(client, userdata, mid):
    print("publish: {}".format(mid))

def main():
    client = mqtt.Client(client_id='',
                     clean_session=True, protocol=mqtt.MQTTv311)

    client.username_pw_set(conf["MESHBLU_USER"], conf["MESHBLU_PASSWORD"])
    client.on_connect = on_connect
    client.on_publish = on_publish

    client.connect(conf["MESHBLU_URL"], 1883, 60)

    while True:
        retval = sensing()
        if retval:
             message = json.dumps({"devices":
                          conf["SEND_TO"],
                              "payload": retval})
             print(message)
             client.publish("message",message)
        sleep(5)

if __name__ == '__main__':
    main()

今回はMeshbluをMQTTブローカーに使っているため、messageのフォーマットが決まっています。他のMQTTブローカーを使うときはpayloadだけで構いません。またdevicesのキーに宛先を指定して、topic名はmessageを固定で使う仕様になっています。

{"payload": {"pressure": "999.56", "temperature": "28.94", "humidity": "59.14"}, 
 "devices": "28cbe216-1c1c-477a-bbd5-5ee81d30ba02"}

テスト

MQTT subscribe

MQTTのクライアントは、MQTTブローカーのホストにMosquittoのクライアントをインストールします。

$ sudo apt-get install mosquitto_client

mosquitto_subコマンドを使ってsubscribeします。こちらもMeshbluの仕様なのでtopic名やユーザー名はMQTTブローカーの仕様に合わせて使います。

$ mosquitto_sub \
  -h localhost \
  -p 1883 \
  -t 28cbe216-1c1c-477a-bbd5-5ee81d30ba02 \
  -u 28cbe216-1c1c-477a-bbd5-5ee81d30ba02 \
  -P 9e7cbe84 \
  -d
Received CONNACK
Received SUBACK
Subscribed (mid: 1): 0

MQTT publish

Raspberry Pi 2に戻り、作成したbme280_publish.pyをsudoで実行します。piユーザーをi2cグループに追加している場合はsudoは不要です。

$ sudo ./bme280_publish.py
{"payload": {"pressure": "999.96", "temperature": "28.79", "humidity": "58.76"}, "devices": "28cbe216-1c1c-477a-bbd5-5ee81d30ba02"}
publish: 1
{"payload": {"pressure": "999.97", "temperature": "28.74", "humidity": "58.07"}, "devices": "28cbe216-1c1c-477a-bbd5-5ee81d30ba02"}
publish: 2

5秒間隔でBME280から取得した環境データをMQTTブローカーにpublishし始めました。

再びMQTTブローカーのホストに戻ると、mosquitto_subコマンドを実行しているシェルにメッセージが標準出力されました。

...
Subscribed (mid: 1): 0
Received PUBLISH (d0, q0, r0, m0, '28cbe216-1c1c-477a-bbd5-5ee81d30ba02', ... (71 bytes))
{"data":{"pressure":"999.97","temperature":"28.74","humidity":"58.07"}}
Received PUBLISH (d0, q0, r0, m0, '28cbe216-1c1c-477a-bbd5-5ee81d30ba02', ... (71 bytes))
{"data":{"pressure":"999.97","temperature":"28.74","humidity":"58.07"}}