Hi
I am using a RPI Zero W as a PVR frontend. When on Raspbian Kodi would freeze whenever i clicked on a channel. OSMC however works like a charm and I have all settings perfectly put in place. Being the greedy person I am, I want to now integrate a Retropie. I wrote a python script based on cec/curses to present a menu that the user can choose with the TV remote. I can login to SSH and run this script. Curses presents the screen on my SSH terminal. I can select OSMC and Kodi shows up. How do I integrate this into the boot sequence? So far I have created a bootlist service that points to this and sudo systemctl disable mediacenter but Rpi freezes when it reaches the end of the boot sequence. I need to plug in a init=/bin/bash to revert stuff. I also tried getting mediacenter service to point to bootlist.py and still it freezes on boot.
-
Can somebody give me an idea of what should work. I am new to systemd but from what I gather it is a richer brother of init.
-
Can I permanently plug in init=/bin/bash and start the bootup sequence from shell so that I dont have to repeatedly unplug and replug the SDCard when it freezes?
#! /usr/bin/python
import cec
print(cec)
import time
import curses
import subprocess
import os
class pyCecClient:
key =0
keypressed = False
cecconfig = cec.libcec_configuration()
lib = {}
menuList = ["OSMC","RetroPie","Command Line"]
curSel = 0
# don't enable debug logging by default
log_level = cec.CEC_LOG_TRAFFIC
# create a new libcec_configuration
def SetConfiguration(self):
self.cecconfig.strDeviceName = "pyLibCec"
self.cecconfig.bActivateSource = 0
self.cecconfig.deviceTypes.Add(cec.CEC_DEVICE_TYPE_RECORDING_DEVICE)
self.cecconfig.clientVersion = cec.LIBCEC_VERSION_CURRENT
def SetKeyPressCallback(self, callback):
self.cecconfig.SetKeyPressCallback(callback)
pass
# detect an adapter and return the com port path
def DetectAdapter(self):
retval = None
adapters = self.lib.DetectAdapters()
for adapter in adapters:
print("found a CEC adapter:")
print("port: " + adapter.strComName)
print("vendor: " + hex(adapter.iVendorId))
print("product: " + hex(adapter.iProductId))
retval = adapter.strComName
return retval
# initialise libCEC
def InitLibCec(self):
self.lib = cec.ICECAdapter.Create(self.cecconfig)
# print libCEC version and compilation information
print("libCEC version " + self.lib.VersionToString(self.cecconfig.serverVersion) + " loaded: " + self.lib.GetLibInfo())
# search for adapters
adapter = self.DetectAdapter()
if adapter == None:
print("No adapters found")
else:
if self.lib.Open(adapter):
print("connection opened")
#mythread = threading.Thread(target=self.MainLoop)
#mythread.start()
stdscr = curses.initscr()
curses.start_color()
for ctr,option in enumerate(self.menuList):
if ctr == self.curSel:
stdscr.addstr(ctr,0,option, curses.A_STANDOUT)
else:
stdscr.addstr(ctr,0,option)
stdscr.refresh()
while True:
time.sleep(1)
if self.keypressed is True:
#print self.key
if self.key == 0:
break
else:
if self.key == 1 and self.curSel>0:
self.curSel = self.curSel - 1
elif self.key == 2 and self.curSel<len(self.menuList)-1:
self.curSel = self.curSel +1
self.keypressed = False
for ctr,option in enumerate(self.menuList):
if ctr == self.curSel:
stdscr.addstr(ctr,0,option, curses.A_STANDOUT)
else:
stdscr.addstr(ctr,0,option)
stdscr.refresh()
curses.endwin()
if self.curSel == 0:
subprocess.Popen("systemctl start mediacenter", shell=True)
else:
print("failed to open a connection to the CEC adapter")
# key press callback
def KeyPressCallback(self, key, duration):
#print("[key pressed] " + str(key))
if duration >0:
self.key = key
self.keypressed = True
while self.keypressed:
time.sleep(1)
return 0
def __init__(self):
self.SetConfiguration()
# key press callback
def key_press_callback(key, duration):
return lib.KeyPressCallback(key, duration)
if __name__ == '__main__':
# initialise libCEC
lib = pyCecClient()
lib.SetKeyPressCallback(key_press_callback)
# initialise libCEC and enter the main loop
lib.InitLibCec()
I’ll not be able to help you debug your script, but it seems to me that you might need to boot your Pi Zero into what used to be called runlevel 3, which is a non-graphic multi-user state. From this you’ll still have SSH access.
To do this you’d need to run:
sudo systemctl set-default multi-user.target
and to revert to its usual state:
sudo systemctl set-default graphical.target
So if I set default to multi-user, I should be able to SSH in and make modifications. But what would be the command to proceed to graphical.target without rebooting? Something like sudo systemctl continue graphical.target so that my changes to services can be tested. Thanks!
You could either try
sudo systemctl start mediacenter
or
sudo systemctl isolate graphical.target
which will change to the new target/runlevel without needing a reboot.
I just tested sudo systemctl set-default multi-user.target but Kodi still loads on reboot. Looks into systemd folder mediacenter.service is under multi-user.target.wants folder.
Damn, you’re right.
Backtracking a bit, you said:
Could you show us this bootlist service?
I can’t speak for the Pi Zero, since I’ve never owned one, but the Pi2/3 can be booted with mediacenter disabled.
I think I finally figured what you were suggesting. So I disabled mediacenter in systemd. Then, I rebooted. This time I ssh’ed and enabled bootlist manually and checked status. Lo and behold, I come to my real source of problem.
bootlist.py[823]: File "/home/osmc/bootlist.py", line 267, in <module>
bootlist.py[823]: lib.InitLibCec()
bootlist.py[823]: File "/home/osmc/bootlist.py", line 98, in InitLibCec
bootlist.py[823]: stdscr = curses.initscr()
bootlist.py[823]: File "/usr/lib/python2.7/curses/__init__.py", line 33, in initscr
bootlist.py[823]: fd=_sys.__stdout__.fileno())
bootlist.py[823]: _curses.error: setupterm: could not find terminal
Here is my bootlist service. It is a ripoff from mediacenter but I think the terminal is not setup for curses. Is there a service that bootlist should run after which would set up the terminal? Or is there an alternative graphical interface to curses for me to show a menu for the user to select from?
[Unit]
Description = media center application
After = remote-fs.target network-online.target mysql.service mariadb.service
Wants = network-online.target
[Service]
Type = simple
TimeoutStopSec = 20
ExecStart = /home/osmc/bootlist.py >/home/osmc/out.log 2>/home/osmc/err.log
Restart = on-abort
[Install]
WantedBy = multi-user.target
I tried these two variable exports and still status reports same error at current time.
export TERM=linux
export TERMINFO=/lib/terminfo
Just a quick guess but during startup the TV will probably act like the system console, so the device will be something like /dev/console or perhaps /dev/tty0. (The system journal contains the line console [tty0] enabled, FYI.)
Nice suggestion. I was able to throw some text to my TV screen from my SSH session using
echo TextHere > /dev/tty0
I need to now figure out how to get curses to default to /dev/tty0 if it fails to initialize otherwise. Will keep you posted!
So, here is an update. Here is the command in bootlist.service. When I run it from my SSH session, it works perfectly throwing up the menu on my TV and responding to the remote but when I run sudo systemctl start bootlist curses is unable to find terminal. I think there is something in the service configuration that is preventing it from detecting /dev/tty0. Any ideas?
/home/osmc/bootlist.py >/dev/tty0 2>&1
Looks like you’re sending it stdout, which with systemd is probably the sys journal.
I’m out of time for today, but check here, with regard to StandardOutput=
Finally, got it working. From elsewhere, got to know that systemd doesnt understand redirection. So, here is the working service file. No need of any env variables. Thanks a bunch @dillthedog
[Unit]
Description = media center application
After = remote-fs.target network-online.target mysql.service mariadb.service
Wants = network-online.target
[Service]
Type = simple
TimeoutStopSec = 20
ExecStart = /home/osmc/bootlist.py
StandardInput = tty
StandardOutput = tty
TTYPath = /dev/tty0
Restart = on-abort
[Install]
WantedBy = multi-user.target
We unbind FB on Kodi start to save memory and restore in watchdog
Thanks for the info…my code shouldnt be messing with Kodi rite since the redirection will be dead anyways once my code exits after starting mediacenter