interface & application programming

i used this week to work on the interface for my final project. i knew i wanted to use the ssd1306 oled display i used in week 9 in conjunction with some buttons. because i was going to make my own buttons for the final project, i wanted to make sure that my board work with regular buttons so that what i started with.

i bootloaded the samd11 with arduino and programmed it to serial write up, down, left, or right based on what button was pressed.

i then wrote a python script that would read those inputs and display information based on what the user was looking at. i've attached the final code bellow that also sends transactions. because i interfaced the oled directy with the raspberry pi, i was able to use the Adafruit_SSD1306 library to disaply things to it.

the way i setup the UI was to have four views: HOME_VIEW, VOTES_VIEW, INDIVIDUAL_VIEW and CONFIRM_VIEW that toggled between eachother based on what the user needed. the HOME_VIEW is a default view that when a user presses any button, it toggles itself off and toggles the VOTES_VIEW on.

the VOTES_VIEW lists the sets of votes and when a user clicks a vote to vote on, it toggels itself off and toggles the INDIVIDUAL_VIEW on. it loops perfectly by using an index that gets incremented and decremented but clicking up or down and moduloed by the length of the array of votes. at the bottom of the view, it displays the the four actions that can be done by the buttons, go up or down, press enter to choose a vote, or go back to the HOME_VIEW by click the lock button.

the INDIVIDUAL_VIEW asks the user to vote yes or no and the user gets displayed what they choose based on an array that points to yes or no. when the user makes a vote, it toggles itseld off and toggles CONFIRM_VIEW on. at the bottom of the view, it displays the four actions that can be done by the buttons, go up or down, vote or go back.

the CONFIRM_VIEW functions in the same manner as the INDIVIDUAL_VIEW but is just there to unsure that the user doesn't vote in manner that they didn't wish to accidentally. once a user confirms a vote, a "sending tx---->" message is displayed until the transaction is sent, which then sends the user back to the HOME_VIEW. at the bottom of the view, it displays the four actions that can be done by the buttons, go up or down, enter to confirm or go back.

here's a demo of the interface and the code for the interface:

import time

import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306

from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

import subprocess
import serial

# Raspberry Pi pin configuration:
RST = None     # on the PiOLED this pin isnt used
# Note the following are only used with SPI:
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0

# 128x32 display with hardware I2C:
disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST)

# Initialize library.
disp.begin()

# Clear display.
disp.clear()
disp.display()

# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = disp.width
height = disp.height
image = Image.new('1', (width, height))

# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)

# Draw a black filled box to clear the image.
draw.rectangle((0,0,width,height), outline=0, fill=0)

# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = -2
top = padding
bottom = height-padding
# Move left to right keeping track of the current x position for drawing shapes.
x = 0

font = ImageFont.load_default()


# dao --environment aragon:rinkeby exec 0xd781d3Ab8e963caB04202993986721B20fC853dF 0xb3dca023cef5d2182b222a7b91b78723f60347ea vote "10" "true" "false"

ORG_CONTRACT = "0xd781d3Ab8e963caB04202993986721B20fC853dF"
VOTE_CONTRACT = "0xb3dca023cef5d2182b222a7b91b78723f60347ea"

HOME_VIEW = True
VOTES_VIEW = False
INDIVIDUAL_VIEW = False
CONFIRM_VIEW = False

ser = serial.Serial('/dev/ttyACM0', 9600)

votes = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
i = 0
Vote_choice = 0
vote_type = ""

