From f4d08c64a23c00e80e81df8158ffb1d6b65de368 Mon Sep 17 00:00:00 2001 From: Ace Date: Wed, 22 Nov 2023 12:45:07 +0100 Subject: [PATCH 1/4] test async --- inky_run.py | 6 +- inkycal/display/display.py | 22 ++-- inkycal/main.py | 221 ++++--------------------------------- 3 files changed, 33 insertions(+), 216 deletions(-) diff --git a/inky_run.py b/inky_run.py index 50cf8fac..e2fff6a5 100644 --- a/inky_run.py +++ b/inky_run.py @@ -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 diff --git a/inkycal/display/display.py b/inkycal/display/display.py index e24b355c..51652a21 100644 --- a/inkycal/display/display.py +++ b/inkycal/display/display.py @@ -4,6 +4,7 @@ """ import os import logging +import traceback from importlib import import_module from PIL import Image @@ -43,7 +44,7 @@ def __init__(self, epaper_model): 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 @@ def render(self, im_black: Image.Image, im_colour=Image.Image or None) -> None: 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,20 +82,19 @@ def render(self, im_black: Image.Image, im_colour=Image.Image or None) -> None: epaper = self._epaper - if not self.supports_colour: + if self.supports_colour: + 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.display(epaper.getbuffer(im_black), epaper.getbuffer(im_colour)) print('Done') - - elif self.supports_colour: - if not im_colour: - raise Exception('im_colour is required for coloured epaper displays') + else: print('Initialising..', end='') epaper.init() print('Updating display......', end='') - epaper.display(epaper.getbuffer(im_black), epaper.getbuffer(im_colour)) + epaper.display(epaper.getbuffer(im_black)) print('Done') print('Sending E-Paper to deep sleep...', end='') @@ -173,9 +172,10 @@ def get_display_size(cls, model_name): 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: diff --git a/inkycal/main.py b/inkycal/main.py index 08ed6c50..2b83dc83 100644 --- a/inkycal/main.py +++ b/inkycal/main.py @@ -1,6 +1,3 @@ -#!python3 -# -*- coding: utf-8 -*- - """ Main class for inkycal Project Copyright by aceinnolab @@ -9,11 +6,12 @@ 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.setLevel(logging.ERROR) - if not os.path.exists(f'{top_level}/logs'): os.mkdir(f'{top_level}/logs') @@ -37,9 +34,7 @@ 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 @@ def __init__(self, settings_path=None, render=True): 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 @@ def __init__(self, settings_path=None, render=True): # 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 @@ def countdown(self, interval_mins=None): 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 @@ def _needs_image_update(self, _list): 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 @@ def run(self): 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 @@ def run(self): 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 @@ def calibrate(self): 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 @@ def _calibration_check(self): 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') From f1bcec9074e7a90caba01ca5a46d27532490673e Mon Sep 17 00:00:00 2001 From: Ace Date: Wed, 22 Nov 2023 13:26:22 +0100 Subject: [PATCH 2/4] fix certifi --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2dbb567d..0b6c540f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ arrow==1.3.0 -certifi==2023.11.17 +certifi==2023.7.22 cycler==0.12.1 feedparser==6.0.10 fonttools==4.45.0 From 03fa62cdc20c94fd66838ca7edae6a91dabd3562 Mon Sep 17 00:00:00 2001 From: Ace Date: Wed, 22 Nov 2023 16:34:28 +0100 Subject: [PATCH 3/4] fix release not found --- inkycal/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inkycal/main.py b/inkycal/main.py index 2b83dc83..6c6f4f78 100644 --- a/inkycal/main.py +++ b/inkycal/main.py @@ -72,8 +72,8 @@ def __init__(self, settings_path:str or None=None, render:bool=True): # 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("'", "") + if line.startswith('__version__'): + self._release = line.split("=")[-1].replace("'", "").replace('"', "").replace(" ", "") break self.render = render From b44177130235d10c1f952298539c76b24fde309e Mon Sep 17 00:00:00 2001 From: Ace Date: Wed, 22 Nov 2023 16:49:55 +0100 Subject: [PATCH 4/4] format readme --- README.md | 150 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 111 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index fdb87187..d2e91fff 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Welcome to inkycal v2.0.3! +

