Added main file (work in progress!)
Work in progress! Serves as the main file for inkycal.
This commit is contained in:
		
							
								
								
									
										189
									
								
								inkycal/main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								inkycal/main.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,189 @@ | |||||||
|  | from config import Settings, Layout | ||||||
|  | from inkycal.custom import * | ||||||
|  |  | ||||||
|  | import os.path.exists | ||||||
|  | import traceback | ||||||
|  | import logging | ||||||
|  | import arrow | ||||||
|  | import time | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |   from PIL import Image | ||||||
|  | except ImportError: | ||||||
|  |   print('Pillow is not installed! Please install with:') | ||||||
|  |   print('pip3 install Pillow') | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |   import numpy | ||||||
|  | except ImportError: | ||||||
|  |   print('numpy is not installed! Please install with:') | ||||||
|  |   print('pip3 install numpy') | ||||||
|  |  | ||||||
|  | logger = logging.getLogger('inkycal') | ||||||
|  | logger.setLevel(level=logging.DEBUG) | ||||||
|  |  | ||||||
|  | class inkycal: | ||||||
|  |   """Main class""" | ||||||
|  |  | ||||||
|  |   def __init__(self, settings_path, render=False): | ||||||
|  |     """initialise class | ||||||
|  |     settings_path = str -> location/folder of settings file | ||||||
|  |     render = bool -> show something on the ePaper? | ||||||
|  |     """ | ||||||
|  |     # Check if render is boolean | ||||||
|  |     if not isinstance(render, bool): | ||||||
|  |       raise Exception('render must be True or False, not "{}"'.format(render)) | ||||||
|  |     self.render = render | ||||||
|  |  | ||||||
|  |     # load+validate settings file. Import and setup specified modules | ||||||
|  |     self.Settings = Settings(settings_path) | ||||||
|  |     self.active_modules = self.Settings.active_modules() | ||||||
|  |     for module in self.active_modules: | ||||||
|  |       try: | ||||||
|  |         loader = 'from modules import {0}'.format(module) | ||||||
|  |         module_data = self.Settings.get_config(module) | ||||||
|  |         size, conf = module_data['size'], module_data['config'] | ||||||
|  |         setup = 'self.{} = {}(size, conf)'.format(module, module) | ||||||
|  |         exec(loader) | ||||||
|  |         exec(setup) | ||||||
|  |         logger.debug(('{}: size: {}, config: {}'.format(module, size, conf))) | ||||||
|  |  | ||||||
|  |       # If a module was not found, print an error message | ||||||
|  |       except ImportError: | ||||||
|  |         print( | ||||||
|  |           'Could not find module: "{}". Please try to import manually.'.format( | ||||||
|  |           module)) | ||||||
|  |  | ||||||
|  |     # Give an OK message | ||||||
|  |     print('loaded inkycal') | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   def countdown(self, interval_mins=None ): | ||||||
|  |     """Returns the remaining time in seconds until next display update""" | ||||||
|  |  | ||||||
|  |     # Validate update interval | ||||||
|  |     allowed_intervals = [10, 15, 20, 30, 60] | ||||||
|  |  | ||||||
|  |     # Check if empty, if empty, use value from settings file | ||||||
|  |     if interval_mins == None: | ||||||
|  |       interval_mins = self.Settings.update_interval | ||||||
|  |  | ||||||
|  |     # Check if integer | ||||||
|  |     if not isinstance(interval_mins, int): | ||||||
|  |       raise Exception('Update interval must be an integer -> 60') | ||||||
|  |  | ||||||
|  |     # Check if value is supported | ||||||
|  |     if interval_mins not in allowed_intervals: | ||||||
|  |       raise Exception('Update interval is {}, but should be one of: {}'.format( | ||||||
|  |         interval_mins, allowed_intervals)) | ||||||
|  |  | ||||||
|  |     # Find out at which minutes the update should happen | ||||||
|  |     now = arrow.now() | ||||||
|  |     update_timings = [(60 - int(interval_mins)*updates) for updates in | ||||||
|  |                       range(60//int(interval_mins))][::-1] | ||||||
|  |  | ||||||
|  |     # Calculate time in mins until next update | ||||||
|  |     minutes = [_ for _ in update_timings if _>= now.minute][0] - now.minute | ||||||
|  |  | ||||||
|  |     # Print the remaining time in mins until next update | ||||||
|  |     print('{0} Minutes left until next refresh'.format(minutes)) | ||||||
|  |  | ||||||
|  |     # Calculate time in seconds until next update | ||||||
|  |     remaining_time = minutes*60 + (60 - now.second) | ||||||
|  |  | ||||||
|  |     # Return seconds until next update | ||||||
|  |     return remaining_time | ||||||
|  |  | ||||||
|  |   def test(self): | ||||||
|  |     """Test if inkycal can be run correctly""" | ||||||
|  |  | ||||||
|  |     for module in self.active_modules: | ||||||
|  |       generate_im = 'self.{0}.generate_image()'.format(module) | ||||||
|  |       print('generating image for {} module...'.format(module), end = '') | ||||||
|  |       try: | ||||||
|  |         exec(generate_im) | ||||||
|  |         print('OK!') | ||||||
|  |       except Exception as Error: | ||||||
|  |         print('Error!') | ||||||
|  |         print(traceback.format_exc()) | ||||||
|  |  | ||||||
|  |   def run(self, render = True): | ||||||
|  |     """Runs the main inykcal program nonstop (cannot be stopped anymore!) | ||||||
|  |     Set render to True to show something on the display""" | ||||||
|  |      | ||||||
|  |     # TODO: rendering | ||||||
|  |     # TODO: printing traceback on display (or at least a smaller message?) | ||||||
|  |     # Upside down | ||||||
|  |     # Calibration | ||||||
|  |     # Stitch images together ,merge black&colour if required | ||||||
|  |  | ||||||
|  |     # Count the number of times without any crashs | ||||||
|  |     counter = 1 | ||||||
|  |  | ||||||
|  |     while True: | ||||||
|  |       print('Generating images for all modules...') | ||||||
|  |       for module in self.active_modules: | ||||||
|  |         generate_im = 'self.{0}.generate_image()'.format(module) | ||||||
|  |         try: | ||||||
|  |           exec(generate_im) | ||||||
|  |         except Exception as Error: | ||||||
|  |           print('Error!') | ||||||
|  |           message = traceback.format_exc() | ||||||
|  |           print(message) | ||||||
|  |           counter = 0 | ||||||
|  |       print('OK') | ||||||
|  |  | ||||||
|  |       if render == True: | ||||||
|  |         print('rendering....') | ||||||
|  | ##      if upside_down == True: | ||||||
|  | ##      image = image.rotate(180, expand=True) | ||||||
|  | ##      if three_colour_support == True: | ||||||
|  | ##        image_col = image_col.rotate(180, expand=True) | ||||||
|  |  | ||||||
|  |       print('\ninkycal has been running without any errors for', end = ' ') | ||||||
|  |       print('{} display_updates'.format(counter)) | ||||||
|  |       counter += 1 | ||||||
|  |  | ||||||
|  |       sleep_time = self.countdown(10) ##### | ||||||
|  |       time.sleep(sleep_time) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   def _merge() | ||||||
|  |       """Stitches images from each module a single one (for each colour) | ||||||
|  |       Merges black and colour band for black-white epaper | ||||||
|  |       """ | ||||||
|  |  | ||||||
|  |       image = Image.new('RGB',  | ||||||
|  |       im_location = images | ||||||
|  |       # Check if both files exist | ||||||
|  |       # Center sub images | ||||||
|  |  | ||||||
|  |  | ||||||
|  |       for module in self.active_modules: | ||||||
|  |          | ||||||
|  |         im1_name, im2_name = module+'.png', module+'_colour.png' | ||||||
|  |  | ||||||
|  |         # Check if display can only show black-white | ||||||
|  |         if self.Settings.supports_colour == False: | ||||||
|  |           if exists(im1_name) and exists(im2_name): | ||||||
|  |             im1 = Image.open(images+im1_name).convert('RGBA') | ||||||
|  |             im2 = Image.open(images+im2_name).convert('RGBA') | ||||||
|  |  | ||||||
|  |             # White to transparent pixels | ||||||
|  |             def clear_white(img): | ||||||
|  |               """Replace all white pixels from image with transparent pixels | ||||||
|  |               """ | ||||||
|  |               x = numpy.asarray(img.convert('RGBA')).copy() | ||||||
|  |               x[:, :, 3] = (255 * (x[:, :, :3] != 255).any(axis=2)).astype(numpy.uint8) | ||||||
|  |               return Image.fromarray(x) | ||||||
|  |  | ||||||
|  |             # Paste black pixels of im2 on im1 | ||||||
|  |             im2 = clear_white(im2) | ||||||
|  |             im1.paste(im2, (0,0), im2) | ||||||
|  |             im1.save(module+'_comb.png', 'PNG') | ||||||
|  |  | ||||||
|  |         # Check if display can support colour | ||||||
|  |         elif self.Settings.supports_colour == True: | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user