Skip to content

Commit f5335ba

Browse files
authored
Adds mqtt example (#68)
Adds mqtt example by @robmarkcole - see also: https://github.com/robmarkcole/rpi-enviro-mqtt
1 parent f19fbc1 commit f5335ba

File tree

2 files changed

+213
-0
lines changed

2 files changed

+213
-0
lines changed

examples/mqtt-all.py

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
"""
2+
Run mqtt broker on localhost: sudo apt-get install mosquitto mosquitto-clients
3+
4+
Example run: python3 mqtt-all.py --broker 192.168.1.164 --topic enviro
5+
"""
6+
#!/usr/bin/env python3
7+
8+
import argparse
9+
import ST7735
10+
import time
11+
from bme280 import BME280
12+
from pms5003 import PMS5003, ReadTimeoutError
13+
from enviroplus import gas
14+
15+
try:
16+
# Transitional fix for breaking change in LTR559
17+
from ltr559 import LTR559
18+
19+
ltr559 = LTR559()
20+
except ImportError:
21+
import ltr559
22+
23+
from subprocess import PIPE, Popen, check_output
24+
from PIL import Image, ImageDraw, ImageFont
25+
from fonts.ttf import RobotoMedium as UserFont
26+
import json
27+
28+
import paho.mqtt.client as mqtt
29+
import paho.mqtt.publish as publish
30+
31+
try:
32+
from smbus2 import SMBus
33+
except ImportError:
34+
from smbus import SMBus
35+
36+
37+
DEFAULT_MQTT_BROKER_IP = "localhost"
38+
DEFAULT_MQTT_BROKER_PORT = 1883
39+
DEFAULT_MQTT_TOPIC = "enviroplus"
40+
41+
# mqtt callbacks
42+
def on_connect(client, userdata, flags, rc):
43+
print(f"CONNACK received with code {rc}")
44+
if rc == 0:
45+
print("connected OK")
46+
else:
47+
print("Bad connection Returned code=", rc)
48+
49+
50+
def on_publish(client, userdata, mid):
51+
print("mid: " + str(mid))
52+
53+
54+
# Read values from BME280 and PMS5003 and return as dict
55+
def read_values(bme280, pms5003):
56+
# Compensation factor for temperature
57+
comp_factor = 2.25
58+
59+
values = {}
60+
cpu_temp = get_cpu_temperature()
61+
raw_temp = bme280.get_temperature() # float
62+
comp_temp = raw_temp - ((cpu_temp - raw_temp) / comp_factor)
63+
values["temperature"] = int(comp_temp)
64+
values["pressure"] = round(
65+
int(bme280.get_pressure() * 100), -1
66+
) # round to nearest 10
67+
values["humidity"] = int(bme280.get_humidity())
68+
try:
69+
pm_values = pms5003.read() # int
70+
values["pm1"] = pm_values.pm_ug_per_m3(1)
71+
values["pm25"] = pm_values.pm_ug_per_m3(2.5)
72+
values["pm10"] = pm_values.pm_ug_per_m3(10)
73+
except ReadTimeoutError:
74+
pms5003.reset()
75+
pm_values = pms5003.read()
76+
values["pm1"] = pm_values.pm_ug_per_m3(1)
77+
values["pm25"] = pm_values.pm_ug_per_m3(2.5)
78+
values["pm10"] = pm_values.pm_ug_per_m3(10)
79+
data = gas.read_all()
80+
values["oxidised"] = int(data.oxidising / 1000)
81+
values["reduced"] = int(data.reducing / 1000)
82+
values["nh3"] = int(data.nh3 / 1000)
83+
values["lux"] = int(ltr559.get_lux())
84+
return values
85+
86+
87+
# Get CPU temperature to use for compensation
88+
def get_cpu_temperature():
89+
process = Popen(["vcgencmd", "measure_temp"], stdout=PIPE, universal_newlines=True)
90+
output, _error = process.communicate()
91+
return float(output[output.index("=") + 1 : output.rindex("'")])
92+
93+
94+
# Get Raspberry Pi serial number to use as ID
95+
def get_serial_number():
96+
with open("/proc/cpuinfo", "r") as f:
97+
for line in f:
98+
if line[0:6] == "Serial":
99+
return line.split(":")[1].strip()
100+
101+
102+
# Check for Wi-Fi connection
103+
def check_wifi():
104+
if check_output(["hostname", "-I"]):
105+
return True
106+
else:
107+
return False
108+
109+
110+
# Display Raspberry Pi serial and Wi-Fi status on LCD
111+
def display_status(disp, mqtt_broker):
112+
# Width and height to calculate text position
113+
WIDTH = disp.width
114+
HEIGHT = disp.height
115+
# Text settings
116+
font_size = 16
117+
font = ImageFont.truetype(UserFont, font_size)
118+
119+
wifi_status = "connected" if check_wifi() else "disconnected"
120+
text_colour = (255, 255, 255)
121+
back_colour = (0, 170, 170) if check_wifi() else (85, 15, 15)
122+
id = get_serial_number()
123+
message = "{}\nWi-Fi: {}\nmqtt-broker: {}".format(id, wifi_status, mqtt_broker)
124+
img = Image.new("RGB", (WIDTH, HEIGHT), color=(0, 0, 0))
125+
draw = ImageDraw.Draw(img)
126+
size_x, size_y = draw.textsize(message, font)
127+
x = (WIDTH - size_x) / 2
128+
y = (HEIGHT / 2) - (size_y / 2)
129+
draw.rectangle((0, 0, 160, 80), back_colour)
130+
draw.text((x, y), message, font=font, fill=text_colour)
131+
disp.display(img)
132+
133+
134+
def main():
135+
parser = argparse.ArgumentParser(description="Publish enviroplus values over mqtt")
136+
parser.add_argument(
137+
"--broker", default=DEFAULT_MQTT_BROKER_IP, type=str, help="mqtt broker IP",
138+
)
139+
parser.add_argument(
140+
"--port", default=DEFAULT_MQTT_BROKER_PORT, type=int, help="mqtt broker port",
141+
)
142+
parser.add_argument(
143+
"--topic", default=DEFAULT_MQTT_TOPIC, type=str, help="mqtt topic"
144+
)
145+
args = parser.parse_args()
146+
147+
print(
148+
"""mqtt-all.py - Reads temperature, pressure, humidity,
149+
PM2.5, and PM10 from Enviro plus and sends data over mqtt.
150+
151+
broker: {}
152+
port: {}
153+
topic: {}
154+
155+
Press Ctrl+C to exit!
156+
157+
""".format(
158+
args.broker, args.port, args.topic
159+
)
160+
)
161+
162+
mqtt_client = mqtt.Client()
163+
mqtt_client.on_connect = on_connect
164+
mqtt_client.on_publish = on_publish
165+
mqtt_client.connect(args.broker, port=args.port)
166+
167+
bus = SMBus(1)
168+
169+
# Create BME280 instance
170+
bme280 = BME280(i2c_dev=bus)
171+
172+
# Create LCD instance
173+
disp = ST7735.ST7735(
174+
port=0, cs=1, dc=9, backlight=12, rotation=270, spi_speed_hz=10000000
175+
)
176+
177+
# Initialize display
178+
disp.begin()
179+
180+
# Create PMS5003 instance
181+
pms5003 = PMS5003()
182+
183+
# Raspberry Pi ID
184+
device_serial_number = get_serial_number()
185+
id = "raspi-" + device_serial_number
186+
187+
# Display Raspberry Pi serial and Wi-Fi status
188+
print("Raspberry Pi serial: {}".format(get_serial_number()))
189+
print("Wi-Fi: {}\n".format("connected" if check_wifi() else "disconnected"))
190+
print("MQTT broker IP: {}".format(args.broker))
191+
192+
time_since_update = 0
193+
update_time = time.time()
194+
195+
# Main loop to read data, display, and send over mqtt
196+
mqtt_client.loop_start()
197+
while True:
198+
try:
199+
time_since_update = time.time() - update_time
200+
values = read_values(bme280, pms5003)
201+
values["serial"] = device_serial_number
202+
print(values)
203+
mqtt_client.publish(args.topic, json.dumps(values))
204+
if time_since_update > 145:
205+
update_time = time.time()
206+
display_status(disp, args.broker)
207+
except Exception as e:
208+
print(e)
209+
210+
211+
if __name__ == "__main__":
212+
main()

library/setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ install_requires =
3838
astral
3939
pytz
4040
sounddevice
41+
paho-mqtt
4142

4243
[flake8]
4344
exclude =

0 commit comments

Comments
 (0)