5

I am trying to invoke a bash command from my python application in order to change background light on my touch screen. The python application will run on my Raspberry Pi (Rasbian/stretch).

It's not complicated to run the bash command in a terminal: sudo sh -c "echo 80 > /sys/class/backlight/rpi_backlight/brightness" will certainly dim the screen (which is what I want). But how can I sudo scripts in my python application? (I know that there are several threads talking about this, for example this Using sudo with Python script, but I do not understand how to do it in practice?)

This is my code:

#!/usr/bin/env python3
import subprocess
import time
import sys

# read arguments from the run command: 
# idle time before dim (in seconds)
idleTimeBeforeDimMS = int( sys.argv[1] )*1000

# brightness when dimmed (between 0 and 255)
brightnessDimmed = int( sys.argv[2] )
brightnessFull = 255

def get(cmd):
    # just a helper function
    return subprocess.check_output(cmd).decode("utf-8").strip()

isIdle0 = False
stateChanged = False
timeIntervalToWatchChangesS = 100 / 1000

while True:
    time.sleep( timeIntervalToWatchChangesS )

    currentIdleTimeMS = int( get("xprintidle") )

    isIdle = currentIdleTimeMS > idleTimeBeforeDimMS
    stateChanged = isIdle0 != isIdle

    if isIdle and stateChanged:
        # idling
        bashCommand = "echo 50 > /sys/class/backlight/rpi_backlight/brightness"
        subprocess.run(['bash', '-c', bashCommand])
    elif not isIdle and stateChanged:
        # active
        bashCommand = "echo 255 > /sys/class/backlight/rpi_backlight/brightness"
        subprocess.run(['bash', '-c', bashCommand])

        # set current state as initial one for the next loop cycle
    isIdle0 = isIdle

If I run the script right out of box, I get an error with my bash command: bash: /sys/class/backlight/rpi_backlight/brightness: Permission denied. That's ok, I understand that I am missing the sudo-part, but where should I put it?

Hauns TM
  • 1,909
  • 2
  • 22
  • 38
  • 1
    As that is in `/sys`, you should be able set that with `sysctl` which would make the command simpler as it would start with `sudo sysctl` without the bash and echo. – Dan D. Apr 16 '19 at 23:36

2 Answers2

7

Put it in front of the shell just like you do interactively:

subprocess.run(['sudo', 'bash', '-c', bashCommand])
that other guy
  • 116,971
  • 11
  • 170
  • 194
  • Thanks! My goal is to autostart/run my script when the raspberry is powered on and I can't have a password prompt for sudo by that time. If this solves my problem I'll mark it as answer. – Hauns TM Apr 17 '19 at 04:49
  • 1
    You'll have to configure sudo for passwordless operation separately – that other guy Apr 17 '19 at 05:19
7

I would recommend just running your python script with sudo... ie: sudo myscript.py. That way any commands that it might run will already have privileges.

You could use that_other_guy's answer but your script will still prompt you for your password (at least in my case it did). Therefore that answer isn't that good.

If you really want to automate it but you don't wanna run it as root... you'll need to use that_other_guys's answer but also echo your password as shown here.

That's a bit hacky though. I would just run the python script itself with root privileges.

However if you really don't want to run it as root then you can do this:

>>> from subprocess import run, PIPE
>>> cmd = "echo mypassword | sudo -S ls"
>>> out = run(cmd, shell=True, stdout=PIPE)
>>> output = [i for i in out.stdout.decode().split('\n') if i]
>>> output
['build', 'dist', '__init__.py', 'palindrome', 'palindrome.egg-info', 'LICENSE', 'README.md', 'setup.py']
m.a.d.cat
  • 195
  • 2
  • 8