Merge pull request #54 from spincrisis/patch-1
[EVA-2020-02-2.git] / examples / all-in-one-no-pm.py
1 #!/usr/bin/env python3
2
3 import time
4 import colorsys
5 import os
6 import sys
7 import ST7735
8 try:
9 # Transitional fix for breaking change in LTR559
10 from ltr559 import LTR559
11 ltr559 = LTR559()
12 except ImportError:
13 import ltr559
14
15 from bme280 import BME280
16 from enviroplus import gas
17 from subprocess import PIPE, Popen
18 from PIL import Image
19 from PIL import ImageDraw
20 from PIL import ImageFont
21 from fonts.ttf import RobotoMedium as UserFont
22 import logging
23
24 logging.basicConfig(
25 format='%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s',
26 level=logging.INFO,
27 datefmt='%Y-%m-%d %H:%M:%S')
28
29 logging.info("""all-in-one.py - Displays readings from all of Enviro plus' sensors
30 Press Ctrl+C to exit!
31 """)
32
33 # BME280 temperature/pressure/humidity sensor
34 bme280 = BME280()
35
36 # Create ST7735 LCD display class
37 st7735 = 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
47 st7735.begin()
48
49 WIDTH = st7735.width
50 HEIGHT = st7735.height
51
52 # Set up canvas and font
53 img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
54 draw = ImageDraw.Draw(img)
55 path = os.path.dirname(os.path.realpath(__file__))
56 font_size = 20
57 font = ImageFont.truetype(UserFont, font_size)
58
59 message = ""
60
61 # The position of the top bar
62 top_pos = 25
63
64
65 # Displays data and text on the 0.96" LCD
66 def display_text(variable, data, unit):
67 # Maintain length of list
68 values[variable] = values[variable][1:] + [data]
69 # Scale the values for the variable between 0 and 1
70 colours = [(v - min(values[variable]) + 1) / (max(values[variable])
71 - min(values[variable]) + 1) for v in values[variable]]
72 # Format the variable name and value
73 message = "{}: {:.1f} {}".format(variable[:4], data, unit)
74 logging.info(message)
75 draw.rectangle((0, 0, WIDTH, HEIGHT), (255, 255, 255))
76 for i in range(len(colours)):
77 # Convert the values to colours from red to blue
78 colour = (1.0 - colours[i]) * 0.6
79 r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour,
80 1.0, 1.0)]
81 # Draw a 1-pixel wide rectangle of colour
82 draw.rectangle((i, top_pos, i+1, HEIGHT), (r, g, b))
83 # Draw a line graph in black
84 line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos)))\
85 + top_pos
86 draw.rectangle((i, line_y, i+1, line_y+1), (0, 0, 0))
87 # Write the text at the top in black
88 draw.text((0, 0), message, font=font, fill=(0, 0, 0))
89 st7735.display(img)
90
91
92 # Get the temperature of the CPU for compensation
93 def get_cpu_temperature():
94 process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE, universal_newlines=True)
95 output, _error = process.communicate()
96 return float(output[output.index('=') + 1:output.rindex("'")])
97
98
99 # Tuning factor for compensation. Decrease this number to adjust the
100 # temperature down, and increase to adjust up
101 factor = 2.25
102
103 cpu_temps = [get_cpu_temperature()] * 5
104
105 delay = 0.5 # Debounce the proximity tap
106 mode = 0 # The starting mode
107 last_page = 0
108 light = 1
109
110 # Create a values dict to store the data
111 variables = ["temperature",
112 "pressure",
113 "humidity",
114 "light",
115 "oxidised",
116 "reduced",
117 "nh3"]
118
119 values = {}
120
121 for v in variables:
122 values[v] = [1] * WIDTH
123
124 # The main loop
125 try:
126 while True:
127 proximity = ltr559.get_proximity()
128
129 # If the proximity crosses the threshold, toggle the mode
130 if proximity > 1500 and time.time() - last_page > delay:
131 mode += 1
132 mode %= len(variables)
133 last_page = time.time()
134
135 # One mode for each variable
136 if mode == 0:
137 # variable = "temperature"
138 unit = "C"
139 cpu_temp = get_cpu_temperature()
140 # Smooth out with some averaging to decrease jitter
141 cpu_temps = cpu_temps[1:] + [cpu_temp]
142 avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
143 raw_temp = bme280.get_temperature()
144 data = raw_temp - ((avg_cpu_temp - raw_temp) / factor)
145 display_text(variables[mode], data, unit)
146
147 if mode == 1:
148 # variable = "pressure"
149 unit = "hPa"
150 data = bme280.get_pressure()
151 display_text(variables[mode], data, unit)
152
153 if mode == 2:
154 # variable = "humidity"
155 unit = "%"
156 data = bme280.get_humidity()
157 display_text(variables[mode], data, unit)
158
159 if mode == 3:
160 # variable = "light"
161 unit = "Lux"
162 if proximity < 10:
163 data = ltr559.get_lux()
164 else:
165 data = 1
166 display_text(variables[mode], data, unit)
167
168 if mode == 4:
169 # variable = "oxidised"
170 unit = "kO"
171 data = gas.read_all()
172 data = data.oxidising / 1000
173 display_text(variables[mode], data, unit)
174
175 if mode == 5:
176 # variable = "reduced"
177 unit = "kO"
178 data = gas.read_all()
179 data = data.reducing / 1000
180 display_text(variables[mode], data, unit)
181
182 if mode == 6:
183 # variable = "nh3"
184 unit = "kO"
185 data = gas.read_all()
186 data = data.nh3 / 1000
187 display_text(variables[mode], data, unit)
188
189 # Exit cleanly
190 except KeyboardInterrupt:
191 sys.exit(0)