Skip to content

Commit 654986f

Browse files
authored
Merge pull request #1 from pimoroni/master
Merge from pimoroni/master
2 parents 7614d18 + a4ac620 commit 654986f

22 files changed

+921
-317
lines changed

Enviro-Plus-pHAT.jpg

46.3 KB
Loading

Enviro-mini-pHAT.jpg

45.4 KB
Loading

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
# Enviro+
1+
# Enviro+
22

33
Designed for environmental monitoring, Enviro+ lets you measure air quality (pollutant gases and particulates), temperature, pressure, humidity, light, and noise level. Learn more - https://shop.pimoroni.com/products/enviro-plus
44

5+
56
[![Build Status](https://travis-ci.com/pimoroni/enviroplus-python.svg?branch=master)](https://travis-ci.com/pimoroni/enviroplus-python)
67
[![Coverage Status](https://coveralls.io/repos/github/pimoroni/enviroplus-python/badge.svg?branch=master)](https://coveralls.io/github/pimoroni/enviroplus-python?branch=master)
78
[![PyPi Package](https://img.shields.io/pypi/v/enviroplus.svg)](https://pypi.python.org/pypi/enviroplus)
@@ -11,6 +12,11 @@ Designed for environmental monitoring, Enviro+ lets you measure air quality (pol
1112

1213
You're best using the "One-line" install method if you want all of the UART serial configuration for the PMS5003 particulate matter sensor to run automatically.
1314

15+
**Note** The code in this repository supports both the Enviro+ and Enviro Mini boards. _The Enviro Mini board does not have the Gas sensor or the breakout for the PM sensor._
16+
17+
![Enviro Plus pHAT](./Enviro-Plus-pHAT.jpg)
18+
![Enviro Mini pHAT](./Enviro-mini-pHAT.jpg)
19+
1420
## One-line (Installs from GitHub)
1521

1622
```
@@ -48,6 +54,12 @@ And install additional dependencies:
4854
sudo apt install python-numpy python-smbus python-pil python-setuptools
4955
```
5056

57+
## Alternate Software & User Projects
58+
59+
* enviro monitor - https://github.com/roscoe81/enviro-monitor
60+
* mqtt-all - https://github.com/robmarkcole/rpi-enviro-mqtt - now upstream: [see examples/mqtt-all.py](examples/mqtt-all.py)
61+
* adafruit_io.py - https://github.com/dedSyn4ps3/enviroplus-python/blob/master/examples/adafruit_io.py - uses Adafruit Blinka and BME280 libraries to publish to Adafruit IO
62+
5163
## Help & Support
5264

5365
* GPIO Pinout - https://pinout.xyz/pinout/enviro_plus

examples/all-in-one-enviro-mini.py

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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+
115+
values = {}
116+
117+
for v in variables:
118+
values[v] = [1] * WIDTH
119+
120+
# The main loop
121+
try:
122+
while True:
123+
proximity = ltr559.get_proximity()
124+
125+
# If the proximity crosses the threshold, toggle the mode
126+
if proximity > 1500 and time.time() - last_page > delay:
127+
mode += 1
128+
mode %= len(variables)
129+
last_page = time.time()
130+
131+
# One mode for each variable
132+
if mode == 0:
133+
# variable = "temperature"
134+
unit = "C"
135+
cpu_temp = get_cpu_temperature()
136+
# Smooth out with some averaging to decrease jitter
137+
cpu_temps = cpu_temps[1:] + [cpu_temp]
138+
avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
139+
raw_temp = bme280.get_temperature()
140+
data = raw_temp - ((avg_cpu_temp - raw_temp) / factor)
141+
display_text(variables[mode], data, unit)
142+
143+
if mode == 1:
144+
# variable = "pressure"
145+
unit = "hPa"
146+
data = bme280.get_pressure()
147+
display_text(variables[mode], data, unit)
148+
149+
if mode == 2:
150+
# variable = "humidity"
151+
unit = "%"
152+
data = bme280.get_humidity()
153+
display_text(variables[mode], data, unit)
154+
155+
if mode == 3:
156+
# variable = "light"
157+
unit = "Lux"
158+
if proximity < 10:
159+
data = ltr559.get_lux()
160+
else:
161+
data = 1
162+
display_text(variables[mode], data, unit)
163+
164+
# Exit cleanly
165+
except KeyboardInterrupt:
166+
sys.exit(0)

examples/all-in-one-no-pm.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,23 +67,22 @@ def display_text(variable, data, unit):
6767
# Maintain length of list
6868
values[variable] = values[variable][1:] + [data]
6969
# 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]]
70+
vmin = min(values[variable])
71+
vmax = max(values[variable])
72+
colours = [(v - vmin + 1) / (vmax - vmin + 1) for v in values[variable]]
7273
# Format the variable name and value
7374
message = "{}: {:.1f} {}".format(variable[:4], data, unit)
7475
logging.info(message)
7576
draw.rectangle((0, 0, WIDTH, HEIGHT), (255, 255, 255))
7677
for i in range(len(colours)):
7778
# Convert the values to colours from red to blue
7879
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)]
80+
r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour, 1.0, 1.0)]
8181
# Draw a 1-pixel wide rectangle of colour
82-
draw.rectangle((i, top_pos, i+1, HEIGHT), (r, g, b))
82+
draw.rectangle((i, top_pos, i + 1, HEIGHT), (r, g, b))
8383
# 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))
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))
8786
# Write the text at the top in black
8887
draw.text((0, 0), message, font=font, fill=(0, 0, 0))
8988
st7735.display(img)

examples/all-in-one.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import time
44
import colorsys
5-
import os
65
import sys
76
import ST7735
87
try:
@@ -72,23 +71,22 @@ def display_text(variable, data, unit):
7271
# Maintain length of list
7372
values[variable] = values[variable][1:] + [data]
7473
# Scale the values for the variable between 0 and 1
75-
colours = [(v - min(values[variable]) + 1) / (max(values[variable])
76-
- min(values[variable]) + 1) for v in values[variable]]
74+
vmin = min(values[variable])
75+
vmax = max(values[variable])
76+
colours = [(v - vmin + 1) / (vmax - vmin + 1) for v in values[variable]]
7777
# Format the variable name and value
7878
message = "{}: {:.1f} {}".format(variable[:4], data, unit)
7979
logging.info(message)
8080
draw.rectangle((0, 0, WIDTH, HEIGHT), (255, 255, 255))
8181
for i in range(len(colours)):
8282
# Convert the values to colours from red to blue
8383
colour = (1.0 - colours[i]) * 0.6
84-
r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour,
85-
1.0, 1.0)]
84+
r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour, 1.0, 1.0)]
8685
# Draw a 1-pixel wide rectangle of colour
87-
draw.rectangle((i, top_pos, i+1, HEIGHT), (r, g, b))
86+
draw.rectangle((i, top_pos, i + 1, HEIGHT), (r, g, b))
8887
# Draw a line graph in black
89-
line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos)))\
90-
+ top_pos
91-
draw.rectangle((i, line_y, i+1, line_y+1), (0, 0, 0))
88+
line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos))) + top_pos
89+
draw.rectangle((i, line_y, i + 1, line_y + 1), (0, 0, 0))
9290
# Write the text at the top in black
9391
draw.text((0, 0), message, font=font, fill=(0, 0, 0))
9492
st7735.display(img)
@@ -200,7 +198,7 @@ def get_cpu_temperature():
200198
try:
201199
data = pms5003.read()
202200
except pmsReadTimeoutError:
203-
logging.warn("Failed to read PMS5003")
201+
logging.warning("Failed to read PMS5003")
204202
else:
205203
data = float(data.pm_ug_per_m3(1.0))
206204
display_text(variables[mode], data, unit)
@@ -211,7 +209,7 @@ def get_cpu_temperature():
211209
try:
212210
data = pms5003.read()
213211
except pmsReadTimeoutError:
214-
logging.warn("Failed to read PMS5003")
212+
logging.warning("Failed to read PMS5003")
215213
else:
216214
data = float(data.pm_ug_per_m3(2.5))
217215
display_text(variables[mode], data, unit)
@@ -222,7 +220,7 @@ def get_cpu_temperature():
222220
try:
223221
data = pms5003.read()
224222
except pmsReadTimeoutError:
225-
logging.warn("Failed to read PMS5003")
223+
logging.warning("Failed to read PMS5003")
226224
else:
227225
data = float(data.pm_ug_per_m3(10))
228226
display_text(variables[mode], data, unit)

0 commit comments

Comments
 (0)