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