From 1e6f248da1a76874f09de3dda1624398383dc1f6 Mon Sep 17 00:00:00 2001 From: Remy Moll Date: Tue, 24 Oct 2023 21:57:05 +0200 Subject: [PATCH] small bugfixes and deployment setup --- .gitignore | 3 +- deploy/deploy.playbook.yml | 36 ++++++++++++++++ deploy/setup.playbook.yml | 57 +++++++++++++++++++++++++ deploy/templates/eink-show.service.j2 | 14 ++++++ deploy/templates/eink-show.timer.j2 | 9 ++++ deploy/templates/wpa_supplicant.conf.j2 | 0 image_convert.py | 8 +++- image_get.py | 25 ++++++----- image_show.py | 2 - 9 files changed, 139 insertions(+), 15 deletions(-) create mode 100644 deploy/deploy.playbook.yml create mode 100644 deploy/setup.playbook.yml create mode 100644 deploy/templates/eink-show.service.j2 create mode 100644 deploy/templates/eink-show.timer.j2 create mode 100644 deploy/templates/wpa_supplicant.conf.j2 diff --git a/.gitignore b/.gitignore index fce20ab..036203b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ keys.py *.pyc -.image-cache/ \ No newline at end of file +.image-cache/ +test.png \ No newline at end of file diff --git a/deploy/deploy.playbook.yml b/deploy/deploy.playbook.yml new file mode 100644 index 0000000..2e47f20 --- /dev/null +++ b/deploy/deploy.playbook.yml @@ -0,0 +1,36 @@ +- name: Basic setup tasks for Raspberry Pi + hosts: raspberrypi + become: true + vars: + code_dest: /home/pi/eink + service_target_dir: /etc/systemd/system/ + + tasks: + - name: Pull the latest version of the code + git: + repo: https://git.kluster.moll.re/remoll/eink.git + dest: "{{ code_dest }}" + version: main + + - name: Install from the pipenv-file + command: "pipenv install --system --deploy" + args: + chdir: "{{ code_dest }}" + + - name: Copy unit files + template: + src: ./templates/{{ item }}.j2 + dest: "{{ service_target_dir }}/{{ item }}" + loop: + - eink-show.service + - eink-show.timer + + - name: Enable units + systemd: + daemon_reload: yes + name: "{{ item }}" + state: started + enabled: yes + loop: + - eink-show.service + - eink-show.timer \ No newline at end of file diff --git a/deploy/setup.playbook.yml b/deploy/setup.playbook.yml new file mode 100644 index 0000000..29c389d --- /dev/null +++ b/deploy/setup.playbook.yml @@ -0,0 +1,57 @@ +- name: Basic setup tasks for Raspberry Pi + hosts: raspberrypi + become: true + + tasks: + - name: Add local ssh key + ansible.posix.authorized_key: + user: "{{ ansible_user }}" + state: present + # copy file present on the controller to the remote host + # https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html + key: "{{ lookup('file', '~/.ssh/default.pub') }}" + + - name: apt update all packages + apt: + update_cache: yes + upgrade: yes + + - name: Install required packages + apt: + name: + - git + - python3-pipenv + - python3-dev + - python3-setuptools + - python3-rpi.gpio + - python3-spidev + state: present + + - name: Enable SPI and I2C interfaces + lineinfile: + path: /boot/config.txt + regexp: "^#?(dtparam=i2c_arm|dtparam=spi)" + line: "{{ item }}" + state: present + with_items: + - "dtparam=i2c_arm=on" + - "dtparam=spi=on" + + - name: Reboot the Raspberry Pi + reboot: + delay: 5 + connect_timeout: 20 + reboot_timeout: 300 + + - name: Wait for the Raspberry Pi to reboot + wait_for_connection: + delay: 5 + timeout: 300 + + - name: Add wifi networks from secrets + template: + src: templates/wpa_supplicant.conf.j2 + dest: /etc/wpa_supplicant/wpa_supplicant.conf + owner: root + group: root + mode: 0600 diff --git a/deploy/templates/eink-show.service.j2 b/deploy/templates/eink-show.service.j2 new file mode 100644 index 0000000..6f11dff --- /dev/null +++ b/deploy/templates/eink-show.service.j2 @@ -0,0 +1,14 @@ +[Unit] +Description=Show new photo onto the eink display + +[Service] +Type=oneshot + +WorkingDirectory={{ code_dest }} +#EnvironmentFile={{ service_config_dir }}/restic.env + +ExecStart=python main.py + + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/deploy/templates/eink-show.timer.j2 b/deploy/templates/eink-show.timer.j2 new file mode 100644 index 0000000..5909751 --- /dev/null +++ b/deploy/templates/eink-show.timer.j2 @@ -0,0 +1,9 @@ +[Unit] +Description=Run photo update regularly + +[Timer] +OnCalendar=Tue 11:00 +Persistent=true + +[Install] +WantedBy=timers.target \ No newline at end of file diff --git a/deploy/templates/wpa_supplicant.conf.j2 b/deploy/templates/wpa_supplicant.conf.j2 new file mode 100644 index 0000000..e69de29 diff --git a/image_convert.py b/image_convert.py index 079214b..3f9c8b1 100644 --- a/image_convert.py +++ b/image_convert.py @@ -1,5 +1,6 @@ from PIL import Image import io +import os black_base = [0, 0, 0] white_base = [255, 255, 255] @@ -41,7 +42,8 @@ class ImageShrink: image = Image.open(io.BytesIO(image)) image = self.shrink(image) image = self.convert_to_reduced_colors(image) - # image.save("test.png") + if os.uname().machine == "x86_64": + image.save("test.png") return image @@ -52,5 +54,9 @@ class ImageShrink: def convert_to_reduced_colors(self, image: Image) -> Image: + # convert image to RGB if it's not first + if image.mode != "RGB": + print("Converting image to RGB") + image = image.convert("RGB") new_image = image.quantize(colors = len(palette), palette=ref_image, dither=True) return new_image diff --git a/image_get.py b/image_get.py index ac1cc4c..9a6e886 100644 --- a/image_get.py +++ b/image_get.py @@ -14,18 +14,15 @@ class ImageGetter: headers = { "x-api-key": keys.immich_api_key } - - def __init__(self): - self.cached_num = 10 - self.cached_path = Path("./.image-cache/") - pass + cached_num = 10 + cached_path = Path("./.image-cache/") def get_random_image(self) -> bytearray: try: - ids = self.get_random_image_ids(num=self.cached_num + 1) - bytes = self.get_image_file(ids[0]) - self.save_cached_files(ids[1:]) + id = self.get_random_image_ids()[0] + bytes = self.get_image_file(id) + self.save_cached_files() except (h.ConnectError, h.HTTPStatusError, h.NetworkError, h.RequestError, h.DecodingError, h.TransportError, ImageGetException): print("Loading image from cache") bytes = self.load_cached_file() @@ -50,6 +47,7 @@ class ImageGetter: ids = [] for i in range(num): image = random.choice(images) + print(f"Image considered: {image['exifInfo']}") ids.append(image["id"]) return ids @@ -66,16 +64,21 @@ class ImageGetter: return response.content - def save_cached_files(self, image_ids: list[str]) -> None: + def save_cached_files(self) -> None: """Ensures self.cached_num files are at self.cached_path at any time""" if not self.cached_path.exists(): self.cached_path.mkdir() present_count = len(list(self.cached_path.glob("*"))) - for i in range(self.cached_num - present_count): + missing = self.cached_num - present_count + if missing == 0: + return + + ids = self.get_random_image_ids(missing) + for i, id in enumerate(ids): print(f"Caching image {i + 1}") new_cache = self.cached_path / f"{uuid.uuid4()}" - new_cache.write_bytes(self.get_image_file(image_ids[i])) + new_cache.write_bytes(self.get_image_file(id)) def load_cached_file(self) -> bytearray: diff --git a/image_show.py b/image_show.py index a471ff5..db9ef28 100644 --- a/image_show.py +++ b/image_show.py @@ -1,8 +1,6 @@ from PIL import Image, ImageDraw from waveshare-epaper import epd7in3f - - # BLACK = 0x000000 # 0000 BGR # WHITE = 0xffffff # 0001 # GREEN = 0x00ff00 # 0010