1

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 !! :)

Guillaume
  • 2,752
  • 5
  • 27
  • 42
  • 1
    Try re-installing `libnotify4` Check [this](https://bugs.launchpad.net/ubuntu/+source/libnotify4/+bug/748159). – Anshul Goyal Jul 01 '14 at 09:59
  • I tried to re-install dbus, libnotify4 but nothing happens... Thank you, it seems to be a bug from my Ubuntu's install. – Guillaume Jul 01 '14 at 10:12
  • I've found a question [here](http://stackoverflow.com/questions/5623289/pynotify-runs-fine-interactively-but-crashes-when-run-programmatically-on-fedo) but the solution doesn't works for me. Damned! – Guillaume Jul 01 '14 at 12:25
  • 1
    Is the dbus daemon up for you? Check `sudo service dbus status` and also check the value of `echo $DBUS_SESSION_BUS_ADDRESS` from within the script, and see if it is different from your shell's environment value. In general, cron runs with a reduced environment set, so it is quite possible for some environment variable to be missing from your cron environment. Since I'm using ubuntu, and you are on kubuntu, I think this should be the cause. – Anshul Goyal Jul 01 '14 at 12:33
  • Anyway, I found a solution ! The notify is working when I add: `os.environ.setdefault("DBUS_SESSION_BUS_ADDRESS", "unix:abstract=/tmp/dbus-M0JCXXbuhC")`. But I think I will be working just for my computer, this is not a real solution for the others. Maybe using `try notify/except DBUS="unix:etc"` Edit: Sorry I have not seen your response – Guillaume Jul 01 '14 at 12:36
  • Yes, you're right. I have read the result of `echo $DBUS_SESSION_BUS_ADDRESS'` in a terminal. But when I try to read it in the script, there's an error. (don't remember the error) – Guillaume Jul 01 '14 at 12:39
  • Now that you have one working version, you can check [this](http://unix.stackexchange.com/a/28496/46799) and [this](http://stackoverflow.com/q/3302240/1860929) to access the dbus session variables generically on any unix system – Anshul Goyal Jul 01 '14 at 12:41
  • Ok, I've the solution and edited my question/response. Thank you very much to help me to solve this problem !! – Guillaume Jul 01 '14 at 13:35
  • Cool then. Don't forget to accept, upvote, and hand out the bounty :D – Anshul Goyal Jul 01 '14 at 13:35
  • No problem! In 16 hours I will do it. – Guillaume Jul 01 '14 at 13:40

2 Answers2

1

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

Community
  • 1
  • 1
Anshul Goyal
  • 73,278
  • 37
  • 149
  • 186
  • Thanks for your response, I have edited my question with the modification. But the notification don't appear any more. I've also tried to add `&& cd /home/path/` but no change. – Guillaume Jul 01 '14 at 08:00
  • @Guillaume which user's crontab do you use? Are you trying this locally, or on a remote server? This will only display the message if you do it locally for your logged in user's crontab. – Anshul Goyal Jul 01 '14 at 08:04
  • I'm trying to display locally, not on a server. But I've tried to display a message with zenity, and it's working. There's a problem with notify-send – Guillaume Jul 01 '14 at 08:23
  • @Guillaume I tried things locally, and it works for me. the script and cron entry are already there. I've `notify-send 0.7.6` – Anshul Goyal Jul 01 '14 at 08:30
  • Same version 0.7.6 on Kubuntu 14.04 for me -_-' ... Very weird – Guillaume Jul 01 '14 at 08:33
  • @Guillaume You will have to give the remainder of the script as well, I guess. Because, the part you have given already works for me after some changes. – Anshul Goyal Jul 01 '14 at 08:34
  • I've updated my question with all the code, but the end is working. I think I will use zenity, it's not very important... – Guillaume Jul 01 '14 at 08:52
  • @Guillaume Well if my answer/discussion helped, don't forget to accept and upvote this answer :) – Anshul Goyal Jul 01 '14 at 08:58
  • Ok, I'm waiting for few days and I will vote for you if nobody finds a real solution, thanks a lot for your help. – Guillaume Jul 01 '14 at 09:01
  • I think I have found the bug, (next edit in my question). Have you an idea? – Guillaume Jul 01 '14 at 09:29
  • @Guillaume this one also works for me. Check edits to my answer. I think you missed out the `DISPLAY` variable, check if adding that helps – Anshul Goyal Jul 01 '14 at 09:36
  • Same issue, and the DISPLAY var was called in the cron line. With `os.environ.setdefault('DISPLAY', ':0.0')` I've the same gio.Error – Guillaume Jul 01 '14 at 09:42
0

crontab is considered an external host -- it doesn't have permission to write to your display.

Workaround: allow anyone to write to your display. Type this in your shell when you're logged in:

xhost +
johntellsall
  • 14,394
  • 4
  • 46
  • 40
  • Thanks, so if I understand, no need the "os.environ" ? – Guillaume Jun 28 '14 at 17:30
  • either do `os.environ['DISPLAY']=':0'` in Python, or in the call: `subprocess.call('DISPLAY=:0 '+cmd2, shell=True)`. The latter relies on you running the Bash shell, but that's pretty common. – johntellsall Jun 28 '14 at 17:33
  • It don't work, here is the return of the log file: `access control disabled, clients can connect from any host`. But the notification don't display on the screen – Guillaume Jun 29 '14 at 14:39
  • hmm. Try the long form of `DISPLAY`, with the hostname/IP address and `:0`. See also http://askubuntu.com/questions/432255/what-is-display-environment-variable – johntellsall Jun 29 '14 at 17:27
  • same issue with `:0`, I have 2 screnns so I think `:0.0` is better. But with one screen, (I tried) nothing append... – Guillaume Jun 30 '14 at 07:41