diff --git a/apps/oled_piroman5/README.md b/apps/oled_piroman5/README.md index e998e0779..fb02c8e45 100644 --- a/apps/oled_piroman5/README.md +++ b/apps/oled_piroman5/README.md @@ -1,6 +1,6 @@ # OLED IP Display -Simple example using **piroman5** Raspberry Pi OLED driver (based on `luma.oled`) to show the current IP address and timestamp on a small OLED screen. The fan on BCM pin 18 of the piroman5 max board is automatically controlled based on the CPU temperature. +Simple example using **piroman5** Raspberry Pi OLED driver (based on `luma.oled`) to show the current IP address and timestamp on a small OLED screen. The fan on BCM pin 18 of the piroman5 max board is automatically controlled based on the CPU temperature and can be limited to a percentage of a two-minute interval with the ``--fan-duty`` option. ## Installation @@ -16,11 +16,19 @@ sudo apt install libgpiod-dev ## Running -Add an entry to ``crontab`` so the script runs every minute: +Add an entry to ``crontab`` so the script runs every two minutes: ```bash -* * * * * /usr/bin/python3 /path/to/ip_display.py +*/2 * * * * /usr/bin/python3 /path/to/ip_display.py ``` -Each run updates the OLED with the current IP address and the date/time (including seconds). The fan is powered on when the script starts. It remains on whenever the CPU temperature is 50 °C or higher and turns off once the temperature falls below that threshold. +To run the fan for less than the full two minutes when the CPU is cool, pass a percentage with ``--fan-duty`` (default is ``100``): + +```bash +*/2 * * * * /usr/bin/python3 /path/to/ip_display.py --fan-duty 75 +``` + +Each run updates the OLED with the current IP address and the date/time (including seconds). The fan is powered on when the script starts. It remains on whenever the CPU temperature is 50 °C or higher and, when cooler, runs only for the specified portion of the two-minute cycle. + +The display also shows the current fan duty setting as ``Duty: /120s`` on the last line. diff --git a/apps/oled_piroman5/ip_display.py b/apps/oled_piroman5/ip_display.py index 7a21844e3..e4b044a5d 100644 --- a/apps/oled_piroman5/ip_display.py +++ b/apps/oled_piroman5/ip_display.py @@ -1,10 +1,12 @@ #!/usr/bin/env python3 """Display IP address and time on the OLED using the piroman5 driver. -This script is designed to be called from ``cron`` once per minute. +This script is designed to be called from ``cron`` once every two minutes. It updates the OLED with the current IPv4 address and timestamp, and -controls the cooling fan on the piroman5 max board when the CPU -temperature exceeds ``50°C``. +controls the cooling fan on the piroman5 max board. By default the +fan runs continuously, but a different duty cycle (e.g. 75 or 50) may +be specified via ``--fan-duty`` to run the fan only for part of the +two-minute interval when the CPU temperature is below ``50°C``. Dependencies can be installed with:: @@ -13,6 +15,7 @@ from datetime import datetime import subprocess +import argparse # piroman5 OLED driver, built on luma.oled from luma.core.interface.serial import i2c @@ -44,9 +47,30 @@ def get_ip_address(interface="eth0"): return "0.0.0.0" +def parse_args(): + """Return parsed command line arguments.""" + + parser = argparse.ArgumentParser( + description="Update the OLED and control the cooling fan once." + ) + parser.add_argument( + "--fan-duty", + type=int, + default=100, + help=( + "Percentage of the two-minute cycle to run the fan when the CPU " + "temperature is below the threshold (0-100)." + ), + ) + return parser.parse_args() + + def main(): """Update the OLED and control the cooling fan once.""" + args = parse_args() + args.fan_duty = max(0, min(args.fan_duty, 100)) + # Prevent gpiozero from resetting the pin states on exit so the fan # remains in the state we set. Older versions of gpiozero may not # expose ``Device._shutdown``, so handle that case gracefully. @@ -66,8 +90,6 @@ def main(): fan = OutputDevice(FAN_PIN, active_high=True) - # Ensure the fan starts running when the program launches - fan.on() rgb_leds = [OutputDevice(pin, active_high=True) for pin in RGBFAN_PIN] rgb_leds[0].on() rgb_leds[1].on() @@ -80,8 +102,12 @@ def main(): ip = get_ip_address("eth0") now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + total_runtime = 120 + fan_on_duration = total_runtime * args.fan_duty / 100 + remaining = total_runtime + temp = cpu.temperature - if temp >= TEMP_THRESHOLD: + if temp >= TEMP_THRESHOLD or remaining > total_runtime - fan_on_duration: fan.on() else: fan.off() @@ -100,11 +126,16 @@ def main(): draw.text((0, 0), ip, font=font, fill=255) draw.text((0, 16), now, font=font, fill=255) draw.text((0, 32), f"CPU {temp:.1f}C F:{fan_status}", font=font, fill=255) + draw.text( + (0, 48), + f"Duty: {args.fan_duty}%/{int(total_runtime)}s", + font=font, + fill=255, + ) - remaining = 60 while remaining >= 0: temp = cpu.temperature - if temp >= TEMP_THRESHOLD: + if temp >= TEMP_THRESHOLD or remaining > total_runtime - fan_on_duration: fan.on() else: fan.off()