Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6d6d3dd
Prep for v0.0.2
Gadgetoid Mar 13, 2020
f8d8834
Update README for 0.0.2
Gadgetoid Mar 13, 2020
ed42179
Merge pull request #56 from roscoe81/master
Gadgetoid Mar 13, 2020
97ee1d8
Fix noise_floor bug
Gadgetoid Mar 16, 2020
be4d0fc
Test tweaks and linting
Gadgetoid Mar 17, 2020
e9c9367
Test noise, fix gas
Gadgetoid Mar 17, 2020
4cc6c62
Move package and requires to setup.cfg
Gadgetoid Mar 24, 2020
e72e568
Drop Python 2.6
Gadgetoid Apr 29, 2020
87221e4
Merge pull request #57 from pimoroni/test-tweaks-and-linting
Gadgetoid Apr 29, 2020
5a376dd
Catch #61 with tests and fix
Gadgetoid Apr 29, 2020
04e4888
Merge pull request #62 from pimoroni/patch-noise-and-test-fixes
Gadgetoid Apr 29, 2020
0c5c946
Include python cffi in setup dependencies
mendhak May 8, 2020
f3e6204
Merge pull request #64 from mendhak/issue63-missing-cffi
Gadgetoid May 15, 2020
230698a
Added supported board images and example
Jun 3, 2020
6c6e553
Merge pull request #69 from piofthings/master
Gadgetoid Jun 4, 2020
6a89566
Correcting examples
petermcd Jun 17, 2020
f19fbc1
Merge pull request #72 from petermcd/example-fixes
Gadgetoid Jun 18, 2020
f5335ba
Adds mqtt example (#68)
robmarkcole Jun 18, 2020
f984ea1
Added user projects section to README
Gadgetoid Jun 18, 2020
032fa13
Merge pull request #73 from pimoroni/patch-user-projects-readme
Gadgetoid Jun 18, 2020
a1a12d7
Update mqtt-all.py
robmarkcole Jul 11, 2020
47f1b58
Merge pull request #77 from robmarkcole/update-mqtt
Gadgetoid Jul 14, 2020
c161c52
Fix combined.py indentation for Python 3.x
Gadgetoid Jul 30, 2020
3e4b64c
Experimental fix to communicate Py version reqs for #78
Gadgetoid Jul 30, 2020
ddb2f5d
Minute instead month in backup file name
svetlemodry Aug 5, 2020
a4ac620
Merge pull request #80 from svetlemodry/svetlemodry-datestamp-fix
Gadgetoid Aug 5, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Enviro-Plus-pHAT.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Enviro-mini-pHAT.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Enviro+
# Enviro+

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


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

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.

**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._

![Enviro Plus pHAT](./Enviro-Plus-pHAT.jpg)
![Enviro Mini pHAT](./Enviro-mini-pHAT.jpg)

## One-line (Installs from GitHub)

```
Expand Down Expand Up @@ -48,6 +54,12 @@ And install additional dependencies:
sudo apt install python-numpy python-smbus python-pil python-setuptools
```

## Alternate Software & User Projects

* enviro monitor - https://github.com/roscoe81/enviro-monitor
* mqtt-all - https://github.com/robmarkcole/rpi-enviro-mqtt - now upstream: [see examples/mqtt-all.py](examples/mqtt-all.py)
* 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

## Help & Support

* GPIO Pinout - https://pinout.xyz/pinout/enviro_plus
Expand Down
166 changes: 166 additions & 0 deletions examples/all-in-one-enviro-mini.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#!/usr/bin/env python3

import time
import colorsys
import os
import sys
import ST7735
try:
# Transitional fix for breaking change in LTR559
from ltr559 import LTR559
ltr559 = LTR559()
except ImportError:
import ltr559

from bme280 import BME280
from enviroplus import gas
from subprocess import PIPE, Popen
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
from fonts.ttf import RobotoMedium as UserFont
import logging

logging.basicConfig(
format='%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s',
level=logging.INFO,
datefmt='%Y-%m-%d %H:%M:%S')

logging.info("""all-in-one.py - Displays readings from all of Enviro plus' sensors
Press Ctrl+C to exit!
""")

# BME280 temperature/pressure/humidity sensor
bme280 = BME280()

# Create ST7735 LCD display class
st7735 = ST7735.ST7735(
port=0,
cs=1,
dc=9,
backlight=12,
rotation=270,
spi_speed_hz=10000000
)

# Initialize display
st7735.begin()

WIDTH = st7735.width
HEIGHT = st7735.height

# Set up canvas and font
img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
draw = ImageDraw.Draw(img)
path = os.path.dirname(os.path.realpath(__file__))
font_size = 20
font = ImageFont.truetype(UserFont, font_size)

message = ""

# The position of the top bar
top_pos = 25


# Displays data and text on the 0.96" LCD
def display_text(variable, data, unit):
# Maintain length of list
values[variable] = values[variable][1:] + [data]
# Scale the values for the variable between 0 and 1
vmin = min(values[variable])
vmax = max(values[variable])
colours = [(v - vmin + 1) / (vmax - vmin + 1) for v in values[variable]]
# Format the variable name and value
message = "{}: {:.1f} {}".format(variable[:4], data, unit)
logging.info(message)
draw.rectangle((0, 0, WIDTH, HEIGHT), (255, 255, 255))
for i in range(len(colours)):
# Convert the values to colours from red to blue
colour = (1.0 - colours[i]) * 0.6
r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour, 1.0, 1.0)]
# Draw a 1-pixel wide rectangle of colour
draw.rectangle((i, top_pos, i + 1, HEIGHT), (r, g, b))
# Draw a line graph in black
line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos))) + top_pos
draw.rectangle((i, line_y, i + 1, line_y + 1), (0, 0, 0))
# Write the text at the top in black
draw.text((0, 0), message, font=font, fill=(0, 0, 0))
st7735.display(img)


