Greetings,
I am trying to get a bme680 sensor to publish its readings to my homeassistant instance, using mqtt.
After much grinding of teeth, and pulling at what little hair I have remaining, I’ve got the following code so far:
#!/usr/bin/env python3
"""
Run mqtt broker on localhost: sudo apt-get install mosquitto mosquitto-clients
Example run: python3 mqtt-all.py --broker 192.168.1.164 --topic enviro --username xxx --password xxxx
"""
import argparse
import time
import ssl
import bme680
import json
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
try:
from smbus2 import SMBus
except ImportError:
from smbus import SMBus
# set up mqtt
DEFAULT_MQTT_BROKER_IP = "<-REMOVED FOR FORUM POST->"
DEFAULT_MQTT_BROKER_PORT = 1883
DEFAULT_MQTT_TOPIC = "envirobme680"
DEFAULT_READ_INTERVAL = 5
DEFAULT_TLS_MODE = False
DEFAULT_USERNAME = "<-REMOVED FOR FORUM POST->"
DEFAULT_PASSWORD = "<-REMOVED FOR FORUM POST->"
# mqtt callbacks
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("connected OK")
else:
print("Bad connection Returned code=", rc)
def on_publish(client, userdata, mid):
print("mid: " + str(mid))
# Get CPU temperature to use for compensation
def get_cpu_temperature():
process = Popen(
["vcgencmd", "measure_temp"], stdout=PIPE, universal_newlines=True
)
output, _error = process.communicate()
return float(output[output.index("=") + 1:output.rindex("'")])
# Get Raspberry Pi serial number to use as ID
def get_serial_number():
with open("/proc/cpuinfo", "r") as f:
for line in f:
if line[0:6] == "Serial":
return line.split(":")[1].strip()
def main():
parser = argparse.ArgumentParser(
description="Publish enviroplus values over mqtt"
)
parser.add_argument(
"--broker",
default=DEFAULT_MQTT_BROKER_IP,
type=str,
help="mqtt broker IP",
)
parser.add_argument(
"--port",
default=DEFAULT_MQTT_BROKER_PORT,
type=int,
help="mqtt broker port",
)
parser.add_argument(
"--topic", default=DEFAULT_MQTT_TOPIC, type=str, help="mqtt topic"
)
parser.add_argument(
"--interval",
default=DEFAULT_READ_INTERVAL,
type=int,
help="the read interval in seconds",
)
parser.add_argument(
"--tls",
default=DEFAULT_TLS_MODE,
action='store_true',
help="enable TLS"
)
parser.add_argument(
"--username",
default=DEFAULT_USERNAME,
type=str,
help="mqtt username"
)
parser.add_argument(
"--password",
default=DEFAULT_PASSWORD,
type=str,
help="mqtt password"
)
args = parser.parse_args()
# Raspberry Pi ID
device_serial_number = get_serial_number()
device_id = "raspi-" + device_serial_number
print(
f"""mqtt-all.py - Reads Enviro plus data and sends over mqtt.
broker: {args.broker}
client_id: {device_id}
port: {args.port}
topic: {args.topic}
tls: {args.tls}
username: {args.username}
password: {args.password}
Press Ctrl+C to exit!
"""
)
mqtt_client = mqtt.Client(client_id=device_id)
if args.username and args.password:
mqtt_client.username_pw_set(args.username, args.password)
mqtt_client.on_connect = on_connect
mqtt_client.on_publish = on_publish
if args.tls is True:
mqtt_client.tls_set(tls_version=ssl.PROTOCOL_TLSv1_2)
if args.username is not None:
mqtt_client.username_pw_set(args.username, password=args.password)
mqtt_client.connect(args.broker, port=args.port)
bus = SMBus(1)
# set up bme680 instance
sensor = bme680.BME680()
sensor.set_humidity_oversample(bme680.OS_2X)
sensor.set_pressure_oversample(bme680.OS_4X)
sensor.set_temperature_oversample(bme680.OS_8X)
sensor.set_filter(bme680.FILTER_SIZE_3)
sensor.set_gas_status(bme680.ENABLE_GAS_MEAS)
sensor.set_gas_heater_temperature(320)
sensor.set_gas_heater_duration(150)
sensor.select_gas_heater_profile(0)
# Main loop to read data, display, and send over mqtt
mqtt_client.loop_start()
while True:
try:
if sensor.get_sensor_data():
output = "T:{0:.1f} C, P:{1:.1f} hPa, H:{2:.1f} %".format(sensor.data.temperature / 2.33, sensor.data.pressure, sensor.data.humidity)
if sensor.data.heat_stable:
print(" {0}, Gas:{1:.1f} Ohms".format(output, sensor.data.gas_resistance))
else:
print(output)
mqtt_client.publish(args.topic, json.dumps(output))
mqtt_client.publish(args.topic)
display_status(disp, args.broker)
time.sleep(args.interval)
except Exception as e:
print(e)
time.sleep(1)
if __name__ == "__main__":
main()
Which does kind of do something interesting:
>>> %Run Enviro-mqtt-example-bme680-modded-v1.1.py
mqtt-all.py - Reads Enviro plus data and sends over mqtt.
broker: "<-REMOVED FOR FORUM POST->"
client_id: "<-REMOVED FOR FORUM POST->"
port: 1883
topic: envirobme680
tls: False
username: "<-REMOVED FOR FORUM POST->"
password: "<-REMOVED FOR FORUM POST->"
Press Ctrl+C to exit!
connected OK
local variable 'output' referenced before assignment
T:10.4 C, P:1021.6 hPa, H:59.2 %
mid: 1
mid: 2
T:10.4 C, P:1021.6 hPa, H:59.2 %, Gas:28219.7 Ohms
T:10.4 C, P:1021.6 hPa, H:59.1 %, Gas:27636.2 Ohms
T:10.5 C, P:1021.6 hPa, H:59.1 %, Gas:31961.8 Ohms
T:10.5 C, P:1021.6 hPa, H:59.0 %, Gas:35656.6 Ohms
T:10.5 C, P:1021.6 hPa, H:59.0 %, Gas:39136.8 Ohms
The readings are only received at the mqtt broker once. here is a snippet of whats being received at the other end:
Listen to a topic
Listening to
envirobme680
Message 1 received on envirobme680 at 12:04:
QoS: 0 - Retain: false
Message 0 received on envirobme680 at 12:04:
"T:10.8 C, P:1021.5 hPa, H:57.5 %"
QoS: 0 - Retain: false
No further messages are received. Only the first couple.
Is anyone able to assist me in getting this working, please? I’m a bit outside my comfort zone, and still very much a pythonic newbie!
Thanks for any help , I am genuinely very grateful.