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