def query_altimeter(sql_ctrl: SQLController) -> float: # Logic taken from: # https://github.com/adafruit/Adafruit_CircuitPython_MPL3115A2/blob/master/examples/mpl3115a2_simpletest.py altitude = round(altimeter.altitude, 2) # Safety check for altitude # If altitude is above or below these extremes, there is a value error # These are rounded ~values for Mt. Everest & Dead Sea if altitude > 10000 or altitude < -1000: logging.info('Altitude ERROR: {a}'.format(a=altitude)) # Change the value of altitude prior to saving it altitude = sql_ctrl.get_last_altitude() # Save the rowid, so we can go back and change to a future altitude, # ensuring the replacement altitude is from this hike (i.e. altimeter fails on 1st picture) last_rowid = sql_ctrl.get_last_rowid() # This entry in the database will be the next index, hence the +1 altitude_error_list.append(last_rowid + 1) else: # We have received a valid altitude logging.info('Altitude is: {a}'.format(a=altitude)) # First we need to check to see if there are altitude values to go back and fix while len(altitude_error_list) > 0: # get last ROWID in the list and change the altitude rowid = altitude_error_list.pop() sql_ctrl.set_altitude_for_rowid(rowid, altitude) # We now have an error checked altitude to return return altitude
def camcapture(pi_cam: picamera, cam_num: int, hike_num: int, photo_index: int, sql_controller: SQLController): print('select cam{n}'.format(n=cam_num)) if cam_num < 1 or cam_num > 3: raise Exception( '{n} is an invalid camera number. It must be 1, 2, or 3.'.format( n=cam_num)) else: if cam_num == 1: gpio.output(SEL_1, True) gpio.output(SEL_2, False) print("cam 1 selected") if cam_num == 2: gpio.output(SEL_1, False) gpio.output(SEL_2, False) print("cam 2 selected") if cam_num == 3: gpio.output(SEL_1, True) gpio.output(SEL_2, True) print("cam 3 selected") time.sleep(0.2) # it takes some time for the pin selection # Build image file path image_path = '{d}hike{h}/{p}_cam{c}.jpg'.format(d=DIRECTORY, h=hike_num, p=photo_index, c=cam_num) print(image_path) # Take the picture pi_cam.capture(image_path) sql_controller.set_image_path(cam_num, image_path, hike_num, photo_index) print('cam {c} -- picture taken!'.format(c=cam_num))
def main(): initialize_logger(CAMERA_PATH) logging.info('Starting transfer script...') # 1. Copy all files from camera storage location to projector storage location # if a file being copied has the same name as a file already on the projector, # the old file will be overwritten logging.info('Begin SSH copy') try: os.system('scp -r {c}* {p}'.format(c=CAMERA_PATH, p=PROJECTOR_PATH)) except Exception as error: logging.exception('===== Error while trying to copy data to projector ===== ') logging.exception(error) # 2. Remove all pictures on camera delete_picture_directories(CAMERA_PATH) # 3. Delete camera DB data # This removes all the data but does not drop tables (next indexes will be preseerved) sql_controller = SQLController(database=CAMERA_DB) sql_controller.delete_picture_and_hikes_tables() # 4. Start the remote script # subprocess.call('ssh [email protected] python3 /home/pi/capra/test-projector-insert.py', shell=True) # subprocess.call('ssh [email protected] export DISPLAY=:0', shell=True) subprocess.call('ssh [email protected] python3 /home/pi/Developer/capra-slideshow/slideshow-fade-image.py', shell=True) # subprocess.call('ssh [email protected] export DISPLAY=:0 && python3 /home/pi/Developer/capra-slideshow/slideshow-fade-image.py', shell=True) logging.info('...finished transfer script \n')
def getDBControllers(): global dbSRCController, dbDESTController dbSRCController = SQLController(database=SRCDBPATH) # TODO: if dest does not exist, create a new DB by copying the skeleton file dbDESTController = SQLController(database=DESTDBPATH)
def setUpClass(self): # NOTE - if the database or id is changed, all the tests will break # They are dependent upon that self.sql_controller = SQLController(database=self.DB, directory=self.directory) self.picture = self.sql_controller.get_picture_with_id(11994) # For testing directly on the sql statements self.sql_statements = SQLStatements()
def getDBControllers(): global dbSRCController, dbSRCController_remote, dbDESTController # this is a locally saved db, copied from camera dbSRCController = SQLController(database=CAMERA_DB) # the remote database in the camera dbSRCController_remote = SQLController(database=CAMERA_DB_REMOTE) # if dest does not exist, create a new DB by copying and renaming the skeleton file if (not os.path.exists(PROJECTOR_DB)): src_file = DATAPATH + g.DBNAME_INIT shutil.copy(src_file, DATAPATH + g.DBNAME_MASTER) # copy the file to destination dir dbDESTController = SQLController(database=PROJECTOR_DB)
class TestDatabase(unittest.TestCase): DB = '/home/pi/capra-storage/capra_camera.db' DB_EMPTY = '/home/pi/capra/tests/test_db_camera_empty.db' sql_controller = SQLController(database=DB) def test_get_last_altitude(self): sql_controller = SQLController(database=self.DB_EMPTY) alt = sql_controller.get_last_altitude() self.assertEqual(alt, 0)
def setUpClass(self): # NOTE - if the database or id is changed, all the tests will break # They are dependent upon that self.sql_controller = SQLController(database=self.DB, directory=self.directory) self.picture = self.sql_controller.get_picture_with_id(11994) # For testing directly on the sql statements self.sql_statements = SQLStatements() # Grab an array of hikes from the database sql = 'SELECT hike_id FROM hikes ORDER BY hike_id ASC;' rows = self.sql_controller._execute_query_for_anything(sql) i = 0 for r in rows: self.hikes.append(r[0]) # Grab the first picture_id from each hike from the database sql = 'SELECT picture_id FROM pictures WHERE hike={h} ORDER BY index_in_hike ASC LIMIT 1;'.format(h=r[0]) pid = self.sql_controller._execute_query_for_int(sql) self.picture_ids.append(pid) i += 1
def setupSQLController(self): '''Initializes the database connection.\n If on Mac/Windows give dialog box to select database, otherwise it will use the global defined location for the database''' # Mac/Windows: select the location if platform.system() == 'Darwin' or platform.system() == 'Windows': # filename = QFileDialog.getOpenFileName(self, 'Open file', '', 'Database (*.db)') # self.database = filename[0] # self.directory = os.path.dirname(self.database) self.database = '/Users/Jordan/Dropbox/Everyday Design Studio/A Projects/100 Ongoing/Capra/capra-storage/capra-storage-jordan-projector/capra_projector_jun2021_min_test_0708.db' self.directory = '/Users/Jordan/Dropbox/Everyday Design Studio/A Projects/100 Ongoing/Capra/capra-storage/capra-storage-jordan-projector' else: # Raspberry Pi: preset location self.database = g.DATAPATH_PROJECTOR + g.DBNAME_MASTER self.directory = g.DATAPATH_PROJECTOR print(self.database) print(self.directory) self.sql_controller = SQLController(database=self.database, directory=self.directory) # self.picture = self.sql_controller.get_picture_with_id(20000) # 28300 self.picture = self.sql_controller.get_random_picture()
class DatabaseMergedMayTests(unittest.TestCase): DB = 'tests/capra_projector_apr2021_min_test_full_merged.db' directory = 'capra-storage' sql_controller = None sql_statements = None picture = None @classmethod def setUpClass(self): # NOTE - if the database or id is changed, all the tests will break # They are dependent upon that self.sql_controller = SQLController(database=self.DB, directory=self.directory) self.picture = self.sql_controller.get_picture_with_id(11994) # For testing directly on the sql statements self.sql_statements = SQLStatements()
def main(): # Initialize and setup hardware #initialize_GPIOs() # Define the GPIO pin modes i2c_bus = smbus.SMBus(1) # Setup I2C bus i2c = busio.I2C(3, 2) # Setup I2C for DS3231 - TODO merge with smbus get_RTC_time(i2c) # Update system time from RTC turn_off_leds() # TODO - why do we need to hello_blinks() # Say hello through LEDs pzo = gpio.PWM(PIEZO, 100) beep(pzo, C, 0.25, 0.1, 3) #pi_cam = initialize_picamera(RESOLUTION) # Setup the camera initialize_background_play_pause() # Setup play/pause button prev_pause = True print("initialized piezo pin OK") print('Initializing camera object') gpio.output(SEL_1, False) gpio.output(SEL_2, False) time.sleep(0.2) print('Select pins OK') pi_cam = picamera.PiCamera() time.sleep(0.2) print('Cam init OK') pi_cam.resolution = RESOLUTION print('Resolution OK') pi_cam.rotation = 180 print('Rotation OK') # As long as initially paused, do not create new hike yet print("Waiting for initial unpause...") while (shared.pause): if (not prev_pause): logging.info('Paused') prev_pause = True print(">>PAUSED!<<") blink(LED_RED, 1, 0.3) time.sleep(1) print("Initial unpause!") # Create SQL controller and update hike information sql_controller = SQLController(database=DB) created = sql_controller.will_create_new_hike(NEW_HIKE_TIME, DIRECTORY) if created: # new hike created; blink four times blink(LED_RED, 4, 0.2) os.chmod( DIRECTORY, 766) # set permissions to be read and written to when run manually os.chmod(DB, 766) else: # continuing last hike; blink two times blink(LED_RED, 2, 0.2) time.sleep(1) hike_num = sql_controller.get_last_hike_id() photo_index = sql_controller.get_last_photo_index_of_hike(hike_num) # Initialize logger initialize_logger(hike_num) # Start the time lapse # -------------------------------------------------------------------------- while (True): # Pause the program if applicable while (shared.pause): if (not prev_pause): logging.info('Paused') beep(a, 0.1, 0.1, 2, 2) prev_pause = True print(">>PAUSED!<<") blink(LED_RED, 1, 0.3) time.sleep(1) # If applicable, log 'unpaused' if (prev_pause): logging.info('Unpaused') prev_pause = False # Read the time as UNIX timestamp current_time = get_RTC_time(i2c) # New picture: increment photo index & add row to database photo_index += 1 sql_controller.create_new_picture(hike_num, photo_index, current_time) query_altimeter(i2c_bus) # Query Altimeter first (takes a while) # Take pictures camcapture(pi_cam, 1, hike_num, photo_index, sql_controller) camcapture(pi_cam, 2, hike_num, photo_index, sql_controller) camcapture(pi_cam, 3, hike_num, photo_index, sql_controller) # Update the database with metadata for picture & hike altitude = read_altimeter(i2c_bus) sql_controller.set_picture_time_altitude(altitude, hike_num, photo_index) sql_controller.set_hike_endtime_picture_count(photo_index, hike_num) # timestamp = time.time() # OLD: this takes the time from the RPi, not the DS3221 timestamp = get_RTC_time(i2c) # Blink on every fourth picture if (photo_index % 4 == 0): blink(LED_BLUE, 1, 0.1) logging.info('cameras still alive') # Wait until 2.5 seconds have passed since last picture while (get_RTC_time(i2c) < timestamp + 2.5): pass
def __init__(self, win): # Setup the window self.window = win self.window.title("Capra Slideshow") self.window.geometry("1280x720") # self.window.geometry("720x1280") self.window.configure(background='purple') self.canvas = Canvas(root, width=1280, height=720, background="#888", highlightthickness=0) # self.canvas.configure(bg='#444') self.canvas.pack(expand='yes', fill='both') # Hardware control events self.window.bind( GPIO.add_event_detect(clk, GPIO.BOTH, callback=self.detected_rotary_change)) self.clkLastState = GPIO.input(clk) # Using GPIO.BOTH and GPIO input state, however I have noticed glitches. This will need to be ironed out # May need to use an after loop self.rotary_button_state = GPIO.input(rotary_button) self.rotary_button_state = not self.rotary_button_state # default is True, so set it to False self.window.bind( GPIO.add_event_detect(rotary_button, GPIO.BOTH, callback=self.rotary_button_pressed)) self.window.bind( GPIO.add_event_detect(BUTTON_PLAY_PAUSE, GPIO.FALLING, callback=self.button_pressed_play_pause)) self.window.bind( GPIO.add_event_detect(BUTTON_NEXT, GPIO.FALLING, callback=self.button_pressed_next)) self.window.bind( GPIO.add_event_detect(BUTTON_PREVIOUS, GPIO.FALLING, callback=self.button_pressed_previous)) # self.window.bind(GPIO.add_event_detect(SLIDER_SWITCH_MODE_0, GPIO.FALLING, callback=self.switch_mode_0)) # self.window.bind(GPIO.add_event_detect(SLIDER_SWITCH_MODE_1, GPIO.BOTH, callback=self.switch_mode_1)) # self.window.bind(GPIO.add_event_detect(SLIDER_SWITCH_MODE_2, GPIO.FALLING, callback=self.switch_mode_2)) self.determine_switch_mode() self.window.bind( GPIO.add_event_detect(BUTTON_MODE, GPIO.FALLING, callback=self.button_mode)) # Initialization for database implementation self.sql_controller = SQLController(database=DB) self.picture_starter = self.sql_controller.get_first_time_picture_in_hike( 10) self.picture = self.sql_controller.next_time_picture_in_hike( self.picture_starter) # Initialization for images and associated properties self.alpha = 0 # Initialize current and next images self.current_raw_top = Image.open( self._build_filename(self.picture_starter.camera1), 'r') self.next_raw_top = Image.open( self._build_filename(self.picture.camera1), 'r') self.current_raw_mid = Image.open( self._build_filename(self.picture_starter.camera2), 'r') self.next_raw_mid = Image.open( self._build_filename(self.picture.camera2), 'r') self.current_raw_bot = Image.open(blank_path, 'r') self.next_raw_bot = Image.open(blank_path, 'r') # Display the first 3 images to the screen self.display_photo_image_top = ImageTk.PhotoImage(self.current_raw_top) self.image_label_top = Label(master=self.canvas, image=self.display_photo_image_top, borderwidth=0) self.image_label_top.pack(side='right', fill='both', expand='yes') # self.image_label_top.place(x=20, rely=0.0, anchor='nw') self.display_photo_image_mid = ImageTk.PhotoImage(self.current_raw_mid) self.image_label_mid = Label(master=self.canvas, image=self.display_photo_image_mid, borderwidth=0) self.image_label_mid.pack(side='right', fill='both', expand='yes') # self.image_label_mid.place(x=20, y=405, anchor='nw') self.display_photo_image_bot = ImageTk.PhotoImage(self.current_raw_bot) self.image_label_bot = Label(master=self.canvas, image=self.display_photo_image_bot, borderwidth=0) self.image_label_bot.pack(side='right', fill='both', expand='yes') # self.image_label_bot.place(x=20, y=810, anchor='nw') # Hike labels self.label_mode = Label(self.canvas, text='Modes: ') self.label_hike = Label(self.canvas, text='Hike: ') self.label_index = Label(self.canvas, text='Index: ') self.label_alt = Label(self.canvas, text='Altitude: ') self.label_date = Label(self.canvas, text='Date: ') self.label_mode.place(relx=1.0, y=0, anchor='ne') self.label_hike.place(relx=1.0, y=22, anchor='ne') self.label_index.place(relx=1.0, y=44, anchor='ne') self.label_alt.place(relx=1.0, y=66, anchor='ne') self.label_date.place(relx=1.0, y=88, anchor='ne') # Start background threads which will continue for life of the class root.after(0, func=self.check_accelerometer) root.after(10, func=self.update_text) root.after(15, func=self.fade_image) root.after(self.TRANSITION_DELAY, func=self.auto_play_slideshow)
class Slideshow: # GLOBAL CLASS STATE VARIABLES (COUNTERS, BOOLS, ETC) MODE = 0 # 0 = Time | 1 = Altitude | 2 = Color # TODO - make into struct TRANSITION_DELAY = 4000 # Autoplay time between pictures (in milliseconds) IS_TRANSITION_FORWARD = True # Autoplay direction (forward or backward) PLAY = True # Autoplay (Play/Pause) bool IS_ACROSS_HIKES = False # Is rotary encoder pressed down ROTARY_COUNT = 0 # Used exclusively for testing rotary encoder steps def __init__(self, win): # Setup the window self.window = win self.window.title("Capra Slideshow") self.window.geometry("1280x720") # self.window.geometry("720x1280") self.window.configure(background='purple') self.canvas = Canvas(root, width=1280, height=720, background="#888", highlightthickness=0) # self.canvas.configure(bg='#444') self.canvas.pack(expand='yes', fill='both') # Hardware control events self.window.bind( GPIO.add_event_detect(clk, GPIO.BOTH, callback=self.detected_rotary_change)) self.clkLastState = GPIO.input(clk) # Using GPIO.BOTH and GPIO input state, however I have noticed glitches. This will need to be ironed out # May need to use an after loop self.rotary_button_state = GPIO.input(rotary_button) self.rotary_button_state = not self.rotary_button_state # default is True, so set it to False self.window.bind( GPIO.add_event_detect(rotary_button, GPIO.BOTH, callback=self.rotary_button_pressed)) self.window.bind( GPIO.add_event_detect(BUTTON_PLAY_PAUSE, GPIO.FALLING, callback=self.button_pressed_play_pause)) self.window.bind( GPIO.add_event_detect(BUTTON_NEXT, GPIO.FALLING, callback=self.button_pressed_next)) self.window.bind( GPIO.add_event_detect(BUTTON_PREVIOUS, GPIO.FALLING, callback=self.button_pressed_previous)) # self.window.bind(GPIO.add_event_detect(SLIDER_SWITCH_MODE_0, GPIO.FALLING, callback=self.switch_mode_0)) # self.window.bind(GPIO.add_event_detect(SLIDER_SWITCH_MODE_1, GPIO.BOTH, callback=self.switch_mode_1)) # self.window.bind(GPIO.add_event_detect(SLIDER_SWITCH_MODE_2, GPIO.FALLING, callback=self.switch_mode_2)) self.determine_switch_mode() self.window.bind( GPIO.add_event_detect(BUTTON_MODE, GPIO.FALLING, callback=self.button_mode)) # Initialization for database implementation self.sql_controller = SQLController(database=DB) self.picture_starter = self.sql_controller.get_first_time_picture_in_hike( 10) self.picture = self.sql_controller.next_time_picture_in_hike( self.picture_starter) # Initialization for images and associated properties self.alpha = 0 # Initialize current and next images self.current_raw_top = Image.open( self._build_filename(self.picture_starter.camera1), 'r') self.next_raw_top = Image.open( self._build_filename(self.picture.camera1), 'r') self.current_raw_mid = Image.open( self._build_filename(self.picture_starter.camera2), 'r') self.next_raw_mid = Image.open( self._build_filename(self.picture.camera2), 'r') self.current_raw_bot = Image.open(blank_path, 'r') self.next_raw_bot = Image.open(blank_path, 'r') # Display the first 3 images to the screen self.display_photo_image_top = ImageTk.PhotoImage(self.current_raw_top) self.image_label_top = Label(master=self.canvas, image=self.display_photo_image_top, borderwidth=0) self.image_label_top.pack(side='right', fill='both', expand='yes') # self.image_label_top.place(x=20, rely=0.0, anchor='nw') self.display_photo_image_mid = ImageTk.PhotoImage(self.current_raw_mid) self.image_label_mid = Label(master=self.canvas, image=self.display_photo_image_mid, borderwidth=0) self.image_label_mid.pack(side='right', fill='both', expand='yes') # self.image_label_mid.place(x=20, y=405, anchor='nw') self.display_photo_image_bot = ImageTk.PhotoImage(self.current_raw_bot) self.image_label_bot = Label(master=self.canvas, image=self.display_photo_image_bot, borderwidth=0) self.image_label_bot.pack(side='right', fill='both', expand='yes') # self.image_label_bot.place(x=20, y=810, anchor='nw') # Hike labels self.label_mode = Label(self.canvas, text='Modes: ') self.label_hike = Label(self.canvas, text='Hike: ') self.label_index = Label(self.canvas, text='Index: ') self.label_alt = Label(self.canvas, text='Altitude: ') self.label_date = Label(self.canvas, text='Date: ') self.label_mode.place(relx=1.0, y=0, anchor='ne') self.label_hike.place(relx=1.0, y=22, anchor='ne') self.label_index.place(relx=1.0, y=44, anchor='ne') self.label_alt.place(relx=1.0, y=66, anchor='ne') self.label_date.place(relx=1.0, y=88, anchor='ne') # Start background threads which will continue for life of the class root.after(0, func=self.check_accelerometer) root.after(10, func=self.update_text) root.after(15, func=self.fade_image) root.after(self.TRANSITION_DELAY, func=self.auto_play_slideshow) # root.after(0, func=self.check_mode) def _build_next_raw_images(self, next_picture: Picture): # print('build images') self.next_raw_top = Image.open( self._build_filename(next_picture.camera1), 'r') self.next_raw_mid = Image.open( self._build_filename(next_picture.camera2), 'r') # self.next_raw_bot = Image.open(blank_path, 'r') def _build_filename(self, end_of_path: str) -> str: # return '{p}{e}'.format(p=PATH, e=end_of_path) return '{e}'.format(p=PATH, e=end_of_path) # Loops for the life of the program, fading between the current image and the NEXT image def fade_image(self): # print('Fading the image at alpha of: ', self.alpha) # print(time.time()) if self.alpha < 1.0: # Top image self.current_raw_top = Image.blend(self.current_raw_top, self.next_raw_top, self.alpha) # self.current_raw_top = self.next_raw_top self.display_photo_image_top = ImageTk.PhotoImage( self.current_raw_top) self.image_label_top.configure(image=self.display_photo_image_top) # Middle image self.current_raw_mid = Image.blend(self.current_raw_mid, self.next_raw_mid, self.alpha) # self.current_raw_mid = self.next_raw_mid self.display_photo_image_mid = ImageTk.PhotoImage( self.current_raw_mid) self.image_label_mid.configure(image=self.display_photo_image_mid) # Bottom image self.current_raw_bot = Image.blend(self.current_raw_bot, self.next_raw_bot, self.alpha) # self.current_raw_bot = self.next_raw_bot self.display_photo_image_bot = ImageTk.PhotoImage( self.current_raw_bot) self.image_label_bot.configure(image=self.display_photo_image_bot) self.alpha = self.alpha + 0.0417 # self.alpha = self.alpha + 0.0209 root.after(83, self.fade_image) def update_text(self): self.determine_switch_mode() if self.MODE == 0: mode = 'Mode: Time' elif self.MODE == 1: mode = 'Mode: Altitude' elif self.MODE == 2: mode = 'Mode: Color' else: mode = 'Mode: ERROR' hike = 'Hike {n}'.format(n=self.picture.hike_id) hike_sz = self.sql_controller.get_size_of_hike(self.picture) index = '{x} / {n}'.format(x=self.picture.index_in_hike, n=hike_sz) altitude = '{a}m'.format(a=self.picture.altitude) value = datetime.datetime.fromtimestamp(self.picture.time) date_time = value.strftime('%-I:%M:%S%p on %d %b, %Y') date = '{d}'.format(d=date_time) self.label_mode.configure(text=mode) self.label_hike.configure(text=hike) self.label_index.configure(text=index) self.label_alt.configure(text=altitude) self.label_date.configure(text=date) root.after(500, self.update_text) # TODO - track down where the random number being printed to the terminal is coming from def auto_play_slideshow(self): # print('Auto incremented slideshow') if (self.PLAY): if self.IS_TRANSITION_FORWARD: # Advance forward on autoplay self.picture = self.sql_controller.get_next_picture( current_picture=self.picture, mode=self.MODE, is_across_hikes=self.IS_ACROSS_HIKES) self._build_next_raw_images(self.picture) self.alpha = .2 self.picture.print_obj() # This is a print() else: # Advance backward on autoplay self.picture = self.sql_controller.get_previous_picture( current_picture=self.picture, mode=self.MODE, is_across_hikes=self.IS_ACROSS_HIKES) self._build_next_raw_images(self.picture) self.alpha = .2 self.picture.print_obj() # This is a print() root.after(self.TRANSITION_DELAY, self.auto_play_slideshow) # BCM HARDWARE CONTROLS def detected_rotary_change(self, event): clkState = GPIO.input(clk) cntState = GPIO.input(cnt) # The encoder has moved if clkState != self.clkLastState: self.determine_switch_mode() # Increment if cntState != clkState: # Next picture self.IS_TRANSITION_FORWARD = True # For auto slideshow self.ROTARY_COUNT += 1 print("Rotary +: ", self.ROTARY_COUNT) self.picture = self.sql_controller.get_next_picture( current_picture=self.picture, mode=self.MODE, is_across_hikes=self.IS_ACROSS_HIKES) self._build_next_raw_images(self.picture) self.alpha = .2 # Resets amount of fade between pictures self.picture.print_obj() # This is a print() # Decrement else: # Previous picture self.IS_TRANSITION_FORWARD = False # For auto slideshow self.ROTARY_COUNT -= 1 print("Rotary -: ", self.ROTARY_COUNT) self.picture = self.sql_controller.get_previous_picture( current_picture=self.picture, mode=self.MODE, is_across_hikes=self.IS_ACROSS_HIKES) self._build_next_raw_images(self.picture) self.alpha = .2 # Resets amount of fade between pictures self.picture.print_obj() # This is a print() self.clkLastState = clkState # TODO - try around with this in or out depending on the rotary encoder # sleep(0.1) def rotary_button_pressed(self, event): print('rotary pressed') self.IS_ACROSS_HIKES = not self.IS_ACROSS_HIKES print('Is across hikes: {i}'.format(i=self.IS_ACROSS_HIKES)) # Another way to detect rotary encoder button press # self.rotary_button_state = not self.rotary_button_state # print('Rotary button state: {i}'.format(i=self.rotary_button_state)) # sleep(0.1) def button_pressed_play_pause(self, event): self.PLAY = not self.PLAY if self.PLAY: print('Pressed Play') else: print('Pressed Pause') def button_pressed_next(self, event): print('Next pressed') def button_pressed_previous(self, event): print('Previous pressed') def button_mode(self, event): # self.MODE += 1 # self.MODE = self.MODE % 3 # to loop count back to 0 from 3 print('Mode button not incrementing | Current mode = {n}'.format( n=self.MODE)) def determine_switch_mode(self): switch_mode_0_state = GPIO.input(SLIDER_SWITCH_MODE_0) switch_mode_1_state = GPIO.input(SLIDER_SWITCH_MODE_1) switch_mode_2_state = GPIO.input(SLIDER_SWITCH_MODE_2) # print(switch_mode_0_state) # print(switch_mode_1_state) # print(switch_mode_2_state) if switch_mode_0_state == 0: self.MODE = 0 elif switch_mode_1_state == 0: self.MODE = 1 elif switch_mode_2_state == 0: self.MODE = 2 else: print("ERROR") # print('MODE: {m}'.format(m=self.MODE)) # ADC HARDWARE CONTROLS def check_accelerometer(self): ax = AnalogIn(mcp, ACCELEROMETER_X).value ay = AnalogIn(mcp, ACCELEROMETER_Y).value az = AnalogIn(mcp, ACCELEROMETER_Z).value pitch = 180 * math.atan(ax / math.sqrt(ay * ay + az * az)) / math.pi roll = 180 * math.atan(ay / math.sqrt(ax * ax + az * az)) / math.pi if pitch > 35 and roll < 34: orientation = 'correct vertical' elif pitch < 31 and roll > 34: orientation = 'upside down vertical' else: orientation = 'horizontal' # print(orientation) # TODO - calculate pitch and roll correctly # if roll > -45 and roll < 45: # orientation = 'landscape' # elif roll >= 45 or roll <= -45: # orientation = 'vertical' root.after(500, self.check_accelerometer)
def test_get_last_altitude(self): sql_controller = SQLController(database=self.DB_EMPTY) alt = sql_controller.get_last_altitude() self.assertEqual(alt, 0)
def main(): # Initialize logger that is used while device starts up # Once a hike is started the logger switches to a hike specific log initialize_startup_logger() # Initialize and setup hardware rgb_led.turn_off() rgb_led.turn_pink() piezo.play_power_on_jingle() pi_cam = initialize_picamera(g.CAM_RESOLUTION) # Setup the camera initialize_background_turn_off() # Setup the Off button initialize_background_play_pause() # Setup Play/Pause button prev_pause = True logging.info('--------------------- POWERED ON ---------------------') # As long as initially paused, do not create new hike yet while shared.pause: # Check for turn off button, LOW battery, or LOW storage check_button_turn_off() check_low_battery_turn_off() check_low_storage_turn_off() if round(time.time(), 0) % 60 == 0: logging.info('>>>>>Another minute initially PAUSED') time.sleep(1) logging.info('>>>>>Pause button pressed --> FIRST UNPAUSE') rgb_led.turn_off() # Create SQL controller and update hike information sql_controller = SQLController(database=g.DB) timestamp = round(time.time(), 0) created = sql_controller.will_create_new_hike(g.NEW_HIKE_TIME, g.DIRECTORY, timestamp) if created: # new hike created: blink teal rgb_led.blink_teal_new_hike() else: # continue last hike: blink green rgb_led.blink_green_continue_hike() time.sleep(1) hike_num = sql_controller.get_last_hike_id() photo_index = sql_controller.get_last_photo_index_of_hike(hike_num) # Switch to the hike specific logfile switch_to_hike_logger(hike_num) logging.info( '--------------------- NEW RECORDING SESSION STARTED ---------------------' ) # Start the time lapse # -------------------------------------------------------------------------- while (True): # Check for turn off button, LOW battery, or LOW storage check_button_turn_off() check_low_battery_turn_off() check_low_storage_turn_off() # Pause the program if applicable while shared.pause: if not prev_pause: logging.info('>PAUSED<') prev_pause = True rgb_led.turn_pink() piezo.play_paused_jingle() # Check for turn off button, LOW battery, or LOW storage check_button_turn_off() check_low_battery_turn_off() check_low_storage_turn_off() if round(time.time(), 0) % 60 == 0: logging.info('>>>>> + 1 minute PAUSED') time.sleep(1) # Unpause program if prev_pause: logging.info('>UNPAUSED<') prev_pause = False rgb_led.turn_off() piezo.play_start_recording_jingle() # Read the time as UNIX timestamp timestamp = round(time.time(), 0) logging.info('Unix Timestamp: {t}'.format(t=timestamp)) # New picture: increment photo index & add row to database photo_index += 1 # Get altitude before a new entry is added to the database altitude = query_altimeter(sql_controller) sql_controller.create_new_picture(hike_num, photo_index, timestamp) # Take pictures camcapture(pi_cam, 1, hike_num, photo_index, sql_controller) camcapture(pi_cam, 2, hike_num, photo_index, sql_controller) camcapture(pi_cam, 3, hike_num, photo_index, sql_controller) # Update the database with metadata for picture & hike sql_controller.set_picture_altitude(altitude, hike_num, photo_index) sql_controller.set_hike_endtime_picture_count(timestamp, photo_index, hike_num) # Blink to notify that the timelapse is still going rgb_led.blink_green_new_picture() # Log on every 5th picture if photo_index % 5 == 0: logging.info('Cameras still alive (5 pictures taken)') # Wait until 5 seconds have passed since starting to take the pictures while time.time() < timestamp + g.CAM_INTERVAL: pass
class DatabaseMay2021Tests(unittest.TestCase): DB = 'tests/capra_projector_may2021.db' directory = 'capra-storage' sql_controller = None sql_statements = None picture = None @classmethod def setUpClass(self): # NOTE - if the database or id is changed, all the tests will break # They are dependent upon that self.sql_controller = SQLController(database=self.DB, directory=self.directory) self.picture = self.sql_controller.get_picture_with_id(11994) # For testing directly on the sql statements self.sql_statements = SQLStatements() def test_get_picture_with_id(self): self.assertEqual(self.picture.picture_id, 11994) self.assertEqual(self.picture.hike_id, 10) self.assertEqual(self.picture.altitude, 2123.5) # 20,284 total pictures in database # x .05 # 1,014.2 -> rounds to 1,015 skip in the global ranks def test_get_next_color_skip_in_global(self): self.assertEqual(self.picture.picture_id, 11994) self.assertEqual(self.picture.colorrank_global, 10549) # id color_rank_global # 11994 10549 + 1015 pic = self.sql_controller.get_next_color_skip_in_global(self.picture) self.assertEqual(pic.colorrank_global, 11564) self.assertEqual(pic.picture_id, 1398) pic = self.sql_controller.get_next_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 12579) pic = self.sql_controller.get_next_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 13594) pic = self.sql_controller.get_next_color_skip_in_global(pic) pic = self.sql_controller.get_next_color_skip_in_global(pic) pic = self.sql_controller.get_next_color_skip_in_global(pic) pic = self.sql_controller.get_next_color_skip_in_global(pic) pic = self.sql_controller.get_next_color_skip_in_global(pic) pic = self.sql_controller.get_next_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 19684) self.assertEqual(pic.picture_id, 30037) # wrap around pic = self.sql_controller.get_next_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 415) self.assertEqual(pic.picture_id, 8493) # 4146 20284 pic = self.sql_controller.get_picture_with_id(4146) pic = self.sql_controller.get_next_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 1015) self.assertEqual(pic.picture_id, 10321) # 4887 19270 pic = self.sql_controller.get_picture_with_id(4887) pic = self.sql_controller.get_next_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 1) self.assertEqual(pic.picture_id, 1102) def test_get_previous_color_skip_in_global(self): self.assertEqual(self.picture.picture_id, 11994) self.assertEqual(self.picture.colorrank_global, 10549) # id color_rank_global # 11994 10549 - 1015 pic = self.sql_controller.get_previous_color_skip_in_global( self.picture) self.assertEqual(pic.colorrank_global, 9534) self.assertEqual(pic.picture_id, 29239) pic = self.sql_controller.get_previous_color_skip_in_global(pic) pic = self.sql_controller.get_previous_color_skip_in_global(pic) pic = self.sql_controller.get_previous_color_skip_in_global(pic) pic = self.sql_controller.get_previous_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 5474) pic = self.sql_controller.get_previous_color_skip_in_global(pic) pic = self.sql_controller.get_previous_color_skip_in_global(pic) pic = self.sql_controller.get_previous_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 2429) pic = self.sql_controller.get_previous_color_skip_in_global(pic) pic = self.sql_controller.get_previous_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 399) # wrap back around pic = self.sql_controller.get_previous_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 19668) self.assertEqual(pic.picture_id, 25289) # 8388 310 pic = self.sql_controller.get_picture_with_id(8388) pic = self.sql_controller.get_previous_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 19579) self.assertEqual(pic.picture_id, 6668) # 1102 1 pic = self.sql_controller.get_picture_with_id(1102) pic = self.sql_controller.get_previous_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 19270) self.assertEqual(pic.picture_id, 4887) # 10321 1015 pic = self.sql_controller.get_picture_with_id(10321) pic = self.sql_controller.get_previous_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 20284) self.assertEqual(pic.picture_id, 4146)
class DatabaseOriginal4Tests(unittest.TestCase): DB = 'tests/capra_projector_jan2021_min_test.db' # no / infront makes the path relative directory = 'capra-storage' sql_controller = None sql_statements = None picture = None @classmethod def setUpClass(self): # NOTE - if the database or id is changed, all the tests will break # They are dependent upon that self.sql_controller = SQLController(database=self.DB, directory=self.directory) self.picture = self.sql_controller.get_picture_with_id(1994) # For testing directly on the sql statements self.sql_statements = SQLStatements() def test_get_picture_with_id(self): self.assertEqual(self.picture.picture_id, 1994) self.assertEqual(self.picture.altitude, 936.62) def test_picture_object(self): picture = self.sql_controller.get_picture_with_id(1994) self.assertEqual(picture.picture_id, 1994) self.assertEqual(picture.time, 1556391512.0) self.assertEqual(picture.year, 2019) self.assertEqual(picture.month, 4) self.assertEqual(picture.day, 27) self.assertEqual(picture.minute, 718) self.assertEqual(picture.dayofweek, 5) self.assertEqual(picture.hike_id, 3) self.assertEqual(picture.index_in_hike, 878) self.assertEqual(picture.altitude, 936.62) self.assertEqual(picture.altrank_hike, 855) self.assertEqual(picture.altrank_global, 2355) self.assertEqual(picture.altrank_global_h, 1970) hsvColor = QColor() hsvColor.setHsv(91, 18, 220) self.assertEqual(picture.color_hsv, hsvColor) rgbColor = QColor(204, 219, 220) self.assertEqual(picture.color_rgb, rgbColor) self.assertEqual(picture.colorrank_hike, 1776) self.assertEqual(picture.colorrank_global, 2785) self.assertEqual(picture.colorrank_global_h, 2891) self.assertEqual(picture.colors_count, 4) colorList = [ QColor(204, 219, 220), QColor(52, 46, 17), QColor(122, 117, 75), QColor(17, 17, 15) ] self.assertEqual(picture.colors_rgb, colorList) self.assertEqual(picture.colors_conf, [0.22, 0.18, 0.16, 0.11]) self.assertEqual(picture.camera1, '/media/pi/capra-hd/hike3/878_cam1.jpg') self.assertEqual(picture.camera2, '/media/pi/capra-hd/hike3/878_cam2.jpg') self.assertEqual(picture.camera3, '/media/pi/capra-hd/hike3/878_cam3.jpg') self.assertEqual(picture.cameraf, '/media/pi/capra-hd/hike3/878_cam2f.jpg') self.assertEqual(picture.created, '2021-02-16 09:39:15') self.assertEqual(picture.updated, '2021-02-16 09:39:15') # Time # -------------------------------------------------------------------------- def test_get_next_time_in_hikes(self): # next picture by 1 pic = self.sql_controller.get_next_time_in_hikes(self.picture, 1) self.assertEqual(pic.time, 1556391516.0) self.assertEqual(pic.picture_id, 1995) # next picture by 94 pic = self.sql_controller.get_next_time_in_hikes(self.picture, 94) self.assertEqual(pic.time, 1556391888.0) self.assertEqual(pic.picture_id, 2088) # next picture by enough to wrap it around pic = self.sql_controller.get_next_time_in_hikes(self.picture, 1674) self.assertEqual(pic.time, 1556323240.0) self.assertEqual(pic.picture_id, 10) # offset is more than total list size, but is below the row pic = self.sql_controller.get_next_time_in_hikes( self.picture, 27 + 3658) self.assertEqual(pic.time, 1556391620.0) self.assertEqual(pic.picture_id, 2021) # offset is more than total list size, but is above the row pic = self.sql_controller.get_next_time_in_hikes( self.picture, 1675 + 3658) self.assertEqual(pic.time, 1556323244.0) self.assertEqual(pic.picture_id, 11) def test_get_previous_time_in_hikes(self): # previous picture by 1 pic = self.sql_controller.get_previous_time_in_hikes(self.picture, 1) self.assertEqual(pic.time, 1556391508.0) self.assertEqual(pic.picture_id, 1993) # previous picture by 94 pic = self.sql_controller.get_previous_time_in_hikes(self.picture, 94) self.assertEqual(pic.time, 1556391136.0) self.assertEqual(pic.picture_id, 1900) # previous picture by enough to wrap it around pic = self.sql_controller.get_previous_time_in_hikes( self.picture, 1994) self.assertEqual(pic.time, 1556400336.0) self.assertEqual(pic.picture_id, 3658) pic = self.sql_controller.get_previous_time_in_hikes( self.picture, 2021) self.assertEqual(pic.time, 1556400228.0) self.assertEqual(pic.picture_id, 3631) # offset is more than total list size, but is above the row pic = self.sql_controller.get_previous_time_in_hikes( self.picture, 11 + 3658) self.assertEqual(pic.time, 1556391468.0) self.assertEqual(pic.picture_id, 1983) # offset is more than total list size, but is below the row pic = self.sql_controller.get_previous_time_in_hikes( self.picture, 2000 + 3658) self.assertEqual(pic.time, 1556400312.0) self.assertEqual(pic.picture_id, 3652) def test_get_next_time_in_global(self): # in minute pic = self.sql_controller.get_next_time_in_global(self.picture, 1) self.assertEqual(pic.picture_id, 1995) pic = self.sql_controller.get_next_time_in_global(self.picture, 6) self.assertEqual(pic.picture_id, 2000) # below pic = self.sql_controller.get_next_time_in_global(self.picture, 7) self.assertEqual(pic.picture_id, 2001) pic = self.sql_controller.get_next_time_in_global(self.picture, 2556) self.assertEqual(pic.picture_id, 892) # wrap around pic = self.sql_controller.get_next_time_in_global(self.picture, 2557) self.assertEqual(pic.picture_id, 893) pic = self.sql_controller.get_next_time_in_global(self.picture, 3657) self.assertEqual(pic.picture_id, 1993) # moding below pic = self.sql_controller.get_next_time_in_global(self.picture, 3659) self.assertEqual(pic.picture_id, 1995) pic = self.sql_controller.get_next_time_in_global(self.picture, 3668) self.assertEqual(pic.picture_id, 2004) # moding above pic = self.sql_controller.get_next_time_in_global(self.picture, 6216) self.assertEqual(pic.picture_id, 894) pic = self.sql_controller.get_next_time_in_global(self.picture, 6714) self.assertEqual(pic.picture_id, 1392) def test_get_previous_time_in_global(self): # in minute pic = self.sql_controller.get_previous_time_in_global(self.picture, 1) self.assertEqual(pic.picture_id, 1993) pic = self.sql_controller.get_previous_time_in_global(self.picture, 8) self.assertEqual(pic.picture_id, 1986) # above pic = self.sql_controller.get_previous_time_in_global(self.picture, 9) self.assertEqual(pic.picture_id, 1985) pic = self.sql_controller.get_previous_time_in_global( self.picture, 834) self.assertEqual(pic.picture_id, 1160) pic = self.sql_controller.get_previous_time_in_global( self.picture, 1101) self.assertEqual(pic.picture_id, 893) # wrap around above pic = self.sql_controller.get_previous_time_in_global( self.picture, 1102) self.assertEqual(pic.picture_id, 892) # wrap around below pic = self.sql_controller.get_previous_time_in_global( self.picture, 1800) self.assertEqual(pic.picture_id, 194) # moding above pic = self.sql_controller.get_previous_time_in_global( self.picture, 3659) self.assertEqual(pic.picture_id, 1993) pic = self.sql_controller.get_previous_time_in_global( self.picture, 3668) self.assertEqual(pic.picture_id, 1984) # moding below pic = self.sql_controller.get_previous_time_in_global( self.picture, 7116) self.assertEqual(pic.picture_id, 2194) def test_get_next_time_skip_in_hikes(self): # id time hike index_in_hike (hike | index) = id # 1566 1556389800 3 450 --> (4 | 80) = 3354 # (451/2158) * 385 = 80.46 (ceiling then subtract 1) pic = self.sql_controller.get_picture_with_id(1566) pic = self.sql_controller.get_next_time_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 3354) # wrap around # 3354 1556399120 4 80 --> (1 | 187) = 188 # (81/385) * 892 = 187.66 pic = self.sql_controller.get_next_time_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 188) # 188 1556323952 1 187 --> (2 | 46) = 939 # (188/892) * 223 = 47.0 pic = self.sql_controller.get_next_time_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 939) # 939 1556377384 2 46 --> (3 | 454) = 1570 # (47/223) * 2158 = 454.8 pic = self.sql_controller.get_next_time_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1570) # 3000 1556395536 3 1884 --> (4 | 336) = 3610 # (1885/2158) * 385 = 336.29 pic = self.sql_controller.get_picture_with_id(3000) pic = self.sql_controller.get_next_time_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 3610) def test_get_previous_time_skip_in_hikes(self): # id time hike index_in_hike (hike | index) = id # 1566 1556389800 3 450 --> (2 | 46) = 939 # (451/2158) * 223 = 46.6 pic = self.sql_controller.get_picture_with_id(1566) pic = self.sql_controller.get_previous_time_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 939) # 939 1556377384 2 46 --> (1 | 187) = 188 # (47/223) * 892 = 188.0 pic = self.sql_controller.get_previous_time_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 188) # 188 1556323952 1 187 --> (4 | 81) = 3355 # (188/892) * 385 = 81.14 pic = self.sql_controller.get_previous_time_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 3355) # 3654 1556400320 4 380 --> (3 | 2135) = 3251 # (381/385) * 2158 = 2135.58 pic = self.sql_controller.get_picture_with_id(3654) pic = self.sql_controller.get_previous_time_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 3251) def test_get_next_time_skip_in_global(self): # id time minute id # 1994 1556391512 718 -> 733 2219 # 2000 1556391536 718 -> 733 2225 pic = self.sql_controller.get_next_time_skip_in_global(self.picture) self.assertEqual(pic.picture_id, 2219) pic = self.sql_controller.get_picture_with_id(2000) pic = self.sql_controller.get_next_time_skip_in_global(pic) self.assertEqual(pic.picture_id, 2225) # id time minute id # 650 1556325800 1063 -> 1078 875 # 688 1556325952 1065 -> 1080 906 # 872 1556326688 1078 -> 493 1090 # 885 1556326740 1079 -> 494 1103 pic = self.sql_controller.get_picture_with_id(650) pic = self.sql_controller.get_next_time_skip_in_global(pic) self.assertEqual(pic.picture_id, 875) pic = self.sql_controller.get_picture_with_id(688) pic = self.sql_controller.get_next_time_skip_in_global(pic) self.assertEqual(pic.picture_id, 906) pic = self.sql_controller.get_picture_with_id(872) pic = self.sql_controller.get_next_time_skip_in_global(pic) self.assertEqual(pic.picture_id, 1090) pic = self.sql_controller.get_picture_with_id(885) pic = self.sql_controller.get_next_time_skip_in_global(pic) self.assertEqual(pic.picture_id, 1103) def test_get_previous_time_skip_in_global(self): # id time minute id # 1994 1556391512 718 -> 703 1769 # 1769 1556390612 703 -> 688 1544 pic = self.sql_controller.get_previous_time_skip_in_global( self.picture) self.assertEqual(pic.picture_id, 1769) pic = self.sql_controller.get_previous_time_skip_in_global(pic) self.assertEqual(pic.picture_id, 1544) # id time minute id # 1135 1556388076 661 -> 481 912 # 912 1556377276 481 -> 1066 694 pic = self.sql_controller.get_picture_with_id(1135) pic = self.sql_controller.get_previous_time_skip_in_global(pic) self.assertEqual(pic.picture_id, 912) # wrap arounds pic = self.sql_controller.get_previous_time_skip_in_global(pic) self.assertEqual(pic.picture_id, 694) # 1050 1556377828 490 -> 1075 832 pic = self.sql_controller.get_picture_with_id(1056) pic = self.sql_controller.get_previous_time_skip_in_global(pic) self.assertEqual(pic.picture_id, 838) # Altitude # -------------------------------------------------------------------------- def test_get_next_altitude_in_hikes(self): # forward by 1 pic = self.sql_controller.get_next_altitude_in_hikes(self.picture, 1) self.assertEqual(pic.altrank_global_h, 1971) # forward by 94 pic = self.sql_controller.get_next_altitude_in_hikes(pic, 94) self.assertEqual(pic.altrank_global_h, 2065) # wrap to top of list pic = self.sql_controller.get_picture_with_id(3274) pic = self.sql_controller.get_next_altitude_in_hikes(pic, 2) self.assertEqual(pic.altrank_global_h, 1) # mod to row below pic = self.sql_controller.get_next_altitude_in_hikes( self.picture, 6 + 3658) self.assertEqual(pic.picture_id, 1987) # mod to row above pic = self.sql_controller.get_next_altitude_in_hikes( self.picture, 3600 + 3658) self.assertEqual(pic.picture_id, 1912) def test_get_previous_altitude_in_hikes(self): # backward by 1 pic = self.sql_controller.get_previous_altitude_in_hikes( self.picture, 1) self.assertEqual(pic.altrank_global_h, 1969) # backward by 94 pic = self.sql_controller.get_previous_altitude_in_hikes( self.picture, 94) self.assertEqual(pic.altrank_global_h, 1876) # wrap to bottom of list pic = self.sql_controller.get_picture_with_id(592) pic = self.sql_controller.get_previous_altitude_in_hikes(pic, 6) self.assertEqual(pic.picture_id, 3276) # mod to row above pic = self.sql_controller.get_previous_altitude_in_hikes( self.picture, 10 + 3658) self.assertEqual(pic.altrank_global_h, 1960) # mod to row below pic = self.sql_controller.get_previous_altitude_in_hikes( self.picture, 2000 + 3658) self.assertEqual(pic.altrank_global_h, 3628) def test_get_next_altitude_in_global(self): # forward by 1 pic = self.sql_controller.get_next_altitude_in_global(self.picture, 1) self.assertEqual(pic.altrank_global, 2356) # forward by 3 pic = self.sql_controller.get_next_altitude_in_global(self.picture, 3) self.assertEqual(pic.altrank_global, 2358) # wrap to top of list pic = self.sql_controller.get_picture_with_id(2976) pic = self.sql_controller.get_next_altitude_in_global(pic, 1) self.assertEqual(pic.picture_id, 524) # mod to row below pic = self.sql_controller.get_next_altitude_in_global( self.picture, 100 + 3658) self.assertEqual(pic.altrank_global, 2455) # mod to row above pic = self.sql_controller.get_next_altitude_in_global( self.picture, 2000 + 3658) self.assertEqual(pic.altrank_global, 697) def test_get_previous_altitude_in_global(self): # previous by 1 pic = self.sql_controller.get_previous_altitude_in_global( self.picture, 1) self.assertEqual(pic.altrank_global, 2354) # previous by 3 pic = self.sql_controller.get_previous_altitude_in_global( self.picture, 3) self.assertEqual(pic.altrank_global, 2352) # wrap to bottom of list pic = self.sql_controller.get_picture_with_id(544) pic = self.sql_controller.get_previous_altitude_in_global(pic, 3) self.assertEqual(pic.picture_id, 3032) # mod to row above pic = self.sql_controller.get_previous_altitude_in_global( self.picture, 100 + 3658) self.assertEqual(pic.altrank_global, 2255) # mod to row below pic = self.sql_controller.get_previous_altitude_in_global( self.picture, 2360 + 3658) self.assertEqual(pic.altrank_global, 3653) def test_get_next_altitude_skip_in_hikes(self): # id time hike alt_rank_hike id (hike | alt_rank_hike) # wrap around # 1994 1556391512 3 855 --> 707 (1 | 354) # (855/2158) * 892 = 353.41 pic = self.sql_controller.get_next_altitude_skip_in_hikes(self.picture) self.assertEqual(pic.picture_id, 707) # 1094 1556378004 2 47 --> 3577 (4 | 82) # (47/223) * 385 = 81.14 pic = self.sql_controller.get_picture_with_id(1094) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 3577) # 34 1556323336 1 800 --> 938 (2 | 200) # (800/892) * 223 = 200.0 pic = self.sql_controller.get_picture_with_id(34) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 938) # Testing the lower edge # --------------------------------- # 524 1556325296 1 1 --> 1048 (2 | 1) # (1/892) * 223 = 0.25 pic = self.sql_controller.get_picture_with_id(524) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1048) # 563 1556325452 1 3 --> 1048 (2 | 1) # (3/892) * 223 = 0.75 pic = self.sql_controller.get_picture_with_id(563) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1048) # 592 1556325568 1 4 --> 1048 (2 | 1) # (4/892) * 223 = 1.0 pic = self.sql_controller.get_picture_with_id(592) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1048) # 594 1556325576 1 5 --> 1078 (2 | 2) # (5/892) * 223 = 1.25 pic = self.sql_controller.get_picture_with_id(594) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1078) # 595 1556325580 1 6 --> 1078 (2 | 2) # (6/892) * 223 = 1.5 pic = self.sql_controller.get_picture_with_id(595) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1078) # 2 1556323208 1 891 --> 912 (2 | 223) # (891/892) * 223 = 222.75 pic = self.sql_controller.get_picture_with_id(2) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 912) # 3658 1556400336 4 1 --> 1124 (3 | 6) # (1/384) * 2158 = 5.62 pic = self.sql_controller.get_picture_with_id(3658) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1125) # 3274 1556398800 4 384 --> 3033 (3 | 2153) # (384/385) * 2158 = 2152.39 pic = self.sql_controller.get_picture_with_id(3274) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 3033) # 3275 1556398804 4 385 --> 2976 (3 | 2158) # (385/385) * 2158 = 2158.0 pic = self.sql_controller.get_picture_with_id(3275) pic = self.sql_controller.get_next_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 2976) def test_get_previous_altitude_skip_in_hikes(self): # id time hike alt_rank_hike id (hike | alt_rank_hike) # wrap back to hike 3 # ------------------- # 619 1556325676 1 26 --> 1228 (3 | 63) # (26/892) * 2158 = 62.9 pic = self.sql_controller.get_picture_with_id(619) pic = self.sql_controller.get_previous_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1228) # 2 1556323208 1 891 --> 3036 (3 | 2156) # (891/892) * 2158 = 2155.58 pic = self.sql_controller.get_picture_with_id(2) pic = self.sql_controller.get_previous_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 3036) # ------------------- # 1017 1556377696 2 210 --> 49 (1 | 840) # (210/223) * 892 = 840.0 pic = self.sql_controller.get_picture_with_id(1017) pic = self.sql_controller.get_previous_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 49) # 1994 1556391512 3 855 --> 3507 (4 | 153) # (855/2158) * 385 = 152.537 pic = self.sql_controller.get_previous_altitude_skip_in_hikes( self.picture) self.assertEqual(pic.picture_id, 3507) # 1127 1556388044 3 10 --> 3657 (4 | 2) # (10/2158) * 223 = 1.03 pic = self.sql_controller.get_picture_with_id(1127) pic = self.sql_controller.get_previous_altitude_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 3657) def test_get_next_altitude_skip_in_global(self): # 1994 | 2355 + (3658 * .05) = 2537.9 pic = self.sql_controller.get_next_altitude_skip_in_global( self.picture) self.assertEqual(pic.altrank_global, 2538) self.assertEqual(pic.picture_id, 2207) # 524 | 1 + (3658 * .05) = 183.9 pic = self.sql_controller.get_picture_with_id(524) pic = self.sql_controller.get_next_altitude_skip_in_global(pic) self.assertEqual(pic.altrank_global, 184) self.assertEqual(pic.picture_id, 514) # 183 # 3006 | 3475 + (3658 * .05) = 3657.9 pic = self.sql_controller.get_picture_with_id(3006) pic = self.sql_controller.get_next_altitude_skip_in_global(pic) self.assertEqual(pic.altrank_global, 3658) # wrap around bottom to the top # ------------------------------------ # 3059 | 3476 + (3658 * .05) = 3658.9 pic = self.sql_controller.get_picture_with_id(3059) pic = self.sql_controller.get_next_altitude_skip_in_global(pic) self.assertEqual(pic.altrank_global, 1) # 2973 | 3600 + (3658 * .05) = 3782.9 pic = self.sql_controller.get_picture_with_id(2973) pic = self.sql_controller.get_next_altitude_skip_in_global(pic) self.assertEqual(pic.altrank_global, 125) self.assertEqual(pic.picture_id, 455) def test_get_previous_altitude_skip_in_global(self): # 1994 | 2355 - (3658 * .05) # 2355 - 183 = 2172 pic = self.sql_controller.get_previous_altitude_skip_in_global( self.picture) self.assertEqual(pic.altrank_global, 2172) # 3489 | 1800 - (3658 * .05) # 1800 - 183 = 1617 pic = self.sql_controller.get_picture_with_id(3489) pic = self.sql_controller.get_previous_altitude_skip_in_global(pic) self.assertEqual(pic.altrank_global, 1617) # 2976 | 3658 - (3658 * .05) # 3658 - 183 = 3475 pic = self.sql_controller.get_picture_with_id(2976) pic = self.sql_controller.get_previous_altitude_skip_in_global(pic) self.assertEqual(pic.altrank_global, 3475) self.assertEqual(pic.picture_id, 3006) # wrap around from top to the bottom # ------------------------------------ # 613 | 20 - (3658 * .05) + 3658 # 20 - 183 + 3658 = 3495 pic = self.sql_controller.get_picture_with_id(613) # 20 rank pic = self.sql_controller.get_previous_altitude_skip_in_global(pic) self.assertEqual(pic.altrank_global, 3495) self.assertEqual(pic.picture_id, 3056) # 513 | 183 - (3658 * .05) + 3658 # 183 - 183 + 3658 = 3658 pic = self.sql_controller.get_picture_with_id(513) pic = self.sql_controller.get_previous_altitude_skip_in_global(pic) self.assertEqual(pic.altrank_global, 3658) self.assertEqual(pic.picture_id, 2976) # Color # -------------------------------------------------------------------------- def test_get_next_color_in_hikes(self): # forward by 1 pic = self.sql_controller.get_next_color_in_hikes(self.picture, 1) self.assertEqual(pic.colorrank_global_h, 2892) # forward by 2 pic = self.sql_controller.get_next_color_in_hikes(self.picture, 2) self.assertEqual(pic.colorrank_global_h, 2893) # wrap to top of list pic = self.sql_controller.get_picture_with_id(3369) pic = self.sql_controller.get_next_color_in_hikes(pic, 8) self.assertEqual(pic.picture_id, 883) # mod to row below pic = self.sql_controller.get_next_color_in_hikes( self.picture, 9 + 3658) self.assertEqual(pic.colorrank_global_h, 2900) # mod to row above pic = self.sql_controller.get_next_color_in_hikes( self.picture, 800 + 3658) self.assertEqual(pic.colorrank_global_h, 33) def test_get_previous_color_in_hikes(self): # backward by 1 pic = self.sql_controller.get_previous_color_in_hikes(self.picture, 1) self.assertEqual(pic.colorrank_global_h, 2890) # backward by 5 pic = self.sql_controller.get_previous_color_in_hikes(self.picture, 5) self.assertEqual(pic.colorrank_global_h, 2886) # wrap to bottom of list pic = self.sql_controller.get_picture_with_id(341) pic = self.sql_controller.get_previous_color_in_hikes(pic, 25) self.assertEqual(pic.picture_id, 3482) self.assertEqual(pic.colorrank_global_h, 3658) # mod to row above pic = self.sql_controller.get_previous_color_in_hikes( self.picture, 891 + 3658) self.assertEqual(pic.colorrank_global_h, 2000) # mod to row below pic = self.sql_controller.get_previous_color_in_hikes( self.picture, 2900 + 3658) self.assertEqual(pic.colorrank_global_h, 3649) def test_get_next_color_in_global(self): # forward by 1 pic = self.sql_controller.get_next_color_in_global(self.picture, 1) self.assertEqual(pic.colorrank_global, 2786) # forward by 10 pic = self.sql_controller.get_next_color_in_global(self.picture, 10) self.assertEqual(pic.colorrank_global, 2795) # wrap to top of list pic = self.sql_controller.get_picture_with_id(3482) pic = self.sql_controller.get_next_color_in_global(pic, 4) self.assertEqual(pic.picture_id, 518) self.assertEqual(pic.colorrank_global, 1) # mod to row below pic = self.sql_controller.get_next_color_in_global( self.picture, 500 + 3658) self.assertEqual(pic.colorrank_global, 3285) # mod to row above pic = self.sql_controller.get_next_color_in_global( self.picture, 900 + 3658) self.assertEqual(pic.colorrank_global, 27) def test_get_previous_color_in_global(self): # backward by 1 pic = self.sql_controller.get_previous_color_in_global(self.picture, 1) self.assertEqual(pic.colorrank_global, 2784) # backward by 10 pic = self.sql_controller.get_previous_color_in_global( self.picture, 10) self.assertEqual(pic.colorrank_global, 2775) # wrap to bottom of list pic = self.sql_controller.get_picture_with_id(882) pic = self.sql_controller.get_previous_color_in_global(pic, 2) self.assertEqual(pic.picture_id, 873) self.assertEqual(pic.colorrank_global, 3658) # mod to row above pic = self.sql_controller.get_previous_color_in_global( self.picture, 500 + 3658) self.assertEqual(pic.colorrank_global, 2285) # mod to row below pic = self.sql_controller.get_previous_color_in_global( self.picture, 2800 + 3658) self.assertEqual(pic.colorrank_global, 3643) def test_get_next_color_skip_in_hikes(self): # id hike color_rank_hike id (hike | color_rank_hike) # wrap around hike 1 to hike 4 (color_rank 4 --> 1) # 94 1 772 --> 3508 (4 | 334) # (772/892) * 385 = 333.2 pic = self.sql_controller.get_picture_with_id(94) pic = self.sql_controller.get_next_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 3304) # hike 3 to hike 2 (colors_rank 2 --> 3) # 1994 3 1776 --> 1084 (2 | 183) # (1776/2158) * 223 = 183.53 pic = self.sql_controller.get_next_color_skip_in_hikes(self.picture) self.assertEqual(pic.picture_id, 1087) # hike 2 to hike 1 (colors_rank 3 --> 4) # 1109 2 26 --> 479 (1 | 104) # (26/223) * 892 = 104.0 pic = self.sql_controller.get_picture_with_id(1109) pic = self.sql_controller.get_next_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 479) def test_get_previous_color_skip_in_hikes(self): # id hike color_rank_hike id (hike | color_rank_hike) # wrap to hike 4 to hike 1 (color_rank 1 --> 4) # 3388 4 2 <-- 883 (1 | 5) # (2/385) * 892 = 4.63 pic = self.sql_controller.get_picture_with_id(3388) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 883) # hike 3 to hike 4 (colors_rank 2 --> 1) # 1994 3 1776 <-- 3522 (4 | 317) # (1776/2158) * 385 = 316.85 pic = self.sql_controller.get_previous_color_skip_in_hikes( self.picture) self.assertEqual(pic.picture_id, 3522) # hike 1 to hike 2 (color_rank 4 --> 3) # (1/892) * 223 = 0.25 pic = self.sql_controller.get_picture_with_id(518) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1106) # (2/892) * 223 = 0.5 pic = self.sql_controller.get_picture_with_id(882) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1106) # (3/892) * 223 = 0.75 pic = self.sql_controller.get_picture_with_id(878) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1106) # (4/892) * 223 = 1.0 pic = self.sql_controller.get_picture_with_id(879) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1106) # (5/892) * 223 = 1.25 pic = self.sql_controller.get_picture_with_id(883) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1115) # (7/892) * 223 = 1.75 pic = self.sql_controller.get_picture_with_id(308) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1115) # (8/892) * 223 = 2.0 pic = self.sql_controller.get_picture_with_id(315) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1115) # (9/892) * 223 = 2.25 pic = self.sql_controller.get_picture_with_id(310) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1067) # (10/892) * 223 = 2.5 pic = self.sql_controller.get_picture_with_id(312) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1067) # (11/892) * 223 = 2.75 pic = self.sql_controller.get_picture_with_id(325) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1067) # (12/892) * 223 = 3.0 pic = self.sql_controller.get_picture_with_id(332) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1067) # End of hike 1 # (887/892) * 223 = 221.75 pic = self.sql_controller.get_picture_with_id(373) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1024) # (888/892) * 223 = 222.0 pic = self.sql_controller.get_picture_with_id(9) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1024) # (889/892) * 223 = 222.25 pic = self.sql_controller.get_picture_with_id(386) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1044) # (890/892) * 223 = 222.5 pic = self.sql_controller.get_picture_with_id(1) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1044) # (891/892) * 223 = 222.75 pic = self.sql_controller.get_picture_with_id(143) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1044) # (892/892) * 223 = 223.0 pic = self.sql_controller.get_picture_with_id(873) pic = self.sql_controller.get_previous_color_skip_in_hikes(pic) self.assertEqual(pic.picture_id, 1044) def test_get_next_color_skip_in_global(self): pic = self.sql_controller.get_next_color_skip_in_global(self.picture) self.assertEqual(pic.colorrank_global, 2968) # bottom pic = self.sql_controller.get_picture_with_id(1220) # 3640 pic = self.sql_controller.get_next_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 165) self.assertEqual(pic.picture_id, 2594) def test_get_previous_color_skip_in_global(self): pic = self.sql_controller.get_previous_color_skip_in_global( self.picture) self.assertEqual(pic.colorrank_global, 2602) # top pic = self.sql_controller.get_picture_with_id(310) # 10 pic = self.sql_controller.get_previous_color_skip_in_global(pic) self.assertEqual(pic.colorrank_global, 3485) self.assertEqual(pic.picture_id, 1798)
#!/usr/bin/env python3 import os import sys import time sys.path.append('..') from classes.sql_controller import SQLController DB = '/Volumes/Capra/capra-storage/capra_explorer.db' DB_EMPTY = '/Volumes/Capra/capra-storage/capra_explorer_empty.db' controller = SQLController(database=DB_EMPTY) def test_get_hike_count(): count = controller.get_hike_count() print(count) # assert count == 5, 'Should be 5' def test_get_last_hike_id(): hike_id = controller.get_last_hike_id() print(hike_id) # assert hike_id == 5, 'Should be 5' def test_get_last_hike_time(): val = controller.get_time_since_last_hike() print('Last time: {t}'.format(t=val))
class DatabaseValidityTest(unittest.TestCase): '''This is to test the validity of a given database, which you select on launch The main things tested: \n • Does `hikes` table have same count as `SELECT count(*) FROM pictures WHERE hike=n` \n • Do rank's last values == count \n • Verify hike ranks go 1,2,3...n-2,n-1,n \n • Verify archive ranks go 1,2,3...n-2,n-1,n ''' # hard-coded locations DB = 'tests/capra_projector_jun2021_min_test_0708.db' # no / infront makes the path relative directory = 'capra-storage' sql_controller = None sql_statements = None picture = None # hikes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, # 15, 16, 19, 29, 30, 31, 33, 41, 43, 44, # 50, 51, 52, 53, 54, 58, 59, 60] # first picture_id of each hike # picids_hikes = [2262, 3152, 3373, 5529, 5912, 7300, 8202, 9616, 11062, 11241, # 14801, 17135, 17159, 18885, 21166, 21209, 21768, 1, 82, 144, # 23493, 24612, 25095, 25570, 26996, 27262, 27631, 29765] @classmethod def setUpClass(self): # NOTE - if the database or id is changed, all the tests will break # They are dependent upon that self.sql_controller = SQLController(database=self.DB, directory=self.directory) self.picture = self.sql_controller.get_picture_with_id(1) # For testing directly on the sql statements self.sql_statements = SQLStatements() @classmethod def tearDownClass(self): self.sql_controller = None def test_get_picture_with_id(self): self.assertEqual(self.picture.picture_id, 1) self.assertEqual(self.picture.altitude, 14.25) # Size Calls # -------------------------------------------------------------------------- def test_get_archive_size(self): size = self.sql_controller.get_archive_size() # self.assertEqual(size, 30378) self.assertEqual(size, 30404) def test_hike_sizes_with_ranks(self): print( '\n Hike ID\tcount(*)\thikes table\tindex_in_hike\taltrank_hike\tcolor_rank_hike' ) sql = 'SELECT hike_id FROM hikes' rows = self.sql_controller._execute_query_for_anything(sql) # for h in self.hikes: for r in rows: h = r[0] sz_count = self.sql_controller.get_hike_size_with_id(h) sql = 'SELECT pictures FROM hikes WHERE hike_id={h};'.format(h=h) sz_hikes_table = self.sql_controller._execute_query_for_int(sql) last_index_qry = 'SELECT index_in_hike FROM pictures WHERE hike={h} ORDER BY index_in_hike DESC LIMIT 1;'.format( h=h) last_index = self.sql_controller._execute_query_for_int( last_index_qry) last_altrank_qry = 'SELECT altrank_hike FROM pictures WHERE hike={h} ORDER BY altrank_hike DESC LIMIT 1;'.format( h=h) last_altrank = self.sql_controller._execute_query_for_int( last_altrank_qry) last_colorrank_qry = 'SELECT color_rank_hike FROM pictures WHERE hike={h} ORDER BY color_rank_hike DESC LIMIT 1;'.format( h=h) last_colorrank = self.sql_controller._execute_query_for_int( last_colorrank_qry) if sz_count == sz_hikes_table == last_index == last_altrank == last_colorrank: match = '✅' else: match = '❌' print('{bool} {h}\t\t{cnt}\t\t{tbl}\t\t{ind}\t\t{alt}\t\t{clr}'. format(bool=match, h=h, cnt=sz_count, tbl=sz_hikes_table, ind=last_index, alt=last_altrank, clr=last_colorrank)) def test_incremental_validity_ranks_hikes(self): print('\n\n') sql = 'SELECT hike_id FROM hikes' rows = self.sql_controller._execute_query_for_anything(sql) for r in rows: # same as r = rows[0] h = r[0] queries = [ 'SELECT index_in_hike FROM pictures WHERE hike={h} ORDER BY index_in_hike ASC;' .format(h=h), 'SELECT altrank_hike FROM pictures WHERE hike={h} ORDER BY altrank_hike ASC;' .format(h=h), 'SELECT color_rank_hike FROM pictures WHERE hike={h} ORDER BY color_rank_hike ASC;' .format(h=h) ] for q in queries: print('Testing:\t{q}'.format(q=q)) indexes = self.sql_controller._execute_query_for_anything(q) counter = 1 for i in indexes: self.assertEqual(counter, i[0]) counter += 1 def test_incremental_validity_ranks_archive(self): print('\n\n') queries = [ 'SELECT time_rank_global FROM pictures ORDER BY time_rank_global ASC;', 'SELECT altrank_global FROM pictures ORDER BY altrank_global ASC;', 'SELECT altrank_global_h FROM pictures ORDER BY altrank_global_h ASC;', 'SELECT color_rank_global FROM pictures ORDER BY color_rank_global ASC;', 'SELECT color_rank_global_h FROM pictures ORDER BY color_rank_global_h ASC;' ] for q in queries: print('Testing:\t{q}'.format(q=q)) indexes = self.sql_controller._execute_query_for_anything(q) counter = 1 for i in indexes: self.assertEqual(counter, i[0]) counter += 1
g.init() start_time = time.time() oldDBController = None newDBController = None # PATH = '/media/pi/capra-hd/' PATH = '../capra-sample-data/dbTransform/' OLD_DB = PATH + 'capra_projector_test.db' NEW_DB = PATH + 'capra_camera_test.db' print("Old db: {}".format(OLD_DB)) print("New db: {}".format(NEW_DB)) oldDBController = SQLController(database=OLD_DB) newDBController = SQLController(database=NEW_DB) oldCursor = oldDBController.connection.cursor() newCursor = newDBController.connection.cursor() # *** hikes *** # "hike_id" INTEGER UNIQUE, # "avg_altitude" REAL, # "avg_brightness" REAL, # "avg_hue" REAL, # "avg_hue_lumosity" REAL, # "start_time" REAL UNIQUE, # "end_time" REAL UNIQUE, # "pictures" INTEGER,
class DatabaseTest(unittest.TestCase): # no / infront makes the path relative # DB = 'tests/capra_projector_may2021.db' # DB = 'tests/capra_projector_jun2021_min_full_clean_0618.db' # DB = 'tests/capra_projector_apr2021_min_test_full.db' # DB = 'tests/capra_projector_jun2021_min_test_0623.db' DB = 'tests/capra_projector_jun2021_min_test_0708.db' directory = 'capra-storage' sql_controller = None sql_statements = None picture = None hikes = [] picture_ids = [] # only the 1st picture_id in each hike @classmethod def setUpClass(self): # NOTE - if the database or id is changed, all the tests will break # They are dependent upon that self.sql_controller = SQLController(database=self.DB, directory=self.directory) self.picture = self.sql_controller.get_picture_with_id(11994) # For testing directly on the sql statements self.sql_statements = SQLStatements() # Grab an array of hikes from the database sql = 'SELECT hike_id FROM hikes ORDER BY hike_id ASC;' rows = self.sql_controller._execute_query_for_anything(sql) i = 0 for r in rows: self.hikes.append(r[0]) # Grab the first picture_id from each hike from the database sql = 'SELECT picture_id FROM pictures WHERE hike={h} ORDER BY index_in_hike ASC LIMIT 1;'.format(h=r[0]) pid = self.sql_controller._execute_query_for_int(sql) self.picture_ids.append(pid) i += 1 @classmethod def tearDownClass(self): self.sql_controller = None def test_get_picture_with_id(self): self.assertEqual(self.picture.picture_id, 11994) self.assertEqual(self.picture.altitude, 2128.38) # Size Calls # -------------------------------------------------------------------------- def test_get_hike_size(self): size = self.sql_controller.get_hike_size(self.picture) self.assertEqual(size, 3561) def test_get_archive_size(self): size = self.sql_controller.get_archive_size() self.assertEqual(size, 30404) # Data Types # -------------------------------------------------------------------------- def test_picture_object(self): picture = self.sql_controller.get_picture_with_id(1994) self.assertEqual(picture.picture_id, 1994) self.assertEqual(picture.time, 1556391512.0) self.assertEqual(picture.year, 2019) self.assertEqual(picture.month, 4) self.assertEqual(picture.day, 27) self.assertEqual(picture.minute, 718) self.assertEqual(picture.dayofweek, 5) self.assertEqual(picture.hike_id, 3) self.assertEqual(picture.index_in_hike, 879) self.assertEqual(picture.altitude, 936.62) self.assertEqual(picture.altrank_hike, 855) self.assertEqual(picture.altrank_global, 17954) self.assertEqual(picture.altrank_global_h, 19549) hsvColor = QColor() hsvColor.setHsv(25, 173, 49) self.assertEqual(picture.color_hsv, hsvColor) rgbColor = QColor(49, 43, 16) self.assertEqual(picture.color_rgb, rgbColor) self.assertEqual(picture.colorrank_hike, 167) self.assertEqual(picture.colorrank_global, 3310) self.assertEqual(picture.colorrank_global_h, 15042) self.assertEqual(picture.colors_count, 4) colorList = [QColor(49, 43, 16), QColor(117, 111, 69), QColor(200, 201, 214), QColor(18, 18, 16)] self.assertEqual(picture.colors_rgb, colorList) self.assertEqual(picture.colors_conf, [0.17, 0.16, 0.15, 0.11]) self.assertEqual(picture.camera1, 'capra-storage/hike3/878_cam1.jpg') self.assertEqual(picture.camera2, 'capra-storage/hike3/878_cam2.jpg') self.assertEqual(picture.camera3, 'capra-storage/hike3/878_cam3.jpg') self.assertEqual(picture.cameraf, 'capra-storage/hike3/878_cam2f.jpg') self.assertEqual(picture.created, '2019-08-22 17:44:51') self.assertEqual(picture.updated, '2021-07-08 19:44:47') def test_hike_object(self): hike = self.sql_controller.get_hike_with_id(59) self.assertEqual(hike.hike_id, 59) self.assertEqual(hike.avg_altitude, 916.65) self.assertEqual(hike.avg_altrank, 22) self.assertEqual(hike.start_time, 1598658160.0) self.assertEqual(hike.start_year, 2020) self.assertEqual(hike.start_month, 8) self.assertEqual(hike.start_day, 28) self.assertEqual(hike.start_minute, 1002) self.assertEqual(hike.start_dayofweek, 4) self.assertEqual(hike.end_time, 1598675747.0) self.assertEqual(hike.end_year, 2020) self.assertEqual(hike.end_month, 8) self.assertEqual(hike.end_day, 28) self.assertEqual(hike.end_minute, 1295) self.assertEqual(hike.end_dayofweek, 4) self.assertEqual(hike.color_rgb, QColor(78, 74, 61)) self.assertEqual(hike.color_rank, 11) self.assertEqual(hike.num_pictures, 2134) self.assertEqual(hike.path, 'capra-storage/hike59/') self.assertEqual(hike.created, '2020-08-28 23:42:39') self.assertEqual(hike.updated, '2021-07-08 21:23:04') # UI Databse Calls # -------------------------------------------------------------------------- def test_count_colors_for_hikes(self): size = 128.0 # variable to test different return size of elements # 16 - 24, 14891 # 30 - 44, 18922 # 41 - 81, 21252 # 43 - 62, 21333 # These all have 128 or more pictures picture_ids = [1, 893, 1116, 3274, 3659, 5049, 5953, 7369, 8817, 8996, 12557, 14915, 16641, 18966, 19526, 21395, 23513, 24632, 25116, 25592, 27019, 27286, 27656, 29790] for p in picture_ids: pic = self.sql_controller.get_picture_with_id(p) colors = self.sql_controller.ui_get_colors_for_hike_sortby('alt', pic) self.assertEqual(len(colors), size) colors = self.sql_controller.ui_get_colors_for_hike_sortby('color', pic) self.assertEqual(len(colors), size) colors = self.sql_controller.ui_get_colors_for_hike_sortby('time', pic) self.assertEqual(len(colors), size) # Altitude Graph # TODO - Tests for altitude graph list # Color Bar def test_ui_get_colors_for_hike(self): self.assertEqual(self.picture.picture_id, 11994) self.assertEqual(self.picture.hike_id, 10) rgbColor = QColor(79, 57, 48) self.assertEqual(self.picture.color_rgb, rgbColor) # Sorted by altrank_hike ASC colors = self.sql_controller.ui_get_colors_for_hike_sortby('alt', self.picture) self.assertEqual(len(colors), 128) color0 = QColor(48, 52, 44) color94 = QColor(165, 179, 197) color126 = QColor(200, 199, 210) self.assertEqual(colors[0], color0) self.assertEqual(colors[94], color94) self.assertEqual(colors[126], color126) # Sorted by color_rank_hike ASC colors = self.sql_controller.ui_get_colors_for_hike_sortby('color', self.picture) self.assertEqual(len(colors), 128) color0 = QColor(0, 0, 0) color94 = QColor(1, 1, 1) color126 = QColor(91, 87, 90) self.assertEqual(colors[0], color0) self.assertEqual(colors[94], color94) self.assertEqual(colors[126], color126) # Sorted by time ASC colors = self.sql_controller.ui_get_colors_for_hike_sortby('time', self.picture) self.assertEqual(len(colors), 128) color0 = QColor(48, 52, 44) color94 = QColor(205, 199, 202) color126 = QColor(0, 0, 0) self.assertEqual(colors[0], color0) self.assertEqual(colors[94], color94) self.assertEqual(colors[126], color126) def test_ui_get_colors_for_hike(self): colors = self.sql_controller.ui_get_colors_for_archive_sortby('alt') self.assertEqual(len(colors), 1280) self.assertEqual(colors[94], QColor(100, 135, 219)) colors = self.sql_controller.ui_get_colors_for_archive_sortby('color') self.assertEqual(len(colors), 1280) self.assertEqual(colors[94], QColor(37, 56, 45)) colors = self.sql_controller.ui_get_colors_for_archive_sortby('time') self.assertEqual(len(colors), 1280) self.assertEqual(colors[94], QColor(141, 143, 149)) # Time Bar def test_ui_get_percent_for_hike(self): self.assertEqual(self.picture.picture_id, 11994) self.assertEqual(self.picture.hike_id, 10) percent = self.sql_controller.ui_get_percentage_in_hike_with_mode('alt', self.picture) self.assertEqual(percent, 0.7939) percent = self.sql_controller.ui_get_percentage_in_hike_with_mode('color', self.picture) self.assertEqual(percent, 0.1022) percent = self.sql_controller.ui_get_percentage_in_hike_with_mode('time', self.picture) self.assertEqual(percent, 0.8422) def test_ui_get_percent_for_archive(self): self.assertEqual(self.picture.picture_id, 11994) self.assertEqual(self.picture.hike_id, 10) percent = self.sql_controller.ui_get_percentage_in_archive_with_mode('alt', self.picture) self.assertEqual(percent, 0.9759) percent = self.sql_controller.ui_get_percentage_in_archive_with_mode('color', self.picture) self.assertEqual(percent, 0.1585) percent = self.sql_controller.ui_get_percentage_in_archive_with_mode('time', self.picture) self.assertEqual(percent, 0.3840)
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Capra Transfer Animation") self.setGeometry(0, 0, 1280, 720) # Setups up database connection depending on the system self.setupSQLController() # Setup Bg Thread for getting picture from Database self.threadpool = QThreadPool() self.threadpool.setMaxThreadCount(1) self.newPictureThread = NewPictureThread(self.sql_controller) self.threadpool.start(self.newPictureThread) # Setup BG color # c1 = QColor(9, 24, 94, 255) self.bgcolor = BackgroundColor(self, QVBoxLayout(), Qt.AlignBottom, self.picture.color_rgb) self.setupColorWidgets(self.picture) self.setupAltitudeLabel(self.picture) self.setupTimeLabelAndBar(self.picture) self.superCenterImg = TransferCenterImage(self, self.picture) self.setupAltitudeGraphAndLine(self.picture) self.altitudegraph.hide() self.centerLabel.opacityHide() self.line.hide() # Setup QTimer for checking for new Picture self.handlerCounter = 1 self.timerAnimationHandler = QTimer() self.timerAnimationHandler.timeout.connect(self.animationHandler) self.timerAnimationHandler.start(7000) def animationHandler(self): self.fadeOutTimer = QTimer() self.fadeOutTimer.setSingleShot(True) if self.handlerCounter % 4 == 1: # Color self.fadeMoveInColorWidgets() self.fadeOutTimer.timeout.connect(self.fadeMoveOutColorWidgets) elif self.handlerCounter % 4 == 2: # Altitude self.fadeMoveInAltitudeEverything() self.fadeOutTimer.timeout.connect(self.fadeMoveOutAltitudeEverything) elif self.handlerCounter % 4 == 3: # Time self.fadeMoveInTime() self.fadeOutTimer.timeout.connect(self.fadeMoveOutTime) elif self.handlerCounter % 4 == 0: # New Picture: image, bg color, ui elements global globalPicture self.picture = globalPicture # Update UI Elements self.updateColorWidgets(self.picture) self.updateTimeLabelAndBar(self.picture) self.updateAltitudeLabelAndGraph(self.picture) # self.setupTimeLabelAndBar(self.picture) # self.setupAltitudeLabel(self.picture) # Change Image and Background self.superCenterImg.fadeNewImage(self.picture) self.bgcolor.changeColor(self.picture.color_rgb) self.fadeOutTimer.start(3500) self.handlerCounter += 1 # Database connection - previous db with UI data def setupSQLController(self): '''Initializes the database connection.\n If on Mac/Windows give dialog box to select database, otherwise it will use the global defined location for the database''' # Mac/Windows: select the location if platform.system() == 'Darwin' or platform.system() == 'Windows': # filename = QFileDialog.getOpenFileName(self, 'Open file', '', 'Database (*.db)') # self.database = filename[0] # self.directory = os.path.dirname(self.database) self.database = '/Users/Jordan/Dropbox/Everyday Design Studio/A Projects/100 Ongoing/Capra/capra-storage/capra-storage-jordan-projector/capra_projector_jun2021_min_test_0708.db' self.directory = '/Users/Jordan/Dropbox/Everyday Design Studio/A Projects/100 Ongoing/Capra/capra-storage/capra-storage-jordan-projector' else: # Raspberry Pi: preset location self.database = g.DATAPATH_PROJECTOR + g.DBNAME_MASTER self.directory = g.DATAPATH_PROJECTOR print(self.database) print(self.directory) self.sql_controller = SQLController(database=self.database, directory=self.directory) # self.picture = self.sql_controller.get_picture_with_id(20000) # 28300 self.picture = self.sql_controller.get_random_picture() # self.picture2 = self.sql_controller.get_picture_with_id(27500) # self.picture3 = self.sql_controller.get_picture_with_id(12000) # self.picture4 = self.sql_controller.get_picture_with_id(10700) # 10700, 11990, 12000, 15000, 20000, 27100, 27200, 27300, 27500, 28300 # TODO - should we preload all the UI Data? # self.uiData = self.sql_controller.preload_ui_data() # self.preload = True # Time Mode def setupTimeLabelAndBar(self, picture: Picture): self.timeLabel = UILabelTopCenter(self, '', '') self.timeLabel.setPrimaryText(picture.uitime_hrmm) self.timeLabel.setSecondaryText(picture.uitime_ampm) percent_rank = self.sql_controller.ui_get_percentage_in_archive_with_mode('time', self.picture) self.timebar = TimeBarTransfer(self, percent_rank) self.timeLabel.opacityHide() self.timebar.hide() def updateTimeLabelAndBar(self, picture: Picture): self.timeLabel.setPrimaryText(picture.uitime_hrmm) self.timeLabel.setSecondaryText(picture.uitime_ampm) percent_rank = self.sql_controller.ui_get_percentage_in_archive_with_mode('time', self.picture) self.timebar.trigger_refresh(percent_rank) def fadeMoveInTime(self): self.timeLabel.show() self.timebar.show() # Move in top label self.animMoveInTimeLabel = QPropertyAnimation(self.timeLabel, b"geometry") self.animMoveInTimeLabel.setDuration(2000) self.animMoveInTimeLabel.setStartValue(QRect(0, 360, 1280, 110)) self.animMoveInTimeLabel.setEndValue(QRect(0, 15, 1280, 110)) self.animMoveInTimeLabel.start() # Fade in the timebar fadeTimebar = QGraphicsOpacityEffect() self.timebar.setGraphicsEffect(fadeTimebar) self.animFadeInAltitudeGraph = QPropertyAnimation(fadeTimebar, b"opacity") self.animFadeInAltitudeGraph.setStartValue(0) self.animFadeInAltitudeGraph.setEndValue(1) self.animFadeInAltitudeGraph.setDuration(2000) self.animFadeInAltitudeGraph.start() self.update() def fadeMoveOutTime(self): # Move out time label self.animMoveOutTimeLabel = QPropertyAnimation(self.timeLabel, b"geometry") self.animMoveOutTimeLabel.setDuration(2000) self.animMoveOutTimeLabel.setStartValue(QRect(0, 15, 1280, 110)) self.animMoveOutTimeLabel.setEndValue(QRect(0, 360, 1280, 110)) self.animMoveOutTimeLabel.start() # Fade out time label - issue with interferring with other effects # fadeOutTimeLabel = QGraphicsOpacityEffect() # self.timeLabel.setGraphicsEffect(fadeOutTimeLabel) # self.animFadeOutTimeLabel = QPropertyAnimation(fadeOutTimeLabel, b"opacity") # self.animFadeOutTimeLabel.setStartValue(1) # self.animFadeOutTimeLabel.setEndValue(0) # self.animFadeOutTimeLabel.setDuration(2000) # self.animFadeOutTimeLabel.start() # Fade out the timebar fadeTimebar = QGraphicsOpacityEffect() self.timebar.setGraphicsEffect(fadeTimebar) self.animFadeOutAltitudeGraph = QPropertyAnimation(fadeTimebar, b"opacity") self.animFadeOutAltitudeGraph.setStartValue(1) self.animFadeOutAltitudeGraph.setEndValue(0) self.animFadeOutAltitudeGraph.setDuration(2000) self.animFadeOutAltitudeGraph.start() self.update() # Altitude Mode def setupAltitudeLabel(self, picture: Picture): self.centerLabel = UILabelTopCenter(self, '', 'M') self.centerLabel.setPrimaryText(picture.uialtitude) def setupAltitudeGraphAndLine(self, picture: Picture): archiveSize = self.sql_controller.get_archive_size() idxList = self.sql_controller.chooseIndexes(int(archiveSize), 1280.0) altitudelist = self.sql_controller.ui_get_altitudes_for_archive_sortby('alt', idxList) currentAlt = picture.altitude altitudelist.insert(0, currentAlt) # Append the new altitude at the start of the list altitudelist = sorted(altitudelist) # Sorts so the altitude will fit within the correct spot on the graph self.altitudegraph = AltitudeGraphTransferQWidget(self, True, altitudelist, currentAlt) self.altitudegraph.setGraphicsEffect(UIEffectDropShadow()) MINV = min(altitudelist) MAXV = max(altitudelist) H = 500 self.linePosY = 108 + H - ( ((currentAlt - MINV)/(MAXV-MINV)) * (H-3) ) # print(self.linePosY) self.line = QLabel("line", self) bottomImg = QPixmap("assets/line.png") self.line.setPixmap(bottomImg) self.line.setAlignment(Qt.AlignCenter) self.line.setGeometry(0, int(self.linePosY), 1280, 3) def updateAltitudeLabelAndGraph(self, picture: Picture): self.centerLabel.setPrimaryText(picture.uialtitude) self.setupAltitudeGraphAndLine(picture) def fadeMoveInAltitudeEverything(self): self.altitudegraph.show() self.centerLabel.show() self.line.show() # Alt Line self.animMoveInLine = QPropertyAnimation(self.line, b"geometry") self.animMoveInLine.setDuration(3000) self.animMoveInLine.setStartValue(QRect(0, 360, 1280, 3)) self.animMoveInLine.setEndValue(QRect(0, self.linePosY, 1280, 3)) self.animMoveInLine.start() fadeEffect = QGraphicsOpacityEffect() self.line.setGraphicsEffect(fadeEffect) self.animFadeInLine = QPropertyAnimation(fadeEffect, b"opacity") # self.anim2 = QPropertyAnimation(self.label, b"windowOpacity") self.animFadeInLine.setStartValue(0) self.animFadeInLine.setEndValue(1) self.animFadeInLine.setDuration(1500) self.animFadeInLine.start() # Move in top label self.animMoveInAltitudeValue = QPropertyAnimation(self.centerLabel, b"geometry") self.animMoveInAltitudeValue.setDuration(2000) self.animMoveInAltitudeValue.setStartValue(QRect(0, 360, 1280, 110)) self.animMoveInAltitudeValue.setEndValue(QRect(0, 15, 1280, 110)) self.animMoveInAltitudeValue.start() # Fade in AltitudeGraphTransferQWidget fadeEffect2 = QGraphicsOpacityEffect() self.altitudegraph.setGraphicsEffect(fadeEffect2) self.animFadeInAltitudeGraph = QPropertyAnimation(fadeEffect2, b"opacity") self.animFadeInAltitudeGraph.setStartValue(0) self.animFadeInAltitudeGraph.setEndValue(1) self.animFadeInAltitudeGraph.setDuration(2000) self.animFadeInAltitudeGraph.start() self.update() def fadeMoveOutAltitudeEverything(self): # Label self.animMoveOutAltitudeValue = QPropertyAnimation(self.centerLabel, b"geometry") self.animMoveOutAltitudeValue.setDuration(2000) self.animMoveOutAltitudeValue.setStartValue(QRect(0, 30, 1280, 110)) self.animMoveOutAltitudeValue.setEndValue(QRect(0, 360, 1280, 110)) self.animMoveOutAltitudeValue.start() # Fade Out - Line fadeOutLine = QGraphicsOpacityEffect() self.line.setGraphicsEffect(fadeOutLine) self.animFadeOutLine = QPropertyAnimation(fadeOutLine, b"opacity") self.animFadeOutLine.setStartValue(1) self.animFadeOutLine.setEndValue(0) self.animFadeOutLine.setDuration(2000) self.animFadeOutLine.start() # Fade Out - Graph fadeOutGraph = QGraphicsOpacityEffect() self.altitudegraph.setGraphicsEffect(fadeOutGraph) self.animFadeOutGraph = QPropertyAnimation(fadeOutGraph, b"opacity") self.animFadeOutGraph.setStartValue(1) self.animFadeOutGraph.setEndValue(0) self.animFadeOutGraph.setDuration(2000) self.animFadeOutGraph.start() self.update() # Color Mode def setupColorWidgets(self, picture: Picture): self.colorpalette = ColorPaletteNew(self, True, picture.colors_rgb, picture.colors_conf) self.colorpalette.setGraphicsEffect(UIEffectDropShadow()) archiveSize = self.sql_controller.get_archive_size() idxList = self.sql_controller.chooseIndexes(int(archiveSize), 1280.0) colorlist = self.sql_controller.ui_get_colors_for_archive_sortby('color', idxList) self.colorbar = ColorBarTransfer(self, True, colorlist) self.hideColorWidgets() def updateColorWidgets(self, picture: Picture): self.colorpalette.trigger_refresh(True, picture.colors_rgb, picture.colors_conf) def showColorWidgets(self): self.colorpalette.show() self.colorbar.show() def hideColorWidgets(self): self.colorpalette.hide() self.colorbar.hide() def fadeMoveInColorWidgets(self): self.colorpalette.show() self.colorbar.show() # Move in ColorPalette self.animMoveInColor = QPropertyAnimation(self.colorpalette, b"geometry") self.animMoveInColor.setDuration(2000) self.animMoveInColor.setStartValue(QRect(0, 360, 0, 0)) self.animMoveInColor.setEndValue(QRect(0, 15, 0, 0)) self.animMoveInColor.start() # Fade in ColorBar fadeEffect = QGraphicsOpacityEffect() self.colorbar.setGraphicsEffect(fadeEffect) self.animFadeInColor = QPropertyAnimation(fadeEffect, b"opacity") self.animFadeInColor.setStartValue(0) self.animFadeInColor.setEndValue(1) self.animFadeInColor.setDuration(2000) self.animFadeInColor.start() # This will overwrite the dropshadow effect # fadeEffect = QGraphicsOpacityEffect() # self.colorpalette.setGraphicsEffect(fadeEffect) # self.anim2 = QPropertyAnimation(fadeEffect, b"opacity") # self.anim2.setStartValue(0) # self.anim2.setEndValue(1) # self.anim2.setDuration(2000) # self.anim2.start() self.update() def fadeMoveOutColorWidgets(self): # Move out ColorPalette self.animMoveOutColor = QPropertyAnimation(self.colorpalette, b"geometry") self.animMoveOutColor.setDuration(2000) self.animMoveOutColor.setStartValue(QRect(0, 30, 0, 0)) self.animMoveOutColor.setEndValue(QRect(0, 360, 0, 0)) self.animMoveOutColor.start() # Fade out ColorBar fadeEffect = QGraphicsOpacityEffect() self.colorbar.setGraphicsEffect(fadeEffect) self.animFadeOutColor = QPropertyAnimation(fadeEffect, b"opacity") self.animFadeOutColor.setStartValue(1) self.animFadeOutColor.setEndValue(0) self.animFadeOutColor.setDuration(2000) self.animFadeOutColor.start() self.update() # Keyboard Input def keyPressEvent(self, event): # Closing App if event.key() == Qt.Key_Escape: self.close() elif event.key() == Qt.Key_1: print('1') # self.bgcolor.changeColor(self.picture.color_rgb) elif event.key() == Qt.Key_2: print('2') # self.fadeMoveInColorWidgets() elif event.key() == Qt.Key_3: print('3') # self.fadeMoveOutColorWidgets() elif event.key() == Qt.Key_4: print('4') # self.fadeMoveInAltitudeEverything() elif event.key() == Qt.Key_5: print('5') # self.fadeMoveOutAltitudeEverything() elif event.key() == Qt.Key_6: print('6') # self.fadeMoveInTime() elif event.key() == Qt.Key_7: print('7') # self.fadeMoveOutTime() elif event.key() == Qt.Key_8: print('8') elif event.key() == Qt.Key_9: print('9') elif event.key() == Qt.Key_0: print('0') def closeEvent(self, event): print('User has clicked the red X') self.garbageCollection() def garbageCollection(self): self.newPictureThread.signals.terminate = True