import time import ST7735 import random import math from PIL import Image, ImageDraw, ImageFont from fonts.ttf import RobotoMedium as UserFont import RPi.GPIO as GPIO from grow.moisture import Moisture from grow.pump import Pump GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) BUTTONS = [5, 6, 16, 24] LABELS = ['A', 'B', 'X', 'Y'] channel_count = 3 channel_selected = 0 sensors = [ Moisture(channel=1), Moisture(channel=2), Moisture(channel=3) ] pumps = [ Pump(channel=1), Pump(channel=2), Pump(channel=3) ] GPIO.setup(BUTTONS, GPIO.IN, pull_up_down=GPIO.PUD_UP) font = ImageFont.truetype(UserFont, 14) def handle_button(pin): global channel_selected index = BUTTONS.index(pin) label = LABELS[index] if label == 'A': channel_selected += 1 channel_selected %= channel_count print("Button {} pressed! Channel: {}".format(label, channel_selected)) for pin in BUTTONS: GPIO.add_event_detect(pin, GPIO.FALLING, handle_button, bouncetime=150) display = ST7735.ST7735( port=0, cs=1, dc=9, backlight=12, rotation=270, spi_speed_hz=80000000 ) ramp = [ (192, 225, 254), # Blue (196, 255, 209), # Green (255, 243, 192), # Yellow (254, 192, 192) # Red ] ramp_sat = [ (32, 137, 251), # Blue (100, 255, 124), # Green (254, 219, 82), # Yellow (254, 82, 82), # Red ] def indicator_color(value, r=None): if r is None: r = ramp if value == 1.0: return r[-1] if value == 0.0: return r[0] value *= len(r) - 1 a = int(math.floor(value)) b = a + 1 blend = float(value - a) r, g, b = [int(((r[b][i] - r[a][i]) * blend) + r[a][i]) for i in range(3)] return (r, g, b) display.begin() WIDTH, HEIGHT = display.width, display.height # Only the ALPHA channel is used from these images icon_drop = Image.open("icons/icon-drop.png") icon_nodrop = Image.open("icons/icon-nodrop.png") icon_rightarrow = Image.open("icons/icon-rightarrow.png") icon_snooze = Image.open("icons/icon-snooze.png") plants = [] for x in range(1, 15): plants.append(Image.open("icons/flat-{}.png".format(x))) CHANNEL_W = 40 CHANNEL_M = 2 print(WIDTH, HEIGHT) image = Image.new("RGBA", (WIDTH, HEIGHT), color=(255, 255, 255)) draw = ImageDraw.Draw(image) draw.rectangle((0, 0, 19, 19), (32, 138, 251)) draw.rectangle((0, HEIGHT - 19, 19, HEIGHT), (255, 255, 255)) draw.rectangle((WIDTH - 20, 0, WIDTH, 19), (75, 166, 252)) draw.rectangle((WIDTH - 20, HEIGHT - 19, WIDTH, HEIGHT), (254, 218, 80)) def icon(image, icon, position, color): col = Image.new("RGBA", (20, 20), color=color) image.paste(col, position, mask=icon) icon(image, icon_rightarrow, (0, 0), (255, 255, 255)) icon(image, icon_snooze, (0, HEIGHT - 20), (129, 129, 129)) icon(image, icon_drop, (WIDTH - 20, 0), (255, 255, 255)) icon(image, icon_nodrop, (WIDTH - 20, HEIGHT - 20), (255, 255, 255)) def plant(image, plant, channel): x = [18, 58, 98][channel] y = HEIGHT - plant.height image.paste(plant, (x, y), mask=plant) picked = random.sample(plants, 3) # image.save("test.png") while True: t = time.time() / 10.0 #c1 = (math.sin(math.pi + t * math.pi) + 1.0) / 2.0 #c2 = (math.sin(t * math.pi) + 1.0) / 2.0 #c3 = (math.sin(math.pi + t * math.pi) + 1.0) / 2.0 c1 = 1.0 - sensors[0].saturation c2 = 1.0 - sensors[1].saturation c3 = 1.0 - sensors[2].saturation print(c1, c2, c3) draw.rectangle((21, 0, 138, HEIGHT), (255, 255, 255)) # Erase channel area # Draw background bars draw.rectangle((21, int(c1 * HEIGHT), 58, HEIGHT), indicator_color(c1)) draw.rectangle((61, int(c2 * HEIGHT), 98, HEIGHT), indicator_color(c2)) draw.rectangle((101, int(c3 * HEIGHT), 138, HEIGHT), indicator_color(c3)) # Draw plant images for p in range(3): plant(image, picked[p], p) # Channel selection icons draw.rectangle((33, 2, 48, 17), indicator_color(c1, ramp_sat)) draw.rectangle((33 + 40, 2, 48 + 40, 17), indicator_color(c2, ramp_sat)) draw.rectangle((33 + 80, 2, 48 + 80, 17), indicator_color(c3, ramp_sat)) selected_x = 21 + (40 * channel_selected) + 10 draw.rectangle((selected_x, 0, selected_x + 19, 20), indicator_color([c1, c2, c3][channel_selected], ramp_sat)) draw.polygon([ (selected_x, 20), (selected_x + 9, 25), (selected_x + 19, 20) ], fill=indicator_color([c1, c2, c3][channel_selected], ramp_sat)) draw.text((33 + 3, 2), "1", font=font, fill=(255, 255, 255)) draw.text((33 + 40 + 4, 2), "2", font=font, fill=(255, 255, 255)) draw.text((33 + 80 + 4, 2), "3", font=font, fill=(255, 255, 255)) # Erase snooze icon draw.rectangle((0, HEIGHT - 19, 19, HEIGHT), (255, 255, 255)) r = int(((math.sin(time.time() * 3 * math.pi) + 1.0) / 2.0) * 255) icon(image, icon_snooze, (0, HEIGHT - 20), (r, 129, 129)) display.display(image.convert("RGB")) time.sleep(1.0 / 5)