Skip to content

Commit 73d2c4b

Browse files
committed
fix: remove RPi.GPIO usage. Check for command existance and ignore if not available
1 parent 4da7962 commit 73d2c4b

File tree

1 file changed

+82
-77
lines changed

1 file changed

+82
-77
lines changed

src/jukebox/components/hostif/linux/__init__.py

+82-77
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,12 @@
1010
import jukebox.publishing
1111
import jukebox.speaking_text
1212
from jukebox.multitimer import GenericEndlessTimerClass
13-
import socket
1413

1514
logger = logging.getLogger('jb.host.lnx')
1615
cfg = jukebox.cfghandler.get_handler('jukebox')
1716
# Get the main Thread Publisher
1817
publisher = jukebox.publishing.get_publisher()
1918

20-
# This is a slightly dirty way of checking if we are on an RPi
21-
# JukeBox installs the dependency RPI which has no meaning on other machines
22-
# If it does not exist all is clear
23-
# It could still be installed, which results in a RuntimeError when loaded on a PC
24-
try:
25-
import RPi.GPIO as gpio # noqa: F401
26-
27-
IS_RPI = True
28-
except ModuleNotFoundError:
29-
IS_RPI = False
30-
except RuntimeError as e:
31-
logger.info(f"You don't seem to be on a PI, because loading 'RPi.GPIO' failed: {e.__class__.__name__}: {e}")
32-
IS_RPI = False
33-
3419
# In debug mode, shutdown and reboot command are not actually executed
3520
IS_DEBUG = False
3621
try:
@@ -302,73 +287,60 @@ def start_autohotspot():
302287
return 'not-installed'
303288

304289

305-
@plugin.initialize
306-
def initialize():
307-
wlan_power = cfg.setndefault('host', 'wlan_power', 'disable_power_down', value=True)
308-
card = cfg.setndefault('host', 'wlan_power', 'card', value='wlan0')
309-
if wlan_power:
310-
wlan_disable_power_down(card)
290+
# ---------------------------------------------------------------------------
291+
# RPi-only stuff
292+
# ---------------------------------------------------------------------------
293+
THROTTLE_CODES = {
294+
0x1: "under-voltage detected",
295+
0x2: "ARM frequency capped",
296+
0x4: "currently throttled",
297+
0x8: "soft temperature limit active",
298+
0x10000: "under-voltage has occurred",
299+
0x20000: "ARM frequency capped has occurred",
300+
0x40000: "throttling has occurred",
301+
0x80000: "soft temperature limit has occurred"
302+
}
311303

312304

313-
@plugin.finalize
314-
def finalize():
315-
global timer_temperature
316-
enabled = cfg.setndefault('host', 'publish_temperature', 'enabled', value=True)
317-
wait_time = cfg.setndefault('host', 'publish_temperature', 'timer_interval_sec', value=5)
318-
timer_temperature = GenericEndlessTimerClass('host.timer.cputemp', wait_time, publish_cpu_temperature)
319-
timer_temperature.__doc__ = "Endless timer for publishing CPU temperature"
320-
# Note: Since timer_temperature is an instance of a class from a different module,
321-
# auto-registration would register it with that module. Manually set package to this plugin module
322-
plugin.register(timer_temperature, name='timer_temperature', package=plugin.loaded_as(__name__))
323-
if enabled:
324-
publish_cpu_temperature()
325-
timer_temperature.start()
326-
305+
def command_exists(command):
306+
ret = shutil.which(command)
307+
return ret is not None
327308

328-
@plugin.atexit
329-
def atexit(**ignored_kwargs):
330-
global timer_temperature
331-
timer_temperature.cancel()
332-
return timer_temperature.timer_thread
333309

