How to run Python script in background on boot successfully?

#! /usr/bin/python

import glib
import re
import subprocess
import requests
import bs4
import datetime
import sys
import os
import time
from selenium import webdriver
from pyudev import Context, Monitor
from selenium.common.exceptions import NoSuchElementException


def demote():
    def result():
    	os.setgid(100)
        os.setuid(1000)
    return result


def inotify(title, message):
	subprocess.call('notify-send', '{}
'.format(title), '{0}
'.format(message)], preexec_fn=demote())
	#os.system('notify-send ' + title + ' ' + message)


def get_network_data(tout):
	"""Scrapes balance data from ISP website."""


	if tout is not None:
		driver = webdriver.PhantomJS()
		driver.set_window_size(1120, 550)
		driver.get('http://mydata.myisp.co.ke')
		try:
			acc = driver.find_element_by_id('account')
			tbody = acc.find_element_by_tag_name('tbody')
		
			match_obj = re.findall(r'(\w\s]+)\:\s(\d\s\.\-]+\w]{0,3})\s
](\w\s]+)\:\s(\d\s\.\-]+\w]{0,3})\s
]', tbody.text)
			if match_obj is not None:
				data = {}
				for item in match_obj:
					data.update(dict(zip(*[iter(item)]*2)))


				expiry_date = datetime.datetime.strptime(data'Expire Date'], '%Y-%m-%d')
				remaining = expiry_date - datetime.datetime.now()
				bundle_balance = 'Bundle balance: {0} - {1} day(s) remaining'.format(data'Bundle Balance'], remaining.days)
				airtime_balance = 'Airtime balance: %s' % data'Current Airtime Balance']
				time_now = datetime.datetime.now().strftime('%H:%-M %Y/%m/%d')
				print('Sending nofitication...')
				imon = open('/home/Giantas/bin/monitori.txt', 'a+')
				imon.write(time_now + '
' + bundle_balance + '
' + airtime_balance + '

')
				imon.close()
				full_msg = '{0}
{1}'.format(bundle_balance.capitalize(), airtime_balance.capitalize())
				inotify('Orange Balance', full_msg)
				#subprocess.call('notify-send', 'Orange Balance', '
{0}
{1}'.format(bundle_balance.capitalize(), airtime_balance.capitalize())], preexec_fn=demote())


			else:
				print('Could not retrieve data from page...')
				full_msg = '{0}'.format('Error: Could not retrieve data from page.')
				inotify('Orange Balance', full_msg)
				#subprocess.call('notify-send', 'Orange Balance', '
{0}'.format('Error: Could not retrieve data from page.')], preexec_fn=demote())


		except NoSuchElementException:
			print('Could not locate element...')
			full_msg = '{0}'.format('Error: Could not locate element - acc.')
			inotify('Orange Balance', full_msg)
			#subprocess.call('notify-send', 'iMonitor:get_network_data', '
{0}'.format('Error: Could not locate element - acc.')], preexec_fn=demote())
		
	else:
		print('Could not find USB device...')
		full_msg = '
{0}'.format('Error: Could not find USB device.')
		inotify('Orange Balance', full_msg)
		#subprocess.call('notify-send', 'iMonitor', '
{0}'.format('Error: Could not find USB device.')], preexec_fn=demote())


def identify_phone(observer, device):
	"""Identifies if specific USB device (phone) is connected (tethered)."""


	global last_updated, initial_search, msg_count
	
	current_time = datetime.datetime.now()
	time_diff = current_time - last_updated


	if (time_diff.seconds > 300) or initial_search:
		try:
			time.sleep(0.25)
			tout = subprocess.check_output("lsusb | grep 1234:5678", shell=True)
		except subprocess.CalledProcessError:
			tout = None


		last_updated = datetime.datetime.now()
		initial_search = False


		get_network_data(tout)
		
	if time_diff.seconds > 10:
		msg_count = 1


	if not initial_search and msg_count == 1:
		wait_time = datetime.datetime.fromtimestamp(600 - time_diff.seconds)
		message = wait_time.strftime('You may have to wait %-M minute(s), %-S second(s) before another check is done.')
		print('Could not retrieve data from page...')
		full_msg = '
{0}'.format(message)
		inotify('Orange Balance', full_msg)
		#subprocess.call('notify-send', 'iMonitor:Identify Phone', '
{0}'.format(message)], preexec_fn=demote())
		msg_count += 1


try:
	initial_search = True
	last_updated = datetime.datetime.now()
	msg_count = 1
	try:
	    from pyudev.glib import MonitorObserver


	except ImportError:
	    from pyudev.glib import GUDevMonitorObserver as MonitorObserver


	context = Context()
	monitor = Monitor.from_netlink(context)


	monitor.filter_by(subsystem='usb')
	observer = MonitorObserver(monitor)


	observer.connect('device-added', identify_phone)
	monitor.start()


	glib.MainLoop().run()


except KeyboardInterrupt:
	print('
Shutdown requested.
Exiting gracefully...')
	sys.exit(0)

I have the above script. I would like it to run on boot such that when I tether my phone to my PC I get a desktop notification. I have created a service in /etc/systemd/system/ named *imon.service *with the following configuration

[Unit] 
Description=ImonService 

[Service] 
ExecStart=/path/to/imonitor.py 

[Install] 
WantedBy=multi-user.target 



However, since the script runs as root, I am having a hard time getting it to display a desktop notification to a user logged in via GUI.
Any help would be appreciated.

Other relevant data:
KDE Plasma Version: 5.5.5
OpenSUSE Leap 42.1

Your subject is extremely poor chosen. Your question is unrelated to either Python or background or boot.

Back to your actual question - there is no generic mechanism. For a start, the obvious counter question is - **which **user? Linux is multi-user and there may be multiple users logged in concurrently.

Assuming you somehow decided how to select user - there is no generic mechanism to send notifications between different sessions (I’d love to be proven wrong). Existing “standards” deal with single session only. And implementations of these standards require valid DISPLAY (although strictly speaking nothing in protocol requires it). So I was able to send notification from root to user desktop using “DISPLAY=xxx notify-send bla-bla”. Challenge is to find out DISPLAY value. On systemd based systems you probably can query logind for current sessions and it will also show you display session is running on. Otherwise you are really on your own.

This is not Python code, and that’s where my code falls in. I have posted the pertinent script showing how I have implemented desktop notifications. The script is launched automatically by the imon*.service* hence it runs at **boot **using root user. Furthermore, you can see it’s headless, thus, should run in the **background. However, the desktop notifications need to be viewed by the user (who is logged in through the GUI), only the current user ie the active user in the active session.
Do not take the question literally. There is the real purpose I am intending. I do not get what the fuss is about the way the question is framed when it is a really simple question How to display desktop notifications to me/the logged in user/human user/something I can see? I do not get what is up OpenSUSE forum moderators. If you can’t answer a newbie then perhaps you should question your purpose in moderating.
Kindly help me solve my problem, or refer me to someone who can, before telling me how to phrase the question. As you can see I have no problem with my English, just my usage of terms in Linux - I am a ** newbie.

@giantas.

Please take note: until now I tried to answer and help you as a member, not as a moderator.
The following is however in my guise as moderator.

You may think that your question is simple, that does not mean that the answer is simple. Several members here have tried to bring the message that a solution is not obvious and may even be not possible. That was done in another thread and here also.

You seem to be frustrated because you think there is an easy and obvious solution, but nobody wants to understand you. This is is not the case. Do not utter that frustration to your fellow openSUSE users. They try to help people as good as they can. When you do not act cooperative to their trials to help you, they will most probably ignore you further. I do not think that will help you.

You also mention times and again that you are new to Linux. Please then come to the conclusion that as several long time Unix/Linux users tell you that what you want is not easy/obvious to be done, you should believe them. IMHO that is why you are here, to learn from others.

On 2017-03-19, giantas <giantas@no-mx.forums.microfocus.com> wrote:
> I do not get what is the fuss about the way the question is framed when
> it is a really simple question How to display desktop notifications to
> me/the logged in user/human user/something I can see?

So let’s clarify. You want to Python script to run as root continuously in the background as a service upon boot. And
when that script detects a certain event, you want it send a GUI notification to all GUI-logged-in regular users? Please
let us know if this is all correct or if there’s anything else?

> I do not get what is up OpenSUSE forum moderators. If you can’t answer a newbie then perhaps you should question your
> purpose in moderating.

In general, it’s not a good idea to challenge forum moderators. But it’s never a good idea to challenge people who are
only trying to help you on a voluntary basis when they can find time. If you are a GNU/Linux newbie, please understand
there are likely to be aspects of what you consider to be a `simple question’ to be much more complicated than you may
initially realise.

OK, so this settles “which user”. Now you just need to find out active session and display it runs on. On current openSUSE (as you are posting in openSUSE forum) you can get it from logind. You can either parse loginctl output or use D-Bus Python binding to query logind directly. systemd site contains D-Bus interface specification.

Yes, that is exactly what I meant.
To the issue of moderators, am just sickened with hcvv’s style of moderation which involves asking “why do you think…”, “isn’t it stupid”, etc. Instead, a person (whether newbie or not) ought to be answered in the form “you question has many caveats to it: (1)Linux recognises … (2) Your script… As such you ought to provide more information or research on this, this and this”. I was more infuriated by the form of the answers.

@hcvv @flymail this is the sort of answer I expect from a moderator. Tell me what to look at. Give me information I should search on so as to fill in the “missing perpectives”.

@ arvidjaar thank you. I will check it out https://forums.opensuse.org/images/icons/icon14.png

My apologies for my misconduct. However, I still fail to understand why you cannot provide the “why?” as to how it is not simple. It is @arvidjaar’s answer which has provided this. Perhaps you may have more to add on.

PS: suggestions work better than questions

On 2017-03-22, giantas <giantas@no-mx.forums.microfocus.com> wrote:
>
> flymail;2816936 Wrote:
>> So let’s clarify. You want to Python script to run as root continuously
>> in the background as a service upon boot. And
>> when that script detects a certain event, you want it send a GUI
>> notification to all GUI-logged-in regular users? Please
>> let us know if this is all correct or if there’s anything else?

> Yes, that is exactly what I meant.

I suspect this is not easy. Probably the simplest way to do this is running your Python script through systemd as a
daemon. I strongly suspect you will need to modify the Python code extensively to explicity code GUI notification (e.g.
using https://developer.gnome.org/libnotify/ ) as well as for looking up logged in users (e.g. using
https://pypi.python.org/pypi/psutil ). Depending on the nature and function (and desired frequency) of the notification,
another possible route is running the Python script as a cron job ( https://en.opensuse.org/SDB:Cron ).

I made a cronjob for my normal user. Good thing is it runs the script as the normal user. However, the script does not seem to function at all. I had added a section that would write to a file, which would work even if the desktop notification did not display, but it does not even write to the file.

Am getting

If 'logind' is not a typo you can use command-not-found to lookup the package that conta
ins it, like this: 
   cnf logind


On 2017-03-24, giantas <giantas@no-mx.forums.microfocus.com> wrote:
> I made a cronjob for my normal user. Good thing is it runs the script as
> the normal user. However, the script does not seem to function at all. I
> had added a section that would write to a file, which would work even if
> the desktop notification did not display, but it does not even write to
> the file.

If the script doesn’t run from cron, I suspect it will also not run from systemd on startup. There might be code in your
Python script that generates an error when run from a latent terminal (such as from cron). You need to check the the
terminal log file outputted from cron for this. I can’t remember which log path openSUSE defaults to (I don’t think
it’s /var/log/messages).