pimoroni / fanshim-python

Python library for the Fan SHIM for Raspberry Pi
https://shop.pimoroni.com/products/fan-shim
MIT License
295 stars 85 forks source link

Looking for help with a slightly customized version of automatic.py #47

Closed spiff72 closed 5 years ago

spiff72 commented 5 years ago

I am working on a simple neopixel strip (8 pixels) that acts as a temperature gauge for the CPU, lighting up more of the pixels as the temp increases. I got a python script working, but one requirement of the circuitpython-neopixel library i am using requires that the script is run as root.

So I have 2 questions:

Or is there something different that I could do to make this work? Here is my modified code : `

!/usr/bin/env python3

from fanshim import FanShim from threading import Lock import colorsys import psutil import argparse import time import signal import sys import board import neopixel min_val = 55 max_val = 65

parser = argparse.ArgumentParser() parser.add_argument('--threshold', type=float, default=-1, help='Temperature threshold in degrees C to enable fan') parser.add_argument('--hysteresis', type=float, default=-1, help='Distance from threshold before fan is disabled')

parser.add_argument('--off-threshold', type=float, default=55.0, help='Temperature threshold in degrees C to enable fan') parser.add_argument('--on-threshold', type=float, default=65.0, help='Temperature threshold in degrees C to disable fan') parser.add_argument('--delay', type=float, default=2.0, help='Delay, in seconds, between temperature readings') parser.add_argument('--preempt', action='store_true', default=False, help='Monitor CPU frequency and activate cooling premptively') parser.add_argument('--verbose', action='store_true', default=False, help='Output temp and fan status messages') parser.add_argument('--nobutton', action='store_true', default=False, help='Disable button input') parser.add_argument('--noled', action='store_true', default=False, help='Disable LED control') parser.add_argument('--brightness', type=float, default=255.0, help='LED brightness, from 0 to 255')

args = parser.parse_args()

Choose an open pin connected to the Data In of the NeoPixel strip, i.e. board.D18

NeoPixels must be connected to D10, D12, D18 or D21 to work.

pixel_pin = board.D21

The number of NeoPixels

num_pixels = 8

The order of the pixel colors - RGB or GRB. Some NeoPixels have red and green reversed!

For RGBW NeoPixels, simply change the ORDER to RGBW or GRBW.

ORDER = neopixel.GRBW

pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.25, auto_write=False, pixel_order=ORDER)

def clean_exit(signum, frame): set_fan(False) if not args.noled: fanshim.set_light(0, 0, 0) sys.exit(0)

def update_led_temperature(temp): led_busy.acquire() temp = float(temp) temp -= args.off_threshold temp /= float(args.on_threshold - args.off_threshold) temp = max(0, min(1, temp)) temp = 1.0 - temp temp = 120.0 temp /= 360.0 r, g, b = [int(c 255.0) for c in colorsys.hsv_to_rgb(temp, 1.0, args.brightness / 255.0)] fanshim.set_light(r, g, b) led_busy.release()

def update_neo_temp(temp2): pixels.fill((0,0,0,0)) pixels.show temp2 = float(temp2) print(temp2) temp2 -= min_val print(temp2) temp2 /= float(max_val-min_val) print(temp2) temp2 = max(0, min(1,temp2)) print(temp2)

temp2 = 1.0 - temp2

print(temp2)
color = [((0, 0, 255, 0)),
((0, 128, 255, 0)),
((0, 255, 255, 0)),
((0, 255, 128, 0)),
((128, 255, 0, 0)),
((128, 128, 0, 0)),
((255, 128, 0, 0)),
((255, 0, 0, 0))]

t_test = temp2*8
print(t_test)
t_test = int(t_test)
print(t_test)
for i in range(t_test):
    pixels[i] = color[i]
pixels.show()

def get_cpu_temp(): t = psutil.sensors_temperatures() for x in ['cpu-thermal', 'cpu_thermal']: if x in t: return t[x][0].current print("Warning: Unable to get CPU temperature!") return 0

def get_cpu_freq(): freq = psutil.cpu_freq() return freq

def set_fan(status): global enabled changed = False if status != enabled: changed = True fanshim.set_fan(status) enabled = status return changed

def set_automatic(status): global armed, last_change armed = status last_change = 0

if args.threshold > -1 or args.hysteresis > -1: print(""" The --threshold and --hysteresis parameters have been deprecated. Use --on-threshold and --off-threshold instead! """) sys.exit(1)

fanshim = FanShim() fanshim.set_hold_time(1.0) fanshim.set_fan(False) armed = True enabled = False led_busy = Lock() enable = False is_fast = False last_change = 0 signal.signal(signal.SIGTERM, clean_exit)

if args.noled: led_busy.acquire() fanshim.set_light(0, 0, 0) led_busy.release()

t = get_cpu_temp() if t >= args.threshold: last_change = get_cpu_temp() set_fan(True)

if not args.nobutton: @fanshim.on_release() def release_handler(was_held): global armed if was_held: set_automatic(not armed) elif not armed: set_fan(not enabled)

@fanshim.on_hold()
def held_handler():
    global led_busy
    if args.noled:
        return
    led_busy.acquire()
    for _ in range(3):
        fanshim.set_light(0, 0, 255)
        time.sleep(0.04)
        fanshim.set_light(0, 0, 0)
        time.sleep(0.04)
    led_busy.release()

try: while True: t = get_cpu_temp() f = get_cpu_freq() was_fast = is_fast is_fast = (int(f.current) == int(f.max)) if args.verbose: print("Current: {:05.02f} Target: {:05.02f} Freq {: 5.02f} Automatic: {} On: {}".format(t, args.off_threshold, f.current / 1000.0, armed, enabled))

    if args.preempt and is_fast and was_fast:
        enable = True
    elif armed:
        if t >= args.on_threshold:
            enable = True
        elif t <= args.off_threshold:
            enable = False

    if set_fan(enable):
        last_change = t

    if not args.noled:
        update_led_temperature(t)
        update_neo_temp(t)
    time.sleep(args.delay)

except KeyboardInterrupt: pass

`

spiff72 commented 5 years ago

SOrry for the mess of formatting above - not sure why that happened.

Just to clarify the error logging question above. I would like to know how I can see what (if any errors) are generated and see the stdout of the automatic.py file when it runs as part of the systemd service. I can't figure this part out.

I have attempted to modify the ExecStart= line of the service file to read as follows: ExecStart=/usr/bin/sudo -E /home/pi/fanshim-python/examples/automatic.py --on-threshold 65 --off-threshold 55 --delay 2 --brightness 255

The above works if I use the "original" automatic.py script, but it doesn't start when I use it with my modified automatic.py script.

I also tried the following to get some logging to a file, but this fails to start correctly, even when the unmodifed automatic.py file is used. ExecStart=/usr/bin/sudo -E python3 /home/pi/fanshim-python/examples/automatic.py --on-threshold 65 --off-threshold 55 --delay 2 --brightness 255 >> /home/pi/logfile.txt 2>&1

If I could see the errors I would have an easier time understanding what is wrong (ie is the import board and import neopixel command failing to find them because the sudo python3 path isn't correct??

Thanks!

spiff72 commented 5 years ago

Well - i found the error messages in var/log/syslog. It looks like the sudo -E in ExecStart isn't doing what it did at the command line to get these applications to run.

I am getting the error message about not being able to import my modules.

spiff72 commented 5 years ago

I just tried installing the necessary packages with sudo pip3 (adafruit-blinka and adafruit-circuitpython-neopixel) and this got it all working!