Raspberry Pi 2のPythonを使いスイッチサイエンスが販売しているBME280の環境センサからデータを取れるようになりました。次はPahoのMQTTクライアントをインストールして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ブローカーの実装にはMosca、Mosquitto、Ponteなどいろいろあります。
またMeshbluのJavaScriptクライアントを使うと、データソースとして対応しているfreeboardでは直接ブラウザから、MQTTでpublishされたメッセージをWebScocket経由でsubscribeすることもできます。
PahoのMQTTクライアント
MQTTクライアントはPahoのpaho-mqttを使います。
$ pip install paho-mqtt
MQTTブローカーの設定は簡単にPythonのディクショナリに書いてimportしました。
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するだけです。
# !/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"}}