From a5bf821186fbf8a9e0550a30980cc920b6c864c7 Mon Sep 17 00:00:00 2001 From: shibao Date: Sun, 20 Jul 2025 18:28:26 +0000 Subject: [PATCH] fix docker implementation --- .dockerignore | 11 +++++-- .env.sample | 6 ---- .gitignore | 5 ++- Dockerfile | 31 ++++-------------- README.md | 37 ++++++++++----------- cron_job.sh | 4 --- crontab | 2 +- docker-compose.yml | 2 -- entrypoint.sh | 4 +++ pyproject.toml | 1 - szuru-eink.py | 4 +-- uv.lock | 82 +++++++++++++++++++++++++++++++++++++++------- 12 files changed, 112 insertions(+), 77 deletions(-) delete mode 100644 .env.sample delete mode 100644 cron_job.sh create mode 100644 entrypoint.sh diff --git a/.dockerignore b/.dockerignore index 6b8f750..c47390f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,11 @@ -*.env +__pycache__/ +.gitignore +.tool-versions .venv +*.env +docker-compose.yml +Dockerfile +eink-screen.jpg image.jpg processed.png -interface/ -__pycache__/ +README.md diff --git a/.env.sample b/.env.sample deleted file mode 100644 index 2f29f24..0000000 --- a/.env.sample +++ /dev/null @@ -1,6 +0,0 @@ -SZURU_URL=YOUR_SZURU_URL -SZURU_USER=YOUR_SZURU_USER -SZURU_TOKEN=YOUR_SZURU_TOKEN -EPD_TYPE=YOUR_EPD_TYPE # e.g., 7.5b V2, 5.65f -EINK_IP=YOUR_EINK_IP -DITHERING_MODE=YOUR_DITHERING_MODE # e.g., mono, color diff --git a/.gitignore b/.gitignore index 6b8f750..a329627 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ -*.env +__pycache__/ .venv +*.env image.jpg processed.png -interface/ -__pycache__/ diff --git a/Dockerfile b/Dockerfile index f06380a..d5e0d51 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,28 +1,9 @@ -# Use a lightweight Python base image -FROM python:3.13-slim-bookworm +FROM python:3.11.5-alpine -# Set the working directory in the container WORKDIR /app +RUN pip install uv +COPY . . +RUN uv sync +RUN chmod +x entrypoint.sh -# Install uv and dependencies -COPY pyproject.toml ./ -RUN apt-get update && apt-get install -y cron \ - && rm -rf /var/lib/apt/lists/* -RUN pip install uv && uv sync - -# Copy the application code -COPY szuru-eink.py ./ -COPY epd/ ./epd/ - -# Copy the cron job script and crontab file -COPY cron_job.sh /usr/local/bin/cron_job.sh -COPY crontab /etc/cron.d/szuru-eink-cron - -# Give execution rights on the cron job script -RUN chmod +x /usr/local/bin/cron_job.sh - -# Apply cron job -RUN crontab /etc/cron.d/szuru-eink-cron - -# Run cron -CMD ["cron", "-f"] +ENTRYPOINT ["./entrypoint.sh"] diff --git a/README.md b/README.md index bc785a7..3a85320 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,15 @@ for e-ink displays, and uploads them to a e-ink screens running on the [Waveshare E-Paper ESP32 Driver Board](https://www.waveshare.com/wiki/E-Paper_ESP32_Driver_Board). -![Picture of e-ink screen](https://gitea.bubbletea.dev/shibao/szuru-eink-bot/raw/branch/master/eink-screen.jpg) +![Picture of e-ink +screen](https://gitea.bubbletea.dev/shibao/szuru-eink-bot/raw/branch/master/eink-screen.jpg) ## Features - Fetches random images from a configurable Szurubooru instance. - Resizes and dithered images for e-ink display compatibility. - Supports monochrome and color dithering (for compatible displays). -- Uploads processed images to a Waveshare 7.5b V2 e-ink screen. +- Uploads processed images to a Waveshare e-ink screen. - Configurable via environment variables. - Designed to run as a Docker container on a cron job. @@ -35,9 +36,8 @@ cd szuru-eink ### 2. Configure Environment Variables -Create a `.env` file in the root directory of the project (if it doesn't exist) -and populate it with your Szurubooru API details and e-ink screen configuration. -You can use the `.env.sample` as a reference for the required variables. +Modify `docker-compose.yml` with the environment variables specified for your +display. **Note:** For `EPD_TYPE`, refer to the `epd/epd_config.py` file for a full list of supported display types and their corresponding string labels. For color @@ -55,32 +55,24 @@ docker-compose up --build -d This command will: - Build the Docker image based on the `Dockerfile`. - Create and start a Docker container named `szuru-eink-bot`. -- Copy the environment variables from your `.env` file to `docker-compose.yml` - for the container. +- Configure the environment variables in `docker-compose.yml` for the container. - Set up a cron job inside the container to run the `szuru-eink.py` script at a specified interval (default: every 15 minutes). -- Create a bind mount for logs in `./logs` directory on your host machine. ### 4. Verify Logs -You can check the logs generated by the cron job in the -`./logs/szuru-eink-cron.log` file on your host machine. - -```bash -tail -f logs/szuru-eink-cron.log -``` +You can check the logs by doing `docker-compose logs -f szuru-eink-bot`. ## Project Structure ``` .dockerignore -.env .gitignore .tool-versions Dockerfile README.md crontab -cron_job.sh +entrypoint.sh docker-compose.yml epd/ ├── epd_config.py @@ -94,7 +86,6 @@ szuru-eink.py - `uv` (for dependency management) - `Pillow` (for image processing) -- `python-dotenv` (for loading environment variables in local testing) - `pyszuru` (for interacting with Szurubooru API) - `requests` (for HTTP requests) - `black` (development dependency for code formatting) @@ -110,8 +101,16 @@ is not guaranteed without further testing and potential adjustments to ### Driver Board and Flashing -The e-ink screen used in this project is driven by the [Waveshare E-Paper ESP32 Driver Board](https://www.waveshare.com/wiki/E-Paper_ESP32_Driver_Board). The board was flashed with the sample `Loader_esp32wf` project provided by Waveshare, which exposes the web interface that this Python script interacts with. +The e-ink screen used in this project is driven by the [Waveshare E-Paper ESP32 +Driver Board](https://www.waveshare.com/wiki/E-Paper_ESP32_Driver_Board). The +board was flashed with the sample `Loader_esp32wf` project provided by +Waveshare, which exposes the web interface that this Python script interacts +with. ### 3D Printed Casing -The 3D printed casing for the e-ink screen shown in the preview image was sourced from [lmarzen/esp32-weather-epd](https://github.com/lmarzen/esp32-weather-epd). I covered it in walnut because I like walnut, sourced from [Amazon](https://www.amazon.com/dp/B08SVQBVJN). +The 3D printed casing for the e-ink screen shown in the preview image was +sourced from +[lmarzen/esp32-weather-epd](https://github.com/lmarzen/esp32-weather-epd). I +covered it in walnut because I like walnut, sourced from +[Amazon](https://www.amazon.com/dp/B08SVQBVJN). diff --git a/cron_job.sh b/cron_job.sh deleted file mode 100644 index 6c11081..0000000 --- a/cron_job.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -# Run the Python script using uv -uv run /app/szuru-eink.py diff --git a/crontab b/crontab index 896067f..985c292 100644 --- a/crontab +++ b/crontab @@ -1 +1 @@ -*/15 * * * * root /usr/local/bin/cron_job.sh >> /var/log/szuru-eink-cron.log 2>&1 +*/15 * * * * /usr/local/bin/uv run --project /app /app/szuru-eink.py >/proc/1/fd/1 2>&1 diff --git a/docker-compose.yml b/docker-compose.yml index f127bac..d6cf386 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,5 +11,3 @@ services: - EPD_TYPE=YOUR_EPD_TYPE # e.g., '7.5 V2', 5.65f - EINK_IP=YOUR_EINK_IP - DITHERING_MODE=YOUR_DITHERING_MODE # e.g., mono, color - volumes: - - ./logs:/var/log' diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..0920796 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +set -ou pipefail + +crontab ./crontab && crond -f diff --git a/pyproject.toml b/pyproject.toml index 42ed753..36438d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,6 @@ dependencies = [ "pyszuru==0.3.1", "Requests==2.31.0", "Pillow==11.3.0", - "python-dotenv==1.1.1", ] [project.optional-dependencies] diff --git a/szuru-eink.py b/szuru-eink.py index ceb5eec..3e73f86 100644 --- a/szuru-eink.py +++ b/szuru-eink.py @@ -6,10 +6,10 @@ import random import requests import os import pyszuru -from dotenv import load_dotenv + from PIL import Image -load_dotenv() + from epd.epd_config import palArr, epdArr, EPD_TYPES from epd.image_processor import getErr, getNear, addVal, procImg diff --git a/uv.lock b/uv.lock index e325dd5..f942372 100644 --- a/uv.lock +++ b/uv.lock @@ -112,6 +112,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4a/45/ec96b29162a402fc4c1c5512d114d7b3787b9d1c2ec241d9568b4816ee23/base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2", size = 5621, upload-time = "2021-10-30T22:12:16.658Z" }, ] +[[package]] +name = "black" +version = "24.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/47/c9997eb470a7f48f7aaddd3d9a828244a2e4199569e38128715c48059ac1/black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d", size = 642299, upload-time = "2024-04-26T00:32:15.305Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/89/294c9a6b6c75a08da55e9d05321d0707e9418735e3062b12ef0f54c33474/black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c", size = 205925, upload-time = "2024-04-26T00:32:12.495Z" }, +] + [[package]] name = "certifi" version = "2025.7.14" @@ -143,6 +159,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, ] +[[package]] +name = "click" +version = "8.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -278,6 +306,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d8/30/9aec301e9772b098c1f5c0ca0279237c9766d94b97802e9888010c64b0ed/multidict-6.6.3-py3-none-any.whl", hash = "sha256:8db10f29c7541fc5da4defd8cd697e1ca429db743fa716325f236079b96f775a", size = 12313, upload-time = "2025-06-30T15:53:45.437Z" }, ] +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + [[package]] name = "netaddr" version = "1.3.0" @@ -287,6 +324,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/cc/f4fe2c7ce68b92cbf5b2d379ca366e1edae38cccaad00f69f529b460c3ef/netaddr-1.3.0-py3-none-any.whl", hash = "sha256:c2c6a8ebe5554ce33b7d5b3a306b71bbb373e000bbbf2350dd5213cc56e3dbbe", size = 2262023, upload-time = "2024-05-28T21:30:34.191Z" }, ] +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + [[package]] name = "pillow" version = "11.3.0" @@ -320,6 +375,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, ] +[[package]] +name = "platformdirs" +version = "4.3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, +] + [[package]] name = "propcache" version = "0.3.2" @@ -439,15 +503,6 @@ version = "1.2.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/33/d0/9297d7d8dd74767b4d5560d834b30b2fff17d39987c23ed8656f476e0d9b/python-baseconv-1.2.2.tar.gz", hash = "sha256:0539f8bd0464013b05ad62e0a1673f0ac9086c76b43ebf9f833053527cd9931b", size = 4929, upload-time = "2019-04-04T19:28:57.17Z" } -[[package]] -name = "python-dotenv" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, -] - [[package]] name = "requests" version = "2.31.0" @@ -489,18 +544,23 @@ dependencies = [ { name = "aioipfs" }, { name = "pillow" }, { name = "pyszuru" }, - { name = "python-dotenv" }, { name = "requests" }, ] +[package.optional-dependencies] +dev = [ + { name = "black" }, +] + [package.metadata] requires-dist = [ { name = "aioipfs", specifier = "==0.6.5" }, + { name = "black", marker = "extra == 'dev'", specifier = "==24.4.2" }, { name = "pillow", specifier = "==11.3.0" }, { name = "pyszuru", specifier = "==0.3.1" }, - { name = "python-dotenv", specifier = "==1.1.1" }, { name = "requests", specifier = "==2.31.0" }, ] +provides-extras = ["dev"] [[package]] name = "tqdm"