Run a python program at startup with keyboard support

Suggestions for features and software you would like to see in DietPi, goes here.

Run a python program at startup with keyboard support

Postby superdave156 » Mon Mar 13, 2017 7:39 am

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

Code: Select all
#!/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)
superdave156
 
Posts: 6
Joined: Mon Mar 13, 2017 7:16 am

Re: Run a python program at startup with keyboard support

Postby Fourdee » Mon Mar 13, 2017 1:55 pm

Hi David,

You need to enable StandardIntput=tty in your service, to allow for keyboard input.

Try systemD service that allows for std tty input and output:
Change /root/test.py accordingly, then copy/paste all
Code: Select all
cat << _EOF_ > /etc/systemd/system/python.service
[Unit]
Description=Python
After=local-fs.target network.target

[Service]
Type=oneshot
RemainAfterExit=yes
StandardOutput=tty
StandardInput=tty
ExecStart=/usr/bin/python /root/test.py

[Install]
WantedBy=multi-user.target
_EOF_
systemctl enable python.service
systemctl daemon-reload
If you find our project or support useful, then we’d really appreciate it if you’d consider contributing to the project however you can.
Donating is the easiest – you can use PayPal and Bitcoin.
User avatar
Fourdee
Site Admin
 
Posts: 2062
Joined: Tue Feb 06, 2007 12:36 pm

Re: Run a python program at startup with keyboard support

Postby superdave156 » Mon Mar 13, 2017 10:40 pm

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?

Thanks and all the best,
David
superdave156
 
Posts: 6
Joined: Mon Mar 13, 2017 7:16 am

Re: Run a python program at startup with keyboard support

Postby superdave156 » Tue Mar 14, 2017 1:48 pm

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?

Thanks again,
David
superdave156
 
Posts: 6
Joined: Mon Mar 13, 2017 7:16 am

Re: Run a python program at startup with keyboard support

Postby Fourdee » Tue Mar 14, 2017 4:12 pm

superdave156 wrote:

Hi David,

/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.
If you find our project or support useful, then we’d really appreciate it if you’d consider contributing to the project however you can.
Donating is the easiest – you can use PayPal and Bitcoin.
User avatar
Fourdee
Site Admin
 
Posts: 2062
Joined: Tue Feb 06, 2007 12:36 pm

Re: Run a python program at startup with keyboard support

Postby superdave156 » Thu Mar 16, 2017 11:20 am

Hi again,

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
superdave156
 
Posts: 6
Joined: Mon Mar 13, 2017 7:16 am

Re: Run a python program at startup with keyboard support

Postby Fourdee » Thu Mar 16, 2017 2:45 pm

superdave156 wrote:Hi again,

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

I do enjoy a challenge :)

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
Code: Select all
cat << _EOF_ > /etc/systemd/system/rc-local.service
[Unit]
Description=/etc/rc.local Compatibility
After=dietpi-boot.service dietpi-ramdisk.service dietpi-ramlog.service multi-user.target
Requires=dietpi-boot.service dietpi-ramdisk.service

[Service]
Type=oneshot
ExecStart=/etc/rc.local
StandardOutput=tty
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
_EOF_
systemctl enable rc-local.service
systemctl daemon-reload


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):
Code: Select all
cat << _EOF_ > /etc/systemd/system/python.service
[Unit]
Description=Python start + foreground + keyboard input. After rc-local
Requires=multi-user.target
After=multi-user.target rc-local.service
AllowIsolate=yes

[Service]
Type=oneshot
RemainAfterExit=yes
StandardOutput=tty
StandardInput=tty
ExecStart=/usr/bin/python /root/test.py

[Install]
WantedBy=multi-user.target
_EOF_
systemctl daemon-reload
systemctl enable python.service


Make sure your script is in /root/test.py, then reboot system.
If you find our project or support useful, then we’d really appreciate it if you’d consider contributing to the project however you can.
Donating is the easiest – you can use PayPal and Bitcoin.
User avatar
Fourdee
Site Admin
 
Posts: 2062
Joined: Tue Feb 06, 2007 12:36 pm

Re: Run a python program at startup with keyboard support

Postby superdave156 » Sat Mar 18, 2017 9:24 pm

Thanks for this. It is almost what I need...

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?

Thanks for your help,
Dave
superdave156
 
Posts: 6
Joined: Mon Mar 13, 2017 7:16 am

Re: Run a python program at startup with keyboard support

Postby Fourdee » Sun Mar 19, 2017 2:22 pm

superdave156 wrote: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?

Hi Dave,

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:
Code: Select all
   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)
If you find our project or support useful, then we’d really appreciate it if you’d consider contributing to the project however you can.
Donating is the easiest – you can use PayPal and Bitcoin.
User avatar
Fourdee
Site Admin
 
Posts: 2062
Joined: Tue Feb 06, 2007 12:36 pm

Re: Run a python program at startup with keyboard support

Postby superdave156 » Mon Mar 20, 2017 10:25 pm

Hi again,

Unfortunately that didn't make any difference however I have figured it out for myself and I think my solution would be a great feature for DietPi.

Here's what I did:

modify /DietPi/dietpi/login

add a new function - I inserted it just ahead of Run_Autostart()
Code: Select all
   #Autostart user's script
   Run_User_AutoStart(){
      sudo chmod 755 /root/autostart.sh
      ./autostart.sh
   }

add a new option to function Run_Autostart - insert this before #Uae4arm standard boot
Code: Select all
         #standard boot to Console with automatic login
         elif (( $AUTO_START_INDEX == 7 )); then
            Run_User_AutoStart

modify #Normal Login to this:
Code: Select all
   #----------------------------------------------------------------
   #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:
Code: Select all
#!/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.

What do you think?

Dave
superdave156
 
Posts: 6
Joined: Mon Mar 13, 2017 7:16 am


Return to Requests

Who is online

Users browsing this forum: No registered users and 1 guest