# Get the temperature of the CPU for compensation
def get_cpu_temperature():
process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE, universal_newlines=True)
output, _error = process.communicate()
return float(output[output.index('=') + 1:output.rindex("'")])


# Tuning factor for compensation. Decrease this number to adjust the
# temperature down, and increase to adjust up
factor = 2.25

cpu_temps = [get_cpu_temperature()] * 5

delay = 0.5 # Debounce the proximity tap
mode = 0 # The starting mode
last_page = 0
light = 1

# Create a values dict to store the data
variables = ["temperature",
"pressure",
"humidity",
"light"]

values = {}

for v in variables:
values[v] = [1] * WIDTH

# The main loop
try:
while True:
proximity = ltr559.get_proximity()

# If the proximity crosses the threshold, toggle the mode
if proximity > 1500 and time.time() - last_page > delay:
mode += 1
mode %= len(variables)
last_page = time.time()

# One mode for each variable
if mode == 0:
# variable = "temperature"
unit = "C"
cpu_temp = get_cpu_temperature()
# Smooth out with some averaging to decrease jitter
cpu_temps = cpu_temps[1:] + [cpu_temp]
avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
raw_temp = bme280.get_temperature()
data = raw_temp - ((avg_cpu_temp - raw_temp) / factor)
display_text(variables[mode], data, unit)

if mode == 1:
# variable = "pressure"
unit = "hPa"
data = bme280.get_pressure()
display_text(variables[mode], data, unit)

if mode == 2:
# variable = "humidity"
unit = "%"
data = bme280.get_humidity()
display_text(variables[mode], data, unit)

if mode == 3:
# variable = "light"
unit = "Lux"
if proximity < 10:
data = ltr559.get_lux()
else:
data = 1
display_text(variables[mode], data, unit)

