summaryrefslogtreecommitdiff
path: root/src/xwing_sensor/main.py
blob: 41402e68ce4e28152cdd59cd63dc976e621eb786 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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()