Merge pull request #75 from tijmenvandenbrink/master
[EVA-2020-02-2.git] / examples / weather-and-light.py
old mode 100644 (file)
new mode 100755 (executable)
index c741764..cd8ae96
@@ -1,5 +1,9 @@
 #!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 
+f"Sorry! This program requires Python >= 3.6 ðŸ˜…"
+
+import os
 import time
 import numpy
 import colorsys
@@ -11,7 +15,9 @@ from bme280 import BME280
 from ltr559 import LTR559
 
 import pytz
-from astral import Astral
+from pytz import timezone
+from astral.geocoder import database, lookup
+from astral.sun import sun
 from datetime import datetime, timedelta
 
 try:
@@ -77,54 +83,55 @@ def x_from_sun_moon_time(progress, period, x_range):
     return x
 
 
-def sun_moon_time(dt, city_name, time_zone):
+def sun_moon_time(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'."""
 
-    a = Astral()
-    city = a[city_name]
+    city = lookup(city_name, database())
 
     # Datetime objects for yesterday, today, tomorrow
-    today = dt.date()
-    dt = pytz.timezone(time_zone).localize(dt)
+    utc = pytz.utc
+    utc_dt = datetime.now(tz=utc)
+    local_dt = utc_dt.astimezone(pytz.timezone(time_zone))
+    today = local_dt.date()
     yesterday = today - timedelta(1)
     tomorrow = today + timedelta(1)
 
-    # Sun objects for yesterfay, today, tomorrow
-    sun_yesterday = city.sun(date=yesterday, local=True)
-    sun = city.sun(date=today, local=True)
-    sun_tomorrow = city.sun(date=tomorrow, local=True)
+    # Sun objects for yesterday, 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["sunrise"]
-    sunset_today = sun["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:
+    if sunrise_today < local_dt < sunset_today:
         day = True
         period = sunset_today - sunrise_today
-        mid = sunrise_today + (period / 2)
-        progress = dt - sunrise_today
+        mid = sunrise_today + (period / 2)
+        progress = local_dt - sunrise_today
 
-    elif dt > sunset_today:
+    elif local_dt > sunset_today:
         day = False
         period = sunrise_tomorrow - sunset_today
-        mid = sunset_today + (period / 2)
-        progress = dt - sunset_today
+        mid = sunset_today + (period / 2)
+        progress = local_dt - sunset_today
 
     else:
         day = False
         period = sunrise_today - sunset_yesterday
-        mid = sunset_yesterday + (period / 2)
-        progress = dt - sunset_yesterday
+        mid = sunset_yesterday + (period / 2)
+        progress = local_dt - sunset_yesterday
 
     # Convert time deltas to seconds
     progress = progress.total_seconds()
     period = period.total_seconds()
 
-    return (progress, period, day)
+    return (progress, period, day, local_dt)
 
 
 def draw_background(progress, period, day):
@@ -138,7 +145,7 @@ def draw_background(progress, period, day):
     if day:
         x = WIDTH - x
 
-    # Calculate position on sun/moon's curve
+    # Calculate position on sun/moon's curve
     centre = WIDTH / 2
     y = calculate_y_pos(x, centre)
 
@@ -147,7 +154,7 @@ def draw_background(progress, period, day):
 
     # New image for background colour
     img = Image.new('RGBA', (WIDTH, HEIGHT), color=background)
-    draw = ImageDraw.Draw(img)
+    draw = ImageDraw.Draw(img)
 
     # New image for sun/moon overlay
     overlay = Image.new('RGBA', (WIDTH, HEIGHT), color=(0, 0, 0, 0))
@@ -212,12 +219,12 @@ def analyse_pressure(pressure, t):
         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)])
+        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
+        variance_per_hour = variance * 60 * 60
 
         mean_pressure = numpy.mean(pressure_vals)
 
@@ -240,10 +247,10 @@ def analyse_pressure(pressure, t):
         change_per_hour = 0
         trend = "-"
 
-#    time.sleep(interval)
-
+    # time.sleep(interval)
     return (mean_pressure, change_per_hour, trend)
 
+
 def describe_pressure(pressure):
     """Convert pressure into barometer-type description."""
     if pressure < 970:
@@ -318,14 +325,13 @@ 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 = bme280.get_temperature()
-max_temp = bme280.get_temperature()
+min_temp = None
+max_temp = None
 
 factor = 2.25
 cpu_temps = [get_cpu_temperature()] * 5
@@ -340,15 +346,18 @@ num_vals = 1000
 interval = 1
 trend = "-"
 
+# Keep track of time elapsed
+start_time = time.time()
+
 while True:
-    dt = datetime.now()
-#    dt += timedelta(minutes=5)
-    progress, period, day = sun_moon_time(dt, city_name, time_zone)
+    path = os.path.dirname(os.path.realpath(__file__))
+    progress, period, day, local_dt = sun_moon_time(city_name, time_zone)
     background = draw_background(progress, period, day)
 
     # Time.
-    date_string = dt.strftime("%d %b %y").lstrip('0')
-    time_string = dt.strftime("%H:%M")
+    time_elapsed = time.time() - start_time
+    date_string = local_dt.strftime("%d %b %y").lstrip('0')
+    time_string = local_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)
 
@@ -361,17 +370,25 @@ while True:
     avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
     corr_temperature = temperature - ((avg_cpu_temp - temperature) / factor)
 
-    if corr_temperature < min_temp:
-        min_temp = corr_temperature
-    elif corr_temperature > max_temp:
-        max_temp = corr_temperature
+    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
-    range_string = f"{min_temp:.0f}-{max_temp:.0f}"
+    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("icons/temperature.png")
+    temp_icon = Image.open(f"{path}/icons/temperature.png")
     img.paste(temp_icon, (margin, 18), mask=temp_icon)
 
     # Humidity
@@ -382,7 +399,7 @@ while 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("icons/humidity-" + humidity_desc.lower() + ".png")
+    humidity_icon = Image.open(f"{path}/icons/humidity-{humidity_desc.lower()}.png")
     img.paste(humidity_icon, (margin, 48), mask=humidity_icon)
 
     # Light
@@ -392,7 +409,7 @@ while 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("icons/bulb-" + light_desc.lower() +  ".png")
+    light_icon = Image.open(f"{path}/icons/bulb-{light_desc.lower()}.png")
     img.paste(humidity_icon, (80, 18), mask=light_icon)
 
     # Pressure
@@ -404,7 +421,7 @@ while 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("icons/weather-" + pressure_desc.lower() +  ".png")
+    pressure_icon = Image.open(f"{path}/icons/weather-{pressure_desc.lower()}.png")
     img.paste(pressure_icon, (80, 48), mask=pressure_icon)
 
     # Display image