pythoncronenv

python-notify module & cron: gio.Error


I'm asking some help to show notifications using python-crontab, because everything I've tried do not work. The display is not initilised when the script is launched by cron. When I start it manually, that's work. The codes I've tried:

    #!/usr/bin/env python
    # coding: utf8

    import subprocess
    import os

    #os.environ.setdefault("XAUTHORITY", "/home/guillaume" + "/.Xauthority")

    #os.environ.setdefault('DISPLAY', ':0.0')     # do not work
    #os.environ['DISPLAY'] = ':0.0'               # do not work
    print = os.environ

    cmd2 = 'notify-send test'
    subprocess.call(cmd2, shell=True)

    # more code, which is working (using VLC)
    cmd3 = "cvlc rtp://232.0.2.183:8200 --sout file/mkv:/path/save/file.mkv" # to download TV's flow
    with open("/path/debug_cvlc.log", 'w') as out:
        proc = subprocess.Popen(cmd3, stderr=out, shell=True, preexec_fn=os.setsid)
    pid = proc.pid                  # to get the pid
    with open("/path/pid.log", "w") as f:
       f.write(str(pid))            # to write the pid in a file
    # I'm using the pid to stop the download with another cron's task, and to display another notify message. 
    # Download and stop is working very well, and zenity too. But not notify-send

Thanks

Edit: here are the environment variables I have for this cron's script:

{'LANG': 'fr_FR.UTF-8', 'SHELL': '/bin/sh', 'PWD': '/home/guillaume', 'LOGNAME': 'guillaume', 'PATH': '/usr/bin:/bin', 'HOME': '/home/guillaume', 'DISPLAY': ':0.0'}

Edit2: I'm calling my script in cron like this:

45 9 30 6 * export DISPLAY=:0.0 && python /home/path/script.py > /home/path/debug_cron_on.log 2>&1

I precise I have two screens, so I think DISPLAY:0.0 is the way to display this notify.. But I don't see it.

Edit3: It appears that I've a problem with notify-send, because it's working using zenity:

subprocess.call("zenity --warning --timeout 5 --text='this test is working'", shell=True)

I have notify-send version 0.7.3, and I precise that notify-send is working with the terminal.

Edit4: Next try with python-notify.

import pynotify
pynotify.init("Basic")
n = pynotify.Notification("Title", "TEST")
n.show()

The log file show this: (in french)

    Traceback (most recent call last):
      File "/home/path/script.py", line 22, in <module>
        n.show()
    gio.Error: Impossible de se connecter : Connexion refusée 
 #Translating: Unable to connect : Connection refused

So, I have problem with dbus? what is this?

Solution: Get the DBUS_SESSION_BUS_ADDRESS before creating the cron order:

cron = CronTab()
dbus = os.getenv("DBUS_SESSION_BUS_ADDRESS")   # get the dbus
# creating cron  
cmd_start = "export DBUS_SESSION_BUS_ADDRESS=" + str(dbus) + " && export DISPLAY=:0.0 && cd /path && python /path/script.py > path/debug_cron.log 2>&1"
job = cron.new(cmd_start)
job = job_start.day.on(self.day_on) # and all the lines to set cron, with hours etc..
cron.write()             # write the cron's file

Finally, the cron's line is like that:

20 15 1 7 * export DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-M0JCXXbuhC && export DISPLAY=:0.0 && python script.py

Then the notification is displaying. Problem resolved !! :)


Solution

  • You are calling the cron like

    45 9 30 6 * DISPLAY=:0.0 python /home/path/script.py > /home/path/debug_cron_on.log 2>&1
    

    which is incorrect, since you are not exporting the DISPLAY variable, and the subsequent command does not run.

    Try this instead

    45 9 30 6 * export DISPLAY=:0.0 && cd /home/path/ && python script.py >> debug_cron.log 2>&1
    

    Also, you are setting the DISPLAY variable within your cron job as well, so try if the cron job works without exporting it in the job line

    45 9 30 6 * cd /home/path/ && python script.py >> debug_cron.log 2>&1
    

    EDIT

    While debugging, run the cron job every minute. Following worked for me:

    Cron entry

    * * * * *  cd /home/user/Desktop/test/send-notify && python script.py
    

    script.py

    #!/usr/bin/env python
    
    import subprocess
    import os
    
    os.environ.setdefault('DISPLAY', ':0.0')
    print os.environ
    
    cmd2 = 'notify-send test'
    subprocess.call(cmd2, shell=True)
    

    EDIT 2

    Using pynotify, script.py becomes

    #!/usr/bin/env python
    
    import pynotify
    import os
    
    os.environ.setdefault('DISPLAY', ':0.0')
    
    pynotify.init("Basic")
    n = pynotify.Notification("Title", "TEST123")
    n.show()
    

    and cron entry becomes

    * * * * *  cd /home/user/Desktop/test/send-notify && python script.py
    

    EDIT 3

    One environment variable DBUS_SESSION_BUS_ADDRESS is missing from the cron environment. It can be set in this and this fashion