New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: dynamic modules (no location preference, no preferred position) #94
Comments
@Atrejoe I've tried implementing the requested features without any major changes on the software file, but at this point, it's more easier to refactor the code than modifying each file. |
@Atrejoe
I'll implement the features from the dev branch locally as well. Once I make some more progress, I'll post an update. |
That is not a step, that is a leap! Looking forward to give it a spin! |
@Atrejoe Thanks! It's still going to take a bit longer before it will work as expected (not too familiar with classes, packages etc.) but I'll try my best :D. |
I have reviewed some code and have some suggestions:
, but later we could migrate to a grid:
....
from abc import ABC, abstractmethod
class section(ABC):
# A base class for all Inkycal section implementations
def __init__(self, section_size, section_config):
# Initializes base section,
# sets properties shared amongst all sections
self.name = os.path.basename(__file__).split('.py')[0]
self.width, self.height = section_size
# Validate and store section-specific config
self.configure(section_config)
@abstractmethod
def configure(self,section_config):
# Implementing method should validate and store config
raise NotImplementedError
@abstractmethod
def generate_image(self):
# Implementing method should generate one or more
# images based on dimensions and configuration specified before.
raise NotImplementedError
class inkycal_rss(section):
# RSS section, showing an RSS feed
def __init__(self, section_size, section_config):
"""Initialize inkycal_rss module"""
super().__init__(self, section_size, section_config)
# Set section-specific defaults
self.background_colour = 'white'
self.font_colour = 'black'
self.fontsize = 12
self.font = ImageFont.truetype(
fonts['NotoSans-SemiCondensed'], size = self.fontsize)
self.padding_x = 0.02
self.padding_y = 0.05
print('{0} loaded'.format(self.name))
def configure(self,section_config):
self.config = section_config # todo: validation, store individual variables
def generate_image(self):
"""Generate image for this module"""
# Define new image size with respect to padding
im_width = int(self.width - (self.width * 2 * self.padding_x))
im_height = int(self.height - (self.height * 2 * self.padding_y))
im_size = im_width, im_height
.... This will probably mean that the dynamically determined Having said this, I think you are well underway towards this setup. The code looks much cleaner, testable and maintainable. |
For example purposes, I added a basic unit test: This does nothing really, but your IDE maybe will suggest running the test. |
@Atrejoe Thanks for the detailed feedback.
{
"location": "top",
"type": "inkycal_weather",
"config": {
"api_key": "topsecret",
"location": "Stuttgart, DE"
}
}, The new settings-parser parses all module-names (type) in the form of a list. The idea is that the main file (Inkycal.py) will check which modules to load by looking up this list, before passing on the config for that module for the initialisation. -> load module which requires this config.
def create_sections(self, top_section=0.10, middle_section=0.65, bottom_section=0.25):
"""Allocate fixed percentage height for top and middle section
e.g. 0.2 = 20% (Leave empty for default values)
Set top/bottom_section to 0 to allocate more space for the middle section
""" Allocates 10% to top-section, 65% to middle-section and 25% to bottom section (of total display height). Is this equivalent to setting a fixed relative (but changeable) height for each module? If the height could be set optionally for each module on the web-ui (either by percentage or px), it would be nice. Maybe we could have this approach:
Last, but not least, glad to hear you like the new code :D. It's a big jump, but hopefully, this will make things easier later on :). |
@Atrejoe OK, had a go at this. rss = inkycal_rss((400,100), {'url':'dummy_url'}) But trying to init raises this Error: Am I doing something wrong or does the code need to be adjusted? Thanks in advance :) |
regarding:
Quite strange, again, I'm a python noob, but I'd say you are giving 2 arguments; a tuple and an object. What is you were to assign these to parameters first. (should not matter I think) |
I think, for now this is a shortcoming of the Web-UI: it will just configure a three-panel layer (or with minor tweaks maybe a one-two-or-three panel layout). We cán make this a client-side application, with dynamic panel configuration too, but for now this is too much effort for a small team, we have other stuff to fix. An important reason for this is that I deem it too high of a threshold for non-dev users or day-to-day usage to have to upload a config file via ssh upon each change. This why I keep pushing for a server-side approach: the InkyCal web-service. Another possible route would be serving a configuration-website on the device itself and then generate the file on the device (you could then even implement features like user-triggered-reloading). Also this is not one of my favorites, but I can so why some people would like it. Maybe we should have call one day on this.
I think your approach does match my description. This way you could reduce the number of loaded modules ánd use the same module multiple times with different config, right? See also (5)
Yes I can add this to the web UI, as this is very little effort. I'll add an optional numeric (integer) input.
I do not have a clue how this will go in Python, but I'd be surprised if this is not possible. |
Panel height is now generated in the settings: python file: ical_urls = ['https://calendar.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics']
rss_feeds = ['http://feeds.bbci.co.uk/news/world/rss.xml#']
update_interval = "60"
api_key = ""
location = "Stuttgart, DE"
week_starts_on = "Monday"
calibration_hours = [0,12,18]
model = "epd_7_in_5_v2_colour"
language = "en"
units = "metric"
hours = "24"
top_section = "inkycal_weather"
top_section_height = None
middle_section = "inkycal_calendar"
middle_section_height = 77
bottom_section = "inkycal_rss"
bottom_section_height = 23
inkycal_image_path = "https://github.com/aceisace/Inky-Calendar/blob/master/Gallery/Inky-Calendar-logo.png?raw=true"
inkycal_image_path_body = "" json(c) file: {
"language": "en",
"units": "metric",
"hours": 24,
"model": "epd_7_in_5_v2_colour",
"update_interval": 60,
"calibration_hours": [
0,
12,
18
],
"panels": [
{
"location": "top",
"type": "inkycal_weather",
"height": null,
"config": {
"api_key": "",
"location": "Stuttgart, DE"
}
},
{
"location": "middle",
"type": "inkycal_calendar",
"height": 42,
"config": {
"week_starts_on": "Monday",
"ical_urls": [
"https://calendar.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics"
]
}
},
{
"location": "bottom",
"type": "inkycal_rss",
"height": 25,
"config": {
"rss_urls": [
"http://feeds.bbci.co.uk/news/world/rss.xml#"
]
}
}
]
} |
OK, finally went a step ahead regarding the class inheritance and module template. About this error:
I've copy-pasted the code 1:1, so not modification. After looking up this site, I found the issue: This line: After changing this, the error is no longer happening. It's going to take some more time to use this template on all other modules, but at least this is working as expected.
I like this approach more than the other options. It's easy setting up apache2 and php7 on the rpi to serve the web-ui locally. I don't know the specifics on how the web-ui can load the config from an existing settings.json file, but there are a lot of advantages with this approach.
Yes, this is correct. Inkycal_modules cannot access other modules and therefore cannot initialise themselves. The main file, Inkycal.py (ad interim) is the one that will handle initialising all other modules (specified in settings.json).
Thanks for the modifications in the web-ui. I'll work on the suggestions as soon as I'm done with the modules.
Thanks for the links. They seem to lead in the correct direction :). I'll play around with the code to see what is best suited for this task. |
@Atrejoe I'm wondering if it's at all possible to have something like a dynamic web-ui, where the web-ui shows all self.x paramters of all modules the users has chosen to be displayed. That way, the full configuration could be done within the config file and it would save a lot of work on the web-ui. But I might be thinkting too far ahead... |
It certainly is póssible to make it dynamic, but I wonder if Python would be the best choice. Usually when some something like this is to be done you would:
It is pretty critical for maintenance that this happens on the same codebase. So a python-running webserver in this case would be required. |
Argument validation in Python: |
@Atrejoe Thanks for all the info :). It seems that the way to go for this is to use django/flask in combination with the validation library. |
@Atrejoe I noted that the validation of every single class parameter will take a very long time (a lot of extra code). A lot of the other good python libraries don't validate every single argument either, but instead provide clear instructions on what the parameter requires. I'm thinking of omitting the validation (or at least postpone it for now) to speed up development. |
@Atrejoe I've merged more or less all the features from all different web-uis (manual merge). You don't need to merge them anymore. For now, the web-ui in /dev_ver2_0 also supports:
Thanks for your help so far :) |
Switched from named locations to location numbers -> 1,2,3 Fixed the issue with incorrect quotes for ical- / rss- urls
@Atrejoe Apart from the section height by percentage, ration or pixel-perfect, all other features discussed here have been implemented in release2.0.0 and BETA. |
Panel order should dynamic: panels (modules) should be told their dimensions instead of determining themselves based on figuring out their position by reading from
settings.py
.Any logic that is based on the position (where a panel should know if is it at the top, middle or bottom) is yet to be determined, if to exist at all.
This would also allow changing the number of panels (with a minimum of one of course)
The text was updated successfully, but these errors were encountered: