How can I launch a script in a terminal window from a service

I have two scripts which together allow me to receive and answer phone calls over serial. The first is what I want to run as a service in the background it checks if there is a RING signal and if there is then open a terminal window with the second script running.

They both use python3, the first script is:

while True:
if (ser.inWaiting() > 0):
    x = ser.readline()
    if (x == b'RINGrrn'):
        os.system("gnome-terminal -- python3 /home/user/answer.py")
        exit()

The main part of the second is:

    os.system("clear")
    print("Incoming Call")
    PU = input("Press Enter To Pick Up")
    send_at('ATA' + ';','OK',1)
    os.system("clear")
    print("ON CALL")
    HU = input("Press Enter To Hang Up")
    send_at("AT+CHUPrn" + ';','OK',1)
    os.system("clear")
    print('Call Ended')
    time.sleep(3)
    os.system("clear")
    os.system("gnome-terminal -- python3 /home/user/ring.py")
    os.system("exit")

If I run the first in an open terminal just as "python3 ring.py" it works fine but leaves me with a constant open terminal.

What I want is to run Ring.py as a service or a background process that just launches Answer.py as it’s called.

I tried using a .service file, enabled and started it, htop showed that it was running Ring.py but it wouldn’t launch Answer.py in a terminal window. There’s no error code it just doesn’t show up.

This is the service file:

[Unit]
Description=Detect Incoming Calls

[Service]
Type=simple
User='my username'
ExecStart= /usr/bin/python3 /home/user/Ring.py
Restart=always

[Install]
WantedBy=multi-user.target

How can I get this to work the way I want? Or what am I doing wrong?

Asked By: Nareik Seivad

||

gnome-terminal is a user GUI application and it requires a display server user session up and running first and then, the service launching it will require certain environment variables set and/or proper authentication/permissions granted.

You can specify those environment variables in a system service by for example setting the address to the display server, but that can change and you might need to set it again and there is more to launching a GUI user application from systemd than just specifying those variables, so this is not recommended and a user service is the way to go IMO.

Therefore, you need to setup your service as a user-service in order to interact with your user-session environment by default as the environment variables like $DISPLAY will be automatically inherited by a user service.

To do that you need to, first, place your unit/service file either under /usr/lib/systemd/user/ or under ~/.config/systemd/user/ in your user’s home.

Then, inform systemd about it without needing to reboot like so:

systemctl --user daemon-reload

Then, enable and start and manage it with the --user flag and without sudo like so:

systemctl --user enable unit-name

And:

systemctl --user start unit-name

You will always need to use the --user flag to manage it from now on … for example:

systemctl --user status unit-name

Or:

systemctl --user restart unit-name

Or:

systemctl --user stop unit-name

Notice:

You don’t need to specify a user/group for the user service as it will run as your current logged-in user by default.

You might, also, want to change Restart=always to Restart=on-failure to avoid running multiple instances of your script if status reporting is not set from your script as it appears.

You might, as well, want to change WantedBy=multi-user.target under [Install] section to WantedBy=default.target or similar graphical user target.

Answered By: Raffa