Update all-in-one.py
[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():
87 process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE)
88 output, _error = process.communicate()
847937ac 89 output = output.decode()
9d2c6929
SM
90 return float(output[output.index('=') + 1:output.rindex("'")])
91
ec075941 92
9d2c6929
SM
93# Tuning factor for compensation. Decrease this number to adjust the
94# temperature down, and increase to adjust up
95factor = 0.8
96
97cpu_temps = [0] * 5
98
d7b32dab
SM
99delay = 0.5 # Debounce the proximity tap
100mode = 0 # The starting mode
101last_page = 0
102light = 1
103
104# Create a values dict to store the data
105variables = ["temperature",
106 "pressure",
107 "humidity",
108 "light",
109 "oxidised",
110 "reduced",
111 "nh3",
112 "pm1",
113 "pm25",
114 "pm10"]
115
116values = {}
117
118for v in variables:
119 values[v] = [1] * WIDTH
120
121# The main loop
122try:
123 while True:
124 proximity = ltr559.get_proximity()
125
126 # If the proximity crosses the threshold, toggle the mode
127 if proximity > 1500 and time.time() - last_page > delay:
128 mode += 1
129 mode %= len(variables)
130 last_page = time.time()
131
132 # One mode for each variable
133 if mode == 0:
134 variable = "temperature"
135 unit = "C"
9d2c6929
SM
136 cpu_temp = get_cpu_temperature()
137 # Smooth out with some averaging to decrease jitter
138 cpu_temps = cpu_temps[1:] + [cpu_temp]
139 avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
140 raw_temp = bme280.get_temperature()
141 data = raw_temp - ((avg_cpu_temp - raw_temp) / factor)
d7b32dab
SM
142 display_text(variable, data, unit)
143
144 if mode == 1:
145 variable = "pressure"
146 unit = "hPa"
147 data = bme280.get_pressure()
148 display_text(variable, data, unit)
149
150 if mode == 2:
151 variable = "humidity"
152 unit = "%"
153 data = bme280.get_humidity()
154 display_text(variable, data, unit)
155
156 if mode == 3:
157 variable = "light"
158 unit = "Lux"
159 if proximity < 10:
160 data = ltr559.get_lux()
161 else:
162 data = 1
163 display_text(variable, data, unit)
164
165 if mode == 4:
166 variable = "oxidised"
167 unit = "kO"
168 data = gas.read_all()
169 data = data.oxidising / 1000
170 display_text(variable, data, unit)
171
172 if mode == 5:
173 variable = "reduced"
174 unit = "kO"
175 data = gas.read_all()
176 data = data.reducing / 1000
177 display_text(variable, data, unit)
178
179 if mode == 6:
180 variable = "nh3"
181 unit = "kO"
182 data = gas.read_all()
183 data = data.nh3 / 1000
184 display_text(variable, data, unit)
185
186 if mode == 7:
187 variable = "pm1"
188 unit = "ug/m3"
189 data = pms5003.read()
190 data = data.pm_ug_per_m3(1.0)
191 display_text(variable, data, unit)
192
193 if mode == 8:
194 variable = "pm25"
195 unit = "ug/m3"
196 data = pms5003.read()
197 data = data.pm_ug_per_m3(2.5)
198 display_text(variable, data, unit)
199
200 if mode == 9:
201 variable = "pm10"
f86c4c6d 202 unit = "ug/m3"
d7b32dab
SM
203 data = pms5003.read()
204 data = data.pm_ug_per_m3(10)
205 display_text(variable, data, unit)
206
207# Exit cleanly
208except KeyboardInterrupt:
209 sys.exit(0)