test async
This commit is contained in:
parent
dae4ce31b2
commit
f4d08c64a2
@ -1,7 +1,7 @@
|
||||
#!python3
|
||||
from inkycal import Inkycal # Import Inkycal
|
||||
import asyncio
|
||||
from inkycal import Inkycal
|
||||
|
||||
inky = Inkycal(render=True) # Initialise Inkycal
|
||||
# If your settings.json file is not in /boot, use the full path: inky = Inkycal('path/to/settings.json', render=True)
|
||||
inky.test() # test if Inkycal can be run correctly, running this will show a bit of info for each module
|
||||
inky.run() # If there were no issues, you can run Inkycal nonstop
|
||||
asyncio.run(inky.run()) # If there were no issues, you can run Inkycal nonstop
|
||||
|
@ -4,6 +4,7 @@ Copyright by aceisace
|
||||
"""
|
||||
import os
|
||||
import logging
|
||||
import traceback
|
||||
from importlib import import_module
|
||||
from PIL import Image
|
||||
|
||||
@ -43,7 +44,7 @@ class Display:
|
||||
except FileNotFoundError:
|
||||
raise Exception('SPI could not be found. Please check if SPI is enabled')
|
||||
|
||||
def render(self, im_black: Image.Image, im_colour=Image.Image or None) -> None:
|
||||
def render(self, im_black: Image, im_colour=Image or None) -> None:
|
||||
"""Renders an image on the selected E-Paper display.
|
||||
|
||||
Initlializes the E-Paper display, sends image data and executes command
|
||||
@ -66,7 +67,6 @@ class Display:
|
||||
|
||||
|
||||
Rendering black-white on coloured E-Paper displays:
|
||||
|
||||
>>> sample_image = Image.open('path/to/file.png')
|
||||
>>> display = Display('my_coloured_display')
|
||||
>>> display.render(sample_image, sample_image)
|
||||
@ -82,14 +82,7 @@ class Display:
|
||||
|
||||
epaper = self._epaper
|
||||
|
||||
if not self.supports_colour:
|
||||
print('Initialising..', end='')
|
||||
epaper.init()
|
||||
print('Updating display......', end='')
|
||||
epaper.display(epaper.getbuffer(im_black))
|
||||
print('Done')
|
||||
|
||||
elif self.supports_colour:
|
||||
if self.supports_colour:
|
||||
if not im_colour:
|
||||
raise Exception('im_colour is required for coloured epaper displays')
|
||||
print('Initialising..', end='')
|
||||
@ -97,6 +90,12 @@ class Display:
|
||||
print('Updating display......', end='')
|
||||
epaper.display(epaper.getbuffer(im_black), epaper.getbuffer(im_colour))
|
||||
print('Done')
|
||||
else:
|
||||
print('Initialising..', end='')
|
||||
epaper.init()
|
||||
print('Updating display......', end='')
|
||||
epaper.display(epaper.getbuffer(im_black))
|
||||
print('Done')
|
||||
|
||||
print('Sending E-Paper to deep sleep...', end='')
|
||||
epaper.sleep()
|
||||
@ -173,9 +172,10 @@ class Display:
|
||||
try:
|
||||
driver = import_driver(model_name)
|
||||
return driver.EPD_WIDTH, driver.EPD_HEIGHT
|
||||
except Exception as e:
|
||||
except:
|
||||
logging.error(f'Failed to load driver for ${model_name}. Check spelling?')
|
||||
raise e;
|
||||
print(traceback.format_exc())
|
||||
raise AssertionError("Could not import driver")
|
||||
|
||||
@classmethod
|
||||
def get_display_names(cls) -> list:
|
||||
|
221
inkycal/main.py
221
inkycal/main.py
@ -1,6 +1,3 @@
|
||||
#!python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Main class for inkycal Project
|
||||
Copyright by aceinnolab
|
||||
@ -9,11 +6,12 @@ Copyright by aceinnolab
|
||||
import glob
|
||||
import hashlib
|
||||
import json
|
||||
import traceback
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
import arrow
|
||||
import numpy
|
||||
import asyncio
|
||||
|
||||
|
||||
from inkycal.custom import *
|
||||
from inkycal.display import Display
|
||||
@ -27,7 +25,6 @@ stream_handler = logging.StreamHandler()
|
||||
stream_handler.setLevel(logging.ERROR)
|
||||
|
||||
|
||||
|
||||
if not os.path.exists(f'{top_level}/logs'):
|
||||
os.mkdir(f'{top_level}/logs')
|
||||
|
||||
@ -37,9 +34,7 @@ logging.basicConfig(
|
||||
format='%(asctime)s | %(name)s | %(levelname)s: %(message)s',
|
||||
datefmt='%d-%m-%Y %H:%M:%S',
|
||||
handlers=[
|
||||
|
||||
stream_handler, # add stream handler from above
|
||||
|
||||
RotatingFileHandler( # log to a file too
|
||||
f'{top_level}/logs/inkycal.log', # file to log
|
||||
maxBytes=2097152, # 2MB max filesize
|
||||
@ -71,15 +66,18 @@ class Inkycal:
|
||||
to improve rendering on E-Papers. Set this to False for 9.7" E-Paper.
|
||||
"""
|
||||
|
||||
def __init__(self, settings_path=None, render=True):
|
||||
def __init__(self, settings_path:str or None=None, render:bool=True):
|
||||
"""Initialise Inkycal"""
|
||||
|
||||
self._release = '2.0.3'
|
||||
# Get the release version from setup.py
|
||||
with open(f'{top_level}/setup.py') as setup_file:
|
||||
for line in setup_file:
|
||||
if line.startswith('VERSION'):
|
||||
self._release = line.split('=')[1].strip().replace("'", "")
|
||||
break
|
||||
|
||||
# Check if render was set correctly
|
||||
if render not in [True, False]:
|
||||
raise Exception(f'render must be True or False, not "{render}"')
|
||||
self.render = render
|
||||
self.info = None
|
||||
|
||||
# load settings file - throw an error if file could not be found
|
||||
if settings_path:
|
||||
@ -89,7 +87,7 @@ class Inkycal:
|
||||
self.settings = settings
|
||||
|
||||
except FileNotFoundError:
|
||||
raise SettingsFileNotFoundError
|
||||
raise FileNotFoundError(f"No settings.json file could be found in the specified location: {settings_path}")
|
||||
|
||||
else:
|
||||
try:
|
||||
@ -121,7 +119,7 @@ class Inkycal:
|
||||
# init calibration state
|
||||
self._calibration_state = False
|
||||
|
||||
# Load and intialize modules specified in the settings file
|
||||
# Load and initialise modules specified in the settings file
|
||||
self._module_number = 1
|
||||
for module in settings['modules']:
|
||||
module_name = module['name']
|
||||
@ -168,10 +166,10 @@ class Inkycal:
|
||||
update_timings = [(60 - int(interval_mins) * updates) for updates in
|
||||
range(60 // int(interval_mins))][::-1]
|
||||
|
||||
# Calculate time in mins until next update
|
||||
# Calculate time in minutes until next update
|
||||
minutes = [_ for _ in update_timings if _ >= now.minute][0] - now.minute
|
||||
|
||||
# Print the remaining time in mins until next update
|
||||
# Print the remaining time in minutes until next update
|
||||
print(f'{minutes} minutes left until next refresh')
|
||||
|
||||
# Calculate time in seconds until next update
|
||||
@ -259,12 +257,12 @@ class Inkycal:
|
||||
return res
|
||||
|
||||
|
||||
def run(self):
|
||||
async def run(self):
|
||||
"""Runs main program in nonstop mode.
|
||||
|
||||
Uses an infinity loop to run Inkycal nonstop. Inkycal generates the image
|
||||
from all modules, assembles them in one image, refreshed the E-Paper and
|
||||
then sleeps until the next sheduled update.
|
||||
then sleeps until the next scheduled update.
|
||||
"""
|
||||
|
||||
# Get the time of initial run
|
||||
@ -327,7 +325,7 @@ class Inkycal:
|
||||
|
||||
self._calibration_check()
|
||||
if self._calibration_state:
|
||||
# after calibration we have to forcefully rewrite the screen
|
||||
# after calibration, we have to forcefully rewrite the screen
|
||||
self._remove_hashes(self.image_folder)
|
||||
|
||||
if self.supports_colour:
|
||||
@ -365,7 +363,7 @@ class Inkycal:
|
||||
f'program started {runtime.humanize()}')
|
||||
|
||||
sleep_time = self.countdown()
|
||||
time.sleep(sleep_time)
|
||||
await asyncio.sleep(sleep_time)
|
||||
|
||||
@staticmethod
|
||||
def _merge_bands():
|
||||
@ -536,7 +534,7 @@ class Inkycal:
|
||||
self.Display.calibrate()
|
||||
|
||||
def _calibration_check(self):
|
||||
"""Calibration sheduler
|
||||
"""Calibration scheduler
|
||||
uses calibration hours from settings file to check if calibration is due"""
|
||||
now = arrow.now()
|
||||
# print('hour:', now.hour, 'hours:', self._calibration_hours)
|
||||
@ -547,187 +545,6 @@ class Inkycal:
|
||||
else:
|
||||
self._calibration_state = False
|
||||
|
||||
@classmethod
|
||||
def add_module(cls, filepath):
|
||||
"""registers a third party module for inkycal.
|
||||
|
||||
Uses the full filepath of the third party module to check if it is inside
|
||||
the correct folder, then checks if it's an inkycal module. Lastly, the
|
||||
init files in /inkycal and /inkycal/modules are updated to allow using
|
||||
the new module.
|
||||
|
||||
Args:
|
||||
- filepath: The full filepath of the third party module. Modules should be
|
||||
in Inkycal/inkycal/modules.
|
||||
|
||||
Usage:
|
||||
- download a third-party module. The exact link is provided by the
|
||||
developer of that module and starts with
|
||||
`https://raw.githubusercontent.com/...`
|
||||
|
||||
enter the following in bash to download a module::
|
||||
|
||||
$ cd Inkycal/inkycal/modules #navigate to modules folder in inkycal
|
||||
$ wget https://raw.githubusercontent.com/... #download the module
|
||||
|
||||
then register it with this function::
|
||||
|
||||
>>> from inkycal import Inkycal
|
||||
>>> Inkycal.add_module('/full/path/to/the/module/in/inkycal/modules.py')
|
||||
"""
|
||||
|
||||
module_folder = top_level + '/inkycal/modules'
|
||||
|
||||
if module_folder in filepath:
|
||||
filename = filepath.split('.py')[0].split('/')[-1]
|
||||
|
||||
# Extract name of class from given module and validate if it's an inkycal
|
||||
# module
|
||||
with open(filepath, mode='r') as module:
|
||||
module_content = module.read().splitlines()
|
||||
|
||||
for line in module_content:
|
||||
if '(inkycal_module):' in line:
|
||||
classname = line.split(' ')[-1].split('(')[0]
|
||||
break
|
||||
|
||||
if not classname:
|
||||
raise TypeError("your module doesn't seem to be a correct inkycal module.."
|
||||
"Please check your module again.")
|
||||
|
||||
# Check if filename or classname exists in init of module folder
|
||||
with open(module_folder + '/__init__.py', mode='r') as file:
|
||||
module_init = file.read().splitlines()
|
||||
|
||||
print('checking module init file..')
|
||||
for line in module_init:
|
||||
if filename in line:
|
||||
raise Exception(
|
||||
"A module with this filename already exists! \n"
|
||||
"Please consider renaming your module and try again."
|
||||
)
|
||||
if classname in line:
|
||||
raise Exception(
|
||||
"A module with this classname already exists! \n"
|
||||
"Please consider renaming your class and try again."
|
||||
)
|
||||
print('OK!')
|
||||
|
||||
# Check if filename or classname exists in init of inkycal folder
|
||||
with open(top_level + '/inkycal/__init__.py', mode='r') as file:
|
||||
inkycal_init = file.read().splitlines()
|
||||
|
||||
print('checking inkycal init file..')
|
||||
for line in inkycal_init:
|
||||
if filename in line:
|
||||
raise Exception(
|
||||
"A module with this filename already exists! \n"
|
||||
"Please consider renaming your module and try again."
|
||||
)
|
||||
if classname in line:
|
||||
raise Exception(
|
||||
"A module with this classname already exists! \n"
|
||||
"Please consider renaming your class and try again."
|
||||
)
|
||||
print('OK')
|
||||
|
||||
# If all checks have passed, add the module in the module init file
|
||||
with open(module_folder + '/__init__.py', mode='a') as file:
|
||||
file.write(f'from .{filename} import {classname} # Added by module adder')
|
||||
|
||||
# If all checks have passed, add the module in the inkycal init file
|
||||
with open(top_level + '/inkycal/__init__.py', mode='a') as file:
|
||||
file.write(f'import inkycal.modules.{filename} # Added by module adder')
|
||||
|
||||
print(f"Your module '{filename}' with class '{classname}' has been added "
|
||||
"successfully! Hooray!")
|
||||
return
|
||||
|
||||
# Check if module is inside the modules folder
|
||||
raise Exception(f"Your module should be in {module_folder} "
|
||||
f"but is currently in {filepath}")
|
||||
|
||||
@classmethod
|
||||
def remove_module(cls, filename, remove_file=True):
|
||||
"""unregisters an inkycal module.
|
||||
|
||||
Looks for given filename.py in /modules folder, removes entries of that
|
||||
module in init files inside /inkycal and /inkycal/modules
|
||||
|
||||
Args:
|
||||
- filename: The filename (with .py ending) of the module which should be
|
||||
unregistered. e.g. `'mymodule.py'`
|
||||
- remove_file: ->bool (True/False). If set to True, the module is deleted
|
||||
after unregistering it, else it remains in the /modules folder
|
||||
|
||||
|
||||
Usage:
|
||||
- Look for the module in Inkycal/inkycal/modules which should be removed.
|
||||
Only the filename (with .py) is required, not the full path.
|
||||
|
||||
Use this function to unregister the module from inkycal::
|
||||
|
||||
>>> from inkycal import Inkycal
|
||||
>>> Inkycal.remove_module('mymodule.py')
|
||||
"""
|
||||
|
||||
module_folder = top_level + '/inkycal/modules'
|
||||
|
||||
# Check if module is inside the modules folder and extract classname
|
||||
try:
|
||||
with open(f"{module_folder}/{filename}", mode='r') as file:
|
||||
module_content = file.read().splitlines()
|
||||
|
||||
for line in module_content:
|
||||
if '(inkycal_module):' in line:
|
||||
classname = line.split(' ')[-1].split('(')[0]
|
||||
break
|
||||
|
||||
if not classname:
|
||||
print('The module you are trying to remove is not an inkycal module.. '
|
||||
'Not removing it.')
|
||||
return
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"No module named {filename} found in {module_folder}")
|
||||
return
|
||||
|
||||
filename = filename.split('.py')[0]
|
||||
|
||||
# Create a memory backup of /modules init file
|
||||
with open(module_folder + '/__init__.py', mode='r') as file:
|
||||
module_init = file.read().splitlines()
|
||||
|
||||
print('removing line from module_init')
|
||||
# Remove lines that contain classname
|
||||
with open(module_folder + '/__init__.py', mode='w') as file:
|
||||
for line in module_init:
|
||||
if not classname in line:
|
||||
file.write(line + '\n')
|
||||
else:
|
||||
print('found, removing')
|
||||
|
||||
# Create a memory backup of inkycal init file
|
||||
with open(f"{top_level}/inkycal/__init__.py", mode='r') as file:
|
||||
inkycal_init = file.read().splitlines()
|
||||
|
||||
print('removing line from inkycal init')
|
||||
# Remove lines that contain classname
|
||||
with open(f"{top_level}/inkycal/__init__.py", mode='w') as file:
|
||||
for line in inkycal_init:
|
||||
if filename in line:
|
||||
print('found, removing')
|
||||
else:
|
||||
file.write(line + '\n')
|
||||
|
||||
# remove the file of the third party module if it exists and remove_file
|
||||
# was set to True (default)
|
||||
if os.path.exists(f"{module_folder}/{filename}.py") and remove_file is True:
|
||||
print('deleting module file')
|
||||
os.remove(f"{module_folder}/{filename}.py")
|
||||
|
||||
print(f"Your module '{filename}' with class '{classname}' was removed.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(f'running inkycal main in standalone/debug mode')
|
||||
|
Loading…
Reference in New Issue
Block a user