From: Philip Howard Date: Tue, 3 Mar 2020 12:32:06 +0000 (+0000) Subject: Merge pull request #53 from pimoroni/enviro-non-plus X-Git-Url: https://zdv2.bktei.com/gitweb/EVA-2020-02-2.git/commitdiff_plain/0b149bfc6c839dc37b65c31bc7834a1fc59d60cb?hp=02c9f287f5963f5221b23fb05c2925eb261ca2de Merge pull request #53 from pimoroni/enviro-non-plus Migrate to Python 3, Fix Assets --- diff --git a/examples/adc.py b/examples/adc.py index 82bda41..a345d23 100755 --- a/examples/adc.py +++ b/examples/adc.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import time from enviroplus import gas diff --git a/examples/all-in-one-no-pm.py b/examples/all-in-one-no-pm.py index 6bb6873..db1ca8c 100755 --- a/examples/all-in-one-no-pm.py +++ b/examples/all-in-one-no-pm.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import time import colorsys @@ -18,6 +18,7 @@ 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( @@ -52,7 +53,8 @@ HEIGHT = st7735.height img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0)) draw = ImageDraw.Draw(img) path = os.path.dirname(os.path.realpath(__file__)) -font = ImageFont.truetype(path + "/fonts/Asap/Asap-Bold.ttf", 20) +font_size = 20 +font = ImageFont.truetype(UserFont, FontSize) message = "" @@ -96,7 +98,7 @@ def get_cpu_temperature(): # Tuning factor for compensation. Decrease this number to adjust the # temperature down, and increase to adjust up -factor = 0.8 +factor = 2.25 cpu_temps = [get_cpu_temperature()] * 5 diff --git a/examples/all-in-one.py b/examples/all-in-one.py index 03e4d58..c0423e6 100755 --- a/examples/all-in-one.py +++ b/examples/all-in-one.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import time import colorsys @@ -19,6 +19,7 @@ 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( @@ -57,8 +58,8 @@ 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 = ImageFont.truetype(path + "/fonts/Asap/Asap-Bold.ttf", 20) +font_size = 20 +font = ImageFont.truetype(UserFont, font_size) message = "" @@ -102,7 +103,7 @@ def get_cpu_temperature(): # Tuning factor for compensation. Decrease this number to adjust the # temperature down, and increase to adjust up -factor = 0.8 +factor = 2.25 cpu_temps = [get_cpu_temperature()] * 5 diff --git a/examples/combined.py b/examples/combined.py old mode 100644 new mode 100755 index e863de3..43668a5 --- a/examples/combined.py +++ b/examples/combined.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import time import colorsys @@ -19,6 +19,7 @@ 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( @@ -57,9 +58,10 @@ 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 = ImageFont.truetype(path + "/fonts/Asap/Asap-Bold.ttf", 20) -smallfont = ImageFont.truetype(path + "/fonts/Asap/Asap-Bold.ttf", 10) +font_size_small = 10 +font_size_large = 20 +font = ImageFont.truetype(UserFont, font_size_large) +smallfont = ImageFont.truetype(UserFont, font_size_small) x_offset = 2 y_offset = 2 @@ -166,7 +168,7 @@ def display_everything(): draw.rectangle((0, 0, WIDTH, HEIGHT), (0, 0, 0)) column_count = 2 row_count = (len(variables)/column_count) - for i in xrange(len(variables)): + for i in range(len(variables)): variable = variables[i] data_value = values[variable][-1] unit = units[i] @@ -175,7 +177,7 @@ def display_everything(): message = "{}: {:.1f} {}".format(variable[:4], data_value, unit) lim = limits[i] rgb = palette[0] - for j in xrange(len(lim)): + for j in range(len(lim)): if data_value > lim[j]: rgb = palette[j+1] draw.text((x, y), message, font=smallfont, fill=rgb) @@ -192,7 +194,7 @@ def get_cpu_temperature(): # Tuning factor for compensation. Decrease this number to adjust the # temperature down, and increase to adjust up -factor = 1.95 +factor = 2.25 cpu_temps = [get_cpu_temperature()] * 5 diff --git a/examples/compensated-temperature.py b/examples/compensated-temperature.py index 74b6bab..b648f57 100755 --- a/examples/compensated-temperature.py +++ b/examples/compensated-temperature.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import time from bme280 import BME280 @@ -38,7 +38,7 @@ def get_cpu_temperature(): # Tuning factor for compensation. Decrease this number to adjust the # temperature down, and increase to adjust up -factor = 0.8 +factor = 2.25 cpu_temps = [get_cpu_temperature()] * 5 diff --git a/examples/fonts/Asap/Asap-Bold.ttf b/examples/fonts/Asap/Asap-Bold.ttf deleted file mode 100644 index 52a14e5..0000000 Binary files a/examples/fonts/Asap/Asap-Bold.ttf and /dev/null differ diff --git a/examples/fonts/Asap/Asap-BoldItalic.ttf b/examples/fonts/Asap/Asap-BoldItalic.ttf deleted file mode 100644 index df29023..0000000 Binary files a/examples/fonts/Asap/Asap-BoldItalic.ttf and /dev/null differ diff --git a/examples/fonts/Asap/Asap-Italic.ttf b/examples/fonts/Asap/Asap-Italic.ttf deleted file mode 100644 index b07a0bc..0000000 Binary files a/examples/fonts/Asap/Asap-Italic.ttf and /dev/null differ diff --git a/examples/fonts/Asap/Asap-Medium.ttf b/examples/fonts/Asap/Asap-Medium.ttf deleted file mode 100644 index 81ef310..0000000 Binary files a/examples/fonts/Asap/Asap-Medium.ttf and /dev/null differ diff --git a/examples/fonts/Asap/Asap-MediumItalic.ttf b/examples/fonts/Asap/Asap-MediumItalic.ttf deleted file mode 100644 index 6f8d906..0000000 Binary files a/examples/fonts/Asap/Asap-MediumItalic.ttf and /dev/null differ diff --git a/examples/fonts/Asap/Asap-Regular.ttf b/examples/fonts/Asap/Asap-Regular.ttf deleted file mode 100644 index af00196..0000000 Binary files a/examples/fonts/Asap/Asap-Regular.ttf and /dev/null differ diff --git a/examples/fonts/Asap/Asap-SemiBold.ttf b/examples/fonts/Asap/Asap-SemiBold.ttf deleted file mode 100644 index 5328f3f..0000000 Binary files a/examples/fonts/Asap/Asap-SemiBold.ttf and /dev/null differ diff --git a/examples/fonts/Asap/Asap-SemiBoldItalic.ttf b/examples/fonts/Asap/Asap-SemiBoldItalic.ttf deleted file mode 100644 index 6415ef2..0000000 Binary files a/examples/fonts/Asap/Asap-SemiBoldItalic.ttf and /dev/null differ diff --git a/examples/fonts/Asap/OFL.txt b/examples/fonts/Asap/OFL.txt deleted file mode 100644 index ad56d30..0000000 --- a/examples/fonts/Asap/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Asap Project Authors (omnibus.type@gmail.com) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/examples/gas.py b/examples/gas.py index 2f84944..5d72cb9 100755 --- a/examples/gas.py +++ b/examples/gas.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import time from enviroplus import gas diff --git a/examples/icons/bulb-bright.png b/examples/icons/bulb-bright.png new file mode 100644 index 0000000..5697a81 Binary files /dev/null and b/examples/icons/bulb-bright.png differ diff --git a/examples/icons/bulb-dark.png b/examples/icons/bulb-dark.png new file mode 100644 index 0000000..a91e24b Binary files /dev/null and b/examples/icons/bulb-dark.png differ diff --git a/examples/icons/bulb-dim.png b/examples/icons/bulb-dim.png new file mode 100644 index 0000000..a91e24b Binary files /dev/null and b/examples/icons/bulb-dim.png differ diff --git a/examples/icons/bulb-light.png b/examples/icons/bulb-light.png new file mode 100644 index 0000000..f8fb791 Binary files /dev/null and b/examples/icons/bulb-light.png differ diff --git a/examples/icons/humidity-bad.png b/examples/icons/humidity-bad.png new file mode 100644 index 0000000..5a7201c Binary files /dev/null and b/examples/icons/humidity-bad.png differ diff --git a/examples/icons/humidity-good.png b/examples/icons/humidity-good.png new file mode 100644 index 0000000..ba450db Binary files /dev/null and b/examples/icons/humidity-good.png differ diff --git a/examples/icons/humidity.png b/examples/icons/humidity.png new file mode 100644 index 0000000..5a7201c Binary files /dev/null and b/examples/icons/humidity.png differ diff --git a/examples/icons/temperature.png b/examples/icons/temperature.png new file mode 100644 index 0000000..54a826f Binary files /dev/null and b/examples/icons/temperature.png differ diff --git a/examples/icons/weather-change.png b/examples/icons/weather-change.png new file mode 100644 index 0000000..21215b7 Binary files /dev/null and b/examples/icons/weather-change.png differ diff --git a/examples/icons/weather-dry.png b/examples/icons/weather-dry.png new file mode 100644 index 0000000..2302926 Binary files /dev/null and b/examples/icons/weather-dry.png differ diff --git a/examples/icons/weather-fair.png b/examples/icons/weather-fair.png new file mode 100644 index 0000000..2302926 Binary files /dev/null and b/examples/icons/weather-fair.png differ diff --git a/examples/icons/weather-rain.png b/examples/icons/weather-rain.png new file mode 100644 index 0000000..a7dea2f Binary files /dev/null and b/examples/icons/weather-rain.png differ diff --git a/examples/icons/weather-storm.png b/examples/icons/weather-storm.png new file mode 100644 index 0000000..2017245 Binary files /dev/null and b/examples/icons/weather-storm.png differ diff --git a/examples/lcd.py b/examples/lcd.py index 7e50c94..10413b9 100755 --- a/examples/lcd.py +++ b/examples/lcd.py @@ -1,7 +1,8 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import ST7735 from PIL import Image, ImageDraw, ImageFont +from fonts.ttf import RobotoMedium as UserFont import logging logging.basicConfig( @@ -38,7 +39,7 @@ draw = ImageDraw.Draw(img) # Text settings. font_size = 25 -font = ImageFont.truetype("fonts/Asap/Asap-Bold.ttf", font_size) +font = ImageFont.truetype(UserFont, font_size) text_colour = (255, 255, 255) back_colour = (0, 170, 170) diff --git a/examples/light.py b/examples/light.py index b18a78b..db61e6a 100755 --- a/examples/light.py +++ b/examples/light.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import time import logging diff --git a/examples/luftdaten.py b/examples/luftdaten.py index 9995914..d2d6562 100755 --- a/examples/luftdaten.py +++ b/examples/luftdaten.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import requests import ST7735 @@ -7,6 +7,7 @@ from bme280 import BME280 from pms5003 import PMS5003, ReadTimeoutError from subprocess import PIPE, Popen, check_output from PIL import Image, ImageDraw, ImageFont +from fonts.ttf import RobotoMedium as UserFont try: from smbus2 import SMBus @@ -74,7 +75,6 @@ def read_values(): def get_cpu_temperature(): process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE, universal_newlines=True) output, _error = process.communicate() - output = output.decode() return float(output[output.index('=') + 1:output.rindex("'")]) @@ -150,7 +150,7 @@ def send_to_luftdaten(values, id): # Compensation factor for temperature -comp_factor = 1.2 +comp_factor = 2.25 # Raspberry Pi ID to send to Luftdaten id = "raspi-" + get_serial_number() @@ -161,7 +161,7 @@ HEIGHT = disp.height # Text settings font_size = 16 -font = ImageFont.truetype("fonts/Asap/Asap-Bold.ttf", font_size) +font = ImageFont.truetype(UserFont, font_size) # Display Raspberry Pi serial and Wi-Fi status print("Raspberry Pi serial: {}".format(get_serial_number())) diff --git a/examples/particulates.py b/examples/particulates.py index c1b3c67..04a4950 100755 --- a/examples/particulates.py +++ b/examples/particulates.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import time from pms5003 import PMS5003, ReadTimeoutError diff --git a/examples/weather-and-light.py b/examples/weather-and-light.py new file mode 100755 index 0000000..fde1d96 --- /dev/null +++ b/examples/weather-and-light.py @@ -0,0 +1,424 @@ +#!/usr/bin/env python3 + +import os +import time +import numpy +import colorsys +from PIL import Image, ImageDraw, ImageFont, ImageFilter +from fonts.ttf import RobotoMedium as UserFont + +import ST7735 +from bme280 import BME280 +from ltr559 import LTR559 + +import pytz +from astral.geocoder import database, lookup +from astral.sun import sun +from datetime import datetime, timedelta + +try: + from smbus2 import SMBus +except ImportError: + from smbus import SMBus + + +def calculate_y_pos(x, centre): + """Calculates the y-coordinate on a parabolic curve, given x.""" + centre = 80 + y = 1 / centre * (x - centre) ** 2 + + return int(y) + + +def circle_coordinates(x, y, radius): + """Calculates the bounds of a circle, given centre and radius.""" + + x1 = x - radius # Left + x2 = x + radius # Right + y1 = y - radius # Bottom + y2 = y + radius # Top + + return (x1, y1, x2, y2) + + +def map_colour(x, centre, start_hue, end_hue, day): + """Given an x coordinate and a centre point, a start and end hue (in degrees), + and a Boolean for day or night (day is True, night False), calculate a colour + hue representing the 'colour' of that time of day.""" + + start_hue = start_hue / 360 # Rescale to between 0 and 1 + end_hue = end_hue / 360 + + sat = 1.0 + + # Dim the brightness as you move from the centre to the edges + val = 1 - (abs(centre - x) / (2 * centre)) + + # Ramp up towards centre, then back down + if x > centre: + x = (2 * centre) - x + + # Calculate the hue + hue = start_hue + ((x / centre) * (end_hue - start_hue)) + + # At night, move towards purple/blue hues and reverse dimming + if not day: + hue = 1 - hue + val = 1 - val + + r, g, b = [int(c * 255) for c in colorsys.hsv_to_rgb(hue, sat, val)] + + return (r, g, b) + + +def x_from_sun_moon_time(progress, period, x_range): + """Recalculate/rescale an amount of progress through a time period.""" + + x = int((progress / period) * x_range) + + return x + + +def sun_moon_time(dt, city_name, time_zone): + """Calculate the progress through the current sun/moon period (i.e day or + night) from the last sunrise or sunset, given a datetime object 't'.""" + + city = lookup(city_name, database()) + + # Datetime objects for yesterday, today, tomorrow + today = dt.date() + dt = pytz.timezone(time_zone).localize(dt) + yesterday = today - timedelta(1) + tomorrow = today + timedelta(1) + + # Sun objects for yesterfay, today, tomorrow + sun_yesterday = sun(city.observer, date=yesterday) + sun_today = sun(city.observer, date=today) + sun_tomorrow = sun(city.observer, date=tomorrow) + + # Work out sunset yesterday, sunrise/sunset today, and sunrise tomorrow + sunset_yesterday = sun_yesterday["sunset"] + sunrise_today = sun_today["sunrise"] + sunset_today = sun_today["sunset"] + sunrise_tomorrow = sun_tomorrow["sunrise"] + + # Work out lengths of day or night period and progress through period + if sunrise_today < dt < sunset_today: + day = True + period = sunset_today - sunrise_today + mid = sunrise_today + (period / 2) + progress = dt - sunrise_today + + elif dt > sunset_today: + day = False + period = sunrise_tomorrow - sunset_today + mid = sunset_today + (period / 2) + progress = dt - sunset_today + + else: + day = False + period = sunrise_today - sunset_yesterday + mid = sunset_yesterday + (period / 2) + progress = dt - sunset_yesterday + + # Convert time deltas to seconds + progress = progress.total_seconds() + period = period.total_seconds() + + return (progress, period, day) + + +def draw_background(progress, period, day): + """Given an amount of progress through the day or night, draw the + background colour and overlay a blurred sun/moon.""" + + # x-coordinate for sun/moon + x = x_from_sun_moon_time(progress, period, WIDTH) + + # If it's day, then move right to left + if day: + x = WIDTH - x + + # Calculate position on sun/moon's curve + centre = WIDTH / 2 + y = calculate_y_pos(x, centre) + + # Background colour + background = map_colour(x, 80, mid_hue, day_hue, day) + + # New image for background colour + img = Image.new('RGBA', (WIDTH, HEIGHT), color=background) + draw = ImageDraw.Draw(img) + + # New image for sun/moon overlay + overlay = Image.new('RGBA', (WIDTH, HEIGHT), color=(0, 0, 0, 0)) + overlay_draw = ImageDraw.Draw(overlay) + + # Draw the sun/moon + circle = circle_coordinates(x, y, sun_radius) + overlay_draw.ellipse(circle, fill=(200, 200, 50, opacity)) + + # Overlay the sun/moon on the background as an alpha matte + composite = Image.alpha_composite(img, overlay).filter(ImageFilter.GaussianBlur(radius=blur)) + + return composite + + +def overlay_text(img, position, text, font, align_right=False, rectangle=False): + draw = ImageDraw.Draw(img) + w, h = font.getsize(text) + if align_right: + x, y = position + x -= w + position = (x, y) + if rectangle: + x += 1 + y += 1 + position = (x, y) + border = 1 + rect = (x - border, y, x + w, y + h + border) + rect_img = Image.new('RGBA', (WIDTH, HEIGHT), color=(0, 0, 0, 0)) + rect_draw = ImageDraw.Draw(rect_img) + rect_draw.rectangle(rect, (255, 255, 255)) + rect_draw.text(position, text, font=font, fill=(0, 0, 0, 0)) + img = Image.alpha_composite(img, rect_img) + else: + draw.text(position, text, font=font, fill=(255, 255, 255)) + return img + + +def get_cpu_temperature(): + with open("/sys/class/thermal/thermal_zone0/temp", "r") as f: + temp = f.read() + temp = int(temp) / 1000.0 + return temp + + +def correct_humidity(humidity, temperature, corr_temperature): + dewpoint = temperature - ((100 - humidity) / 5) + corr_humidity = 100 - (5 * (corr_temperature - dewpoint)) + return min(100, corr_humidity) + + +def analyse_pressure(pressure, t): + global time_vals, pressure_vals, trend + if len(pressure_vals) > num_vals: + pressure_vals = pressure_vals[1:] + [pressure] + time_vals = time_vals[1:] + [t] + + # Calculate line of best fit + line = numpy.polyfit(time_vals, pressure_vals, 1, full=True) + + # Calculate slope, variance, and confidence + slope = line[0][0] + intercept = line[0][1] + variance = numpy.var(pressure_vals) + residuals = numpy.var([(slope * x + intercept - y) for x, y in zip(time_vals, pressure_vals)]) + r_squared = 1 - residuals / variance + + # Calculate change in pressure per hour + change_per_hour = slope * 60 * 60 + variance_per_hour = variance * 60 * 60 + + mean_pressure = numpy.mean(pressure_vals) + + # Calculate trend + if r_squared > 0.5: + if change_per_hour > 0.5: + trend = ">" + elif change_per_hour < -0.5: + trend = "<" + elif -0.5 <= change_per_hour <= 0.5: + trend = "-" + + if trend != "-": + if abs(change_per_hour) > 3: + trend *= 2 + else: + pressure_vals.append(pressure) + time_vals.append(t) + mean_pressure = numpy.mean(pressure_vals) + change_per_hour = 0 + trend = "-" + +# time.sleep(interval) + + return (mean_pressure, change_per_hour, trend) + +def describe_pressure(pressure): + """Convert pressure into barometer-type description.""" + if pressure < 970: + description = "storm" + elif 970 <= pressure < 990: + description = "rain" + elif 990 <= pressure < 1010: + description = "change" + elif 1010 <= pressure < 1030: + description = "fair" + elif pressure >= 1030: + description = "dry" + else: + description = "" + return description + + +def describe_humidity(humidity): + """Convert relative humidity into good/bad description.""" + if 40 < humidity < 60: + description = "good" + else: + description = "bad" + return description + + +def describe_light(light): + """Convert light level in lux to descriptive value.""" + if light < 50: + description = "dark" + elif 50 <= light < 100: + description = "dim" + elif 100 <= light < 500: + description = "light" + elif light >= 500: + description = "bright" + return description + + +# Initialise the LCD +disp = ST7735.ST7735( + port=0, + cs=1, + dc=9, + backlight=12, + rotation=270, + spi_speed_hz=10000000 +) + +disp.begin() + +WIDTH = disp.width +HEIGHT = disp.height + +# The city and timezone that you want to display. +city_name = "Sheffield" +time_zone = "Europe/London" + +# Values that alter the look of the background +blur = 50 +opacity = 125 + +mid_hue = 0 +day_hue = 25 + +sun_radius = 50 + +# Fonts +font_sm = ImageFont.truetype(UserFont, 12) +font_lg = ImageFont.truetype(UserFont, 14) + +# Margins +margin = 3 + +dt = datetime.now() + +# Set up BME280 weather sensor +bus = SMBus(1) +bme280 = BME280(i2c_dev=bus) + +min_temp = None +max_temp = None + +factor = 2.25 +cpu_temps = [get_cpu_temperature()] * 5 + +# Set up light sensor +ltr559 = LTR559() + +# Pressure variables +pressure_vals = [] +time_vals = [] +num_vals = 1000 +interval = 1 +trend = "-" + +# Keep track of time elapsed +start_time = time.time() + +while True: + path = os.path.dirname(os.path.realpath(__file__)) + dt = datetime.now() + progress, period, day = sun_moon_time(dt, city_name, time_zone) + background = draw_background(progress, period, day) + + # Time. + time_elapsed = time.time() - start_time + date_string = dt.strftime("%d %b %y").lstrip('0') + time_string = dt.strftime("%H:%M") + img = overlay_text(background, (0 + margin, 0 + margin), time_string, font_lg) + img = overlay_text(img, (WIDTH - margin, 0 + margin), date_string, font_lg, align_right=True) + + # Temperature + temperature = bme280.get_temperature() + + # Corrected temperature + cpu_temp = get_cpu_temperature() + cpu_temps = cpu_temps[1:] + [cpu_temp] + avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps)) + corr_temperature = temperature - ((avg_cpu_temp - temperature) / factor) + + if time_elapsed > 30: + if min_temp is not None and max_temp is not None: + if corr_temperature < min_temp: + min_temp = corr_temperature + elif corr_temperature > max_temp: + max_temp = corr_temperature + else: + min_temp = corr_temperature + max_temp = corr_temperature + + temp_string = f"{corr_temperature:.0f}°C" + img = overlay_text(img, (68, 18), temp_string, font_lg, align_right=True) + spacing = font_lg.getsize(temp_string)[1] + 1 + if min_temp is not None and max_temp is not None: + range_string = f"{min_temp:.0f}-{max_temp:.0f}" + else: + range_string = "------" + img = overlay_text(img, (68, 18 + spacing), range_string, font_sm, align_right=True, rectangle=True) + temp_icon = Image.open(path + "/icons/temperature.png") + img.paste(temp_icon, (margin, 18), mask=temp_icon) + + # Humidity + humidity = bme280.get_humidity() + corr_humidity = correct_humidity(humidity, temperature, corr_temperature) + humidity_string = f"{corr_humidity:.0f}%" + img = overlay_text(img, (68, 48), humidity_string, font_lg, align_right=True) + spacing = font_lg.getsize(humidity_string)[1] + 1 + humidity_desc = describe_humidity(corr_humidity).upper() + img = overlay_text(img, (68, 48 + spacing), humidity_desc, font_sm, align_right=True, rectangle=True) + humidity_icon = Image.open(path + "/icons/humidity-" + humidity_desc.lower() + ".png") + img.paste(humidity_icon, (margin, 48), mask=humidity_icon) + + # Light + light = ltr559.get_lux() + light_string = f"{int(light):,}" + img = overlay_text(img, (WIDTH - margin, 18), light_string, font_lg, align_right=True) + spacing = font_lg.getsize(light_string.replace(",", ""))[1] + 1 + light_desc = describe_light(light).upper() + img = overlay_text(img, (WIDTH - margin - 1, 18 + spacing), light_desc, font_sm, align_right=True, rectangle=True) + light_icon = Image.open(path + "/icons/bulb-" + light_desc.lower() + ".png") + img.paste(humidity_icon, (80, 18), mask=light_icon) + + # Pressure + pressure = bme280.get_pressure() + t = time.time() + mean_pressure, change_per_hour, trend = analyse_pressure(pressure, t) + pressure_string = f"{int(mean_pressure):,} {trend}" + img = overlay_text(img, (WIDTH - margin, 48), pressure_string, font_lg, align_right=True) + pressure_desc = describe_pressure(mean_pressure).upper() + spacing = font_lg.getsize(pressure_string.replace(",", ""))[1] + 1 + img = overlay_text(img, (WIDTH - margin - 1, 48 + spacing), pressure_desc, font_sm, align_right=True, rectangle=True) + pressure_icon = Image.open(path + "/icons/weather-" + pressure_desc.lower() + ".png") + img.paste(pressure_icon, (80, 48), mask=pressure_icon) + + # Display image + disp.display(img) diff --git a/examples/weather.py b/examples/weather.py index 5036021..66f18e0 100755 --- a/examples/weather.py +++ b/examples/weather.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import time from bme280 import BME280 diff --git a/library/setup.cfg b/library/setup.cfg index c48c7ba..362646d 100644 --- a/library/setup.cfg +++ b/library/setup.cfg @@ -33,6 +33,10 @@ install_requires = ltr559 st7735 ads1015 + fonts + font-roboto + astral + pytz sounddevice [flake8] diff --git a/library/setup.py b/library/setup.py index 08ebdc5..784db51 100755 --- a/library/setup.py +++ b/library/setup.py @@ -32,5 +32,5 @@ if parse_version(__version__) < minimum_version: setup( packages=['enviroplus'], - install_requires=['setuptools>={}'.format(minimum_version), 'pimoroni-bme280', 'pms5003', 'ltr559', 'st7735', 'ads1015'] + install_requires=['setuptools>={}'.format(minimum_version), 'pimoroni-bme280', 'pms5003', 'ltr559', 'st7735', 'ads1015', 'fonts', 'font-roboto', 'astral', 'pytz'] )