# Exit cleanly
except KeyboardInterrupt:
sys.exit(0)
15 changes: 7 additions & 8 deletions examples/all-in-one-no-pm.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,22 @@ def display_text(variable, data, unit):
# Maintain length of list
values[variable] = values[variable][1:] + [data]
# Scale the values for the variable between 0 and 1
colours = [(v - min(values[variable]) + 1) / (max(values[variable])
- min(values[variable]) + 1) for v in values[variable]]
vmin = min(values[variable])
vmax = max(values[variable])
colours = [(v - vmin + 1) / (vmax - vmin + 1) for v in values[variable]]
# Format the variable name and value
message = "{}: {:.1f} {}".format(variable[:4], data, unit)
logging.info(message)
draw.rectangle((0, 0, WIDTH, HEIGHT), (255, 255, 255))
for i in range(len(colours)):
# Convert the values to colours from red to blue
colour = (1.0 - colours[i]) * 0.6
r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour,
1.0, 1.0)]
r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour, 1.0, 1.0)]
# Draw a 1-pixel wide rectangle of colour
draw.rectangle((i, top_pos, i+1, HEIGHT), (r, g, b))
draw.rectangle((i, top_pos, i + 1, HEIGHT), (r, g, b))
# Draw a line graph in black
line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos)))\
+ top_pos
draw.rectangle((i, line_y, i+1, line_y+1), (0, 0, 0))
line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos))) + top_pos
draw.rectangle((i, line_y, i + 1, line_y + 1), (0, 0, 0))
# Write the text at the top in black
draw.text((0, 0), message, font=font, fill=(0, 0, 0))
st7735.display(img)
Expand Down
22 changes: 10 additions & 12 deletions examples/all-in-one.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import time
import colorsys
import os
import sys
import ST7735
try:
Expand Down Expand Up @@ -72,23 +71,22 @@ def display_text(variable, data, unit):
# Maintain length of list
values[variable] = values[variable][1:] + [data]
# Scale the values for the variable between 0 and 1
colours = [(v - min(values[variable]) + 1) / (max(values[variable])
- min(values[variable]) + 1) for v in values[variable]]
vmin = min(values[variable])
vmax = max(values[variable])
colours = [(v - vmin + 1) / (vmax - vmin + 1) for v in values[variable]]
# Format the variable name and value
message = "{}: {:.1f} {}".format(variable[:4], data, unit)
logging.info(message)
draw.rectangle((0, 0, WIDTH, HEIGHT), (255, 255, 255))
for i in range(len(colours)):
# Convert the values to colours from red to blue
colour = (1.0 - colours[i]) * 0.6
r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour,
1.0, 1.0)]
r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour, 1.0, 1.0)]
# Draw a 1-pixel wide rectangle of colour
draw.rectangle((i, top_pos, i+1, HEIGHT), (r, g, b))
draw.rectangle((i, top_pos, i + 1, HEIGHT), (r, g, b))
# Draw a line graph in black
line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos)))\
+ top_pos
draw.rectangle((i, line_y, i+1, line_y+1), (0, 0, 0))
line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos))) + top_pos
draw.rectangle((i, line_y, i + 1, line_y + 1), (0, 0, 0))
# Write the text at the top in black
draw.text((0, 0), message, font=font, fill=(0, 0, 0))
st7735.display(img)
Expand Down Expand Up @@ -200,7 +198,7 @@ def get_cpu_temperature():
try:
data = pms5003.read()
except pmsReadTimeoutError:
logging.warn("Failed to read PMS5003")
logging.warning("Failed to read PMS5003")
else:
data = float(data.pm_ug_per_m3(1.0))
display_text(variables[mode], data, unit)
Expand All @@ -211,7 +209,7 @@ def get_cpu_temperature():
try:
data = pms5003.read()
except pmsReadTimeoutError:
logging.warn("Failed to read PMS5003")
logging.warning("Failed to read PMS5003")
else:
data = float(data.pm_ug_per_m3(2.5))
display_text(variables[mode], data, unit)
Expand All @@ -222,7 +220,7 @@ def get_cpu_temperature():
try:
data = pms5003.read()
except pmsReadTimeoutError:
logging.warn("Failed to read PMS5003")
logging.warning("Failed to read PMS5003")
else:
data = float(data.pm_ug_per_m3(10))
display_text(variables[mode], data, unit)
Expand Down
Loading