The Raspberry Pi Thread [6]


  1. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #421

    Merging my two files is turning out to be way harder than I thought. No real surprise there, its not uncommon for what I think is going to be the easy part, to be the hardest part. Especially where Python is concerned. Things I only want on one screen are showing up on both etc. And other weirdness going on. Going to have to edit every instance of "img" and change it to img_left in one file and img_right in the other. Then test it and see if it works. I was at it off and on all day yesterday trying different things that didn't work.
      My Computer


  2. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #422

    I've been at this all day and have just one last glitch to figure out.
    Need some help with a Python file. Enviro code - Support - Pimoroni Buccaneers
      My Computer


  3. Posts : 5,707
    insider build 10586.3 win10 pro 64
       #423

    makes my head spin just grazing through it ... good luck.
    alphanumeric said:
    I've been at this all day and have just one last glitch to figure out.
    Need some help with a Python file. Enviro code - Support - Pimoroni Buccaneers
      My Computer


  4. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #424

    My next step is likely to peal back the file to just the temperature code. A separate trouble shouting file with minimal code in it. It should make it easier to scroll up and down to compare blocks etc. It runs without error as it is now.
      My Computer


  5. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #425

    Got it sorted. It won't make much sense unless you read though the thread I linked to above, but I had to create a separate background image for each display. Even though its the same image, they needed to be created independently for what ever reason?
      My Computer


  6. Posts : 5,707
    insider build 10586.3 win10 pro 64
       #426

    4 wire thingie ;)


    I buy a lot of the same thing you do ,does this 4 wire piece look fimular to you ,cant remember what it came with , TY
      My Computer


  7. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #427

    Something similar comes with the Pi Foundation 7 inch touch screen. You only use them if its a really really old model Pi, with the version 1 DSI connector.
    Or you want to power the screen via the GPIO header instead of the Micro USB jack. You or I are likely never going to use the Blue and Yellow jumpers. And I don't think I have ever powered it via the Red and Black jumpers?
    There is a 5 pin right angle male header on the display driver board that they plug into. Not sure what the deal is there, 5 pin header, 4 jumper wires?
      My Computer


  8. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #428

    Tinkering with my new Indoor Outdoor Enviro Python file. The left LCD now has indoor temp top left, outdoor temp top right, indoor humidity lower left, outdoor humidity lower right. Swapped out the Date Time headers at the top for Indoor Outdoor.
    The right side display has Date and Time headers across the top, Light top right and Pressure lower right. UV index will be top left at some point.

    This was the usual some and some . Right now I'm really with how it turned out.

    Current code is as follows.
    Code:
    #!/usr/bin/env python3
    
    import os
    import sys
    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 pytz import timezone
    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(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
        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 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_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 < local_dt < sunset_today:
            day = True
            period = sunset_today - sunrise_today
            # mid = sunrise_today + (period / 2)
            progress = local_dt - sunrise_today
    
        elif local_dt > sunset_today:
            day = False
            period = sunrise_tomorrow - 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 = local_dt - sunset_yesterday
    
        # Convert time deltas to seconds
        progress = progress.total_seconds()
        period = period.total_seconds()
    
        return (progress, period, day, local_dt)
    
    def draw_background_left(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_left = map_colour(x, 80, mid_hue, day_hue, day)
        
        # New image for background colour
        img_left = Image.new('RGBA', (WIDTH, HEIGHT), color=background_left)
        
        # 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_left = Image.alpha_composite(img_left, overlay).filter(ImageFilter.GaussianBlur(radius=blur))
    
        return composite_left
    
    def draw_background_right(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_right = map_colour(x, 80, mid_hue, day_hue, day)
        
        # New image for background colour
        img_right = Image.new('RGBA', (WIDTH, HEIGHT), color=background_right)
     
        # 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_right = Image.alpha_composite(img_right, overlay).filter(ImageFilter.GaussianBlur(radius=blur))
    
        return composite_right
    
    def overlay_text_left(img_left, position, text, font, align_right=False, rectangle=False):
        draw = ImageDraw.Draw(img_left)
        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_left = Image.alpha_composite(img_left, rect_img)
        else:
            draw.text(position, text, font=font, fill=(255, 255, 255))
        return img_left
    
    
    def overlay_text_right(img_right, position, text, font, align_right=False, rectangle=False):
        draw = ImageDraw.Draw(img_right)
        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_right = Image.alpha_composite(img_right, rect_img)
        else:
            draw.text(position, text, font=font, fill=(255, 255, 255))
        return img_right
    
    
    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_in(humidity_in):
        """Convert relative humidity into good/bad description."""
        if 30 < humidity_in < 60:
            description = "good"
        else:
            description = "bad"
        return description
    
    
    def describe_humidity_out(humidity_out):
        """Convert relative humidity into good/bad description."""
        if 30 < humidity_out < 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 left LCD
    disp_left = ST7735.ST7735(
        port=0,
        cs=0,
        dc=9,
        #backlight=19,
        rotation=90,
        spi_speed_hz=10000000
    )
    
    disp_left.begin()
    
    
    
    # Initialise the right LCD
    disp_right = ST7735.ST7735(
        port=0,
        cs=1,
        dc=9,
        #backlight=19,
        rotation=90,
        spi_speed_hz=10000000
    )
    
    disp_right.begin()
    
    WIDTH = 160
    HEIGHT = 80
    
    # The city and timezone that you want to display.
    city_name = "Halifax"
    time_zone = "Canada/Atlantic"
    
    # 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
    
    # Set up BME280 weather sensor
    bus = SMBus(1)
    bme_in = BME280(0x76)
    bme_out = BME280(0x77)
    
    min_temp_in = None
    max_temp_in = None
    min_temp_out = None
    max_temp_out = None
    
    # 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__))
        progress, period, day, local_dt = sun_moon_time(city_name, time_zone)
        background_left = draw_background_left(progress, period, day)
        background_right = draw_background_right(progress, period, day)
    
        # Time.
        time_elapsed = time.time() - start_time
        date_string = local_dt.strftime("%B %-d")
        time_string = local_dt.strftime("%-I:%M %p")
        img_left = overlay_text_left(background_left, (0 + margin, 0 + margin), ("Indoor"), font_lg)
        img_left = overlay_text_left(img_left, (WIDTH - margin, 0 + margin), ("Outdoor"), font_lg, align_right=True)
        img_right = overlay_text_right(background_right, (0 + margin, 0 + margin), date_string, font_lg)
        img_right = overlay_text_right(img_right, (WIDTH - margin, 0 + margin), time_string, font_lg, align_right=True)
    
    
        # Temperature in
        temperature_in = bme_in.get_temperature()
    
        if time_elapsed > 30:
            if min_temp_in is not None and max_temp_in is not None:
                if temperature_in < min_temp_in:
                    min_temp_in = temperature_in
                elif temperature_in > max_temp_in:
                    max_temp_in = temperature_in
            else:
                min_temp_in = temperature_in
                max_temp_in = temperature_in
    
        #temp_string = f"{corr_temperature:.0f}°C"
        temp_string_in = f"{temperature_in:.0f}°C"       
        img_left = overlay_text_left(img_left, (68, 18), temp_string_in, font_lg, align_right=True)
        spacing = font_lg.getsize(temp_string_in)[1] + 1
        if min_temp_in is not None and max_temp_in is not None:
            range_string_in = f"{min_temp_in:.0f}-{max_temp_in:.0f}"
        else:
            range_string_in = "------"
        img_left = overlay_text_left(img_left, (68, 18 + spacing), range_string_in, font_sm, align_right=True, rectangle=True)
        temp_icon = Image.open(f"{path}/icons/temperature.png")
        img_left.paste(temp_icon, (margin, 18), mask=temp_icon)
    
        # Temperature out
        temperature_out = bme_out.get_temperature()
    
        if time_elapsed > 30:
            if min_temp_out is not None and max_temp_out is not None:
                if temperature_out < min_temp_out:
                    min_temp_out = temperature_out
                elif temperature_out > max_temp_out:
                    max_temp_out = temperature_out
            else:
                min_temp_out = temperature_out
                max_temp_out = temperature_out
    
        #temp_string = f"{corr_temperature:.0f}°C"
        temp_string_out = f"{temperature_out:.0f}°C"       
        img_left = overlay_text_left(img_left, (WIDTH - margin, 18), temp_string_out, font_lg, align_right=True)
        spacing = font_lg.getsize(temp_string_out.replace(",", ""))[1] + 1
        if min_temp_out is not None and max_temp_out is not None:
            range_string_out = f"{min_temp_out:.0f}-{max_temp_out:.0f}"
        else:
            range_string_out = "------"
        img_left = overlay_text_left(img_left, (WIDTH - margin, 18 + spacing), range_string_out, font_sm, align_right=True, rectangle=True)
        temp_icon = Image.open(f"{path}/icons/temperature.png")
        img_left.paste(temp_icon, (80, 18), mask=temp_icon)
    
    
        # Humidity in
        humidity_in = bme_in.get_humidity()
        humidity_string_in = f"{humidity_in:.0f}%"
        img_left = overlay_text_left(img_left, (68, 48), humidity_string_in, font_lg, align_right=True)
        spacing = font_lg.getsize(humidity_string_in)[1] + 1
        humidity_desc_in = describe_humidity_in(humidity_in).upper()
        img_left = overlay_text_left(img_left, (68, 48 + spacing), humidity_desc_in, font_sm, align_right=True, rectangle=True)
        humidity_icon = Image.open(f"{path}/icons/humidity-{humidity_desc_in.lower()}.png")
        img_left.paste(humidity_icon, (margin, 48), mask=humidity_icon)
    
        # Humidity out
        humidity_out = bme_out.get_humidity()
        humidity_string_out = f"{humidity_out:.0f}%"
        img_left = overlay_text_left(img_left, (WIDTH - margin, 48), humidity_string_out, font_lg, align_right=True)
        spacing = font_lg.getsize(humidity_string_out.replace(",", ""))[1] + 1
        humidity_desc_out = describe_humidity_out(humidity_out).upper()
        img_left = overlay_text_left(img_left, (WIDTH - margin - 1, 48 + spacing), humidity_desc_out, font_sm, align_right=True, rectangle=True)
        humidity_icon = Image.open(f"{path}/icons/humidity-{humidity_desc_out.lower()}.png")
        img_left.paste(humidity_icon, (80, 48), mask=humidity_icon)
    
        # Light
        light = ltr559.get_lux()
        light_string = f"{int(light):,}"
        img_right = overlay_text_right(img_right, (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_right = overlay_text_right(img_right, (WIDTH - margin - 1, 18 + spacing), light_desc, font_sm, align_right=True, rectangle=True)
        light_icon = Image.open(f"{path}/icons/bulb-{light_desc.lower()}.png")
        img_right.paste(humidity_icon, (80, 18), mask=light_icon)
    
    
        # Pressure
        pressure = bme_out.get_pressure()
        t = time.time()
        mean_pressure, change_per_hour, trend = analyse_pressure(pressure, t)
        #pressure_string = f"{int(mean_pressure):} {trend}"
        pressure_string = f"{pressure:.0f} {trend}"
        img_right = overlay_text_left(img_right, (WIDTH - margin, 48), pressure_string, font_lg, align_right=True)
        #pressure_desc = describe_pressure(mean_pressure).upper()
        pressure_desc = describe_pressure(pressure).upper()
        spacing = font_lg.getsize(pressure_string.replace(",", ""))[1] + 1
        img_right = overlay_text_right(img_right, (WIDTH - margin - 1, 48 + spacing), pressure_desc, font_sm, align_right=True, rectangle=True)
        pressure_icon = Image.open(f"{path}/icons/weather-{pressure_desc.lower()}.png")
        img_right.paste(pressure_icon, (80, 48), mask=pressure_icon)
    
        # Display image
        disp_left.display(img_left)
        disp_right.display(img_right)
      My Computer


  9. Posts : 5,707
    insider build 10586.3 win10 pro 64
       #429

    Great work ,thats a lot of code to keep track of ,i cant read 5 lines and retype it with out looking back at the code 4 or 5 times ,my short term memory is fugged ,, I'm getting worse instead of better ...I do envey you.... just on pimoroni and seen this , a tiny pico,,,no no no way i need or will be getting one ,i'm done buying unless its need to finish something
    Pimoroni: Raspberry Pi, Adafruit, micro:bit, and Arduino in the UK
      My Computer


  10. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #430

    That's likely the biggest file I've had to deal with so far. The original file I started with was about a quarter the size. All the blocks of code, many repeating with small differences made it really hard to fix my glitch.

    That Pico is ESP32 based, not RP2040 based. It was released before the Pi PICO was a thing. The "Pico" just means its smaller that a "Nano", as in Arduino Nano.
      My Computer


 

  Related Discussions
Our Sites
Site Links
About Us
Windows 10 Forums is an independent web site and has not been authorized, sponsored, or otherwise approved by Microsoft Corporation. "Windows 10" and related materials are trademarks of Microsoft Corp.

© Designer Media Ltd
All times are GMT -5. The time now is 03:46.
Find Us




Windows 10 Forums