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