From 026b3c1da007ebe475e7aa802bc97b1ece1e4bf0 Mon Sep 17 00:00:00 2001 From: Konrad Weihmann Date: Tue, 23 Aug 2022 09:09:36 +0000 Subject: [PATCH] main: add image hashing build md5 sum over the resulting assembled image(s) and check against a stored hash file to determine if we really need to update the screen. Option can be controlled by new image_hash global option. If info_section is enabled while image_hash is on, the time of update will be stripped from the section, as it is clearly not hashable. In the end this enables us to update the information in the background way more frequent without increasing the stress caused to the display Signed-off-by: Konrad Weihmann --- inkycal/main.py | 65 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/inkycal/main.py b/inkycal/main.py index 499fb65..727c597 100644 --- a/inkycal/main.py +++ b/inkycal/main.py @@ -6,7 +6,10 @@ Main class for inkycal Project Copyright by aceisace """ +import glob +import hashlib import json +import os import traceback from logging.handlers import RotatingFileHandler @@ -168,6 +171,9 @@ class Inkycal: # Path to store images self.image_folder = image_folder + # Remove old hashes + self._remove_hashes(self.image_folder) + # Give an OK message print('loaded inkycal') @@ -235,6 +241,45 @@ class Inkycal: self._assemble() + def _image_hash(self, _in): + """Create a md5sum of a path or a bytes stream.""" + if not isinstance(_in, str): + image_bytes = _in.tobytes() + else: + try: + with open(_in) as i: + return i.read() + except FileNotFoundError: + image_bytes = None + return hashlib.md5(image_bytes).hexdigest() if image_bytes else "" + + def _remove_hashes(self, basepath): + for _file in glob.glob(f"{basepath}/*.hash"): + try: + os.remove(_file) + except: + pass + + def _write_image_hash(self, path, _in): + """Write hash to a file.""" + with open(path, "w") as o: + o.write(self._image_hash(_in)) + + def _needs_image_update(self, _list): + """Check if any image has been updated or not. + Input a list of tuples(str, image).""" + res = False + for item in _list: + _a = self._image_hash(item[0]) + _b = self._image_hash(item[1]) + print("{f1}:{h1} -> {h2}".format(f1=item[0], h1=_a, h2=_b)) + if _a != _b: + res = True + self._write_image_hash(item[0], item[1]) + print("Refresh needed: {a}".format(a=res)) + return res + + def run(self): """Runs main program in nonstop mode. @@ -264,7 +309,10 @@ class Inkycal: errors = [] # store module numbers in here # short info for info-section - self.info = f"{current_time.format('D MMM @ HH:mm')} " + if not self.settings.get('image_hash', False): + self.info = f"{current_time.format('D MMM @ HH:mm')} " + else: + self.info = "" for number in range(1, self._module_number): @@ -299,6 +347,9 @@ class Inkycal: display = self.Display self._calibration_check() + if self._calibration_state: + # after calibration we have to forcefully rewrite the screen + self._remove_hashes(self.image_folder) if self.supports_colour: im_black = Image.open(f"{self.image_folder}canvas.png") @@ -310,7 +361,12 @@ class Inkycal: im_colour = upside_down(im_colour) # render the image on the display - display.render(im_black, im_colour) + if not self.settings.get('image_hash', False) or self._needs_image_update([ + (f"{self.image_folder}/canvas.png.hash", im_black), + (f"{self.image_folder}/canvas_colour.png.hash", im_colour) + ]): + # render the image on the display + display.render(im_black, im_colour) # Part for black-white ePapers elif not self.supports_colour: @@ -321,7 +377,10 @@ class Inkycal: if self.settings['orientation'] == 180: im_black = upside_down(im_black) - display.render(im_black) + if not self.settings.get('image_hash', False) or self._needs_image_update([ + (f"{self.image_folder}/canvas.png.hash", im_black), + ]): + display.render(im_black) print(f'\nNo errors since {counter} display updates \n' f'program started {runtime.humanize()}')