aceinnolab logo

@@ -15,14 +16,25 @@ python

-Inkycal is a software written in python for selected E-Paper displays. It converts these displays into useful information dashboards. It's open-source, free for personal use, fully modular and user-friendly. Despite all this, Inkycal can run well even on the Raspberry Pi Zero. Oh, and it's open for third-party modules! Hooray! +Inkycal is a software written in python for selected E-Paper displays. It converts these displays into useful +information dashboards. It's open-source, free for personal use, fully modular and user-friendly. Despite all this, +Inkycal can run well even on the Raspberry Pi Zero. Oh, and it's open for third-party modules! Hooray! ## ⚠️ Warning: long installation time expected! -Starting october 2023, Raspberry Pi OS is now based on Debian bookworm and uses python 3.11 instead of 3.9 as the default version. Inkycal has been updated to work with python3.11, but the installation of numpy can take a very long time, in some cases even hours. If you do not want to wait this long to install Inkycal, you can also get a ready-to-flash version of Inkycal called InkycalOS-Lite with everything pre-installed for you by sponsoring via [Github Sponsors](https://github.com/sponsors/aceisace). This helps keep up maintenance costs, implement new features and fixing bugs. Please choose the one-time sponsor option and select the one with the plug-and-play version of Inkycal. Then, send your email-address to which InkycalOS-Lite should be sent. +Starting october 2023, Raspberry Pi OS is now based on Debian bookworm and uses python 3.11 instead of 3.9 as the +default version. Inkycal has been updated to work with python3.11, but the installation of numpy can take a very long +time, in some cases even hours. If you do not want to wait this long to install Inkycal, you can also get a +ready-to-flash version of Inkycal called InkycalOS-Lite with everything pre-installed for you by sponsoring +via [Github Sponsors](https://github.com/sponsors/aceisace). This helps keep up maintenance costs, implement new +features and fixing bugs. Please choose the one-time sponsor option and select the one with the plug-and-play version of +Inkycal. Then, send your email-address to which InkycalOS-Lite should be sent. ## Main features -Inkycal is fully modular, you can mix and match any modules you like and configure them on the web-ui. For now, these following built-in modules are supported: + +Inkycal is fully modular, you can mix and match any modules you like and configure them on the web-ui. For now, these +following built-in modules are supported: + * Calendar - Monthly Calendar with option to sync events from iCalendars, e.g. Google. * Agenda - Agenda showing upcoming events from given iCalendar URLs. * Image - Display an Image from URL or local file path. @@ -33,20 +45,32 @@ Inkycal is fully modular, you can mix and match any modules you like and configu * Todoist - Synchronise with Todoist app or website to show todos. * iCanHazDad - Display a random joke from [iCanHazDad.com](iCanhazdad.com). - ## Quickstart + Watch the one-minute video on getting started with Inkycal: [![Inkycal quickstart](https://img.youtube.com/vi/IiIv_nWE5KI/0.jpg)](https://www.youtube.com/watch?v=IiIv_nWE5KI) ## Hardware guide -Before you can start, please ensure you have one of the supported displays and of the supported Raspberry Pi: `|4|3A|3B|3B+|2B|0W|0WH|02W|`. We personally recommend the Raspberry Pi Zero W as this is relatively cheaper, uses less power and is perfect to fit in a small photo frame once you have assembled everything. -**Serial** displays are usually cheaper, but slower. Their main advantage is ease of use, like being able to communicate via SPI. A single update will cause flickering (fully normal on e-paper displays) ranging from a few seconds to half an minute. We recommend these for users who want to get started quickly and for more compact setups, e.g. fitting inside a photo frame. The resolution of these displays ranges from low to medium. Usually, these displays support 2-3 colours, but no colours in between, e.g. fully black, fully red/yellow and fully-white. +Before you can start, please ensure you have one of the supported displays and of the supported Raspberry +Pi: `|4|3A|3B|3B+|2B|0W|0WH|02W|`. We personally recommend the Raspberry Pi Zero W as this is relatively cheaper, uses +less power and is perfect to fit in a small photo frame once you have assembled everything. + +**Serial** displays are usually cheaper, but slower. Their main advantage is ease of use, like being able to communicate +via SPI. A single update will cause flickering (fully normal on e-paper displays) ranging from a few seconds to half an +minute. We recommend these for users who want to get started quickly and for more compact setups, e.g. fitting inside a +photo frame. The resolution of these displays ranges from low to medium. Usually, these displays support 2-3 colours, +but no colours in between, e.g. fully black, fully red/yellow and fully-white. -**Parallel** displays on the other hand do not understand SPI and require their own dedicated driver boards individually configured for these displays. Flickering also takes place here, but an update only takes about one to a few seconds. The resolution is much better than serial e-paper displays, but the cost is also higher. These also have 16 different grayscale levels, which does not compare to the 256 grayscales of LCDs, but far better than serial displays. +**Parallel** displays on the other hand do not understand SPI and require their own dedicated driver boards individually +configured for these displays. Flickering also takes place here, but an update only takes about one to a few seconds. +The resolution is much better than serial e-paper displays, but the cost is also higher. These also have 16 different +grayscale levels, which does not compare to the 256 grayscales of LCDs, but far better than serial displays. -**❗️Important note: e-paper displays cannot be simply connected to the Raspberry Pi, but require a driver board. The links below may or may not contain the required driver board. Please ensure you get the correct driver board for the display!** +**❗️Important note: e-paper displays cannot be simply connected to the Raspberry Pi, but require a driver board. The +links below may or may not contain the required driver board. Please ensure you get the correct driver board for the +display!** | type | vendor | affiliate links to product | |-------------------------------------------|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -64,28 +88,36 @@ Before you can start, please ensure you have one of the supported displays and o | Raspberry Pi Zero W | Raspberry Pi |  Raspberry Pi Zero W | | MicroSD card | Sandisk |  MicroSD card (8GB) | - ## Configuring the Raspberry Pi -Flash Raspberry Pi OS on your microSD card (min. 4GB) with [Raspberry Pi Imager](https://rptl.io/imager). Use the following settings: - -| option |  value | -|:---------------------------|:----------------------------:| -|  hostname |  inkycal | -|  enable ssh |  yes | -|  set username and password |  yes | -|  username |  a username you like | -|  password |  a password you can remember | -|  set Wi-Fi |  yes | -|  Wi-Fi SSID |  your Wi-Fi name | -|  Wi-Fi password |  your Wi-Fi password | - - -1. Create and download `settings.json` file for Inkycal from the [WEB-UI](https://aceisace.eu.pythonanywhere.com/inkycal-config-v2-0-0). Add the modules you want with the add module button. -2. Copy the `settings.json` to the flashed microSD card in the `/boot` folder of microSD card. On Windows, this is the only visible directory on the SD card. On Linux, copy these files to `/boot` of the microSD card. + +Flash Raspberry Pi OS on your microSD card (min. 4GB) with [Raspberry Pi Imager](https://rptl.io/imager). Use the +following settings: + +| option | value | +|:--------------------------|:---------------------------:| +| hostname | inkycal | +| enable ssh | yes | +| set username and password | yes | +| username | a username you like | +| password | a password you can remember | +| set Wi-Fi | yes | +| Wi-Fi SSID | your Wi-Fi name | +| Wi-Fi password | your Wi-Fi password | +| set timezone | your local timezone | + +1. Create and download `settings.json` file for Inkycal from + the [WEB-UI](https://aceisace.eu.pythonanywhere.com/inkycal-config-v2-0-0). Add the modules you want with the add + module button. +2. Copy the `settings.json` to the flashed microSD card in the `/boot` folder of microSD card. On Windows, this is the + only visible directory on the SD card. On Linux, copy these files to `/boot` of the microSD card. 3. Eject the microSD card from your computer now, insert it in the Raspberry Pi and power the Raspberry Pi. -4. Once the green LED has stopped blinking after ~3 minutes, you can connect to your Raspberry Pi via SSH using a SSH Client. We suggest [Termius](https://termius.com/download/windows) -on your smartphone. Use the address: `inkycal.local` with the username and password you set earlier. For more detailed instructions, check out the page from the [Raspberry Pi website](https://www.raspberrypi.org/documentation/remote-access/ssh/) +4. Once the green LED has stopped blinking after ~3 minutes, you can connect to your Raspberry Pi via SSH using a SSH + Client. We suggest [Termius](https://termius.com/download/windows) + on your smartphone. Use the address: `inkycal.local` with the username and password you set earlier. For more + detailed instructions, check out the page from + the [Raspberry Pi website](https://www.raspberrypi.org/documentation/remote-access/ssh/) 5. After connecting via SSH, run the following commands, line by line: + ```bash sudo raspi-config --expand-rootfs sudo sed -i s/#dtparam=spi=on/dtparam=spi=on/ /boot/config.txt @@ -105,17 +137,32 @@ sudo sed -i -E '/^CONF_SWAPSIZE=/s/=.*/=256/' /etc/dphys-swapfile sudo dphys-swapfile setup sudo dphys-swapfile swapon ``` -These commands expand the filesystem, enable SPI and set up the correct timezone on the Raspberry Pi. When running the last command, please select the continent you live in, press enter and then select the capital of the country you live in. Lastly, press enter. + +These commands expand the filesystem, enable SPI and set up the correct timezone on the Raspberry Pi. When running the +last command, please select the continent you live in, press enter and then select the capital of the country you live +in. Lastly, press enter. + 7. Follow the steps in `Installation` (see below) on how to install Inkycal. ## Installing Inkycal -⚠️ Please note that although the developers try to keep the installation as simple as possible, the full installation can sometimes take hours on the Raspberry Pi Zero W and is not guaranteed to go smoothly each time. This is because installing dependencies on the zero w takes a long time and is prone to copy-paste-, permission- and configuration errors. -ℹ️ **Looking for a shortcut to safe a few hours?** We know about this problem and have spent a signifcant amount of time to prepare a pre-configured image with the latest version of Inkycal for the Raspberry Pi Zero. It comes with the latest version of Inkycal, is fully tested and uses the Raspberry Pi OS Lite as it's base image. You only need to copy your settings.json file, we already took care of the rest, including auto-start at boot, enabling spi and installing all dependencies in advance. Pretty neat right? Check the [sponsor button](https://github.com/sponsors/aceisace) at the very top of the repo to get access to Inkycal-OS-Lite. This will help keep this project growing and cover the ongoing expenses too! Win-win for everyone! 🎊 +⚠️ Please note that although the developers try to keep the installation as simple as possible, the full installation +can sometimes take hours on the Raspberry Pi Zero W and is not guaranteed to go smoothly each time. This is because +installing dependencies on the zero w takes a long time and is prone to copy-paste-, permission- and configuration +errors. +ℹ️ **Looking for a shortcut to safe a few hours?** We know about this problem and have spent a signifcant amount of time +to prepare a pre-configured image with the latest version of Inkycal for the Raspberry Pi Zero. It comes with the latest +version of Inkycal, is fully tested and uses the Raspberry Pi OS Lite as it's base image. You only need to copy your +settings.json file, we already took care of the rest, including auto-start at boot, enabling spi and installing all +dependencies in advance. Pretty neat right? Check the [sponsor button](https://github.com/sponsors/aceisace) at the very +top of the repo to get access to Inkycal-OS-Lite. This will help keep this project growing and cover the ongoing +expenses too! Win-win for everyone! 🎊 ### Manual installation + Run the following steps to install Inkycal. Do **not** use sudo for this, except where explicitly specified. + ```bash # the next line is for the Raspberry Pi only sudo apt-get install zlib1g libjpeg-dev libatlas-base-dev rustc libopenjp2-7 python3-dev scons libssl-dev python3-venv python3-pip git libfreetype6-dev wkhtmltopdf @@ -133,7 +180,9 @@ pip install RPi.GPIO==0.7.1 spidev==3.5 ``` ## Running Inkycal + To run Inkycal, type in the following command in the terminal: + ```bash cd $HOME/Inkycal source venv/bin/activate @@ -141,18 +190,23 @@ python3 inky_run.py ``` ## Running on each boot + To make inkycal run on each boot automatically, you can use crontab. Do not use sudo for this + ```bash (crontab -l ; echo "@reboot sleep 60 && cd $HOME/Inkycal && venv/bin/python inky_run.py &")| crontab - ``` ## Updating Inkycal + To update Inkycal to the latest version, navigate to the Inkycal folder, then run: + ```bash git pull ``` + Yep. It's actually that simple! -But, if you have made changes to Inkycal, those will be overwritten. +But, if you have made changes to Inkycal, those will be overwritten. If that is the case, backup your modified files somewhere else if you need them. Then run: ```bash @@ -161,51 +215,69 @@ git pull ``` ## Uninstalling Inkycal + We'll miss you, but we don't want to make it hard for you to leave. Just delete the Inkycal folder, and you're good to go! Additionally, if you want to reset your crontab file, which runs inkycal at boot, run: + ```bash crontab -r ``` ## Modifying Inkycal -Inkycal now runs in a virtual environment to support more devices than just the Raspberry Pi. Therefore, to make changes to Inkycal, navigate to Inkycal, then run: + +Inkycal now runs in a virtual environment to support more devices than just the Raspberry Pi. Therefore, to make changes +to Inkycal, navigate to Inkycal, then run: + ```bash cd $HOME/Inkycal && source venv/bin/activate ``` + Then modify the files as needed and experiment with Inkycal. To deactivate the virtual environment, simply run: + ```bash deactivate ``` ## 3D printed frames -With your setup being complete at this stage, you may want to 3d-print a case. The following files were shared by our friendly community: + +With your setup being complete at this stage, you may want to 3d-print a case. The following files were shared by our +friendly community: [3D-printable case](https://github.com/aceinnolab/Inkycal/wiki/3D-printable-files) ## Contributing -All sorts of contributions are most welcome and appreciated. To start contributing, please follow the [Contribution Guidelines](https://github.com/aceisace/Inkycal/blob/main/.github/CONTRIBUTING.md) -The average response time for issues, PRs and emails is usually 24 hours. In some cases, it might be longer. If you want to have some faster responses, please use Discord (link below) +All sorts of contributions are most welcome and appreciated. To start contributing, please follow +the [Contribution Guidelines](https://github.com/aceisace/Inkycal/blob/main/.github/CONTRIBUTING.md) +The average response time for issues, PRs and emails is usually 24 hours. In some cases, it might be longer. If you want +to have some faster responses, please use Discord (link below) **P.S:** Don't forget to star and/or watch the repo. For those who have done so already, thank you very much! ## Join us on Discord! -We're happy to help, to beginners and developers alike. In fact, you are more likely to get faster support on Discord than on Github. + +We're happy to help, to beginners and developers alike. In fact, you are more likely to get faster support on Discord +than on Github. Inkycal chatroom Discord ## Sponsoring -Inkycal relies on sponsors to keep up maintainance, development and bug-fixing. Please consider sponsoring Inkycal via the sponsor button if you are happy with Inkycal. -We now offer perks depending on the amount contributed for sponsoring, ranging from pre-configured OS images for plug-and-play to development of user-suggested modules. Check out the sponsor page to find out more. -If you have been a previous sponsor, please let us know on our Dicord server or by sending an email. We'll send you the perks after confirming 💯 +Inkycal relies on sponsors to keep up maintainance, development and bug-fixing. Please consider sponsoring Inkycal via +the sponsor button if you are happy with Inkycal. + +We now offer perks depending on the amount contributed for sponsoring, ranging from pre-configured OS images for +plug-and-play to development of user-suggested modules. Check out the sponsor page to find out more. +If you have been a previous sponsor, please let us know on our Dicord server or by sending an email. We'll send you the +perks after confirming 💯 ## As featured on + * [makeuseof - fantastic projects using an eink display](http://makeuseof.com/fantastic-projects-using-an-e-ink-display/) * [magpi.de](https://www.magpi.de/news/maginkcal-ein-kalender-mit-epaper-display-und-raspberry-pi) * [reddit - Inkycal](https://www.reddit.com/r/InkyCal/)