diff options
| -rw-r--r-- | README.md | 87 | ||||
| -rw-r--r-- | pyproject.toml | 45 | ||||
| -rw-r--r-- | src/xwing_sensor/__init__.py | 0 | ||||
| -rw-r--r-- | src/xwing_sensor/main.py | 68 | ||||
| -rw-r--r-- | xwing-sensor.service | 15 |
5 files changed, 215 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..e088361 --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# xwing-sensor + +Reads temperature and humidity from an SI7021 sensor over I2C and displays the readings on a Waveshare 2.13 inch e-Paper HAT, running on a Raspberry Pi Zero 2 W. + +## Hardware + +- Raspberry Pi Zero 2 W +- SI7021 temperature/humidity sensor (I2C, address `0x40`, bus 1) +- Waveshare 2.13 inch e-Paper HAT (250×122 px, SPI) + +Waveshare HAT documentation and wiring guide: +https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT_Manual#Overview + +## System dependencies + +Before running `uv sync`, install the required system libraries. + +**Pillow build dependencies:** + +```bash +sudo apt-get update && sudo apt-get install -y \ + build-essential \ + python3-dev \ + libjpeg62-turbo-dev \ + zlib1g-dev \ + libfreetype-dev \ + libopenjp2-7-dev +``` + +**lg GPIO library:** + +The `lgpio` Python package requires the `lg` C library. Follow the install instructions at https://github.com/joan2937/lg, which requires `swig`: + +```bash +sudo apt-get install -y swig +``` + +Then build and install `lg` per the instructions in that repository. + +## Waveshare EPD library + +The `waveshare_epd` library is **not bundled** in this repo. Download it from Waveshare's GitHub: + +```bash +git clone https://github.com/waveshare/e-Paper +``` + +The `lib/` directory (`e-Paper/RaspberryPi_JetsonNano/python/lib`) must be on `PYTHONPATH` at runtime. When running as a systemd service this is handled via the `Environment=` line in the unit file (see below). For manual runs: + +```bash +PYTHONPATH=/home/pi/e-Paper/RaspberryPi_JetsonNano/python/lib uv run xwing-sensor +``` + +The import in `main.py` uses `epd2in13_V4` — adjust to match your HAT version if needed. + +## Setup + +```bash +uv sync +``` + +## Running as a systemd service + +Copy the unit file to systemd and enable it: + +```bash +sudo cp xwing-sensor.service /etc/systemd/system/ +sudo systemctl daemon-reload +sudo systemctl enable xwing-sensor +sudo systemctl start xwing-sensor +``` + +Check status or logs: + +```bash +sudo systemctl status xwing-sensor +journalctl -u xwing-sensor -f +``` + +Before enabling, verify the paths in `xwing-sensor.service` match your environment: + +| Field | Default value | What to check | +|---|---|---| +| `User` | `pi` | The user that owns the project directory | +| `WorkingDirectory` | `/home/pi/xwing_sensor` | Absolute path to this repo on the Pi | +| `PYTHONPATH` | `/home/pi/e-Paper/…/lib` | Where you cloned the Waveshare repo | +| `ExecStart` | `/home/pi/xwing_sensor/.venv/bin/xwing-sensor` | Created by `uv sync` | diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4255c1d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,45 @@ +[project] +name = "xwing-sensor" +version = "0.3.0" +description = "SI7021 temperature/humidity sensor display for Waveshare 2.13in e-Paper HAT" +requires-python = ">=3.13" +dependencies = [ + "smbus2", + "Pillow", + "RPi.GPIO", + "spidev", + "gpiozero", + "lgpio", +] + +[project.scripts] +xwing-sensor = "xwing_sensor.main:main" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["src/xwing_sensor"] + +[tool.bumpversion] +current_version = "0.3.0" +parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)" +serialize = ["{major}.{minor}.{patch}"] +search = "{current_version}" +replace = "{new_version}" +regex = false +ignore_missing_version = false +ignore_missing_files = false +tag = true +sign_tags = false +tag_name = "v{new_version}" +tag_message = "Bump version: {current_version} → {new_version}" +allow_dirty = false +commit = true +message = "Bump version: {current_version} → {new_version}" +moveable_tags = [] +commit_args = "" +setup_hooks = [] +pre_commit_hooks = [] +post_commit_hooks = [] diff --git a/src/xwing_sensor/__init__.py b/src/xwing_sensor/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/xwing_sensor/__init__.py diff --git a/src/xwing_sensor/main.py b/src/xwing_sensor/main.py new file mode 100644 index 0000000..41402e6 --- /dev/null +++ b/src/xwing_sensor/main.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +""" +Reads temperature and humidity from an SI7021 sensor (I2C) and renders +the values to a Waveshare 2.13 inch e-Paper HAT. + +The Waveshare EPD library (waveshare_epd) is not bundled in this repo. +See README.md for setup instructions. +""" +import time + +from smbus2 import SMBus +from PIL import Image, ImageDraw, ImageFont +from waveshare_epd import epd2in13_V4 # adjust module name for your HAT version + +I2C_BUS = 1 +I2C_ADDR = 0x40 +POLL_INTERVAL = 120 # seconds between display refreshes + + +def read_si7021(bus: SMBus) -> tuple[float, float]: + """Return (temp_c, humidity_pct) from the SI7021 sensor.""" + rh_raw = bus.read_i2c_block_data(I2C_ADDR, 0xE5, 2) # measure RH, hold master + time.sleep(0.1) + humidity = ((rh_raw[0] * 256 + rh_raw[1]) * 125 / 65536.0) - 6 + + temp_raw = bus.read_i2c_block_data(I2C_ADDR, 0xE3, 2) # measure temp, hold master + time.sleep(0.1) + temp_c = ((temp_raw[0] * 256 + temp_raw[1]) * 175.72 / 65536.0) - 46.85 + + return temp_c, humidity + + +def render(epd: epd2in13_V4.EPD, temp_c: float, humidity: float) -> None: + """Draw sensor readings on the e-paper display. + + The 2.13in HAT is 122×250 px (portrait). We create a landscape image + (250×122) by swapping width/height, which matches the typical Waveshare + example convention of passing (epd.height, epd.width) to Image.new. + """ + image = Image.new("1", (epd.height, epd.width), 255) # 255 = white background + draw = ImageDraw.Draw(image) + + font_large = ImageFont.load_default(size=40) + font_small = ImageFont.load_default(size=22) + + draw.text((10, 8), f"{temp_c:.1f} \u00b0C", font=font_large, fill=0) + draw.text((10, 62), f"{humidity:.1f} % RH", font=font_small, fill=0) + + epd.display(epd.getbuffer(image)) + + +def main() -> None: + epd = epd2in13_V4.EPD() + epd.init() + epd.Clear() + + bus = SMBus(I2C_BUS) + try: + while True: + temp_c, humidity = read_si7021(bus) + render(epd, temp_c, humidity) + time.sleep(POLL_INTERVAL) + except KeyboardInterrupt: + epd.sleep() + + +if __name__ == "__main__": + main() diff --git a/xwing-sensor.service b/xwing-sensor.service new file mode 100644 index 0000000..f8e3095 --- /dev/null +++ b/xwing-sensor.service @@ -0,0 +1,15 @@ +[Unit] +Description=xwing-sensor: SI7021 temperature/humidity display on e-Paper HAT +After=multi-user.target + +[Service] +Type=simple +User=pi +WorkingDirectory=/home/pi/xwing_sensor +Environment=PYTHONPATH=/home/pi/e-Paper/RaspberryPi_JetsonNano/python/lib +ExecStart=/home/pi/xwing_sensor/.venv/bin/xwing-sensor +Restart=on-failure +RestartSec=10 + +[Install] +WantedBy=multi-user.target |
