Adds mqtt example (#68)
[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 vmin = min(values[variable])
71 vmax = max(values[variable])
72 colours = [(v - vmin + 1) / (vmax - vmin + 1) for v in values[variable]]
73 # Format the variable name and value
74 message = "{}: {:.1f} {}".format(variable[:4], data, unit)
75 logging.info(message)
76 draw.rectangle((0, 0, WIDTH, HEIGHT), (255, 255, 255))
77 for i in range(len(colours)):
78 # Convert the values to colours from red to blue
79 colour = (1.0 - colours[i]) * 0.6
80 r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour, 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))) + top_pos
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
90
91 # Get the temperature of the CPU for compensation
92 def get_cpu_temperature():
93 process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE, universal_newlines=True)
94 output, _error = process.communicate()
95 return float(output[output.index('=') + 1:output.rindex("'")])
96
97
98 # Tuning factor for compensation. Decrease this number to adjust the
99 # temperature down, and increase to adjust up
100 factor = 2.25
101
102 cpu_temps = [get_cpu_temperature()] * 5
103
104 delay = 0.5 # Debounce the proximity tap
105 mode = 0 # The starting mode
106 last_page = 0
107 light = 1
108
109 # Create a values dict to store the data
110 variables = ["temperature",
111 "pressure",
112 "humidity",
113 "light",
114 "oxidised",
115 "reduced",
116 "nh3"]
117
118 values = {}
119
120 for v in variables:
121 values[v] = [1] * WIDTH
122
123 # The main loop
124 try:
125 while True:
126 proximity = ltr559.get_proximity()
127
128 # If the proximity crosses the threshold, toggle the mode
129 if proximity > 1500 and time.time() - last_page > delay:
130 mode += 1
131 mode %= len(variables)
132 last_page = time.time()
133
134 # One mode for each variable
135 if mode == 0:
136 # variable = "temperature"
137 unit = "C"
138 cpu_temp = get_cpu_temperature()
139 # Smooth out with some averaging to decrease jitter
140 cpu_temps = cpu_temps[1:] + [cpu_temp]
141 avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
142 raw_temp = bme280.get_temperature()
143 data = raw_temp - ((avg_cpu_temp - raw_temp) / factor)
144 display_text(variables[mode], data, unit)
145
146 if mode == 1:
147 # variable = "pressure"
148 unit = "hPa"
149 data = bme280.get_pressure()
150 display_text(variables[mode], data, unit)
151
152 if mode == 2:
153 # variable = "humidity"
154 unit = "%"
155 data = bme280.get_humidity()
156 display_text(variables[mode], data, unit)
157
158 if mode == 3:
159 # variable = "light"
160 unit = "Lux"
161 if proximity < 10:
162 data = ltr559.get_lux()
163 else:
164 data = 1
165 display_text(variables[mode], data, unit)
166
167 if mode == 4:
168 # variable = "oxidised"
169 unit = "kO"
170 data = gas.read_all()
171 data = data.oxidising / 1000
172 display_text(variables[mode], data, unit)
173
174 if mode == 5:
175 # variable = "reduced"
176 unit = "kO"
177 data = gas.read_all()
178 data = data.reducing / 1000
179 display_text(variables[mode], data, unit)
180
181 if mode == 6:
182 # variable = "nh3"
183 unit = "kO"
184 data = gas.read_all()
185 data = data.nh3 / 1000
186 display_text(variables[mode], data, unit)
187
188 # Exit cleanly
189 except KeyboardInterrupt:
190 sys.exit(0)