catching the correct ReadTimeoutError for pms5003
[EVA-2020-02-2.git] / examples / all-in-one.py
1 #!/usr/bin/env python
2
3 import time
4 import colorsys
5 import os
6 import sys
7 import ST7735
8 import ltr559
9
10 from bme280 import BME280
11 from pms5003 import PMS5003, ReadTimeoutError as pmsReadTimeoutError
12 from enviroplus import gas
13 from subprocess import PIPE, Popen
14 from PIL import Image
15 from PIL import ImageDraw
16 from PIL import ImageFont
17
18 print("""all-in-one.py - Displays readings from all of Enviro plus' sensors
19
20 Press Ctrl+C to exit!
21
22 """)
23
24 # BME280 temperature/pressure/humidity sensor
25 bme280 = BME280()
26
27 # PMS5003 particulate sensor
28 pms5003 = PMS5003()
29
30 # Create ST7735 LCD display class
31 st7735 = 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
41 st7735.begin()
42
43 WIDTH = st7735.width
44 HEIGHT = st7735.height
45
46 # Set up canvas and font
47 img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
48 draw = ImageDraw.Draw(img)
49 path = os.path.dirname(os.path.realpath(__file__))
50 font = ImageFont.truetype(path + "/fonts/Asap/Asap-Bold.ttf", 20)
51
52 message = ""
53
54 # The position of the top bar
55 top_pos = 25
56
57
58 # Displays data and text on the 0.96" LCD
59 def 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
63 colours = [(v - min(values[variable]) + 1) / (max(values[variable])
64 - min(values[variable]) + 1) for v in values[variable]]
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
72 r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour,
73 1.0, 1.0)]
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
77 line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos)))\
78 + top_pos
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
84
85 # Get the temperature of the CPU for compensation
86 def get_cpu_temperature():
87 process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE, universal_newlines=True)
88 output, _error = process.communicate()
89 return float(output[output.index('=') + 1:output.rindex("'")])
90
91
92 # Tuning factor for compensation. Decrease this number to adjust the
93 # temperature down, and increase to adjust up
94 factor = 0.8
95
96 cpu_temps = [get_cpu_temperature()] * 5
97
98 delay = 0.5 # Debounce the proximity tap
99 mode = 0 # The starting mode
100 last_page = 0
101 light = 1
102
103 # Create a values dict to store the data
104 variables = ["temperature",
105 "pressure",
106 "humidity",
107 "light",
108 "oxidised",
109 "reduced",
110 "nh3",
111 "pm1",
112 "pm25",
113 "pm10"]
114
115 values = {}
116
117 for v in variables:
118 values[v] = [1] * WIDTH
119
120 # The main loop
121 try:
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:
133 # variable = "temperature"
134 unit = "C"
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)
141 display_text(variables[mode], data, unit)
142
143 if mode == 1:
144 # variable = "pressure"
145 unit = "hPa"
146 data = bme280.get_pressure()
147 display_text(variables[mode], data, unit)
148
149 if mode == 2:
150 # variable = "humidity"
151 unit = "%"
152 data = bme280.get_humidity()
153 display_text(variables[mode], data, unit)
154
155 if mode == 3:
156 # variable = "light"
157 unit = "Lux"
158 if proximity < 10:
159 data = ltr559.get_lux()
160 else:
161 data = 1
162 display_text(variables[mode], data, unit)
163
164 if mode == 4:
165 # variable = "oxidised"
166 unit = "kO"
167 data = gas.read_all()
168 data = data.oxidising / 1000
169 display_text(variables[mode], data, unit)
170
171 if mode == 5:
172 # variable = "reduced"
173 unit = "kO"
174 data = gas.read_all()
175 data = data.reducing / 1000
176 display_text(variables[mode], data, unit)
177
178 if mode == 6:
179 # variable = "nh3"
180 unit = "kO"
181 data = gas.read_all()
182 data = data.nh3 / 1000
183 display_text(variables[mode], data, unit)
184
185 if mode == 7:
186 # variable = "pm1"
187 unit = "ug/m3"
188 try:
189 data = pms5003.read()
190 except pmsReadTimeoutError:
191 pass
192 else:
193 data = data.pm_ug_per_m3(1.0)
194 display_text(variables[mode], data, unit)
195
196 if mode == 8:
197 # variable = "pm25"
198 unit = "ug/m3"
199 try:
200 data = pms5003.read()
201 except pmsReadTimeoutError:
202 pass
203 else:
204 data = data.pm_ug_per_m3(2.5)
205 display_text(variables[mode], data, unit)
206
207 if mode == 9:
208 # variable = "pm10"
209 unit = "ug/m3"
210 try:
211 data = pms5003.read()
212 except pmsReadTimeoutError:
213 pass
214 else:
215 data = data.pm_ug_per_m3(10)
216 display_text(variables[mode], data, unit)
217
218 # Exit cleanly
219 except KeyboardInterrupt:
220 sys.exit(0)