Hi,
I am evaluating DietPi to solve a problem that has happened since the Pi3 was released.
If you run a python program at startup from /etc/rc.local that reads the keyboard you get a crash:
oldterm = termios.tcgetattr(fd)
termios error: (25, ‘inappropriate ioctl for device’)
This did not happen with the Pi2 operating system but does with the Pi3(Pixel) and DietPi.
Is there a way to run the following program automatically at startup without it crashing?
Thanks,
David Taylor
#!/usr/bin/python
#
# startup.py
import os, sys, time
import termios, fcntl
def GetKey():
fd = sys.stdin.fileno()
oldterm = termios.tcgetattr(fd)
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~TERMIOS.ICANON & ~TERMIOS.ECHO
newattr[6][TERMIOS.VMIN] = 1
newattr[6][TERMIOS.VTIME] = 0
termios.tcsetattr(fd, termios.TCSANOW, newattr)
oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
try:
try:
c = sys.stdin.read(1)
# print "Got character", repr(c)
return c
except IOError: pass
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
if __name__ == "__main__":
# give us a chance to quit before launching
print '### Press q to prevent launch or any other key to launch ###'
bLaunch = True
TERMIOS = termios
i = 0
z = 5
while i < z:
print z - i,
i = i + 1
ch = GetKey()
if ch != None:
if ch == 'q':
print
print 'Launch has been stopped by pressing ' + ch
bLaunch = False
break
time.sleep(1)
if bLaunch == True:
print
print "Launch the main loop here"
exit(0)
Thanks for your very useful reply.
What I actually did was add the missing line
StandardInput=tty
to /etc/systemd/system/rc-local.service
and now my python program starts up correctly from rc.local as it always did before “Pixel”.
I checked in the Pixel os but it does not have a /etc/systemd/system/rc-local.service file or a /etc/systemd/system/python.service file so I could not apply the fix to it so I will stay with DietPi.
I am running my home central heating with the pi and find that SD cards do not last long. I am downloading weather data and other stuff regularly so am stressing the SD I think. As these files are temporary could I be loading them into RAM memory instead? If so, what folder should I save them to?
Hi again,
I was a bit hasty when I said that this problem is fixed.
When run as I described by adding the missing line
StandardInput=tty
to /etc/systemd/system/rc-local.service
keyboard presses get displayed but my python program is not seeing them. What actually happens is that my key presses are seen by the login.
When run using the python.service you suggested it starts up really early in the boot sequence then just dies.
Is it possible to automatically start a python program (that reads the keyboard) right at the end of the boot sequence after everything else has completed?
/etc/rc.local uses systemD service Type=idle. This will be launched after SystemD has finished all bootup services. So you could try idle and add After=rc.local
When run using the python.service you suggested it starts up really early in the boot sequence then just dies.
Service type is oneshot. So SystemD will launch the python script and wait until it exits, before carrying on. You could try Type=simple which will thread this into the background.
Another way to delay start of script, add a simple sleep 10 to the start of python code.
Thanks for your reply. I’ve tried these suggestions but am getting nowhere. I just don’t have enough Linux knowledge.
Having created DietPi you clearly like a challenge so if you can get the startup.py program I posted earlier to start and work from /etc/rc.local without crashing then I will make a generous donation to the DietPi cause of $100. It might be a simple thing or it might take you a while but as a hint, it worked perfectly well in the standard Raspian as supplied with all pi before pi3.
All the very best and in anticipation of success…
David
Ok, so the main issue with trying to run this under rc.local, as Type=idle runs a background process, keyboard inputs will not go to your python script currently, or, take foreground blocking mode.
We’ll need to modify rc-local.service slightly, to launch prior to end of SystemD multi-user.target, instead of Type=idle
Then, we create a service for your python script /root/test.py, with support for foreground process and blocking mode (Type=oneshot) and keyboard input (StandardInput=tty):
I created a fresh DietPi SD card, ran your scripts and added my test.py program. In test.py I set z = 50 to give a 50 second countdown and added an led flash every second so I could see that the program was running. I then rebooted.
During the boot my program started running, counted down for about 5 seconds then stopped and the login appeared.
After I logged in I got the # prompt.
All I need now is for my test.py program to keep running and have the focus until I press a key to stop it. Then, when test.py has exited I need the login to appear. That should be possible shouldn’t it?
Currently, test.py is being executed, then it finishes once you press a key, or, i reaches 5. As the script is finished, the login prompt appears.
You’ll need to create a loop in your python code, that waits for user input without a time limit, before the script finishes.
I dont do Python, so syntax may be incorrect, but something like this should do it:
while True:
ch = GetKey()
if ch != None:
if ch == 'q':
print
print 'Launch has been stopped by pressing ' + ch
bLaunch = False
break
time.sleep(1)
exit(0)
add a new option to function Run_Autostart - insert this before #Uae4arm standard boot
#standard boot to Console with automatic login
elif (( $AUTO_START_INDEX == 7 )); then
Run_User_AutoStart
modify #Normal Login to this:
#----------------------------------------------------------------
#Normal Login
if (( $DIETPI_INSTALL_STAGE == 1 )); then
/DietPi/dietpi/dietpi-banner 1
if (( $AUTO_START_INDEX > 0 )); then
Run_AutoStart
else
Run_User_AutoStart
fi
#----------------------------------------------------------------
save /DietPi/dietpi/login
create file /root/autostart.sh similar to this one:
#!/bin/bash
#////////////////////////////////////
# DietPi autostart Script
#
#////////////////////////////////////
# Created by David Taylor / superdave156@gmail.com
#
#////////////////////////////////////
#
# Info:
# - filename /root/autostart.sh
# - activated when DietPi-config item 9 (Autostart Options) then items 0 or 7 selected.
# - Allows you to autostart your own Python program with full keyboard support - unlike Pixel!
#////////////////////////////////////
#
#////////////////////////////////////
# Add your own autostart commands here:
#for example
sudo chmod 755 /root/Python/test.py
/usr/bin/python /root/Python/test.py
exit 0
That’s it!
If you have the boot configured to “Console: Manual Login” then you have to login then autostart.sh runs
If you have the boot configured to “Console: Automatic Login” then autostart.sh runs and you have a headless autostarting python program. Because the keyboard is available you can break into the program loop to work on the code.
To add this feature to DietPi all you would need to do is apply the above mods with the python lines commented out of autostart.sh and put test.py into /root/Python.
Then anyone who wants to run a python program at startup can use test.py as a base.