| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | """
 | 
					
						
							| 
									
										
										
										
											2020-11-24 00:40:07 +01:00
										 |  |  | Third party module template (inkycal-compatible module) | 
					
						
							| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-03 16:16:07 +02:00
										 |  |  | Copyright by aceinnolab | 
					
						
							| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ############################################################################# | 
					
						
							|  |  |  | #                           Required imports (do not remove) | 
					
						
							|  |  |  | ############################################################################# | 
					
						
							|  |  |  | # Required for setting up this module | 
					
						
							|  |  |  | from inkycal.modules.template import inkycal_module | 
					
						
							|  |  |  | from inkycal.custom import * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ############################################################################# | 
					
						
							| 
									
										
										
										
											2020-11-24 00:40:07 +01:00
										 |  |  | #                           Built-in library imports (change as desired) | 
					
						
							| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | ############################################################################# | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Built-in libraries go here | 
					
						
							|  |  |  | from random import shuffle | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ############################################################################# | 
					
						
							| 
									
										
										
										
											2020-11-24 00:40:07 +01:00
										 |  |  | #                         External library imports (always use try-except) | 
					
						
							| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | ############################################################################# | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # For external libraries, which require installing, | 
					
						
							|  |  |  | # use try...except ImportError to check if it has been installed | 
					
						
							|  |  |  | # If it is not found, print a short message on how to install this dependency | 
					
						
							|  |  |  | try: | 
					
						
							| 
									
										
										
										
											2022-04-02 01:30:17 +02:00
										 |  |  |     import feedparser | 
					
						
							| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | except ImportError: | 
					
						
							| 
									
										
										
										
											2022-04-02 01:30:17 +02:00
										 |  |  |     print('feedparser is not installed! Please install with:') | 
					
						
							|  |  |  |     print('pip3 install feedparser') | 
					
						
							| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | ############################################################################# | 
					
						
							|  |  |  | #                         Filename + logging (do not remove) | 
					
						
							|  |  |  | ############################################################################# | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Get the name of this file, set up logging for this filename | 
					
						
							| 
									
										
										
										
											2022-10-03 02:56:04 +02:00
										 |  |  | logger = logging.getLogger(__name__) | 
					
						
							| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-02 01:30:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | ############################################################################# | 
					
						
							|  |  |  | #                         Class setup | 
					
						
							|  |  |  | ############################################################################# | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-24 00:40:07 +01:00
										 |  |  | # Change 'Simple' to a different name, the first letter must be a Capital! | 
					
						
							|  |  |  | # Avoid naming the class with too long names | 
					
						
							| 
									
										
										
										
											2020-06-13 15:13:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Simple(inkycal_module): | 
					
						
							| 
									
										
										
										
											2022-04-02 01:30:17 +02:00
										 |  |  |     """ Simple Class
 | 
					
						
							|  |  |  |     Once sentence describing what this module does, | 
					
						
							|  |  |  |     e.g. Display hello world with your name! | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # name is the name that will be shown on the web-ui | 
					
						
							|  |  |  |     # may be same or different to the class name (Do not remove this) | 
					
						
							|  |  |  |     name = "Simple - say hello world" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # create a dictionary containing variables which your module must have | 
					
						
							|  |  |  |     # to run correctly, e.g. if your module needs an 'api-key' and a 'name': | 
					
						
							|  |  |  |     requires = { | 
					
						
							|  |  |  |         # A simple text input; users can choose what to enter by keyboard | 
					
						
							|  |  |  |         'api_key': {"label": "Please enter your api-key from some-website"}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # A simple text input; users can choose what to enter by keyboard | 
					
						
							|  |  |  |         'username': {"label": "Please enter a username"}, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     # The format for the above is: |"key_name": {"Desription what this means"},| | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # create a dictionary containing variables which your module optionally | 
					
						
							|  |  |  |     # can have to run correctly, e.g. if your module needs has optional | 
					
						
							|  |  |  |     # parameters like: 'api-key' and a 'name': | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ######################################################################### | 
					
						
							|  |  |  |     optional = { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # A simple text input with multiple values separated by a comma | 
					
						
							|  |  |  |         'hobbies': {"label": "What is/are your hobbies? Separate multiple ones " | 
					
						
							|  |  |  |                              "with a comma"}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # A simple text input which should be a number | 
					
						
							|  |  |  |         'age': {"label": "What is your age? Please enter a number"}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # A dropdown list variable. This will allow users to select something | 
					
						
							|  |  |  |         # from the list in options. Instead of True/False, you can have | 
					
						
							|  |  |  |         # strings, numbers and other datatypes. Add as many options as you need | 
					
						
							|  |  |  |         'likes_inkycal': { | 
					
						
							|  |  |  |             "label": "Do you like Inkycal?", | 
					
						
							|  |  |  |             "options": [True, False], | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # A dropdown list with a fallback value in case the user didn't select | 
					
						
							|  |  |  |         # anything | 
					
						
							|  |  |  |         'show_smiley': { | 
					
						
							|  |  |  |             "label": "Show a smiley next to your name?", | 
					
						
							|  |  |  |             "options": [True, False], | 
					
						
							|  |  |  |             "default": True, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ######################################################################## | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Initialise the class (do not remove) | 
					
						
							|  |  |  |     def __init__(self, config): | 
					
						
							|  |  |  |         """Initialize your module module""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Initialise this module via the inkycal_module template (required) | 
					
						
							|  |  |  |         super().__init__(config) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         config = config['config'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Check if all required parameters are present | 
					
						
							|  |  |  |         # remove this if your module has no required parameters | 
					
						
							|  |  |  |         for param in self.requires: | 
					
						
							| 
									
										
										
										
											2022-04-10 06:35:08 +02:00
										 |  |  |             if param not in config: | 
					
						
							| 
									
										
										
										
											2022-04-02 01:30:17 +02:00
										 |  |  |                 raise Exception('config is missing {}'.format(param)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # the web-UI removes any blank space from the input | 
					
						
							|  |  |  |         # It can only output strings or booleans, integers and lists need to be | 
					
						
							|  |  |  |         # converted manually, e.g. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # if you need a boolean (True/False), no conversion is needed: | 
					
						
							|  |  |  |         self.show_smiley = config['show_smiley'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # if you need a single word input, like the api-ley, no conversion is needed | 
					
						
							|  |  |  |         self.api_key = config['api_key'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # if you need a integer (number) input, you have to convert this to a int | 
					
						
							|  |  |  |         # -----------------------------------------------------------------------# | 
					
						
							|  |  |  |         # bad example :/ | 
					
						
							|  |  |  |         self.age = int(config["age"]) | 
					
						
							|  |  |  |         # Remember age was a optional parameter? What if no age was entered | 
					
						
							|  |  |  |         # and there is no fallback value? Then the age would be None. | 
					
						
							|  |  |  |         # This would cause crashing right here | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # good example :) | 
					
						
							|  |  |  |         if config["age"] and isinstance(config["age"], str): | 
					
						
							|  |  |  |             self.age = int(config["age"]) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.age = 10  # just a joke, no offense | 
					
						
							|  |  |  |         # -> Check if age was entered and if it's a string (entered via web-UI) | 
					
						
							|  |  |  |         # If something was entered for age, convert it to a number | 
					
						
							|  |  |  |         # The else statement is executed when nothing was entered for age | 
					
						
							|  |  |  |         # You could assign a custom value now or print something. | 
					
						
							|  |  |  |         # -----------------------------------------------------------------------# | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # if you need a list of words, you have to convert the string to a list | 
					
						
							|  |  |  |         # -----------------------------------------------------------------------# | 
					
						
							|  |  |  |         # good example :) | 
					
						
							|  |  |  |         if config["hobbies"] and isinstance(config["hobbies"], str): | 
					
						
							|  |  |  |             self.hobbies = config["age"].split(",") | 
					
						
							|  |  |  |             # split splits the string on each comma -> gives a list | 
					
						
							|  |  |  |             # even if a single value was entered, it will be converted to a list | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.hobbies = []  # empty list if nothing was entered by user | 
					
						
							|  |  |  |         # -----------------------------------------------------------------------# | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # give an OK message | 
					
						
							| 
									
										
										
										
											2022-10-03 02:56:04 +02:00
										 |  |  |         print(f'{__name__} loaded') | 
					
						
							| 
									
										
										
										
											2022-04-02 01:30:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     ############################################################################# | 
					
						
							|  |  |  |     #                 Validation of module specific parameters   (optional)     # | 
					
						
							|  |  |  |     ############################################################################# | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _validate(self): | 
					
						
							|  |  |  |         """Validate module-specific parameters""" | 
					
						
							|  |  |  |         # Check the type of module-specific parameters | 
					
						
							|  |  |  |         # This function is optional, but useful for debugging. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Here, we are checking if do_something (from init) is True/False | 
					
						
							|  |  |  |         if not isinstance(self.age, int): | 
					
						
							|  |  |  |             print(f"age has to be a number, but given value is {self.age}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ############################################################################# | 
					
						
							|  |  |  |     #                       Generating the image                                # | 
					
						
							|  |  |  |     ############################################################################# | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def generate_image(self): | 
					
						
							|  |  |  |         """Generate image for this module""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Define new image size with respect to padding | 
					
						
							|  |  |  |         im_width = int(self.width - (2 * self.padding_left)) | 
					
						
							|  |  |  |         im_height = int(self.height - (2 * self.padding_top)) | 
					
						
							|  |  |  |         im_size = im_width, im_height | 
					
						
							|  |  |  |         logger.info('image size: {} x {} px'.format(im_width, im_height)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Use logger.info(), logger.debug(), logger.warning() to display | 
					
						
							|  |  |  |         # useful information for the developer | 
					
						
							|  |  |  |         logger.info('image size: {} x {} px'.format(im_width, im_height)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Create an image for black pixels and one for coloured pixels (required) | 
					
						
							|  |  |  |         im_black = Image.new('RGB', size=im_size, color='white') | 
					
						
							|  |  |  |         im_colour = Image.new('RGB', size=im_size, color='white') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ################################################################# | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         #                    Your code goes here                        # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Write/Draw something on the image | 
					
						
							| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-02 01:30:17 +02:00
										 |  |  |         #   You can use these custom functions to help you create the image: | 
					
						
							|  |  |  |         # - write()               -> write text on the image | 
					
						
							|  |  |  |         # - get_fonts()           -> see which fonts are available | 
					
						
							|  |  |  |         # - get_system_tz()       -> Get the system's current timezone | 
					
						
							|  |  |  |         # - auto_fontsize()       -> Scale the fontsize to the provided height | 
					
						
							|  |  |  |         # - textwrap()            -> Split a paragraph into smaller lines | 
					
						
							|  |  |  |         # - internet_available()  -> Check if internet is available | 
					
						
							|  |  |  |         # - draw_border()         -> Draw a border around the specified area | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # If these aren't enough, take a look at python Pillow (imaging library)'s | 
					
						
							|  |  |  |         # documentation. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ################################################################# | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # return the images ready for the display | 
					
						
							|  |  |  |         return im_black, im_colour | 
					
						
							| 
									
										
										
										
											2020-05-23 01:45:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							| 
									
										
										
										
											2022-10-03 02:56:04 +02:00
										 |  |  |     print('running {0} in standalone mode'.format(__name__)) | 
					
						
							| 
									
										
										
										
											2020-06-13 15:13:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | ################################################################################ | 
					
						
							|  |  |  | # Last steps | 
					
						
							|  |  |  | # Wow, you made your own module for the inkycal project! Amazing :D | 
					
						
							|  |  |  | # To make sure this module can be used with inkycal, you need to edit 2 files: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-04 16:21:33 +02:00
										 |  |  | # 1) Inkycal/inkycal/modules/__init__.py | 
					
						
							| 
									
										
										
										
											2020-06-13 15:13:13 +02:00
										 |  |  | # Add this into the modules init file: | 
					
						
							|  |  |  | # from .filename import Class | 
					
						
							|  |  |  | # where filename is the name of your module | 
					
						
							|  |  |  | # where Class is the name of your class e.g. Simple in this case | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-04 16:21:33 +02:00
										 |  |  | # 2) Inkycal/inkycal/__init__.py | 
					
						
							| 
									
										
										
										
											2020-06-13 15:13:13 +02:00
										 |  |  | # Before the line # Main file, add this: | 
					
						
							|  |  |  | # import inkycal.modules.filename | 
					
						
							|  |  |  | # Where the filename is the name of your file inside the modules folder | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # How do I now import my module? | 
					
						
							|  |  |  | # from inkycal.modules import Class | 
					
						
							|  |  |  | # Where Class is the name of the class inside your module (e.g. Simple) |