# SPDX-FileCopyrightText: 2020 Richard Albritton for Adafruit Industries # # SPDX-License-Identifier: MIT import time import board import microcontroller import displayio import busio from analogio import AnalogIn import neopixel import adafruit_adt7410 from adafruit_bitmap_font import bitmap_font from adafruit_display_text.label import Label from adafruit_button import Button import adafruit_touchscreen from adafruit_pyportal import PyPortal # ------------- Constants ------------- # # Sound Effects soundDemo = "/sounds/sound.wav" soundBeep = "/sounds/beep.wav" soundTab = "/sounds/tab.wav" # Hex Colors WHITE = 0xFFFFFF RED = 0xFF0000 YELLOW = 0xFFFF00 GREEN = 0x00FF00 BLUE = 0x0000FF PURPLE = 0xFF00FF BLACK = 0x000000 # Default Label styling TABS_X = 0 TABS_Y = 15 # Default button styling: BUTTON_HEIGHT = 40 BUTTON_WIDTH = 80 # Default State view_live = 1 icon = 1 icon_name = "Ruby" button_mode = 1 switch_state = 0 # ------------- Functions ------------- # # Backlight function # Value between 0 and 1 where 0 is OFF, 0.5 is 50% and 1 is 100% brightness. def set_backlight(val): val = max(0, min(1.0, val)) try: board.DISPLAY.auto_brightness = False except AttributeError: pass board.DISPLAY.brightness = val # Helper for cycling through a number set of 1 to x. def numberUP(num, max_val): num += 1 if num <= max_val: return num else: return 1 # Set visibility of layer def layerVisibility(state, layer, target): try: if state == "show": time.sleep(0.1) layer.append(target) elif state == "hide": layer.remove(target) except ValueError: pass # This will handle switching Images and Icons def set_image(group, filename): """Set the image file for a given goup for display. This is most useful for Icons or image slideshows. :param group: The chosen group :param filename: The filename of the chosen image """ print("Set image to ", filename) if group: group.pop() if not filename: return # we're done, no icon desired # CircuitPython 6 & 7 compatible image_file = open(filename, "rb") image = displayio.OnDiskBitmap(image_file) image_sprite = displayio.TileGrid( image, pixel_shader=getattr(image, "pixel_shader", displayio.ColorConverter()) ) # # CircuitPython 7+ compatible # image = displayio.OnDiskBitmap(filename) # image_sprite = displayio.TileGrid(image, pixel_shader=image.pixel_shader) group.append(image_sprite) # return a reformatted string with word wrapping using PyPortal.wrap_nicely def text_box(target, top, string, max_chars): text = pyportal.wrap_nicely(string, max_chars) new_text = "" test = "" for w in text: new_text += "\n" + w test += "M\n" text_height = Label(font, text="M", color=0x03AD31) text_height.text = test # Odd things happen without this glyph_box = text_height.bounding_box target.text = "" # Odd things happen without this target.y = int(glyph_box[3] / 2) + top target.text = new_text def get_Temperature(source): if source: # Only if we have the temperature sensor celsius = source.temperature else: # No temperature sensor celsius = microcontroller.cpu.temperature return (celsius * 1.8) + 32 # ------------- Inputs and Outputs Setup ------------- # light_sensor = AnalogIn(board.LIGHT) try: # attempt to init. the temperature sensor i2c_bus = busio.I2C(board.SCL, board.SDA) adt = adafruit_adt7410.ADT7410(i2c_bus, address=0x48) adt.high_resolution = True except ValueError: # Did not find ADT7410. Probably running on Titano or Pynt adt = None # ------------- Screen Setup ------------- # pyportal = PyPortal() pyportal.set_background("/images/loading.bmp") # Display an image until the loop starts pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=1) # Touchscreen setup [ Rotate 270 ] display = board.DISPLAY display.rotation = 270 if board.board_id == "pyportal_titano": screen_width = 320 screen_height = 480 set_backlight( 1 ) # 0.3 brightness does not cause the display to be visible on the Titano else: screen_width = 240 screen_height = 320 set_backlight(0.3) # We want three buttons across the top of the screen TAB_BUTTON_Y = 0 TAB_BUTTON_HEIGHT = 40 TAB_BUTTON_WIDTH = int(screen_width / 3) # We want two big buttons at the bottom of the screen BIG_BUTTON_HEIGHT = int(screen_height / 3.2) BIG_BUTTON_WIDTH = int(screen_width / 2) BIG_BUTTON_Y = int(screen_height - BIG_BUTTON_HEIGHT) # Initializes the display touch screen area ts = adafruit_touchscreen.Touchscreen( board.TOUCH_YD, board.TOUCH_YU, board.TOUCH_XR, board.TOUCH_XL, calibration=((5200, 59000), (5800, 57000)), size=(screen_width, screen_height), ) # ------------- Display Groups ------------- # splash = displayio.Group() # The Main Display Group view1 = displayio.Group() # Group for View 1 objects view2 = displayio.Group() # Group for View 2 objects view3 = displayio.Group() # Group for View 3 objects # ------------- Setup for Images ------------- # bg_group = displayio.Group() splash.append(bg_group) set_image(bg_group, "/images/BGimage.bmp") icon_group = displayio.Group() icon_group.x = 180 icon_group.y = 120 icon_group.scale = 1 view2.append(icon_group) # ---------- Text Boxes ------------- # # Set the font and preload letters font = bitmap_font.load_font("/fonts/Helvetica-Bold-16.bdf") font.load_glyphs(b"abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890- ()") # Text Label Objects feed1_label = Label(font, text="Text Window 1", color=0xE39300) feed1_label.x = TABS_X feed1_label.y = TABS_Y view1.append(feed1_label) feed2_label = Label(font, text="Text Window 2", color=0xFFFFFF) feed2_label.x = TABS_X feed2_label.y = TABS_Y view2.append(feed2_label) sensors_label = Label(font, text="Data View", color=0x03AD31) sensors_label.x = TABS_X sensors_label.y = TABS_Y view3.append(sensors_label) sensor_data = Label(font, text="Data View", color=0x03AD31) sensor_data.x = TABS_X + 16 # Indents the text layout sensor_data.y = 150 view3.append(sensor_data) # ---------- Display Buttons ------------- # # This group will make it easy for us to read a button press later. buttons = [] # Main User Interface Buttons button_view1 = Button( x=0, # Start at furthest left y=0, # Start at top width=TAB_BUTTON_WIDTH, # Calculated width height=TAB_BUTTON_HEIGHT, # Static height label="View 1", label_font=font, label_color=0xFF7E00, fill_color=0x5C5B5C, outline_color=0x767676, selected_fill=0x1A1A1A, selected_outline=0x2E2E2E, selected_label=0x525252, ) buttons.append(button_view1) # adding this button to the buttons group button_view2 = Button( x=TAB_BUTTON_WIDTH, # Start after width of a button y=0, width=TAB_BUTTON_WIDTH, height=TAB_BUTTON_HEIGHT, label="View 2", label_font=font, label_color=0xFF7E00, fill_color=0x5C5B5C, outline_color=0x767676, selected_fill=0x1A1A1A, selected_outline=0x2E2E2E, selected_label=0x525252, ) buttons.append(button_view2) # adding this button to the buttons group button_view3 = Button( x=TAB_BUTTON_WIDTH * 2, # Start after width of 2 buttons y=0, width=TAB_BUTTON_WIDTH, height=TAB_BUTTON_HEIGHT, label="View 3", label_font=font, label_color=0xFF7E00, fill_color=0x5C5B5C, outline_color=0x767676, selected_fill=0x1A1A1A, selected_outline=0x2E2E2E, selected_label=0x525252, ) buttons.append(button_view3) # adding this button to the buttons group button_switch = Button( x=0, # Start at furthest left y=BIG_BUTTON_Y, width=BIG_BUTTON_WIDTH, height=BIG_BUTTON_HEIGHT, label="Light Switch", label_font=font, label_color=0xFF7E00, fill_color=0x5C5B5C, outline_color=0x767676, selected_fill=0x1A1A1A, selected_outline=0x2E2E2E, selected_label=0x525252, ) buttons.append(button_switch) # adding this button to the buttons group button_2 = Button( x=BIG_BUTTON_WIDTH, # Starts just after button 1 width y=BIG_BUTTON_Y, width=BIG_BUTTON_WIDTH, height=BIG_BUTTON_HEIGHT, label="Light Color", label_font=font, label_color=0xFF7E00, fill_color=0x5C5B5C, outline_color=0x767676, selected_fill=0x1A1A1A, selected_outline=0x2E2E2E, selected_label=0x525252, ) buttons.append(button_2) # adding this button to the buttons group # Add all of the main buttons to the splash Group for b in buttons: splash.append(b) # Make a button to change the icon image on view2 button_icon = Button( x=150, y=60, width=BUTTON_WIDTH, height=BUTTON_HEIGHT, label="Icon", label_font=font, label_color=0xFFFFFF, fill_color=0x8900FF, outline_color=0xBC55FD, selected_fill=0x5A5A5A, selected_outline=0xFF6600, selected_label=0x525252, style=Button.ROUNDRECT, ) buttons.append(button_icon) # adding this button to the buttons group # Add this button to view2 Group view2.append(button_icon) # Make a button to play a sound on view2 button_sound = Button( x=150, y=170, width=BUTTON_WIDTH, height=BUTTON_HEIGHT, label="Sound", label_font=font, label_color=0xFFFFFF, fill_color=0x8900FF, outline_color=0xBC55FD, selected_fill=0x5A5A5A, selected_outline=0xFF6600, selected_label=0x525252, style=Button.ROUNDRECT, ) buttons.append(button_sound) # adding this button to the buttons group # Add this button to view2 Group view3.append(button_sound) # pylint: disable=global-statement def switch_view(what_view): global view_live if what_view == 1: button_view1.selected = False button_view2.selected = True button_view3.selected = True layerVisibility("hide", splash, view2) layerVisibility("hide", splash, view3) layerVisibility("show", splash, view1) elif what_view == 2: # global icon button_view1.selected = True button_view2.selected = False button_view3.selected = True layerVisibility("hide", splash, view1) layerVisibility("hide", splash, view3) layerVisibility("show", splash, view2) else: button_view1.selected = True button_view2.selected = True button_view3.selected = False layerVisibility("hide", splash, view1) layerVisibility("hide", splash, view2) layerVisibility("show", splash, view3) # Set global button state view_live = what_view print("View {view_num:.0f} On".format(view_num=what_view)) # pylint: enable=global-statement # Set veriables and startup states button_view1.selected = False button_view2.selected = True button_view3.selected = True button_switch.label = "OFF" button_switch.selected = True layerVisibility("show", splash, view1) layerVisibility("hide", splash, view2) layerVisibility("hide", splash, view3) # Update out Labels with display text. text_box( feed1_label, TABS_Y, "The text on this screen is wrapped so that all of it fits nicely into a " "text box that is {} x {}.".format( feed1_label.bounding_box[2], feed1_label.bounding_box[3] * 2 ), 30, ) text_box(feed2_label, TABS_Y, "Tap on the Icon button to meet a new friend.", 18) text_box( sensors_label, TABS_Y, "This screen can display sensor readings and tap Sound to play a WAV file.", 28, ) board.DISPLAY.show(splash) # ------------- Code Loop ------------- # while True: touch = ts.touch_point light = light_sensor.value sensor_data.text = "Touch: {}\nLight: {}\nTemp: {:.0f}°F".format( touch, light, get_Temperature(adt) ) # Will also cause screen to dim when hand is blocking sensor to touch screen # # Adjust backlight # if light < 1500: # set_backlight(0.1) # elif light < 3000: # set_backlight(0.5) # else: # set_backlight(1) # ------------- Handle Button Press Detection ------------- # if touch: # Only do this if the screen is touched # loop with buttons using enumerate() to number each button group as i for i, b in enumerate(buttons): if b.contains(touch): # Test each button to see if it was pressed print("button{} pressed".format(i)) if i == 0 and view_live != 1: # only if view1 is visible pyportal.play_file(soundTab) switch_view(1) while ts.touch_point: pass if i == 1 and view_live != 2: # only if view2 is visible pyportal.play_file(soundTab) switch_view(2) while ts.touch_point: pass if i == 2 and view_live != 3: # only if view3 is visible pyportal.play_file(soundTab) switch_view(3) while ts.touch_point: pass if i == 3: pyportal.play_file(soundBeep) # Toggle switch button type if switch_state == 0: switch_state = 1 b.label = "ON" b.selected = False pixel.fill(WHITE) print("Switch ON") else: switch_state = 0 b.label = "OFF" b.selected = True pixel.fill(BLACK) print("Switch OFF") # for debounce while ts.touch_point: pass print("Switch Pressed") if i == 4: pyportal.play_file(soundBeep) # Momentary button type b.selected = True print("Button Pressed") button_mode = numberUP(button_mode, 5) if button_mode == 1: pixel.fill(RED) elif button_mode == 2: pixel.fill(YELLOW) elif button_mode == 3: pixel.fill(GREEN) elif button_mode == 4: pixel.fill(BLUE) elif button_mode == 5: pixel.fill(PURPLE) switch_state = 1 button_switch.label = "ON" button_switch.selected = False # for debounce while ts.touch_point: pass print("Button released") b.selected = False if i == 5 and view_live == 2: # only if view2 is visible pyportal.play_file(soundBeep) b.selected = True while ts.touch_point: pass print("Icon Button Pressed") icon = numberUP(icon, 3) if icon == 1: icon_name = "Ruby" elif icon == 2: icon_name = "Gus" elif icon == 3: icon_name = "Billie" b.selected = False text_box( feed2_label, TABS_Y, "Every time you tap the Icon button the icon image will " "change. Say hi to {}!".format(icon_name), 18, ) set_image(icon_group, "/images/" + icon_name + ".bmp") if i == 6 and view_live == 3: # only if view3 is visible b.selected = True while ts.touch_point: pass print("Sound Button Pressed") pyportal.play_file(soundDemo) b.selected = False