
Final Deliverables
Raspberry Pi Housing


Wearable Device




Engineering Drawings



Computer Program
************************************************************
            ***  Program Implementation - STUDENT CODE BEGINS HERE!  ***
            ************************************************************
            Below this line is where you should IMPLEMENT each of the
            required tasks.
                - DO NOT define any functions in this section!
                - You can liken this to a main() function where you
                  would implement your individual functions in your
                  Lab Mini-Milestones
                - PAY ATTENTION TO YOUR INDENTATIONS!!!!
            '''
            ## Start with indentation aligned with this comment
            
            #Variable/object initializations
            #LED status guide
            #Starting message
            print("Red led - Fall detected")
            print("Green led (solid) - Standby mode")
            print("Green led (flashing) - Charging\n\n\n")
            #Initialize files that the program will write to
            Start_Up_Routine()
            
            #Account login and password for twilio account
            account_sid = "AC7aa58358d003cc3b1b4dd33a53962c8e"
            auth_token = "a907c4305a35e1daa00e9b471e91f06b"
            #Contacts to call upon medical emergency
            priority_contact = "+16479182542" #Dorian's Number
            contacts = [priority_contact]
            #Initializing the twilio object and its client
            Twilio = Twilio_Client(account_sid, auth_token, contacts)
            Twilio.Initialize_Client()
            #Initializing the sensor object
            Sensor = Orientation_Sensor()
            #Initializing the button object and the charging button on pin 21 and pin 26 respectively
            Push_Button = Button(21)
            Charging_Button = Button(26)
            #^^ Is meant to simulate what would happen if the watch was charging. The button doesn't actually exist, it's just for demo purposes
            #Initializing the buzzer object on pin 18
            buzzer = Buzzer(18)
            #Initializing the red and green leds on pins 24 and 12 respectively
            Red_Led = LED(24)
            Green_Led = LED(12)
            
            #Initializing the watch graphical user interface
            Watch = Watchface()
            
            #Getting a buffer of data - prevents an index error later on
            Read_Data(Sensor,5,0.1)
            #Counter to keep count of time, this allows the program to read data from the sensor at set intervals
            counter = 0
            #Insures that the program runs at a set speed
            program_speed_limit = 0.05
            
            
            Green_Led.on()
            
            
            
            while True:
                
                time.sleep(program_speed_limit)
                emergency_flag = False
                #Read data
                if (round(counter,2)%0.75 == 0):
                    Read_Data(Sensor,5,0.1)
                    Calculate_Rolling_Average(10)
                    Calculate_Average_Velocity(2,0.75)
                    Calculate_Average_Acceleration(2,0.75)
                    
                #Flags that determine if a fall has occured
                sudden_movement_flag = Detect_Sudden_Movement()
                flag_rolling_ank, flag_rolling_wr = Detect_Pos_Diff()
                flags = [flag_rolling_ank, flag_rolling_wr, sudden_movement_flag]
                #Based on the flags, did a fall happen?                
                Detect_Fall(flags, Sensor, Watch, Push_Button, Twilio, buzzer, Red_Led, Green_Led)
                #Manual help request
                if (Push_Button.is_pressed):
                    
                    emergency_flag = Manual_Alert(Push_Button, Watch, buzzer, Red_Led, Green_Led)
                #Manual_Alert has registered as true, help is needed
                if (emergency_flag):
                    Twilio.Call_For_Help()
                    #Getting a buffer of data - prevents an index error later on
                    Read_Data(Sensor,10,0.1)
                    Calculate_Rolling_Average(10)
                    Calculate_Average_Velocity(2,0.75)
                    Calculate_Average_Acceleration(2,0.75)
Watch.Rectangle_Transition(Watch.colour_bank["black"])
                #Watch is charging
                if (Charging_Button.is_pressed):
                    #Device put to charge, back up files
                    Archiving_Routine()
                    
                    #Getting a buffer of data - prevents an index error later on
                    Read_Data(Sensor,10,0.1)
                    Calculate_Rolling_Average(10)
                    Calculate_Average_Velocity(2,0.75)
                    Calculate_Average_Acceleration(2,0.75)
                    
                    Watch.Charging(Green_Led, Charging_Button)
                #Display the time
                Watch.Display_Time()
                counter+=program_speed_limit
                
            
            
            
            
            '''
            ************************************************************
            ***   Program Implementation - STUDENT CODE ENDS HERE!   ***
            ************************************************************
            '''
        except:
            (type, value, traceback) = sys.exc_info()
            sys.excepthook(type, value, traceback)
            sys.exit(1)
    def stop(self):
        self.is_running = False
        print('stopping thread...')
        self.terminate()
'''
************************************************************
***   Function Definitions - STUDENT CODE BEGINS HERE!   ***
************************************************************
Below this line is where you should DEFINE all functions
    - Any output devices that are used in your functions
      should be defined here as well
    - PAY ATTENTION TO YOUR INDENTATIONS!!!!