while True:

    if HOME_VIEW:
        # Draw a black filled box to clear the image.
        draw.rectangle((0, 0, width, height), outline=0, fill=0)
        draw.text((x, top), "VIRAL VOTING", font=font, fill=255)
        draw.text((x, top + 16), "press any button ", font=font, fill=255)
        draw.text((x, top + 25), "to start", font=font, fill=255)
        if (ser.in_waiting > 0):
            bytes_string = ser.readline()
            user_command = str(bytes_string, 'utf-8')
            if "UP" in user_command or "DOWN" in user_command or "LEFT" in user_command or "RIGHT" in user_command:
                HOME_VIEW = False
                VOTES_VIEW = True

    if VOTES_VIEW:
        # Draw a black filled box to clear the image.
        draw.rectangle((0, 0, width, height), outline=0, fill=0)

        draw.text((x, top), "vote #: " + str(votes[i % len(votes)]) + "<---", font=font, fill=255)
        draw.text((x, top + 8), "vote #: " + str(votes[(i+1) % len(votes)]), font=font, fill=255)
        draw.text((x, top + 16), "vote #: " + str(votes[(i+2) % len(votes)]), font=font, fill=255)
        draw.text((x, top + 25), "UP, DOWN, ENTER, LOCK", font=font, fill=255)

        if (ser.in_waiting > 0):
            bytes_string = ser.readline()
            user_command = str(bytes_string, 'utf-8')
            if "UP" in user_command:
                i -= 1
            if "DOWN" in user_command:
                i += 1
            if "LEFT" in user_command:
                Vote_choice = i % len(votes)
                i = 0
                INDIVIDUAL_VIEW = True
                VOTES_VIEW = False
            if "RIGHT" in user_command:
                i = 0
                Vote_choice = 0
                HOME_VIEW = True
                VOTES_VIEW = False

    if INDIVIDUAL_VIEW:
        # Draw a black filled box to clear the image.
        draw.rectangle((0, 0, width, height), outline=0, fill=0)

        draw.text((x, top), "VOTE FOR #" + str(votes[Vote_choice]), font=font, fill=255)
        if i % 2 == 0:
            draw.text((x, top + 8), "yes<---", font=font, fill=255)
            draw.text((x, top + 16), "no", font=font, fill=255)
        else:
            draw.text((x, top + 8), "yes", font=font, fill=255)
            draw.text((x, top + 16), "no<---", font=font, fill=255)

        draw.text((x, top + 25), "UP, DOWN, VOTE, BACK", font=font, fill=255)

        if (ser.in_waiting > 0):
            bytes_string = ser.readline()
            user_command = str(bytes_string, 'utf-8')
            if "UP" in user_command:
                i -= 1
            if "DOWN" in user_command:
                i += 1
            if "LEFT" in user_command:
                if i % 2:
                    vote_type = "NO"
                else:
                    vote_type = "YES"
                i = 1  # default to no when confirmation page opens
                INDIVIDUAL_VIEW = False
                CONFIRM_VIEW = True
            if "RIGHT" in user_command:
                Vote_choice = 0
                i = 0
                vote_type = ""
                INDIVIDUAL_VIEW = False
                VOTES_VIEW = True

    if CONFIRM_VIEW:
        # Draw a black filled box to clear the image.
        draw.rectangle((0, 0, width, height), outline=0, fill=0)

        draw.text((x, top), "VOTE " + vote_type + " FOR #" + str(votes[Vote_choice]) + "?", font=font, fill=255)
        if i % 2 == 0:
            draw.text((x, top + 8), "yes<---", font=font, fill=255)
            draw.text((x, top + 16), "no", font=font, fill=255)
        else:
            draw.text((x, top + 8), "yes", font=font, fill=255)
            draw.text((x, top + 16), "no<---", font=font, fill=255)

        draw.text((x, top + 25), "UP, DOWN, ENTER, BACK", font=font, fill=255)

        if (ser.in_waiting > 0):
            bytes_string = ser.readline()
            user_command = str(bytes_string, 'utf-8')
            if "UP" in user_command:
                i -= 1
            if "DOWN" in user_command:
                i += 1
            if "LEFT" in user_command:
                if i % 2:
                    i = 0
                    vote_type = ""
                    CONFIRM_VIEW = False
                    INDIVIDUAL_VIEW = True
                else:
                    draw.rectangle((0, 0, width, height), outline=0, fill=0)
                    draw.text((x, top), "SENDING TX --->", font=font, fill=255)
                    disp.image(image)
                    disp.display()
                    time.sleep(.1)

                    if vote_type == "YES":
                        cmd = "dao --environment aragon:rinkeby exec " + ORG_CONTRACT + " " + VOTE_CONTRACT + " vote " + "\"" + str(votes[Vote_choice]) + "\"" + " \"true\" \"true\""
                        subprocess.call(cmd, shell=True)
                    elif vote_type == "NO":
                        cmd = "dao --environment aragon:rinkeby exec " + ORG_CONTRACT + " " + VOTE_CONTRACT + " vote " + "\"" + str(votes[Vote_choice]) + "\"" + " \"false\" \"true\""
                        subprocess.call(cmd, shell=True)
                    CONFIRM_VIEW = False

            if "RIGHT" in user_command:
                i = 0
                vote_type = ""
                CONFIRM_VIEW = False
                INDIVIDUAL_VIEW = True

    # Display image.
    disp.image(image)
    disp.display()
    time.sleep(.1)