small bugfixes and deployment setup
This commit is contained in:
parent
bddcb587a1
commit
1e6f248da1
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
keys.py
|
keys.py
|
||||||
*.pyc
|
*.pyc
|
||||||
.image-cache/
|
.image-cache/
|
||||||
|
test.png
|
36
deploy/deploy.playbook.yml
Normal file
36
deploy/deploy.playbook.yml
Normal file
@ -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
|
57
deploy/setup.playbook.yml
Normal file
57
deploy/setup.playbook.yml
Normal file
@ -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
|
14
deploy/templates/eink-show.service.j2
Normal file
14
deploy/templates/eink-show.service.j2
Normal file
@ -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
|
9
deploy/templates/eink-show.timer.j2
Normal file
9
deploy/templates/eink-show.timer.j2
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Run photo update regularly
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=Tue 11:00
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
0
deploy/templates/wpa_supplicant.conf.j2
Normal file
0
deploy/templates/wpa_supplicant.conf.j2
Normal file
@ -1,5 +1,6 @@
|
|||||||
from PIL import Image
|
from PIL import Image
|
||||||
import io
|
import io
|
||||||
|
import os
|
||||||
|
|
||||||
black_base = [0, 0, 0]
|
black_base = [0, 0, 0]
|
||||||
white_base = [255, 255, 255]
|
white_base = [255, 255, 255]
|
||||||
@ -41,7 +42,8 @@ class ImageShrink:
|
|||||||
image = Image.open(io.BytesIO(image))
|
image = Image.open(io.BytesIO(image))
|
||||||
image = self.shrink(image)
|
image = self.shrink(image)
|
||||||
image = self.convert_to_reduced_colors(image)
|
image = self.convert_to_reduced_colors(image)
|
||||||
# image.save("test.png")
|
if os.uname().machine == "x86_64":
|
||||||
|
image.save("test.png")
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
@ -52,5 +54,9 @@ class ImageShrink:
|
|||||||
|
|
||||||
|
|
||||||
def convert_to_reduced_colors(self, image: Image) -> Image:
|
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)
|
new_image = image.quantize(colors = len(palette), palette=ref_image, dither=True)
|
||||||
return new_image
|
return new_image
|
||||||
|
25
image_get.py
25
image_get.py
@ -14,18 +14,15 @@ class ImageGetter:
|
|||||||
headers = {
|
headers = {
|
||||||
"x-api-key": keys.immich_api_key
|
"x-api-key": keys.immich_api_key
|
||||||
}
|
}
|
||||||
|
cached_num = 10
|
||||||
def __init__(self):
|
cached_path = Path("./.image-cache/")
|
||||||
self.cached_num = 10
|
|
||||||
self.cached_path = Path("./.image-cache/")
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def get_random_image(self) -> bytearray:
|
def get_random_image(self) -> bytearray:
|
||||||
try:
|
try:
|
||||||
ids = self.get_random_image_ids(num=self.cached_num + 1)
|
id = self.get_random_image_ids()[0]
|
||||||
bytes = self.get_image_file(ids[0])
|
bytes = self.get_image_file(id)
|
||||||
self.save_cached_files(ids[1:])
|
self.save_cached_files()
|
||||||
except (h.ConnectError, h.HTTPStatusError, h.NetworkError, h.RequestError, h.DecodingError, h.TransportError, ImageGetException):
|
except (h.ConnectError, h.HTTPStatusError, h.NetworkError, h.RequestError, h.DecodingError, h.TransportError, ImageGetException):
|
||||||
print("Loading image from cache")
|
print("Loading image from cache")
|
||||||
bytes = self.load_cached_file()
|
bytes = self.load_cached_file()
|
||||||
@ -50,6 +47,7 @@ class ImageGetter:
|
|||||||
ids = []
|
ids = []
|
||||||
for i in range(num):
|
for i in range(num):
|
||||||
image = random.choice(images)
|
image = random.choice(images)
|
||||||
|
print(f"Image considered: {image['exifInfo']}")
|
||||||
ids.append(image["id"])
|
ids.append(image["id"])
|
||||||
|
|
||||||
return ids
|
return ids
|
||||||
@ -66,16 +64,21 @@ class ImageGetter:
|
|||||||
return response.content
|
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"""
|
"""Ensures self.cached_num files are at self.cached_path at any time"""
|
||||||
if not self.cached_path.exists():
|
if not self.cached_path.exists():
|
||||||
self.cached_path.mkdir()
|
self.cached_path.mkdir()
|
||||||
|
|
||||||
present_count = len(list(self.cached_path.glob("*")))
|
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}")
|
print(f"Caching image {i + 1}")
|
||||||
new_cache = self.cached_path / f"{uuid.uuid4()}"
|
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:
|
def load_cached_file(self) -> bytearray:
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
from PIL import Image, ImageDraw
|
from PIL import Image, ImageDraw
|
||||||
from waveshare-epaper import epd7in3f
|
from waveshare-epaper import epd7in3f
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# BLACK = 0x000000 # 0000 BGR
|
# BLACK = 0x000000 # 0000 BGR
|
||||||
# WHITE = 0xffffff # 0001
|
# WHITE = 0xffffff # 0001
|
||||||
# GREEN = 0x00ff00 # 0010
|
# GREEN = 0x00ff00 # 0010
|
||||||
|
Loading…
x
Reference in New Issue
Block a user