Adapting modules for new web-ui (do not use yet)
This commit is contained in:
parent
29788f0313
commit
035ce65f06
@ -7,8 +7,8 @@ from inkycal.display import Display
|
||||
import inkycal.modules.inkycal_agenda
|
||||
import inkycal.modules.inkycal_calendar
|
||||
import inkycal.modules.inkycal_weather
|
||||
import inkycal.modules.inkycal_rss
|
||||
#import inkycal.modules.inkycal_image
|
||||
import inkycal.modules.inkycal_feeds
|
||||
# import inkycal.modules.inkycal_image
|
||||
# import inkycal.modules.inkycal_server
|
||||
|
||||
# Main file
|
||||
|
@ -1,2 +1 @@
|
||||
from .settings_parser import Settings
|
||||
from .layout import Layout
|
||||
|
@ -124,5 +124,4 @@ class Layout:
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('running {0} in standalone/debug mode'.format(
|
||||
os.path.basename(__file__).split('.py')[0]))
|
||||
|
||||
os.path.basename(__file__).split('.py')[0]))
|
@ -1,207 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Json settings parser for inkycal project
|
||||
Copyright by aceisace
|
||||
"""
|
||||
from inkycal.config.layout import Layout
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
from jsmin import jsmin
|
||||
|
||||
logger = logging.getLogger('settings')
|
||||
logger.setLevel(level=logging.DEBUG)
|
||||
|
||||
class Settings:
|
||||
"""Load and validate settings from the settings file"""
|
||||
|
||||
_supported_languages = ['en', 'de', 'ru', 'it', 'es', 'fr', 'el', 'sv', 'nl',
|
||||
'pl', 'ua', 'nb', 'vi', 'zh_tw', 'zh-cn', 'ja', 'ko']
|
||||
_supported_units = ['metric', 'imperial']
|
||||
_supported_hours = [12, 24]
|
||||
_supported_update_interval = [10, 15, 20, 30, 60]
|
||||
_supported_display_orientation = ['normal', 'upside_down']
|
||||
_supported_models = [
|
||||
'epd_7_in_5_v2_colour', 'epd_7_in_5_v2',
|
||||
'epd_7_in_5_colour', 'epd_7_in_5',
|
||||
'epd_5_in_83_colour','epd_5_in_83',
|
||||
'epd_4_in_2_colour', 'epd_4_in_2',
|
||||
'9_in_7'
|
||||
]
|
||||
|
||||
def __init__(self, settings_file_path):
|
||||
"""Load settings from path (folder or settings.json file)
|
||||
Set show_info_section to False to hide the info section"""
|
||||
try:
|
||||
if settings_file_path.endswith('settings.json'):
|
||||
folder = settings_file_path.split('/settings.json')[0]
|
||||
else:
|
||||
folder = settings_file_path
|
||||
|
||||
os.chdir(folder)
|
||||
if os.path.exists('settings.jsonc'):
|
||||
with open("settings.jsonc") as jsonc_file:
|
||||
# minify in order to remove comments
|
||||
minified = jsmin(jsonc_file.read())
|
||||
|
||||
# remove known invalid json (comma followed by closing accolades)
|
||||
minified = minified.replace(",}","}")
|
||||
settings = json.loads(minified)
|
||||
self._settings = settings
|
||||
else:
|
||||
with open("settings.json") as file:
|
||||
settings = json.load(file)
|
||||
self._settings = settings
|
||||
|
||||
except FileNotFoundError:
|
||||
print('No settings file found in specified location')
|
||||
|
||||
# Validate the settings
|
||||
self._validate()
|
||||
|
||||
# Get the height-percentages of the modules
|
||||
if self.info_section == True:
|
||||
self.Layout = Layout(model=self.model, use_info_section = True)
|
||||
else:
|
||||
self.Layout = Layout(model=self.model, use_info_section = False)
|
||||
|
||||
all_heights = [_['height'] for _ in self._settings['panels']]
|
||||
num_modules = len(self.active_modules())
|
||||
|
||||
|
||||
# check if height have (or have not) been provided for all modules
|
||||
if len(all_heights) == num_modules:
|
||||
|
||||
# If no height is provided, use default values
|
||||
if list(set(all_heights)) == [None]:
|
||||
self.Layout.create_sections()
|
||||
|
||||
# if all heights are specified, use given values
|
||||
else:
|
||||
logger.info('Setting section height according to settings file')
|
||||
|
||||
to_decimal = lambda percentage: percentage/100
|
||||
|
||||
top_height = [to_decimal(_['height']) for _ in
|
||||
self._settings['panels'] if _['location'] == 'top']
|
||||
|
||||
middle_height = [to_decimal(_['height']) for _ in
|
||||
self._settings['panels'] if _['location'] == 'middle']
|
||||
|
||||
bottom_height = [to_decimal(_['height']) for _ in
|
||||
self._settings['panels'] if _['location'] == 'bottom']
|
||||
|
||||
self.Layout.create_sections(
|
||||
top_section = top_height[0] if top_height else 0,
|
||||
middle_section = middle_height[0] if middle_height else 0,
|
||||
bottom_section = bottom_height[0] if bottom_height else 0)
|
||||
|
||||
# If only some heights were defined, raise an error
|
||||
else:
|
||||
print("Section height is not defined for all sections.")
|
||||
print("Please leave height empty for all modules")
|
||||
print("OR specify the height for all sections")
|
||||
raise Exception('Module height is not specified in all modules!')
|
||||
|
||||
|
||||
def _validate(self):
|
||||
"""Validate the basic config"""
|
||||
settings = self._settings
|
||||
|
||||
required = ['language', 'units', 'hours', 'model', 'calibration_hours',
|
||||
'display_orientation', 'info_section']
|
||||
|
||||
# Check if all required settings exist
|
||||
for param in required:
|
||||
if not param in settings:
|
||||
raise Exception (
|
||||
'required parameter: `{0}` not found in settings file!'.format(param))
|
||||
|
||||
# Attempt to parse the parameters
|
||||
self.language = settings['language']
|
||||
self.units = settings['units']
|
||||
self.hours = settings['hours']
|
||||
self.model = settings['model']
|
||||
self.update_interval = settings['update_interval']
|
||||
self.calibration_hours = settings['calibration_hours']
|
||||
self.display_orientation = settings['display_orientation']
|
||||
self.info_section = settings['info_section']
|
||||
|
||||
# Validate the parameters
|
||||
if (not isinstance(self.language, str) or self.language not in
|
||||
self._supported_languages):
|
||||
print('Language not supported, switching to fallback, en')
|
||||
self.language = 'en'
|
||||
|
||||
if (not isinstance(self.units, str) or self.units not in
|
||||
self._supported_units):
|
||||
print('units not supported, switching to fallback, metric')
|
||||
self.units = 'metric'
|
||||
|
||||
if (not isinstance(self.hours, int) or self.hours not in
|
||||
self._supported_hours):
|
||||
print('hour-format not supported, switching to fallback, 24')
|
||||
self.hours = 24
|
||||
|
||||
if (not isinstance(self.model, str) or self.model not in
|
||||
self._supported_models):
|
||||
print('model not supported, switching to fallback, epd_7_in_5')
|
||||
self.model = 'epd_7_in_5'
|
||||
|
||||
if (not isinstance(self.update_interval, int) or self.update_interval
|
||||
not in self._supported_update_interval):
|
||||
print('update-interval not supported, switching to fallback, 60')
|
||||
self.update_interval = 60
|
||||
|
||||
if (not isinstance(self.calibration_hours, list)):
|
||||
print('calibration_hours not supported, switching to fallback, [0,12,18]')
|
||||
self.calibration_hours = [0,12,18]
|
||||
|
||||
if (not isinstance(self.display_orientation, str) or self.display_orientation not in
|
||||
self._supported_display_orientation):
|
||||
print('display orientation not supported, switching to fallback, normal')
|
||||
self.display_orientation = 'normal'
|
||||
|
||||
if (not isinstance(self.info_section, bool)):
|
||||
print('info_section must be True/False. Switching to fallback: False')
|
||||
self.info_section = False
|
||||
|
||||
print('Settings file OK!')
|
||||
|
||||
def active_modules(self):
|
||||
modules = [section['type'] for section in self._settings['panels']]
|
||||
return modules
|
||||
|
||||
def common_config(self):
|
||||
common_config = {
|
||||
'language' : self.language, 'units' : self.units, 'hours' : self.hours
|
||||
}
|
||||
return common_config
|
||||
|
||||
|
||||
def get_config(self, module_name):
|
||||
"""Ge the config of this module (size, config)"""
|
||||
if module_name not in self.active_modules():
|
||||
print('No config is available for this module')
|
||||
else:
|
||||
for section in self._settings['panels']:
|
||||
if section['type'] == module_name:
|
||||
config = section['config']
|
||||
size = self.Layout.get_size(self.get_position(module_name))
|
||||
return {'size':size, 'config': {**config, **self.common_config()}}
|
||||
|
||||
def get_position(self, module_name):
|
||||
"""Get the position of this module's image on the display"""
|
||||
if module_name not in self.active_modules():
|
||||
print('No position is available for this module')
|
||||
else:
|
||||
for section in self._settings['panels']:
|
||||
if section['type'] == module_name:
|
||||
position = section['location']
|
||||
return position
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('running {0} in standalone/debug mode'.format(
|
||||
os.path.basename(__file__).split('.py')[0]))
|
||||
|
@ -11,6 +11,8 @@ from urllib.request import urlopen
|
||||
import os
|
||||
import time
|
||||
|
||||
logger = logging.getLogger('inkycal_custom')
|
||||
logger.setLevel(level=logging.INFO)
|
||||
|
||||
# Get the path to the Inkycal folder
|
||||
top_level = os.path.dirname(
|
||||
@ -107,11 +109,11 @@ def write(image, xy, box_size, text, font=None, **kwargs):
|
||||
|
||||
# Truncate text if text is too long so it can fit inside the box
|
||||
if (text_width, text_height) > (box_width, box_height):
|
||||
logging.debug(('truncating {}'.format(text)))
|
||||
logger.debug(('truncating {}'.format(text)))
|
||||
while (text_width, text_height) > (box_width, box_height):
|
||||
text=text[0:-1]
|
||||
text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1]
|
||||
logging.debug((text))
|
||||
logger.debug((text))
|
||||
|
||||
# Align text to desired position
|
||||
if alignment == "center" or None:
|
||||
|
@ -1,99 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Inky-Calendar epaper functions
|
||||
Copyright by aceisace
|
||||
"""
|
||||
from importlib import import_module
|
||||
from PIL import Image
|
||||
|
||||
|
||||
class Display:
|
||||
"""Display class for inkycal
|
||||
Handles rendering on display"""
|
||||
|
||||
def __init__(self, epaper_model):
|
||||
"""Load the drivers for this epaper model"""
|
||||
if 'colour' in epaper_model:
|
||||
self.supports_colour = True
|
||||
else:
|
||||
self.supports_colour = False
|
||||
|
||||
try:
|
||||
driver_path = 'inkycal.display.drivers.{}'.format(epaper_model)
|
||||
driver = import_module(driver_path)
|
||||
self._epaper = driver.EPD()
|
||||
self.model_name = epaper_model
|
||||
|
||||
except ImportError:
|
||||
raise Exception('This module is not supported. Check your spellings?')
|
||||
|
||||
except FileNotFoundError:
|
||||
raise Exception('SPI could not be found. Please check if SPI is enabled')
|
||||
|
||||
def render(self, im_black, im_colour = None):
|
||||
"""Render an image on the epaper
|
||||
im_colour is required for three-colour epapers"""
|
||||
|
||||
epaper = self._epaper
|
||||
|
||||
if self.supports_colour == False:
|
||||
print('Initialising..', end = '')
|
||||
epaper.init()
|
||||
# For the 9.7" ePaper, the image needs to be flipped by 90 deg first
|
||||
# The other displays flip the image automatically
|
||||
if self.model_name == "9_in_7":
|
||||
im_black.rotate(90, expand=True)
|
||||
print('Updating display......', end = '')
|
||||
epaper.display(epaper.getbuffer(im_black))
|
||||
print('Done')
|
||||
|
||||
elif self.supports_colour == True:
|
||||
if not im_colour:
|
||||
raise Exception('im_colour is required for coloured epaper displays')
|
||||
print('Initialising..', end = '')
|
||||
epaper.init()
|
||||
print('Updating display......', end = '')
|
||||
epaper.display(epaper.getbuffer(im_black), epaper.getbuffer(im_colour))
|
||||
print('Done')
|
||||
|
||||
print('Sending E-Paper to deep sleep...', end = '')
|
||||
epaper.sleep()
|
||||
print('Done')
|
||||
|
||||
def calibrate(self, cycles=3):
|
||||
"""Flush display with single colour to prevent burn-ins (ghosting)
|
||||
cycles -> int. How many times should each colour be flushed?
|
||||
recommended cycles = 3"""
|
||||
|
||||
epaper = self._epaper
|
||||
epaper.init()
|
||||
|
||||
white = Image.new('1', (epaper.width, epaper.height), 'white')
|
||||
black = Image.new('1', (epaper.width, epaper.height), 'black')
|
||||
|
||||
print('----------Started calibration of ePaper display----------')
|
||||
if self.supports_colour == True:
|
||||
for _ in range(cycles):
|
||||
print('Calibrating...', end= ' ')
|
||||
print('black...', end= ' ')
|
||||
epaper.display(epaper.getbuffer(black), epaper.getbuffer(white))
|
||||
print('colour...', end = ' ')
|
||||
epaper.display(epaper.getbuffer(white), epaper.getbuffer(black))
|
||||
print('white...')
|
||||
epaper.display(epaper.getbuffer(white), epaper.getbuffer(white))
|
||||
print('Cycle {0} of {1} complete'.format(_+1, cycles))
|
||||
|
||||
if self.supports_colour == False:
|
||||
for _ in range(cycles):
|
||||
print('Calibrating...', end= ' ')
|
||||
print('black...', end = ' ')
|
||||
epaper.display(epaper.getbuffer(black))
|
||||
print('white...')
|
||||
epaper.display(epaper.getbuffer(white)),
|
||||
print('Cycle {0} of {1} complete'.format(_+1, cycles))
|
||||
|
||||
print('-----------Calibration complete----------')
|
||||
epaper.sleep()
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
from .inkycal_agenda import Agenda
|
||||
from .inkycal_calendar import Calendar
|
||||
from .inkycal_weather import Weather
|
||||
from .inkycal_rss import RSS
|
||||
from .inkycal_feeds import RSS
|
||||
#from .inkycal_image import Image
|
||||
|
@ -14,7 +14,7 @@ import arrow
|
||||
|
||||
filename = os.path.basename(__file__).split('.py')[0]
|
||||
logger = logging.getLogger(filename)
|
||||
logger.setLevel(level=logging.ERROR)
|
||||
logger.setLevel(level=logging.INFO)
|
||||
|
||||
class Agenda(inkycal_module):
|
||||
"""Agenda class
|
||||
@ -33,7 +33,6 @@ class Agenda(inkycal_module):
|
||||
optional = {
|
||||
"ical_files" : {
|
||||
"label":"iCalendar filepaths, separated with a comma",
|
||||
"default":[]
|
||||
},
|
||||
|
||||
"date_format":{
|
||||
@ -45,27 +44,37 @@ class Agenda(inkycal_module):
|
||||
"time_format":{
|
||||
"label":"Use an arrow-supported token for custom time formatting "+
|
||||
"see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. HH:mm",
|
||||
"default":"HH:mm",
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
|
||||
def __init__(self, section_size, section_config):
|
||||
def __init__(self, config):
|
||||
"""Initialize inkycal_agenda module"""
|
||||
|
||||
super().__init__(section_size, section_config)
|
||||
super().__init__(config)
|
||||
|
||||
for param in self.equires:
|
||||
if not param in section_config:
|
||||
config = config['config']
|
||||
|
||||
# Check if all required parameters are present
|
||||
for param in self.requires:
|
||||
if not param in config:
|
||||
raise Exception('config is missing {}'.format(param))
|
||||
|
||||
# module specific parameters
|
||||
self.date_format = self.config['date_format']
|
||||
self.time_format = self.config['time_format']
|
||||
self.language = self.config['language']
|
||||
self.ical_urls = self.config['ical_urls']
|
||||
self.ical_files = self.config['ical_files']
|
||||
self.date_format = config['date_format']
|
||||
self.time_format = config['time_format']
|
||||
self.language = config['language']
|
||||
self.ical_urls = config['ical_urls'].split(',')
|
||||
|
||||
# Check if ical_files is an empty string
|
||||
if config['ical_files'] != "":
|
||||
self.ical_files = config['ical_files'].split(',')
|
||||
else:
|
||||
self.ical_files = []
|
||||
|
||||
# Additional config
|
||||
self.timezone = get_system_tz()
|
||||
|
||||
# give an OK message
|
||||
@ -83,9 +92,6 @@ class Agenda(inkycal_module):
|
||||
if not isinstance(self.language, str):
|
||||
print('language has to be a string: "en" ')
|
||||
|
||||
if not isinstance(self.timezone, str):
|
||||
print('The timezone has bo be a string.')
|
||||
|
||||
if not isinstance(self.ical_urls, list):
|
||||
print('ical_urls has to be a list ["url1", "url2"] ')
|
||||
|
||||
@ -96,8 +102,8 @@ class Agenda(inkycal_module):
|
||||
"""Generate image for this module"""
|
||||
|
||||
# Define new image size with respect to padding
|
||||
im_width = int(self.width - (self.width * 2 * self.margin_x))
|
||||
im_height = int(self.height - (self.height * 2 * self.margin_y))
|
||||
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: {0}'.format(im_size))
|
||||
@ -130,6 +136,7 @@ class Agenda(inkycal_module):
|
||||
|
||||
if self.ical_urls:
|
||||
parser.load_url(self.ical_urls)
|
||||
|
||||
if self.ical_files:
|
||||
parser.load_from_file(self.ical_files)
|
||||
|
||||
@ -139,7 +146,7 @@ class Agenda(inkycal_module):
|
||||
|
||||
# Sort events by beginning time
|
||||
parser.sort()
|
||||
# parser.show_events()
|
||||
#parser.show_events()
|
||||
|
||||
# Set the width for date, time and event titles
|
||||
date_width = int(max([self.font.getsize(
|
||||
@ -147,8 +154,13 @@ class Agenda(inkycal_module):
|
||||
for dates in agenda_events]) * 1.2)
|
||||
logger.debug(('date_width:', date_width))
|
||||
|
||||
# Calculate positions for each line
|
||||
line_pos = [(0, int(line * line_height)) for line in range(max_lines)]
|
||||
logger.debug(('line_pos:', line_pos))
|
||||
|
||||
# Check if any events were filtered
|
||||
if upcoming_events:
|
||||
logger.info('Managed to parse events from urls')
|
||||
|
||||
# Find out how much space the event times take
|
||||
time_width = int(max([self.font.getsize(
|
||||
@ -168,10 +180,6 @@ class Agenda(inkycal_module):
|
||||
x_event = date_width + time_width
|
||||
logger.debug(('x-event:', x_event))
|
||||
|
||||
# Calculate positions for each line
|
||||
line_pos = [(0, int(line * line_height)) for line in range(max_lines)]
|
||||
logger.debug(('line_pos:', line_pos))
|
||||
|
||||
# Merge list of dates and list of events
|
||||
agenda_events += upcoming_events
|
||||
|
||||
@ -216,6 +224,8 @@ class Agenda(inkycal_module):
|
||||
|
||||
# If no events were found, write only dates and lines
|
||||
else:
|
||||
logger.info('no events found')
|
||||
|
||||
cursor = 0
|
||||
for _ in agenda_events:
|
||||
title = _['title']
|
||||
@ -228,10 +238,9 @@ class Agenda(inkycal_module):
|
||||
|
||||
cursor += 1
|
||||
|
||||
logger.info('no events found')
|
||||
|
||||
# return the images ready for the display
|
||||
return im_black, im_colour
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('running {0} in standalone mode'.format(filename))
|
||||
print('running {0} in standalone mode'.format(filename))
|
@ -12,7 +12,7 @@ import arrow
|
||||
|
||||
filename = os.path.basename(__file__).split('.py')[0]
|
||||
logger = logging.getLogger(filename)
|
||||
logger.setLevel(level=logging.ERROR)
|
||||
logger.setLevel(level=logging.DEBUG)
|
||||
|
||||
class Calendar(inkycal_module):
|
||||
"""Calendar class
|
||||
@ -37,12 +37,10 @@ class Calendar(inkycal_module):
|
||||
|
||||
"ical_urls" : {
|
||||
"label":"iCalendar URL/s, separate multiple ones with a comma",
|
||||
"default":[]
|
||||
},
|
||||
|
||||
"ical_files" : {
|
||||
"label":"iCalendar filepaths, separated with a comma",
|
||||
"default":[]
|
||||
},
|
||||
|
||||
"date_format":{
|
||||
@ -59,24 +57,33 @@ class Calendar(inkycal_module):
|
||||
|
||||
}
|
||||
|
||||
def __init__(self, section_size, section_config):
|
||||
def __init__(self, config):
|
||||
"""Initialize inkycal_calendar module"""
|
||||
|
||||
super().__init__(section_size, section_config)
|
||||
super().__init__(config)
|
||||
config = config['config']
|
||||
|
||||
# optional parameters
|
||||
self.weekstart = config['week_starts_on']
|
||||
self.show_events = bool(config['show_events'])
|
||||
self.date_format = config["date_format"]
|
||||
self.time_format = config['time_format']
|
||||
self.language = config['language']
|
||||
|
||||
# module specific parameters
|
||||
if config['ical_urls'] != "":
|
||||
self.ical_urls = config['ical_urls'].split(',')
|
||||
else:
|
||||
self.ical_urls = []
|
||||
|
||||
if config['ical_files'] != "":
|
||||
self.ical_files = config['ical_files'].split(',')
|
||||
else:
|
||||
self.ical_files = []
|
||||
|
||||
# additional configuration
|
||||
self.timezone = get_system_tz()
|
||||
self.num_font = ImageFont.truetype(
|
||||
fonts['NotoSans-SemiCondensed'], size = self.fontsize)
|
||||
self.weekstart = self.config['week_starts_on']
|
||||
self.show_events = self.config['show_events']
|
||||
self.date_format = self.config["date_format"]
|
||||
self.time_format = self.config['time_format']
|
||||
self.language = self.config['language']
|
||||
|
||||
self.timezone = get_system_tz()
|
||||
self.ical_urls = self.config['ical_urls']
|
||||
self.ical_files = self.config['ical_files']
|
||||
|
||||
# give an OK message
|
||||
print('{0} loaded'.format(filename))
|
||||
@ -85,8 +92,8 @@ class Calendar(inkycal_module):
|
||||
"""Generate image for this module"""
|
||||
|
||||
# Define new image size with respect to padding
|
||||
im_width = int(self.width - (2 * self.padding_x))
|
||||
im_height = int(self.height - (2 * self.padding_y))
|
||||
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: {0}'.format(im_size))
|
||||
@ -313,4 +320,4 @@ class Calendar(inkycal_module):
|
||||
return im_black, im_colour
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('running {0} in standalone mode'.format(filename))
|
||||
print('running {0} in standalone mode'.format(filename))
|
@ -18,7 +18,7 @@ except ImportError:
|
||||
|
||||
filename = os.path.basename(__file__).split('.py')[0]
|
||||
logger = logging.getLogger(filename)
|
||||
logger.setLevel(level=logging.ERROR)
|
||||
logger.setLevel(level=logging.INFO)
|
||||
|
||||
class RSS(inkycal_module):
|
||||
"""RSS class
|
||||
@ -28,7 +28,7 @@ class RSS(inkycal_module):
|
||||
name = "Inkycal RSS / Atom"
|
||||
|
||||
requires = {
|
||||
"rss_urls" : {
|
||||
"feed_urls" : {
|
||||
"label":"Please enter ATOM or RSS feed URL/s, separated by a comma",
|
||||
},
|
||||
|
||||
@ -44,23 +44,24 @@ class RSS(inkycal_module):
|
||||
|
||||
}
|
||||
|
||||
def __init__(self, section_size, section_config):
|
||||
"""Initialize inkycal_rss module"""
|
||||
def __init__(self, config):
|
||||
"""Initialize inkycal_feeds module"""
|
||||
|
||||
super().__init__(section_size, section_config)
|
||||
super().__init__(config)
|
||||
|
||||
# Check if required parameters are available in config
|
||||
config = config['config']
|
||||
|
||||
# Check if all required parameters are present
|
||||
for param in self.requires:
|
||||
if not param in section_config:
|
||||
if not param in config:
|
||||
raise Exception('config is missing {}'.format(param))
|
||||
|
||||
# parse required config
|
||||
self.rss_urls = self.config["rss_urls"].split(",")
|
||||
# required parameters
|
||||
self.feed_urls = self.config["feed_urls"].split(",")
|
||||
|
||||
# parse optional config
|
||||
self.shuffle_feeds = self.config["shuffle_feeds"]
|
||||
# optional parameters
|
||||
self.shuffle_feeds = bool(self.config["shuffle_feeds"])
|
||||
|
||||
|
||||
# give an OK message
|
||||
print('{0} loaded'.format(filename))
|
||||
|
||||
@ -75,8 +76,8 @@ class RSS(inkycal_module):
|
||||
"""Generate image for this module"""
|
||||
|
||||
# Define new image size with respect to padding
|
||||
im_width = int(self.width - ( 2 * self.padding_x))
|
||||
im_height = int(self.height - (2 * self.padding_y))
|
||||
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))
|
||||
|
||||
@ -90,7 +91,7 @@ class RSS(inkycal_module):
|
||||
else:
|
||||
raise Exception('Network could not be reached :/')
|
||||
|
||||
# Set some parameters for formatting rss feeds
|
||||
# Set some parameters for formatting feeds
|
||||
line_spacing = 1
|
||||
line_height = self.font.getsize('hg')[1] + line_spacing
|
||||
line_width = im_width
|
||||
@ -103,9 +104,9 @@ class RSS(inkycal_module):
|
||||
line_positions = [
|
||||
(0, spacing_top + _ * line_height ) for _ in range(max_lines)]
|
||||
|
||||
# Create list containing all rss-feeds from all rss-feed urls
|
||||
# Create list containing all feeds from all urls
|
||||
parsed_feeds = []
|
||||
for feeds in self.rss_urls:
|
||||
for feeds in self.feed_urls:
|
||||
text = feedparser.parse(feeds)
|
||||
for posts in text.entries:
|
||||
parsed_feeds.append('•{0}: {1}'.format(posts.title, posts.summary))
|
||||
@ -131,23 +132,21 @@ class RSS(inkycal_module):
|
||||
filtered_feeds = flatten(filtered_feeds)
|
||||
self._filtered_feeds = filtered_feeds
|
||||
|
||||
logger.debug(f'filtered feeds -> {filtered_feeds}')
|
||||
|
||||
# Check if feeds could be parsed and can be displayed
|
||||
if len(filtered_feeds) == 0 and len(parsed_feeds) > 0:
|
||||
print('Feeds could be parsed, but the text is too long to be displayed:/')
|
||||
elif len(filtered_feeds) == 0 and len(parsed_feeds) == 0:
|
||||
print('No feeds could be parsed :/')
|
||||
else:
|
||||
# Write rss-feeds on image
|
||||
# Write feeds on image
|
||||
for _ in range(len(filtered_feeds)):
|
||||
write(im_black, line_positions[_], (line_width, line_height),
|
||||
filtered_feeds[_], font = self.font, alignment= 'left')
|
||||
|
||||
# Cleanup
|
||||
del filtered_feeds, parsed_feeds, wrapped, counter, text
|
||||
|
||||
# Save image of black and colour channel in image-folder
|
||||
return im_black, im_colour
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('running {0} in standalone/debug mode'.format(filename))
|
||||
print(RSS.get_config())
|
||||
print('running {0} in standalone/debug mode'.format(filename))
|
@ -169,8 +169,4 @@ class Todoist(inkycal_module):
|
||||
return im_black, im_colour
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('running {0} in standalone/debug mode'.format(filename))
|
||||
config = {'api_key':'4e166367dcafdd60e6a9f4cbed598d578bf2c359'}
|
||||
size = (480, 100)
|
||||
a = Todoist(size, config)
|
||||
b,c = a.generate_image()
|
||||
print('running {0} in standalone/debug mode'.format(filename))
|
@ -81,42 +81,74 @@ class Weather(inkycal_module):
|
||||
|
||||
}
|
||||
|
||||
def __init__(self, section_size, section_config):
|
||||
def __init__(self, config):
|
||||
"""Initialize inkycal_weather module"""
|
||||
|
||||
super().__init__(section_size, section_config)
|
||||
super().__init__(config)
|
||||
|
||||
# Module specific parameters
|
||||
config = config['config']
|
||||
|
||||
# Check if all required parameters are present
|
||||
for param in self.requires:
|
||||
if not param in section_config:
|
||||
if not param in config:
|
||||
raise Exception('config is missing {}'.format(param))
|
||||
|
||||
# required parameters
|
||||
self.location = self.config['location']
|
||||
self.api_key = self.config['api_key']
|
||||
self.location = config['location']
|
||||
self.api_key = config['api_key']
|
||||
|
||||
# optional parameters
|
||||
self.round_temperature = self.config['round_temperature']
|
||||
self.round_windspeed = self.config['round_windspeed']
|
||||
self.forecast_interval = self.config['forecast_interval']
|
||||
self.units = self.config['units']
|
||||
self.hour_format = self.config['hour_format']
|
||||
self.use_beaufort = self.config['use_beaufort']
|
||||
self.round_temperature = bool(config['round_temperature'])
|
||||
self.round_windspeed = bool(config['round_windspeed'])
|
||||
self.forecast_interval = config['forecast_interval']
|
||||
self.units = config['units']
|
||||
self.hour_format = int(config['hour_format'])
|
||||
self.use_beaufort = bool(config['use_beaufort'])
|
||||
|
||||
# additional configuration
|
||||
self.owm = pyowm.OWM(self.api_key)
|
||||
self.timezone = get_system_tz()
|
||||
self.locale = sys_locale()[0]
|
||||
self.weatherfont = ImageFont.truetype(fonts['weathericons-regular-webfont'],
|
||||
size = self.fontsize)
|
||||
self.weatherfont = ImageFont.truetype(
|
||||
fonts['weathericons-regular-webfont'], size = self.fontsize)
|
||||
|
||||
#self.owm = pyowm.OWM(self.config['api_key'])
|
||||
# give an OK message
|
||||
print('{0} loaded'.format(filename))
|
||||
|
||||
|
||||
def _validate(self):
|
||||
|
||||
if not isinstance(self.location, str):
|
||||
print(f'location should be -> Manchester, USA, not {self.location}')
|
||||
|
||||
if not isinstance(self.api_key, str):
|
||||
print(f'api_key should be a string, not {self.api_key}')
|
||||
|
||||
if not isinstance(self.round_temperature, bool):
|
||||
print(f'round_temperature should be a boolean, not {self.round_temperature}')
|
||||
|
||||
if not isinstance(self.round_windspeed, bool):
|
||||
print(f'round_windspeed should be a boolean, not {self.round_windspeed}')
|
||||
|
||||
if not isinstance(self.forecast_interval, int):
|
||||
print(f'forecast_interval should be a boolean, not {self.forecast_interval}')
|
||||
|
||||
if not isinstance(self.units, str):
|
||||
print(f'units should be a boolean, not {self.units}')
|
||||
|
||||
if not isinstance(self.hour_format, int):
|
||||
print(f'hour_format should be a int, not {self.hour_format}')
|
||||
|
||||
if not isinstance(self.use_beaufort, bool):
|
||||
print(f'use_beaufort should be a int, not {self.use_beaufort}')
|
||||
|
||||
|
||||
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_x))
|
||||
im_height = int(self.height - (2 * self.padding_y))
|
||||
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))
|
||||
|
||||
@ -338,6 +370,10 @@ class Weather(inkycal_module):
|
||||
|
||||
elif self.forecast_interval == 'daily':
|
||||
|
||||
###
|
||||
logger.debug("daily")
|
||||
|
||||
|
||||
def calculate_forecast(days_from_today):
|
||||
"""Get temperature range and most frequent icon code for forecast
|
||||
days_from_today should be int from 1-4: e.g. 2 -> 2 days from today
|
||||
@ -352,7 +388,6 @@ class Weather(inkycal_module):
|
||||
# Get forecasts for each time-object
|
||||
forecasts = [forecast.get_weather_at(_.datetime) for _ in time_range]
|
||||
|
||||
|
||||
# Get all temperatures for this day
|
||||
daily_temp = [round(_.get_temperature(unit=temp_unit)['temp'],
|
||||
ndigits=dec_temp) for _ in forecasts]
|
||||
@ -418,7 +453,6 @@ class Weather(inkycal_module):
|
||||
moonphase = get_moon_phase()
|
||||
|
||||
# Fill weather details in col 1 (current weather icon)
|
||||
# write(im_black, (col_width, row_height), now_str, text_now_pos, font = font)
|
||||
draw_icon(im_colour, weather_icon_pos, (icon_large, icon_large),
|
||||
weathericons[weather_icon])
|
||||
|
||||
@ -481,4 +515,4 @@ class Weather(inkycal_module):
|
||||
return im_black, im_colour
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('running {0} in standalone mode'.format(filename))
|
||||
print('running {0} in standalone mode'.format(filename))
|
@ -1,6 +1,10 @@
|
||||
import abc
|
||||
from inkycal.custom import *
|
||||
|
||||
# Set the root logger to level DEBUG to allow any inkycal module to use the
|
||||
# logger for any level
|
||||
logging.basicConfig(level = logging.DEBUG)
|
||||
|
||||
class inkycal_module(metaclass=abc.ABCMeta):
|
||||
"""Generic base class for inykcal modules"""
|
||||
|
||||
@ -10,16 +14,18 @@ class inkycal_module(metaclass=abc.ABCMeta):
|
||||
callable(subclass.generate_image) or
|
||||
NotImplemented)
|
||||
|
||||
def __init__(self, section_config):
|
||||
def __init__(self, config):
|
||||
"""Initialize module with given config"""
|
||||
|
||||
# Initializes base module
|
||||
# sets properties shared amongst all sections
|
||||
self.config = section_config
|
||||
self.width, self.height = section_config['size']
|
||||
self.config = conf = config['config']
|
||||
self.width, self.height = conf['size']
|
||||
|
||||
self.padding_left = self.padding_right = self.config["padding_x"]
|
||||
self.padding_top = self.padding_bottom = self.config["padding_y"]
|
||||
self.padding_left = self.padding_right = conf["padding_x"]
|
||||
self.padding_top = self.padding_bottom = conf['padding_y']
|
||||
|
||||
self.fontsize = self.config["fontsize"]
|
||||
self.fontsize = conf["fontsize"]
|
||||
self.font = ImageFont.truetype(
|
||||
fonts['NotoSans-SemiCondensed'], size = self.fontsize)
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Module template for Inky-Calendar Project
|
||||
|
||||
Create your own module with this template
|
||||
Developer module template for Inkycal Project
|
||||
|
||||
Copyright by aceisace
|
||||
"""
|
||||
@ -79,9 +77,6 @@ class Simple(inkycal_module):
|
||||
# Initialise this module via the inkycal_module template (required)
|
||||
super().__init__(section_size, section_config)
|
||||
|
||||
# module name (required)
|
||||
self.name = self.__class__.__name__
|
||||
|
||||
# module specific parameters (optional)
|
||||
self.do_something = True
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user