use generic variables; handle pms5003.ReadTimeoutError
[EVA-2020-02-2.git] / examples / all-in-one.py
CommitLineData
d7b32dab
SM
1#!/usr/bin/env python
2
3import time
4import colorsys
5import os
6import sys
7import ST7735
8import ltr559
9
10from bme280 import BME280
11from pms5003 import PMS5003
12from enviroplus import gas
9d2c6929 13from subprocess import PIPE, Popen
d7b32dab
SM
14from PIL import Image
15from PIL import ImageDraw
16from PIL import ImageFont
17
18print("""all-in-one.py - Displays readings from all of Enviro plus' sensors
19
20Press Ctrl+C to exit!
21
22""")
23
24# BME280 temperature/pressure/humidity sensor
25bme280 = BME280()
26
27# PMS5003 particulate sensor
28pms5003 = PMS5003()
29
30# Create ST7735 LCD display class
31st7735 = ST7735.ST7735(
32 port=0,
33 cs=1,
34 dc=9,
35 backlight=12,
36 rotation=270,
37 spi_speed_hz=10000000
38)
39
40# Initialize display
41st7735.begin()
42
43WIDTH = st7735.width
44HEIGHT = st7735.height
45
46# Set up canvas and font
47img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
48draw = ImageDraw.Draw(img)
49path = os.path.dirname(os.path.realpath(__file__))
50font = ImageFont.truetype(path + "/fonts/Asap/Asap-Bold.ttf", 20)
51
52message = ""
53
54# The position of the top bar
55top_pos = 25
56
ec075941 57
d7b32dab
SM
58# Displays data and text on the 0.96" LCD
59def display_text(variable, data, unit):
60 # Maintain length of list
61 values[variable] = values[variable][1:] + [data]
62 # Scale the values for the variable between 0 and 1
ec075941
SM
63 colours = [(v - min(values[variable]) + 1) / (max(values[variable])
64 - min(values[variable]) + 1) for v in values[variable]]
d7b32dab
SM
65 # Format the variable name and value
66 message = "{}: {:.1f} {}".format(variable[:4], data, unit)
67 print(message)
68 draw.rectangle((0, 0, WIDTH, HEIGHT), (255, 255, 255))
69 for i in range(len(colours)):
70 # Convert the values to colours from red to blue
71 colour = (1.0 - colours[i]) * 0.6
ec075941
SM
72 r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour,
73 1.0, 1.0)]
d7b32dab
SM
74 # Draw a 1-pixel wide rectangle of colour
75 draw.rectangle((i, top_pos, i+1, HEIGHT), (r, g, b))
76 # Draw a line graph in black
ec075941
SM
77 line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos)))\
78 + top_pos
d7b32dab
SM
79 draw.rectangle((i, line_y, i+1, line_y+1), (0, 0, 0))
80 # Write the text at the top in black
81 draw.text((0, 0), message, font=font, fill=(0, 0, 0))
82 st7735.display(img)
83
ec075941 84
9d2c6929
SM
85# Get the temperature of the CPU for compensation
86def get_cpu_temperature():
e2d010e2 87 process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE, universal_newlines=True)
9d2c6929
SM
88 output, _error = process.communicate()
89 return float(output[output.index('=') + 1:output.rindex("'")])
90
ec075941 91
9d2c6929
SM
92# Tuning factor for compensation. Decrease this number to adjust the
93# temperature down, and increase to adjust up
94factor = 0.8
95
27156d25 96cpu_temps = [get_cpu_temperature()] * 5
9d2c6929 97
d7b32dab
SM
98delay = 0.5 # Debounce the proximity tap
99mode = 0 # The starting mode
100last_page = 0
101light = 1
102
103# Create a values dict to store the data
104variables = ["temperature",
105 "pressure",
106 "humidity",
107 "light",
108 "oxidised",
109 "reduced",
110 "nh3",
111 "pm1",
112 "pm25",
113 "pm10"]
114
115values = {}
116
117for v in variables:
118 values[v] = [1] * WIDTH
119
120# The main loop
121try:
122 while True:
123 proximity = ltr559.get_proximity()
124
125 # If the proximity crosses the threshold, toggle the mode
126 if proximity > 1500 and time.time() - last_page > delay:
127 mode += 1
128 mode %= len(variables)
129 last_page = time.time()
130
131 # One mode for each variable
132 if mode == 0:
e8fa1c06 133 # variable = "temperature"
d7b32dab 134 unit = "C"
9d2c6929
SM
135 cpu_temp = get_cpu_temperature()
136 # Smooth out with some averaging to decrease jitter
137 cpu_temps = cpu_temps[1:] + [cpu_temp]
138 avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
139 raw_temp = bme280.get_temperature()
140 data = raw_temp - ((avg_cpu_temp - raw_temp) / factor)
e8fa1c06 141 display_text(variables[mode], data, unit)
d7b32dab
SM
142
143 if mode == 1:
e8fa1c06 144 # variable = "pressure"
d7b32dab
SM
145 unit = "hPa"
146 data = bme280.get_pressure()
e8fa1c06 147 display_text(variables[mode], data, unit)
d7b32dab
SM
148
149 if mode == 2:
e8fa1c06 150 # variable = "humidity"
d7b32dab
SM
151 unit = "%"
152 data = bme280.get_humidity()
e8fa1c06 153 display_text(variables[mode], data, unit)
d7b32dab
SM
154
155 if mode == 3:
e8fa1c06 156 # variable = "light"
d7b32dab
SM
157 unit = "Lux"
158 if proximity < 10:
159 data = ltr559.get_lux()
160 else:
161 data = 1
e8fa1c06 162 display_text(variables[mode], data, unit)
d7b32dab
SM
163
164 if mode == 4:
e8fa1c06 165 # variable = "oxidised"
d7b32dab
SM
166 unit = "kO"
167 data = gas.read_all()
168 data = data.oxidising / 1000
e8fa1c06 169 display_text(variables[mode], data, unit)
d7b32dab
SM
170
171 if mode == 5:
e8fa1c06 172 # variable = "reduced"
d7b32dab
SM
173 unit = "kO"
174 data = gas.read_all()
175 data = data.reducing / 1000
e8fa1c06 176 display_text(variables[mode], data, unit)
d7b32dab
SM
177
178 if mode == 6:
e8fa1c06 179 # variable = "nh3"
d7b32dab
SM
180 unit = "kO"
181 data = gas.read_all()
182 data = data.nh3 / 1000
e8fa1c06 183 display_text(variables[mode], data, unit)
d7b32dab
SM
184
185 if mode == 7:
e8fa1c06 186 #variable = "pm1"
d7b32dab 187 unit = "ug/m3"
e8fa1c06
CM
188 try:
189 data = pms5003.read()
190 except pms5003.ReadTimeoutError:
191 pass
192 else:
193 data = data.pm_ug_per_m3(1.0)
194 display_text(variables[mode], data, unit)
d7b32dab
SM
195
196 if mode == 8:
e8fa1c06 197 # variable = "pm25"
d7b32dab
SM
198 unit = "ug/m3"
199 data = pms5003.read()
200 data = data.pm_ug_per_m3(2.5)
e8fa1c06 201 display_text(variables[mode], data, unit)
d7b32dab
SM
202
203 if mode == 9:
e8fa1c06 204 # variable = "pm10"
f86c4c6d 205 unit = "ug/m3"
d7b32dab
SM
206 data = pms5003.read()
207 data = data.pm_ug_per_m3(10)
e8fa1c06 208 display_text(variables[mode], data, unit)
d7b32dab
SM
209
210# Exit cleanly
211except KeyboardInterrupt:
212 sys.exit(0)