Adding all in one weather and light display example
[EVA-2020-02-2.git] / examples / all-in-one-no-pm.py
CommitLineData
c96f1398
TF
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
c96f1398
TF
14
15from bme280 import BME280
16from enviroplus import gas
17from subprocess import PIPE, Popen
18from PIL import Image
19from PIL import ImageDraw
20from PIL import ImageFont
10b73e18 21import logging
c96f1398 22
10b73e18
CM
23logging.basicConfig(
24 format='%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s',
25 level=logging.INFO,
26 datefmt='%Y-%m-%d %H:%M:%S')
27
28logging.info("""all-in-one.py - Displays readings from all of Enviro plus' sensors
c96f1398
TF
29Press Ctrl+C to exit!
30""")
31
32# BME280 temperature/pressure/humidity sensor
33bme280 = BME280()
34
35# Create ST7735 LCD display class
36st7735 = 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
46st7735.begin()
47
48WIDTH = st7735.width
49HEIGHT = st7735.height
50
51# Set up canvas and font
52img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
53draw = ImageDraw.Draw(img)
54path = os.path.dirname(os.path.realpath(__file__))
55font = ImageFont.truetype(path + "/fonts/Asap/Asap-Bold.ttf", 20)
56
57message = ""
58
59# The position of the top bar
60top_pos = 25
61
62
63# Displays data and text on the 0.96" LCD
64def 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)
10b73e18 72 logging.info(message)
c96f1398
TF
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
91def get_cpu_temperature():
e2d010e2 92 process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE, universal_newlines=True)
c96f1398
TF
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
99factor = 0.8
100
27156d25 101cpu_temps = [get_cpu_temperature()] * 5
c96f1398
TF
102
103delay = 0.5 # Debounce the proximity tap
104mode = 0 # The starting mode
105last_page = 0
106light = 1
107
108# Create a values dict to store the data
109variables = ["temperature",
110 "pressure",
111 "humidity",
112 "light",
113 "oxidised",
114 "reduced",
115 "nh3"]
116
117values = {}
118
119for v in variables:
120 values[v] = [1] * WIDTH
121
122# The main loop
123try:
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:
69294f3c 135 # variable = "temperature"
c96f1398
TF
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)
69294f3c 143 display_text(variables[mode], data, unit)
c96f1398
TF
144
145 if mode == 1:
69294f3c 146 # variable = "pressure"
c96f1398
TF
147 unit = "hPa"
148 data = bme280.get_pressure()
69294f3c 149 display_text(variables[mode], data, unit)
c96f1398
TF
150
151 if mode == 2:
69294f3c 152 # variable = "humidity"
c96f1398
TF
153 unit = "%"
154 data = bme280.get_humidity()
69294f3c 155 display_text(variables[mode], data, unit)
c96f1398
TF
156
157 if mode == 3:
69294f3c 158 # variable = "light"
c96f1398
TF
159 unit = "Lux"
160 if proximity < 10:
161 data = ltr559.get_lux()
162 else:
163 data = 1
69294f3c 164 display_text(variables[mode], data, unit)
c96f1398
TF
165
166 if mode == 4:
69294f3c 167 # variable = "oxidised"
c96f1398
TF
168 unit = "kO"
169 data = gas.read_all()
170 data = data.oxidising / 1000
69294f3c 171 display_text(variables[mode], data, unit)
c96f1398
TF
172
173 if mode == 5:
69294f3c 174 # variable = "reduced"
c96f1398
TF
175 unit = "kO"
176 data = gas.read_all()
177 data = data.reducing / 1000
69294f3c 178 display_text(variables[mode], data, unit)
c96f1398
TF
179
180 if mode == 6:
69294f3c 181 # variable = "nh3"
c96f1398
TF
182 unit = "kO"
183 data = gas.read_all()
184 data = data.nh3 / 1000
69294f3c 185 display_text(variables[mode], data, unit)
c96f1398
TF
186
187# Exit cleanly
188except KeyboardInterrupt:
189 sys.exit(0)