310+
@plugin.register
311+
def hdmi_power_down():
312+
"""Power down HDMI circuits to save power if no display is connected
334313
335-
# ---------------------------------------------------------------------------
336-
# RPi-only stuff
337-
# ---------------------------------------------------------------------------
338-
if IS_RPI: # noqa: C901
339-
340-
THROTTLE_CODES = {
341-
0x1: "under-voltage detected",
342-
0x2: "ARM frequency capped",
343-
0x4: "currently throttled",
344-
0x8: "soft temperature limit active",
345-
0x10000: "under-voltage has occurred",
346-
0x20000: "ARM frequency capped has occurred",
347-
0x40000: "throttling has occurred",
348-
0x80000: "soft temperature limit has occurred"
349-
}
350-
351-
@plugin.register
352-
def hdmi_power_down():
353-
"""Power down HDMI circuits to save power if no display is connected
354-
355-
This must be done after every reboot"""
314+
This must be done after every reboot"""
315+
success = False
316+
commandname = "tvservice"
317+
if command_exists(commandname):
356318
logger.info('Power down HDMI circuits')
357-
ret = subprocess.run(['sudo', '/usr/bin/tvservice', '-o'],
358-
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False)
319+
ret = subprocess.run(['sudo', commandname, '-o'],
320+
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False)
359321
if ret.returncode != 0:
360322
logger.error(f"{ret.stdout}")
323+
else:
324+
success = True
325+
else:
326+
logger.info('Power down HDMI not available on this system')
361327

362-
def filter_throttle_codes(code):
363-
for error, msg in THROTTLE_CODES.items():
364-
if code & error > 0:
365-
yield msg
328+
return success
366329

367-
@plugin.register
368-
def get_throttled():
330+
331+
def filter_throttle_codes(code):
332+
for error, msg in THROTTLE_CODES.items():
333+
if code & error > 0:
334+
yield msg
335+
336+
337+
@plugin.register
338+
def get_throttled():
339+
commandname = "vcgencmd"
340+
if command_exists(commandname):
369341
# https://www.raspberrypi.org/documentation/computers/os.html#get_throttled
370-
ret = subprocess.run(['sudo', 'vcgencmd', 'get_throttled'],
371-
stdout=subprocess.PIPE, check=False)
342+
ret = subprocess.run(['sudo', commandname, 'get_throttled'],
343+
stdout=subprocess.PIPE, check=False)
372344
if ret.returncode != 0:
373345
status_string = f"Error in subprocess with code: {ret.returncode}"
374346
logger.error(status_string)
@@ -384,11 +356,44 @@ def get_throttled():
384356
else:
385357
# Decode the bit array after we have handled all the possible exceptions
386358
status_string = "Warning: " + ', '.join(filter_throttle_codes(status_code))
359+
else:
360+
logger.info('Throttled state not available on this system')
361+
status_string = "Not available"
362+
363+
return status_string
364+
365+
366+
# ---------------------------------------------------------------------------
367+
# Init
368+
# ---------------------------------------------------------------------------
369+
@plugin.initialize
370+
def initialize():
371+
wlan_power = cfg.setndefault('host', 'wlan_power', 'disable_power_down', value=True)
372+
card = cfg.setndefault('host', 'wlan_power', 'card', value='wlan0')
373+
if wlan_power:
374+
wlan_disable_power_down(card)
375+
hdmi_off = cfg.setndefault('host', 'rpi', 'hdmi_power_down', value=False)
376+
if hdmi_off:
377+
hdmi_power_down()
378+
379+
380+
@plugin.finalize
381+
def finalize():
382+
global timer_temperature
383+
enabled = cfg.setndefault('host', 'publish_temperature', 'enabled', value=True)
384+
wait_time = cfg.setndefault('host', 'publish_temperature', 'timer_interval_sec', value=5)
385+
timer_temperature = GenericEndlessTimerClass('host.timer.cputemp', wait_time, publish_cpu_temperature)
386+
timer_temperature.__doc__ = "Endless timer for publishing CPU temperature"
387+
# Note: Since timer_temperature is an instance of a class from a different module,
388+
# auto-registration would register it with that module. Manually set package to this plugin module
389+
plugin.register(timer_temperature, name='timer_temperature', package=plugin.loaded_as(__name__))
390+
if enabled:
391+
publish_cpu_temperature()
392+
timer_temperature.start()
387393

388-
return status_string
389394

390-
@plugin.initialize
391-
def rpi_initialize():
392-
hdmi_off = cfg.setndefault('host', 'rpi', 'hdmi_power_down', value=False)
393-
if hdmi_off:
394-
hdmi_power_down()
395+
@plugin.atexit
396+
def atexit(**ignored_kwargs):
397+
global timer_temperature
398+
timer_temperature.cancel()
399+
return timer_temperature.timer_thread

0 commit comments

Comments
 (0)