Raspberry Pi にI2C接続された環境センサ(BME280やBH1750)の計測値を、Python paho-mqtt クライアントを使って Home Assitant 内の MQTT ブローカーへパブリッシュ、ダッシュボードで表示できるようにします。
paho MQTT Python Clientの導入
今回MQTTクライアントをセットアップする、Raspberry Pi Model 1BのシステムとPythonの概要は、次の通り。
|
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 |
~ $ cat /proc/cpuinfo processor : 0 model name : ARMv6-compatible processor rev 7 (v6l) BogoMIPS : 797.66 Features : half thumb fastmult vfp edsp java tls CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xb76 CPU revision : 7 Hardware : BCM2835 Revision : 000e Serial : 00000000576d155e Model : Raspberry Pi Model B Rev 2 ~ $ lsb_release -a Distributor ID: Raspbian Description: Raspbian GNU/Linux 11 (bullseye) Release: 11 Codename: bullseye ~ $ df -h Filesystem Size Used Avail Use% Mounted on /dev/root 15G 3.8G 11G 27% / devtmpfs 183M 0 183M 0% /dev tmpfs 215M 4.0K 215M 1% /dev/shm tmpfs 86M 1.5M 85M 2% /run tmpfs 5.0M 0 5.0M 0% /run/lock /dev/mmcblk0p1 253M 50M 203M 20% /boot tmpfs 43M 0 43M 0% /run/user/1000 ~ $ free -h total used free shared buff/cache available Mem: 429Mi 66Mi 23Mi 1.0Mi 339Mi 307Mi Swap: 0B 0B 0B ~ $ python --version Python 3.9.2 ~ $ python2 --version -bash: python2: command not found |
まず、pipパッケージマネージャで、paho-mqttパッケージをインストールします。
|
1 2 3 4 5 6 7 |
~ $ pip3 install paho-mqtt Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple Collecting paho-mqtt Downloading https://www.piwheels.org/simple/paho-mqtt/paho_mqtt-1.6.1-py3-none-any.whl (75 kB) |████████████████████████████████| 75 kB 45 kB/s Installing collected packages: paho-mqtt Successfully installed paho-mqtt-1.6.1 |
ワンライナー一発パブリッシュをテスト
上述のプロジェクトページ下方に記載されている様々な実行方法のうち、 one-shot manner を謳うPublishモジュールを利用してみましょう。
前回構築した、Home Assistant MQTTブローカーの情報をセットし、例に沿って publish.multiple させます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#!/usr/bin/python3 # -*- coding: utf-8 -*- import paho.mqtt.publish as publish broker = '192.168.51.8' port = 1883 username = 'mqtt-user' password = 'mqtt' # default: qos=0, retain=false pref = "home/piaware2/" msgs = [ {'topic':pref+"Lux1", 'payload':"111"}, (pref+"Lux2", "222")] publish.multiple(msgs, hostname=broker, port=port, auth={'username':username, 'password':password}) |
Home Assistant MQTTブローカー側で、トピックのリッスン機能でメッセージを受信できました。
2組の辞書型計測値をまとめてパブリッシュ
このRaspberry Piに繋いでいるのは、I2Cアドレス違いにした2組のBME280温湿度気圧センサ、BH1750照度センサペアです。
当時の記事にあるように、センサ計測からThingSpeak送信までを担うPythonスクリプトでは、計測値を以下の辞書型データに収めるようにしてありました。
|
1 2 |
data1 = {'Temp':'0', 'Humid':'0', 'PressRaw':'0', 'PressZero':'0', 'Lux':'0'} data2 = {'Temp':'0', 'Humid':'0', 'PressRaw':'0', 'PressZero':'0', 'Lux':'0'} |
tmpfs に上書き出力している実行結果は、このようになっています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
~ $ cat /tmp/ssr_upload -- Data -- DataSet1 : {"Temp": 29.1849609375, "Humid": 70.92466067498252, "PressRaw": 1009.4094628725757, "PressZero": 1017.9685485841861, "Lux": 1059.1666666666667} DataSet2 : {"Temp": 28.598046875, "Humid": 100, "PressRaw": 1010.3089286319575, "PressZero": 1018.8923038401665, "Lux": 1046.6666666666667} CPU Temp = 59.99 deg C Illumi1 = 1059.17 lux Illumi2 = 1046.67 lux Temp1 = 29.18 deg C Temp2 = 28.60 deg C Humidity1 = 70.92 % Humidity2 = 100.00 % Pressure1 = 1009.41 hPa Pressure2 = 1010.31 hPa PressureZ1 = 1017.97 hPa PressureZ2 = 1018.89 hPa -- ThingSpeak -- <Response [200]> |
今回はこの2個の辞書型データを1つにまとめ、JSON型へ変換したものをパブリッシュすれば良いはず。
ダミー計測値データを貼り付けて、次のようなPythonスクリプトを組んでみました。既存のスクリプトへ織り込みやすいよう、関数化しています。
|
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 |
#!/usr/bin/python3 # -*- coding: utf-8 -*- import json import paho.mqtt.publish as publish def pubmqtt(dts): broker = '192.168.51.8' port = 1883 username = 'mqtt-user' password = 'mqtt' # default: qos=0, retain=false topic = "home/piaware2/sensors" msgs = [{'topic': topic, 'payload': json.dumps(dts)}] try: publish.multiple(msgs, hostname=broker, port=port, auth={'username':username, 'password':password}) except Exception as e: print ('MQTT Publish Failed:') print (e) else: print ('MQTT Published Properly') ## MAIN ## data1 = {"Temp": 29.1849609375, "Humid": 70.92466067498252, "PressRaw": 1009.4094628725757, "PressZero": 1017.9685485841861, "Lux": 1059.1666666666667} data2 = {"Temp": 28.598046875, "Humid": 100, "PressRaw": 1010.3089286319575, "PressZero": 1018.8923038401665, "Lux": 1046.6666666666667} #Joint Dict Datas Dim.2x5 datas = [data1, data2] #json.dumps(datas) pubmqtt(datas) |
Home Assistant側では、JSONオブジェクトの塊を受信することができました。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[ { "Temp": 29.40390625, "Humid": 69.92781488628356, "PressRaw": 1007.7369980862717, "PressZero": 1016.2757188855574, "Lux": 686.6666666666667 }, { "Temp": 28.81328125, "Humid": 99.00228393235851, "PressRaw": 1008.6549681486046, "PressZero": 1017.2181835810061, "Lux": 679.1666666666667 } ] |
既存のスクリプトへの織り込み
これを既存のスクリプトへ組み込んだ全体像は、以下の通りです。
|
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
#!/usr/bin/python3 # -*- coding: utf-8 -*- import json, requests, time, smbus, board from adafruit_bme280 import basic as adafruit_bme280 from datetime import datetime as dt import paho.mqtt.publish as publish ## DEVICE KEY ts_key = "################" ## ALTITUDE altitude = 75 data1 = {'Temp':'0', 'Humid':'0', 'PressRaw':'0', 'PressZero':'0', 'Lux':'0'} data2 = {'Temp':'0', 'Humid':'0', 'PressRaw':'0', 'PressZero':'0', 'Lux':'0'} def setDatum(sen, dat): dat['Temp'] = sen.temperature dat['Humid'] = sen.relative_humidity dat['PressRaw'] = sen.pressure if dat['Temp'] != 0 and dat['PressRaw'] != 0: dat['PressZero'] = dat['PressRaw'] + (dat['PressRaw'] * 9.81 * altitude) / (287 * (273.15 + dat['Temp'])) else: dat['PressZero'] = 0 def get_CPUtemp(): f = open("/sys/class/thermal/thermal_zone0/temp","r") tmp = 0 for t in f: tmp = t[:2]+"."+t[2:5] f.close() return float(tmp) def get_Lux(addr): bus = smbus.SMBus(1) lux = bus.read_i2c_block_data(addr,0x10) return (lux[0]*256+lux[1])/1.2 class ThingSpeak: def __init__(self,apiKey): self.apiKey = apiKey def regist(self): request = "field1=" + str(round(data1['Temp'],2)) + \ "&field2=" + str(round(data2['Temp'],2)) + \ "&field3=" + str(round(data1['Humid'],2)) + \ "&field4=" + str(round(data2['Humid'],2)) + \ "&field5=" + str(round(data1['PressZero'],2)) + \ "&field6=" + str(round(data2['PressZero'],2)) + \ "&field7=" + str(round(data1['Lux'],2)) + \ "&field8=" + str(round(data2['Lux'],2)) # "&field8=" + str(round(cputemp,2)) url = "https://api.thingspeak.com/update?key=" + self.apiKey headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"} res = requests.post(url, headers=headers, data=request) print (res) return res def pubmqtt(dts): broker = '192.168.51.8' port = 1883 username = 'mqtt-user' password = 'mqtt' # default: qos=0, retain=false topic = "home/piaware2/sensors" msgs = [{'topic': topic, 'payload': json.dumps(dts)}] try: publish.multiple(msgs, hostname=broker, port=port, auth={'username':username, 'password':password}) except Exception as e: print ('MQTT Publish Failed:') print (e) else: print ('MQTT Published Properly') ## MAIN ## #BME280 i2c = board.I2C() try: sensor1 = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x76) setDatum(sensor1, data1) except: print ("BME280#1 Failure") data1['Temp'] = data1['Humid'] = data1['PressRaw'] = data1['PressZero'] = 0 time.sleep(1) try: sensor2 = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x77) setDatum(sensor2, data2) except: print ("BME280#2 Failure") data2['Temp'] = data2['Humid'] = data2['PressRaw'] = data2['PressZero'] = 0 #BH1750 time.sleep(1) try: data1['Lux'] = get_Lux(addr=0x23) except: print ("BH1750#1 Failure") data1['Lux'] = 0 time.sleep(1) try: data2['Lux'] = get_Lux(addr=0x5c) except: print ("BH1750#2 Failure") data2['Lux'] = 0 #CPU_TEMP cputemp = get_CPUtemp() print (dt.now().strftime('[%Y/%m/%d %H:%M:%S]')) print ('-- Data --') #print ('DataSet1 : ' + json.dumps(data1)) #print ('DataSet2 : ' + json.dumps(data2)) print ('CPU Temp = {0:0.2f} deg C'.format(cputemp)) print ('Illumi1 = {0:0.2f} lux'.format(data1['Lux'])) print ('Illumi2 = {0:0.2f} lux'.format(data2['Lux'])) print ('Temp1 = {0:0.2f} deg C'.format(data1['Temp'])) print ('Temp2 = {0:0.2f} deg C'.format(data2['Temp'])) print ('Humidity1 = {0:0.2f} %'.format(data1['Humid'])) print ('Humidity2 = {0:0.2f} %'.format(data2['Humid'])) print ('Pressure1 = {0:0.2f} hPa'.format(data1['PressRaw'])) print ('Pressure2 = {0:0.2f} hPa'.format(data2['PressRaw'])) print ('PressureZ1 = {0:0.2f} hPa'.format(data1['PressZero'])) print ('PressureZ2 = {0:0.2f} hPa'.format(data2['PressZero'])) print ('-- ThingSpeak --') thingDevice = ThingSpeak(ts_key) thingDevice.regist() print ('-- MQTT --') #MQTT datas = [data1, data2] pubmqtt(datas) print ('Process End') |
実行結果を確認。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
~ $ cat /tmp/ssr_upload [2024/02/28 16:40:19] -- Data -- CPU Temp = 55.69 deg C Illumi1 = 93.33 lux Illumi2 = 94.17 lux Temp1 = 24.94 deg C Temp2 = 24.24 deg C Humidity1 = 64.50 % Humidity2 = 86.34 % Pressure1 = 1007.52 hPa Pressure2 = 1008.39 hPa PressureZ1 = 1016.19 hPa PressureZ2 = 1017.08 hPa -- ThingSpeak -- <Response [200]> -- MQTT -- MQTT Published Properly Process End |
これで、Python paho MQTT Clientによるパブリッシュは実現できたので、次ページではHome Assistant側の受信データ処理へ進みます。