'''
#imports
import os
from twilio.rest import Client
import matplotlib.pyplot as plt
import numpy as np
import pygame
import math
from datetime import datetime as dt
class Twilio_Client:
    def __init__(self, ID, auth, contacts, your_number="+16145023894"):
        self.ID = ID
        self.auth = auth
        self.contacts = contacts
        self.your_number = your_number
def Call_For_Help(self):
        for contact in self.contacts:
            #Text the priority contact
            message = self.client.messages.create(
                to=contact,
                from_= self.your_number,
                body="This is an automated message from Team-13. Your loved one has fallen and needs urgent medical care.")
            #The api does one command a second therefore there needs to be a delay
            time.sleep(2) 
            
            #Call the priority contact
            call = self.client.calls.create(
                url = 'http://demo.twilio.com/docs/voice.xml',
                to=contact,
                from_= self.your_number,
            )
        #Archive and wipe files
        Archiving_Routine()
    def Initialize_Client(self):
        #Creates the twilio client to permit calling/texting
        self.client = Client(self.ID, self.auth)
class Watchface:
    def __init__(self):
        #Initializations
        pygame.init()
        pygame.display.init()
        pygame.font.init()
        #Colour bank
        self.colour_bank = {"red":(255,0,0),
                            "blue":(0,0,255),
                            "green":(0,255,0),
                            "white":(255,255,255),
                            "black":(0,0,0),
                            "yellow":(255,255,0),
                            "turquoise":(64,224,208),
                            "magenta":(255,0,255),
                            "teal":(0,128,128)}
        #Default font
        self.font_style = pygame.font.match_font("arial")
        #Initializing screen
        self.length = 640
        self.width = 480
        self.dimensions = (self.length,self.width)
        self.screen = pygame.display.set_mode(self.dimensions)
        #Allows the watch to keep track of how many milliseconds have passed since initialization
        self.timer = 0
    def Automatic_Help_Request(self,message,time=0):
                
        #Get countdown time as integer
        time_left = int((60-time)//1)
        if (round(time,2)%2==0):
            #Shell update within an if statement to limit program lag
            Combined_Information()
        if time_left < 0:
            #Because of floating point errors the time will appear as negative at zero
            time_left = 0
        time_left = str(time_left)        
        self.screen.fill(self.colour_bank["red"])
        #Message will be written in two lines, initializing variables
        line1 = ""
        line2 = ""
        #Finding desired message
        if message == 1:
            line1 = "Help sequence"
            line2 = "Initialized"
        elif message == 2:
            line1 = "Help sequence"
            line2 = "Aborted"
        elif message == 3:
            line1 = "Help is"
            line2 = "On the way"
        elif message == 4:
            line1 = "Fall detected"
            line2 = "Press button"
            time_left = "to cancel" #"to cancel" isn't the time left but should be written in the same spot as "time left" would be written in
        #Draw circle
        center = (self.length//2,self.width//2)
        pygame.draw.circle(self.screen,self.colour_bank["turquoise"],center,abs(int((self.length/3)-20*math.sin(self.timer/500))))
        #Write message to screen
        self.Text_To_Screen(line1,50,self.colour_bank["black"],self.length/2,3*self.width/8)
        self.Text_To_Screen(line2,50,self.colour_bank["black"],self.length/2,4*self.width/8)
        self.Text_To_Screen(time_left,50,self.colour_bank["black"],self.length/2,5*self.width/8)
        #Update display
        self.Update_Screen()
        
    def Charging(self,Green_Led, Charging_Button):
        counter = 0
        self.Rectangle_Transition(self.colour_bank["teal"])
       
        while Charging_Button.is_pressed:
            if (round(counter,2)%1==0):
                #Shell update within an if statement to limit program lag
                Combined_Information()
            
            #Background
            self.screen.fill(self.colour_bank["teal"])
            #Draw circle and text
            center = (self.length//2,self.width//2)
            pygame.draw.circle(self.screen,self.colour_bank["black"],center,abs(int((self.length/3)-20*math.sin(self.timer/500))))
            self.Text_To_Screen("Charging",50,self.colour_bank["white"],self.length/2,self.width/2)
self.Update_Screen()
            #Flash LED every 3 seconds
            if ((self.timer//1000)%6 == 0):
                Green_Led.off()
            elif ((self.timer//1000)%3 == 0):
                Green_Led.on()
            time.sleep(0.05)
            counter += 0.05
        #Charging has stopped
        Green_Led.off()
        self.Rectangle_Transition(self.colour_bank["black"])
        
    def Display_Time(self):
        #Shell update
        Combined_Information()
        
        #Fetch current time
        time = Get_Current_Time()
        #Update screen to have black background with the time and message displayed
        self.screen.fill(self.colour_bank["black"])
        self.Text_To_Screen(time,100,self.colour_bank["white"],self.length/2,2*self.width/5)
        message = "Push button for 10 seconds for EMS"
        self.Text_To_Screen(message,20,self.colour_bank["white"],self.length/2,3*self.width/4-10*math.sin(self.timer/500)) #The sin function is for animating the text
        self.Update_Screen()
    def Manual_Help_Request(self,time,message):
        if (round(time,2)%2==0):
            #Shell update within an if statement to limit program lag
            Combined_Information()
        
        #Get countdown time as integer and cast as string
        time_left = int((10-time)//1)
        if time_left < 0:
            #Because of floating point errors the time will appear as negative at zero
            time_left = 0
        time_left = str(time_left)
        self.screen.fill(self.colour_bank["white"])
        #Message will be written in two lines, initializing variables
        line1 = ""
        line2 = ""
        #Finding desired message
        if message == 1:
            line1 = "Help sequence"
            line2 = "Initialized"
        elif message == 2:
            line1 = "Help sequence"
            line2 = "Aborted"
        elif message == 3:
            line1 = "Help is"
            line2 = "On the way"
        
        #Draw circle
        center = (self.length//2,self.width//2)
        pygame.draw.circle(self.screen,self.colour_bank["turquoise"],center,abs(int((self.length/3)-20*math.sin(self.timer/500))))
        #Write message to screen
        self.Text_To_Screen(line1,50,self.colour_bank["black"],self.length/2,3*self.width/8)
        self.Text_To_Screen(line2,50,self.colour_bank["black"],self.length/2,4*self.width/8)
        self.Text_To_Screen(time_left,50,self.colour_bank["black"],self.length/2,5*self.width/8)
        #Update display
        self.Update_Screen()
    def Rectangle_Transition(self,colour):
        #General info: this method is the animation between different watch screens
        #The dimensions of the drawn on rectangles
        final_rect_len = self.length
        final_rect_width = self.width//2
        #The rectangles will increase in size, starting from zero
        curr_rect_width = 0
        
        for i in range(2,10):
            #Using the harmonic series to reduce the change in size of rectangles that will be on screen
            curr_rect_width += final_rect_width * (1/i)
            #Rectangle from top
            
            #Dimensions(left, top, length, width)
            dimensions_top = (0,0,self.length,curr_rect_width)
            pygame.draw.rect(self.screen,colour,dimensions_top)
            
            
            #Rectangle from bottom
            top_coord = self.width - curr_rect_width 
            dimensions_bottom = (0,top_coord,self.length,curr_rect_width)
            pygame.draw.rect(self.screen, colour,dimensions_bottom)
            #Update screen
            self.Update_Screen()
            time.sleep(0.1)
        
    def Text_To_Screen(self,text,size,colour,x,y):
        #Setting the specific font and size for the desired text
        text_font = pygame.font.Font(self.font_style,size)
        #Pygame can't write directly onto the screen therefore the font must be "rendered" onto a new surface
        text_surface = text_font.render(text, True, colour)
        #Find how big the new surface is 
        text_rect = text_surface.get_rect()
        #Setting where the middle of the top bar will be placed on the screen
        text_rect.center = (x,y)
        #Paste the text to the screen
        self.screen.blit(text_surface, text_rect)
    def Update_Screen(self):
        #Updates screen and internal clock
        pygame.display.flip()
        self.timer = pygame.time.get_ticks() 
def Alert_User(Sensor, Watch, Push_Button, Twilio, buzzer, Red_Led, Green_Led):
    #Setting initial value to trigger the while loop
    acc = -1
    #Other variable initalizations
    increment = 0.1 #seconds
    threshold = 70 #degrees
    time_limit = 60 #seconds
    message = 4
    counter = 0
    emergency_flag = True
    #Updating the GUI
    Watch.Rectangle_Transition(Watch.colour_bank["red"])
    Green_Led.off()
    Red_Led.on()
    #Turn on buzzer to alert the user
    buzzer.on()
    
    while acc != 0:
        #Waiting to the fall to complete. When fall is finished, acceleration will be zero
        #Display that a fall was detected
        Watch.Automatic_Help_Request(message)
        #Flags
        wrist_zero = False
        ankle_zero = False
        
        #Continue recording data
        time.sleep(0.25)
        Read_Data(Sensor,5,0.1)
        Calculate_Rolling_Average(10)
        Calculate_Average_Velocity(2,0.75)
        Calculate_Average_Acceleration(2,0.75)
        #read wrist data from acceleration file
        accel_file = open('average_acceleration_wr.txt','r')
        last_line = accel_file.readlines()[-1].split()
        yaw_accel = float(last_line[0])
        roll_accel = float(last_line[1])
        pitch_accel = float(last_line[2])
        yaw_zero = False
        roll_zero = False
        pitch_zero = False
        #Deadzoning - in real life the acceleration values will never be zero so as long as they're within a range we'll be good to continue
        if(abs(yaw_accel) < 0.5):
            yaw_zero = True
        if(abs(roll_accel)<0.5):
            roll_zero = True
        if(abs(pitch_accel)<0.5):
            pitch_zero = True
        if (yaw_zero and roll_zero and pitch_zero):
            wrist_zero = True
        #read ankle data from acceleration file
        accel_file = open('average_acceleration_ank.txt','r')
        last_line = accel_file.readlines()[-1].split()
        yaw_accel = float(last_line[0])
        roll_accel = float(last_line[1])
        pitch_accel = float(last_line[2])
        yaw_zero = False
        roll_zero = False
        pitch_zero = False
        #Deadzoning - in real life the acceleration values will never be zero so as long as they're within a range we'll be good to continue
        if(abs(yaw_accel) < 0.5):
            yaw_zero = True
        if(abs(roll_accel)<0.5):
            roll_zero = True
        if(abs(pitch_accel)<0.5):
            pitch_zero = True
        if (yaw_zero and roll_zero and pitch_zero):
            ankle_zero = True
        if (Push_Button.is_pressed):
            emergency_flag = False
            message = 2
            #Update GUI, let the user know that the sequence has been aborted
            Watch.Automatic_Help_Request(message)
            #Turn off buzzer and LED
            buzzer.off()
            Red_Led.off()
            Green_Led.on()
            
            #Extra time to read message
            time.sleep(2)
            Watch.Rectangle_Transition(Watch.colour_bank["black"])
            break
        if (ankle_zero and wrist_zero):
            acc = 0
            #Give the user time to read the message
            time.sleep(1)
        
        
    #Read initial position values
    reference_wr = open('rolling_average_wr.txt', 'r') 
    reference_value_wr = reference_wr.readlines()[-1].split()
    reference_wr.close()
    reference_ank = open('rolling_average_ank.txt', 'r') 
    reference_value_ank = reference_ank.readlines()[-1].split()
    reference_ank.close()
    #Split up the values 
    first_roll_wr = float(reference_value_wr[1])
    first_pitch_wr = float(reference_value_wr[2])
    first_roll_ank = float(reference_value_ank[1])
    first_pitch_ank = float(reference_value_ank[2])
    message = 1
    while emergency_flag:
        time.sleep(increment)
        counter += increment
        
        if Push_Button.is_pressed: #The user has cancelled the alert
            emergency_flag = False
            message = 2
            #Turn off buzzer and LED
            buzzer.off()
            Red_Led.off()
            Green_Led.on()
            #Update the GUI, let them know that the help sequence has been aborted
            Watch.Automatic_Help_Request(message,counter)
            
            #Give user time to read message
            time.sleep(2)
            Watch.Rectangle_Transition(Watch.colour_bank["black"])
            break
        
        else:
            #Update GUI, let them know how much time is left until help arrives
            Watch.Automatic_Help_Request(message,counter)
        #Time limit expired, exit loop and call for help
        if counter >= time_limit:
            #Turn off buzzer and LED
            buzzer.off()
            Red_Led.off()
            Green_Led.on()
            break
if emergency_flag == True:
        #Read new position
        Read_Data(Sensor,5,0.1)
        Calculate_Rolling_Average(5)
        #Get current position
        reference_new_wr = open('rolling_average_wr.txt', 'r')
        ref_new_wr = reference_new_wr.readlines()[-1].split()
        reference_new_wr.close()
        reference_new_ank = open('rolling_average_ank.txt', 'r')
        ref_new_ank = reference_new_ank.readlines()[-1].split()
        reference_new_ank.close()
        second_roll_wr = float(ref_new_wr[1])
        second_pitch_wr = float(ref_new_wr[2])
        second_roll_ank = float(ref_new_ank[1])
        second_pitch_ank = float(ref_new_ank[2])
        #Initializing flags
        wrist_unresponsive = False
        ankle_unresponsive = False
        #Check if both the ankle and wrist have moved drastically from original position in the y and z axis. If so, the user has likely gotten up and is ok
        if (abs(first_roll_wr - second_roll_wr)< threshold and abs(first_pitch_wr - second_pitch_wr)<threshold):
            wrist_unresponsive = True
        if (abs(first_roll_ank - second_roll_ank)< threshold and abs(first_pitch_ank - second_pitch_ank)<threshold):
            ankle_unresponsive = True
        
        #If the user has moved both ankle and wrist above the threshold, they are most likely and haven't canceled the alert
        if (wrist_unresponsive and ankle_unresponsive):
            #Update the GUI
            message = 3
            Watch.Automatic_Help_Request(message,counter)
            
            #Let user read message
            time.sleep(2)
            Watch.Rectangle_Transition(Watch.colour_bank["yellow"])
            Twilio.Call_For_Help()
            #Getting a buffer of data - prevents an index error later on
            Read_Data(Sensor,10,0.1)
            Calculate_Rolling_Average(10)
            Calculate_Average_Velocity(2,0.75)
            Calculate_Average_Acceleration(2,0.75)
Watch.Rectangle_Transition(Watch.colour_bank["black"])
        else:
            #person is okay and up
            message = 2
            #Update the GUI to notify that the sequence has been aborted
            Watch.Automatic_Help_Request(message,counter)
            #Give user time to read message
            time.sleep(2)
            Watch.Rectangle_Transition(Watch.colour_bank["black"])
            
def Archiving_Routine():
    #Move all files to the archive folder
    dst_path = "/home/pi/Emulator/Archive/"
    src_path = "/home/pi/Emulator/"
    current_time = Get_Current_Time_In_Seconds()
    file_suffix = current_time + ".txt"
    
    #Rolling average files
    
    file_prefix = "rolling_average"
    os.replace(src_path+"rolling_average_wr.txt",dst_path+file_prefix+"_wr_"+file_suffix)
    os.replace(src_path+"rolling_average_ank.txt",dst_path+file_prefix+"_ank_"+file_suffix)
    #Average velocity files
    file_prefix = "average_velocity"
    os.replace(src_path+"average_velocity_wr.txt",dst_path+file_prefix+"_wr_"+file_suffix)
    os.replace(src_path+"average_velocity_ank.txt",dst_path+file_prefix+"_ank_"+file_suffix)
    #Average acceleration files
    file_prefix = "average_acceleration"
    os.replace(src_path+"average_acceleration_wr.txt",dst_path+file_prefix+"_wr_"+file_suffix)
    os.replace(src_path+"average_acceleration_ank.txt",dst_path+file_prefix+"_ank_"+file_suffix)
        
    #wipe files clean
    file = open("raw_data_wr.txt",'w')
    file.close()
    file = open("raw_data_ank.txt",'w')
    file.close()
    file = open("rolling_average_wr.txt",'w')
    file.close()
    file = open("rolling_average_ank.txt",'w')
    file.close()
    file = open("average_velocity_wr.txt",'w')
    file.close()
    file = open("average_velocity_ank.txt",'w')
    file.close()
    file = open("average_acceleration_wr.txt",'w')
    file.close()
    file = open("average_acceleration_ank.txt",'w')
    file.close()
def Calculate_Average_Acceleration(data_size,input_interval):
#Average acceleration for wrist
    #Initializing variables
    yaw_difference = 0
    roll_difference = 0
    pitch_difference = 0
    #Open average velocity file and calculate the average acceleration
    with open("average_velocity_wr.txt",'r') as rolling_average_v:
        #Calculate the average rate of change by using the current data and the data x lines in the past
        all_lines = rolling_average_v.readlines()
        last_lines = all_lines[-data_size:]
        initial_position = last_lines[0].split()
        final_position = last_lines[-1].split()
        #Calculate the difference in yaw roll and pitch from the last and first data point
        yaw_difference = float(final_position[0]) - float(initial_position[0])
        roll_difference = float(final_position[1]) - float(initial_position[1])
        pitch_difference = float(final_position[2]) - float(initial_position[2])
        
    #Open a separate file and write the average acceleration                    
    with open("average_acceleration_wr.txt", 'a') as average_acceleration:
        #Calculating the average acceleration
        ayaw_average = yaw_difference/(data_size*input_interval)
        aroll_average = roll_difference/(data_size*input_interval)
        apitch_average = pitch_difference/(data_size*input_interval)
        #Formatting and writing the string
        average = [str(ayaw_average),"\t",str(aroll_average),"\t",str(apitch_average),"\n"]
        average_acceleration.writelines(average)
#Average acceleration for ankle
    #Initializing variables
    yaw_difference = 0
    roll_difference = 0
    pitch_difference = 0
    #Open average velocity file and calculate the average acceleration
    with open("average_velocity_ank.txt",'r') as rolling_average_v:
        #Calculate the average rate of change by using the current data and the data x lines in the past
        all_lines = rolling_average_v.readlines()
        last_lines = all_lines[-data_size:]
        initial_position = last_lines[0].split()
        final_position = last_lines[-1].split()
        #Calculate the difference in yaw roll and pitch from the last and first data point
        yaw_difference = float(final_position[0]) - float(initial_position[0])
        roll_difference = float(final_position[1]) - float(initial_position[1])
        pitch_difference = float(final_position[2]) - float(initial_position[2])
        
    #Open a separate file and write the average acceleration                    
    with open("average_acceleration_ank.txt", 'a') as average_acceleration:
        #Calculating the average acceleration
        ayaw_average = yaw_difference/(data_size*input_interval)
        aroll_average = roll_difference/(data_size*input_interval)
        apitch_average = pitch_difference/(data_size*input_interval)
        #Formatting and writing the string
        average = [str(ayaw_average),"\t",str(aroll_average),"\t",str(apitch_average),"\n"]
        average_acceleration.writelines(average)
def Calculate_Average_Velocity(data_size,input_interval):
#Average velocity for wrist
    
    #Initializing variables
    yaw_difference = 0
    roll_difference = 0
    pitch_difference = 0
    #Open rolling average file and calculate the average velocity
    with open("rolling_average_wr.txt",'r') as rolling_average:
        #Calculate the average rate of change by using the current data and the data x lines in the past
        all_lines = rolling_average.readlines()
        last_lines = all_lines[-data_size:]
        initial_position = last_lines[0].split()
        final_position = last_lines[-1].split()
        #Calculate the difference in yaw roll and pitch from the last and first data point
        yaw_difference = float(final_position[0]) - float(initial_position[0])
        roll_difference = float(final_position[1]) - float(initial_position[1])
        pitch_difference = float(final_position[2]) - float(initial_position[2])
        
    #Open a separate file and write the average velocity        
    with open("average_velocity_wr.txt", 'a') as average_velocity:
        #Calculating the average velocity
        vyaw_average = yaw_difference/(data_size*input_interval)
        vroll_average = roll_difference/(data_size*input_interval)
        vpitch_average = pitch_difference/(data_size*input_interval)
        #Formatting and writing the string
        average = [str(vyaw_average),"\t",str(vroll_average),"\t",str(vpitch_average),"\n"]
        average_velocity.writelines(average)
    #Average velocity for ankle
        
    
    #Initializing variables
    yaw_difference = 0
    roll_difference = 0
    pitch_difference = 0
    #Open rolling average file and calculate the average velocity
    with open("rolling_average_ank.txt",'r') as rolling_average:
        #Calculate the average rate of change by using the current data and the data x lines in the past
        all_lines = rolling_average.readlines()
        last_lines = all_lines[-data_size:]
        initial_position = last_lines[0].split()
        final_position = last_lines[-1].split()
        #Calculate the difference in yaw roll and pitch from the last and first data point
        yaw_difference = float(final_position[0]) - float(initial_position[0])
        roll_difference = float(final_position[1]) - float(initial_position[1])
        pitch_difference = float(final_position[2]) - float(initial_position[2])
        
    #Open a separate file and write the average velocity        
    with open("average_velocity_ank.txt", 'a') as average_velocity:
        #Calculating the average velocity
        vyaw_average = yaw_difference/(data_size*input_interval)
        vroll_average = roll_difference/(data_size*input_interval)
        vpitch_average = pitch_difference/(data_size*input_interval)
        #Formatting and writing the string
        average = [str(vyaw_average),"\t",str(vroll_average),"\t",str(vpitch_average),"\n"]
        average_velocity.writelines(average)
def Calculate_Rolling_Average(data_size):
    #Rolling average for wrist
    
    #Initializing variables
    yaw_total = 0
    roll_total = 0
    pitch_total = 0
    #Read 10 latest data points for pitch roll and yaw
    with open("raw_data_wr.txt",'r') as file1:
        all_lines = file1.readlines()
        #Retreive the last x lines of data
        last_lines = all_lines[-data_size:]
        #iterate through each line in the dataset and find the sum
        for i in range(len(last_lines)):
            line_buffer = last_lines[i]
            line_buffer = line_buffer.split()
            yaw_total += float(line_buffer[0])
            roll_total += float(line_buffer[1])
            pitch_total += float(line_buffer[2])
    #Calculate the average of the last x data points and write to file
    with open("rolling_average_wr.txt",'a') as file2:
        yaw_average = round(yaw_total/data_size,2)
        roll_average = round(roll_total/data_size,2)
        pitch_average = round(pitch_total/data_size,2)
        average = [str(yaw_average),"\t",str(roll_average),"\t",str(pitch_average),"\n"]
        file2.writelines(average)
#Rolling average for ankle
    #Initializing variables
    yaw_total = 0
    roll_total = 0
    pitch_total = 0
    #Read 10 latest data points for pitch roll and yaw
    with open("raw_data_ank.txt",'r') as file1:
        all_lines = file1.readlines()
        #Retreive the last x lines of data
        last_lines = all_lines[-data_size:]
        #iterate through each line in the dataset and find the sum
        for i in range(len(last_lines)):
            line_buffer = last_lines[i]
            line_buffer = line_buffer.split()
            yaw_total += float(line_buffer[0])
            roll_total += float(line_buffer[1])
            pitch_total += float(line_buffer[2])
    #Calculate the average of the last x data points and write to file
    with open("rolling_average_ank.txt",'a') as file2:
        yaw_average = yaw_total/data_size
        roll_average = roll_total/data_size
        pitch_average = pitch_total/data_size
        average = [str(yaw_average),"\t",str(roll_average),"\t",str(pitch_average),"\n"]
        file2.writelines(average)
def Combined_Information():
    #This function is exclusively to display the current state of all of the output devices and the sensor data
    raw_data_file_wr = open("raw_data_wr.txt",'r')
    raw_data_file_ank = open("raw_data_ank.txt",'r')
    rolling_average_file_wr = open("rolling_average_wr.txt",'r')
    rolling_average_file_ank = open("rolling_average_ank.txt",'r')
    raw_data_wr = raw_data_file_wr.readlines()[-1]
    raw_data_ank = raw_data_file_ank.readlines()[-1]
    average_pos_wr = rolling_average_file_wr.readlines()[-1]
    average_pos_ank = rolling_average_file_ank.readlines()[-1]
    #Determines if the output devices are in the on or off state
    red_status = "On" if led6State_var else "Off"
    green_status = "On" if led4State_var else "Off"
    buzzer_status = "On" if buzzer1State_var else "Off"
    #Shell update
    print(raw_data_wr.split()[0],raw_data_wr.split()[1],raw_data_wr.split()[2],"\t\t",
          raw_data_ank.split()[0],raw_data_ank.split()[1],raw_data_ank.split()[2],"\t",
          average_pos_wr.split()[0],average_pos_wr.split()[1],average_pos_wr.split()[2],"\t",
          average_pos_ank.split()[0],average_pos_ank.split()[1],average_pos_ank.split()[2],"\t",
          buzzer_status,"\t\t",red_status,"\t\t",green_status)
          
    
    #Writing all this information to a file
    processed_information_file = open("Processed_info.txt",'a')
    processed_information_file.writelines(["\n",raw_data_wr.split()[0]," ",raw_data_wr.split()[1]," ",raw_data_wr.split()[2],"\t\t",
          raw_data_ank.split()[0]," ",raw_data_ank.split()[1]," ",raw_data_ank.split()[2],"\t",
          average_pos_wr.split()[0]," ",average_pos_wr.split()[1]," ",average_pos_wr.split()[2],"\t",
          average_pos_ank.split()[0]," ",average_pos_ank.split()[1]," ",average_pos_ank.split()[2],"\t",
          buzzer_status,"\t\t",red_status,"\t\t",green_status])
    
def Detect_Fall(flags, Sensor, Watch, Push_Button, Twilio, buzzer, Red_Led, Green_Led):
    #If fall has been detected, alert user
    if flags[0] == True and flags[1] == True and flags[2] == True:
        Alert_User(Sensor, Watch, Push_Button, Twilio, buzzer, Red_Led, Green_Led)
def Detect_Pos_Diff():
    #Initialize flags/variables
    flag_rolling_wr = False
    flag_rolling_ank = False
    threshold = 30
    #Retreive the last two lines in the rolling_average file and separate into initial and final values for wrist
    file_rolling_av_wr = open("rolling_average_wr.txt", 'r')
    rolling_av_wr = file_rolling_av_wr.readlines()
    last_lines_wr = rolling_av_wr[-2:]
    initial_position_wr = last_lines_wr[0].split()
    final_position_wr = last_lines_wr[-1].split()
    #Retreive the last two lines in the rolling_average file and separate into initial and final values for ankle
    file_rolling_av_ank = open("rolling_average_ank.txt", 'r')
    rolling_av_ank = file_rolling_av_ank.readlines()
    last_lines_ank = rolling_av_ank[-2:]
    initial_position_ank = last_lines_ank[0].split()
    final_position_ank = last_lines_ank[-1].split()
    wrist_roll_difference = abs(float(final_position_wr[1]) - float(initial_position_wr[1]))
    wrist_pitch_difference = abs(float(final_position_wr[2]) - float(initial_position_wr[2]))
    ankle_roll_difference = abs(float(final_position_ank[1]) - float(initial_position_ank[1]))
    ankle_pitch_difference = abs(float(final_position_ank[2]) - float(initial_position_ank[2]))
  
    #Check to see if threshold has been crossed
    if wrist_roll_difference >= threshold:
        flag_rolling_wr = True
    if wrist_pitch_difference >= threshold:
        flag_rolling_wr = True
    if ankle_roll_difference >= threshold:
        flag_rolling_ank = True
    if ankle_pitch_difference >= threshold:
        flag_rolling_ank = True
    else:
        pass
return flag_rolling_ank, flag_rolling_wr
        
def Detect_Sudden_Movement():
    #If acceleration is above 7 deg/s^2 the threshold will be crossed
    threshold = 7
    
    #Set the flag to false by default
    sudden_movement_detected = False
    sudden_movement_detected_wr = False
    sudden_movement_detected_ank = False
    #Read the average acceleration and check to see if the threshold was passed for the wrist
    with open("average_acceleration_wr.txt",'r') as accel:
        #Isolating the last line
        everything = accel.readlines()
        average_accel = everything[-1].split()
        #Isolating roll and pitch from the string list
        roll = float(average_accel[1])
        pitch = float(average_accel[2])
        #Check to see if the acceleration has passed the threshold
        if (abs(pitch) >= threshold):
            sudden_movement_detected_wr = True
        elif (abs(roll) >= threshold):
            sudden_movement_detected_wr = True
    #Read the average acceleration and check to see if the threshold was passed for the ankle
    with open("average_acceleration_ank.txt",'r') as accel:
        #Isolating the last line
        everything = accel.readlines()
        average_accel = everything[-1].split()
        #Isolating roll and pitch from the string list
        roll = float(average_accel[1])
        pitch = float(average_accel[2])
        #Check to see if the acceleration has passed the threshold
        if (abs(pitch) >= threshold):
            sudden_movement_detected_ank = True
        elif (abs(roll) >= threshold):
            sudden_movement_detected_ank = True
    if (sudden_movement_detected_wr and sudden_movement_detected_ank):
        sudden_movement_detected = True
        
    #Return the flag
    return sudden_movement_detected
def Get_Current_Time():
    return dt.now().strftime("%H:%M")
def Get_Current_Time_In_Seconds():
    return dt.now().strftime("%H:%M:%S")
def Manual_Alert(Push_Button, Watch, buzzer, Red_Led, Green_Led):
    #If button is pushed to call for help
    Green_Led.off()
    Red_Led.on()
    
    #Initializing variables
    message = 1
    time_interval = 0.1
    counter = 0
emergency_flag = True
    #Updating GUI
    Watch.Rectangle_Transition(Watch.colour_bank["white"])
    #Turn on buzzer to alert the user
    buzzer.on()
    
    while counter < 10:
        if Push_Button.is_pressed:
            
            #Show how much time is left before help is called
            counter += time_interval
            Watch.Manual_Help_Request(counter,message)
            
        else: #Button has been released, help sequence aborted
            #Turn off buzzer and LED
            buzzer.off()
            Red_Led.off()
            Green_Led.on()
            
            #Update GUI, show that help sequence has been aborted
            message = 2
            Watch.Manual_Help_Request(counter,message)
            #Time out the program for 1 second
            time.sleep(1.5)            
            emergency_flag = False
            Watch.Rectangle_Transition(Watch.colour_bank["black"])
            
            break
        
        time.sleep(time_interval)
    if emergency_flag:
        #Call for help
        message = 3
        buzzer.off()
        Red_Led.off()
        Green_Led.on()
        Watch.Manual_Help_Request(10,message)
return emergency_flag
def Read_Data(Sensor,data_size,speed):
    #Reads data from orientation sensor and writes in file
    file_wr = open("raw_data_wr.txt",'a')
    file_ank = open("raw_data_ank.txt",'a')
    for i in range(data_size):
        time.sleep(speed)
        data_tuple = Sensor.euler_angles()        
        data_str = [str(data_tuple[0]),"\t",str(data_tuple[1]),"\t",str(data_tuple[2]),"\n"]
        file_wr.writelines(data_str)
        file_ank.writelines(data_str)
    file_wr.close()
    file_ank.close()
    #Yes, it is a bit redundant, the same data is being written to two files
    #Our design necessitates two distinct sensors, one for the wrist and one of the ankle
    #Because of the limitations of the emulator we can only have one orientation sensor
    #If we were able to run two orientation sensors, the data being written to both files would be different
    #To showcase how the code would work right now we're just writing the same set of data to both files
    
def Start_Up_Routine():
    #Initialize files
    file = open("raw_data_wr.txt",'w')
    file.close()
    file = open("raw_data_ank.txt",'w')
    file.close()
    file = open("rolling_average_wr.txt",'w')
    file.close()
    file = open("rolling_average_ank.txt",'w')
    file.close()
    file = open("average_velocity_wr.txt",'w')
    file.close()
    file = open("average_velocity_ank.txt",'w')
    file.close()
    file = open("average_acceleration_wr.txt",'w')
    file.close()
    file = open("average_acceleration_ank.txt",'w')
    file.close()
    #Purely to staisfy the DP-3 project requirements, not actually needed for functionality
    file = open("Processed_info.txt",'w')
    file.writelines(["|Wr raw pos (x,z,y)|","\t","|Ank raw pos|","\t","|Avg pos Wr|","\t","|Avg pos Ank|","\t","|Buzzer|","\t","|Red LED|","\t","|Green LED|"])
    file.close()
    #shell header
    print("|Wr raw pos (x,z,y)|","\t","|Ank raw pos|","\t",
          "|Avg pos Wr|","\t","|Avg pos Ank|","\t",
          "|Buzzer|","\t","|Red LED|","\t","|Green LED|")
'''
************************************************************
***   Function Definitions - STUDENT CODE ENDS HERE!   ***
************************************************************
'''
if __name__ == "__main__":
    global mainObj
    mainObj = MainWindow_EXEC()
 
Emulator





